diff --git a/.gitignore b/.gitignore index 0c39aa20b6ba8..70ba9aac4f968 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,12 @@ Module.symvers *.dwo *.su *.c.[012]*.* +arch/arm/boot/zImage-dtb +uImage +*.rej +build.log +u-boot/ +uboot/ # # Top-level generic files diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index f3d5817c4ef0f..258902db14bf1 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -373,3 +373,19 @@ Contact: Linux kernel mailing list Description: information about CPUs heterogeneity. cpu_capacity: capacity of cpu#. + +What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/meltdown + /sys/devices/system/cpu/vulnerabilities/spectre_v1 + /sys/devices/system/cpu/vulnerabilities/spectre_v2 +Date: January 2018 +Contact: Linux kernel mailing list +Description: Information about CPU vulnerabilities + + The files are named after the code names of CPU + vulnerabilities. The output of those files reflects the + state of the CPUs in the system. Possible output values: + + "Not affected" CPU is not affected by the vulnerability + "Vulnerable" CPU is affected and no mitigation in effect + "Mitigation: $M" CPU is affected and mitigation $M is in effect diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 05496622b4eff..8122b5f98ea1e 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2599,6 +2599,11 @@ nosmt [KNL,S390] Disable symmetric multithreading (SMT). Equivalent to smt=1. + nospectre_v2 [X86] Disable all mitigations for the Spectre variant 2 + (indirect branch prediction) vulnerability. System may + allow data leaks with this option, which is equivalent + to spectre_v2=off. + noxsave [BUGS=X86] Disables x86 extended register state save and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. @@ -3253,6 +3258,21 @@ pt. [PARIDE] See Documentation/blockdev/paride.txt. + pti= [X86_64] Control Page Table Isolation of user and + kernel address spaces. Disabling this feature + removes hardening, but improves performance of + system calls and interrupts. + + on - unconditionally enable + off - unconditionally disable + auto - kernel detects whether your CPU model is + vulnerable to issues that PTI mitigates + + Not specifying this option is equivalent to pti=auto. + + nopti [X86_64] + Equivalent to pti=off + pty.legacy_count= [KNL] Number of legacy pty's. Overwrites compiled-in default number. @@ -3893,6 +3913,29 @@ sonypi.*= [HW] Sony Programmable I/O Control Device driver See Documentation/laptops/sonypi.txt + spectre_v2= [X86] Control mitigation of Spectre variant 2 + (indirect branch speculation) vulnerability. + + on - unconditionally enable + off - unconditionally disable + auto - kernel detects whether your CPU model is + vulnerable + + Selecting 'on' will, and 'auto' may, choose a + mitigation method at run time according to the + CPU, the available microcode, the setting of the + CONFIG_RETPOLINE configuration option, and the + compiler with which the kernel was built. + + Specific mitigations can also be selected manually: + + retpoline - replace indirect branches + retpoline,generic - google's original retpoline + retpoline,amd - AMD-specific minimal thunk + + Not specifying this option is equivalent to + spectre_v2=auto. + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= diff --git a/Documentation/devicetree/bindings/hwmon/jc42.txt b/Documentation/devicetree/bindings/hwmon/jc42.txt index 07a250498fbb4..f569db58f64a1 100644 --- a/Documentation/devicetree/bindings/hwmon/jc42.txt +++ b/Documentation/devicetree/bindings/hwmon/jc42.txt @@ -34,6 +34,10 @@ Required properties: - reg: I2C address +Optional properties: +- smbus-timeout-disable: When set, the smbus timeout function will be disabled. + This is not supported on all chips. + Example: temp-sensor@1a { diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index 6ca6b9e582a0e..d740989eb5698 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -20,16 +20,16 @@ Required Properties: (CMT1 on sh73a0 and r8a7740) This is a fallback for the above renesas,cmt-48-* entries. - - "renesas,cmt0-r8a73a4" for the 32-bit CMT0 device included in r8a73a4. - - "renesas,cmt1-r8a73a4" for the 48-bit CMT1 device included in r8a73a4. - - "renesas,cmt0-r8a7790" for the 32-bit CMT0 device included in r8a7790. - - "renesas,cmt1-r8a7790" for the 48-bit CMT1 device included in r8a7790. - - "renesas,cmt0-r8a7791" for the 32-bit CMT0 device included in r8a7791. - - "renesas,cmt1-r8a7791" for the 48-bit CMT1 device included in r8a7791. - - "renesas,cmt0-r8a7793" for the 32-bit CMT0 device included in r8a7793. - - "renesas,cmt1-r8a7793" for the 48-bit CMT1 device included in r8a7793. - - "renesas,cmt0-r8a7794" for the 32-bit CMT0 device included in r8a7794. - - "renesas,cmt1-r8a7794" for the 48-bit CMT1 device included in r8a7794. + - "renesas,r8a73a4-cmt0" for the 32-bit CMT0 device included in r8a73a4. + - "renesas,r8a73a4-cmt1" for the 48-bit CMT1 device included in r8a73a4. + - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. + - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790. + - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791. + - "renesas,r8a7791-cmt1" for the 48-bit CMT1 device included in r8a7791. + - "renesas,r8a7793-cmt0" for the 32-bit CMT0 device included in r8a7793. + - "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793. + - "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794. + - "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794. - "renesas,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2. - "renesas,rcar-gen2-cmt1" for 48-bit CMT1 devices included in R-Car Gen2. @@ -46,7 +46,7 @@ Required Properties: Example: R8A7790 (R-Car H2) CMT0 and CMT1 nodes cmt0: timer@ffca0000 { - compatible = "renesas,cmt0-r8a7790", "renesas,rcar-gen2-cmt0"; + compatible = "renesas,r8a7790-cmt0", "renesas,rcar-gen2-cmt0"; reg = <0 0xffca0000 0 0x1004>; interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>, <0 142 IRQ_TYPE_LEVEL_HIGH>; @@ -55,7 +55,7 @@ Example: R8A7790 (R-Car H2) CMT0 and CMT1 nodes }; cmt1: timer@e6130000 { - compatible = "renesas,cmt1-r8a7790", "renesas,rcar-gen2-cmt1"; + compatible = "renesas,r8a7790-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>, <0 121 IRQ_TYPE_LEVEL_HIGH>, diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt index ce02cebac26af..464ddf7b509a5 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.txt +++ b/Documentation/devicetree/bindings/usb/usb-device.txt @@ -11,7 +11,7 @@ Required properties: be used, but a device adhering to this binding may leave out all except for usbVID,PID. - reg: the port number which this device is connecting to, the range - is 1-31. + is 1-255. Example: diff --git a/Documentation/x86/orc-unwinder.txt b/Documentation/x86/orc-unwinder.txt index af0c9a4c65a6d..cd4b29be29af1 100644 --- a/Documentation/x86/orc-unwinder.txt +++ b/Documentation/x86/orc-unwinder.txt @@ -4,7 +4,7 @@ ORC unwinder Overview -------- -The kernel CONFIG_ORC_UNWINDER option enables the ORC unwinder, which is +The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is similar in concept to a DWARF unwinder. The difference is that the format of the ORC data is much simpler than DWARF, which in turn allows the ORC unwinder to be much simpler and faster. diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt new file mode 100644 index 0000000000000..5cd58439ad2d6 --- /dev/null +++ b/Documentation/x86/pti.txt @@ -0,0 +1,186 @@ +Overview +======== + +Page Table Isolation (pti, previously known as KAISER[1]) is a +countermeasure against attacks on the shared user/kernel address +space such as the "Meltdown" approach[2]. + +To mitigate this class of attacks, we create an independent set of +page tables for use only when running userspace applications. When +the kernel is entered via syscalls, interrupts or exceptions, the +page tables are switched to the full "kernel" copy. When the system +switches back to user mode, the user copy is used again. + +The userspace page tables contain only a minimal amount of kernel +data: only what is needed to enter/exit the kernel such as the +entry/exit functions themselves and the interrupt descriptor table +(IDT). There are a few strictly unnecessary things that get mapped +such as the first C function when entering an interrupt (see +comments in pti.c). + +This approach helps to ensure that side-channel attacks leveraging +the paging structures do not function when PTI is enabled. It can be +enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time. +Once enabled at compile-time, it can be disabled at boot with the +'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt). + +Page Table Management +===================== + +When PTI is enabled, the kernel manages two sets of page tables. +The first set is very similar to the single set which is present in +kernels without PTI. This includes a complete mapping of userspace +that the kernel can use for things like copy_to_user(). + +Although _complete_, the user portion of the kernel page tables is +crippled by setting the NX bit in the top level. This ensures +that any missed kernel->user CR3 switch will immediately crash +userspace upon executing its first instruction. + +The userspace page tables map only the kernel data needed to enter +and exit the kernel. This data is entirely contained in the 'struct +cpu_entry_area' structure which is placed in the fixmap which gives +each CPU's copy of the area a compile-time-fixed virtual address. + +For new userspace mappings, the kernel makes the entries in its +page tables like normal. The only difference is when the kernel +makes entries in the top (PGD) level. In addition to setting the +entry in the main kernel PGD, a copy of the entry is made in the +userspace page tables' PGD. + +This sharing at the PGD level also inherently shares all the lower +layers of the page tables. This leaves a single, shared set of +userspace page tables to manage. One PTE to lock, one set of +accessed bits, dirty bits, etc... + +Overhead +======== + +Protection against side-channel attacks is important. But, +this protection comes at a cost: + +1. Increased Memory Use + a. Each process now needs an order-1 PGD instead of order-0. + (Consumes an additional 4k per process). + b. The 'cpu_entry_area' structure must be 2MB in size and 2MB + aligned so that it can be mapped by setting a single PMD + entry. This consumes nearly 2MB of RAM once the kernel + is decompressed, but no space in the kernel image itself. + +2. Runtime Cost + a. CR3 manipulation to switch between the page table copies + must be done at interrupt, syscall, and exception entry + and exit (it can be skipped when the kernel is interrupted, + though.) Moves to CR3 are on the order of a hundred + cycles, and are required at every entry and exit. + b. A "trampoline" must be used for SYSCALL entry. This + trampoline depends on a smaller set of resources than the + non-PTI SYSCALL entry code, so requires mapping fewer + things into the userspace page tables. The downside is + that stacks must be switched at entry time. + c. Global pages are disabled for all kernel structures not + mapped into both kernel and userspace page tables. This + feature of the MMU allows different processes to share TLB + entries mapping the kernel. Losing the feature means more + TLB misses after a context switch. The actual loss of + performance is very small, however, never exceeding 1%. + d. Process Context IDentifiers (PCID) is a CPU feature that + allows us to skip flushing the entire TLB when switching page + tables by setting a special bit in CR3 when the page tables + are changed. This makes switching the page tables (at context + switch, or kernel entry/exit) cheaper. But, on systems with + PCID support, the context switch code must flush both the user + and kernel entries out of the TLB. The user PCID TLB flush is + deferred until the exit to userspace, minimizing the cost. + See intel.com/sdm for the gory PCID/INVPCID details. + e. The userspace page tables must be populated for each new + process. Even without PTI, the shared kernel mappings + are created by copying top-level (PGD) entries into each + new process. But, with PTI, there are now *two* kernel + mappings: one in the kernel page tables that maps everything + and one for the entry/exit structures. At fork(), we need to + copy both. + f. In addition to the fork()-time copying, there must also + be an update to the userspace PGD any time a set_pgd() is done + on a PGD used to map userspace. This ensures that the kernel + and userspace copies always map the same userspace + memory. + g. On systems without PCID support, each CR3 write flushes + the entire TLB. That means that each syscall, interrupt + or exception flushes the TLB. + h. INVPCID is a TLB-flushing instruction which allows flushing + of TLB entries for non-current PCIDs. Some systems support + PCIDs, but do not support INVPCID. On these systems, addresses + can only be flushed from the TLB for the current PCID. When + flushing a kernel address, we need to flush all PCIDs, so a + single kernel address flush will require a TLB-flushing CR3 + write upon the next use of every PCID. + +Possible Future Work +==================== +1. We can be more careful about not actually writing to CR3 + unless its value is actually changed. +2. Allow PTI to be enabled/disabled at runtime in addition to the + boot-time switching. + +Testing +======== + +To test stability of PTI, the following test procedure is recommended, +ideally doing all of these in parallel: + +1. Set CONFIG_DEBUG_ENTRY=y +2. Run several copies of all of the tools/testing/selftests/x86/ tests + (excluding MPX and protection_keys) in a loop on multiple CPUs for + several minutes. These tests frequently uncover corner cases in the + kernel entry code. In general, old kernels might cause these tests + themselves to crash, but they should never crash the kernel. +3. Run the 'perf' tool in a mode (top or record) that generates many + frequent performance monitoring non-maskable interrupts (see "NMI" + in /proc/interrupts). This exercises the NMI entry/exit code which + is known to trigger bugs in code paths that did not expect to be + interrupted, including nested NMIs. Using "-c" boosts the rate of + NMIs, and using two -c with separate counters encourages nested NMIs + and less deterministic behavior. + + while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done + +4. Launch a KVM virtual machine. +5. Run 32-bit binaries on systems supporting the SYSCALL instruction. + This has been a lightly-tested code path and needs extra scrutiny. + +Debugging +========= + +Bugs in PTI cause a few different signatures of crashes +that are worth noting here. + + * Failures of the selftests/x86 code. Usually a bug in one of the + more obscure corners of entry_64.S + * Crashes in early boot, especially around CPU bringup. Bugs + in the trampoline code or mappings cause these. + * Crashes at the first interrupt. Caused by bugs in entry_64.S, + like screwing up a page table switch. Also caused by + incorrectly mapping the IRQ handler entry code. + * Crashes at the first NMI. The NMI code is separate from main + interrupt handlers and can have bugs that do not affect + normal interrupts. Also caused by incorrectly mapping NMI + code. NMIs that interrupt the entry code must be very + careful and can be the cause of crashes that show up when + running perf. + * Kernel crashes at the first exit to userspace. entry_64.S + bugs, or failing to map some of the exit code. + * Crashes at first interrupt that interrupts userspace. The paths + in entry_64.S that return to userspace are sometimes separate + from the ones that return to the kernel. + * Double faults: overflowing the kernel stack because of page + faults upon page faults. Caused by touching non-pti-mapped + data in the entry code, or forgetting to switch to kernel + CR3 before calling into C functions which are not pti-mapped. + * Userspace segfaults early in boot, sometimes manifesting + as mount(8) failing to mount the rootfs. These have + tended to be TLB invalidation issues. Usually invalidating + the wrong PCID, or otherwise missing an invalidation. + +1. https://gruss.cc/files/kaiser.pdf +2. https://meltdownattack.com/meltdown.pdf diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index b0798e281aa6a..ea91cb61a6029 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -1,6 +1,4 @@ - - Virtual memory map with 4 level page tables: 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm @@ -14,13 +12,17 @@ ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB) ... unused hole ... ffffec0000000000 - fffffbffffffffff (=44 bits) kasan shadow memory (16TB) ... unused hole ... + vaddr_end for KASLR +fffffe0000000000 - fffffe7fffffffff (=39 bits) cpu_entry_area mapping +fffffe8000000000 - fffffeffffffffff (=39 bits) LDT remap for PTI ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks ... unused hole ... ffffffef00000000 - fffffffeffffffff (=64 GB) EFI region mapping space ... unused hole ... ffffffff80000000 - ffffffff9fffffff (=512 MB) kernel text mapping, from phys 0 -ffffffffa0000000 - ffffffffff5fffff (=1526 MB) module mapping space (variable) -ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls +ffffffffa0000000 - [fixmap start] (~1526 MB) module mapping space (variable) +[fixmap start] - ffffffffff5fffff kernel-internal fixmap range +ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole Virtual memory map with 5 level page tables: @@ -29,26 +31,31 @@ Virtual memory map with 5 level page tables: hole caused by [56:63] sign extension ff00000000000000 - ff0fffffffffffff (=52 bits) guard hole, reserved for hypervisor ff10000000000000 - ff8fffffffffffff (=55 bits) direct mapping of all phys. memory -ff90000000000000 - ff91ffffffffffff (=49 bits) hole -ff92000000000000 - ffd1ffffffffffff (=54 bits) vmalloc/ioremap space +ff90000000000000 - ff9fffffffffffff (=52 bits) LDT remap for PTI +ffa0000000000000 - ffd1ffffffffffff (=54 bits) vmalloc/ioremap space (12800 TB) ffd2000000000000 - ffd3ffffffffffff (=49 bits) hole ffd4000000000000 - ffd5ffffffffffff (=49 bits) virtual memory map (512TB) ... unused hole ... -ffd8000000000000 - fff7ffffffffffff (=53 bits) kasan shadow memory (8PB) +ffdf000000000000 - fffffc0000000000 (=53 bits) kasan shadow memory (8PB) +... unused hole ... + vaddr_end for KASLR +fffffe0000000000 - fffffe7fffffffff (=39 bits) cpu_entry_area mapping ... unused hole ... ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks ... unused hole ... ffffffef00000000 - fffffffeffffffff (=64 GB) EFI region mapping space ... unused hole ... ffffffff80000000 - ffffffff9fffffff (=512 MB) kernel text mapping, from phys 0 -ffffffffa0000000 - ffffffffff5fffff (=1526 MB) module mapping space -ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls +ffffffffa0000000 - fffffffffeffffff (1520 MB) module mapping space +[fixmap start] - ffffffffff5fffff kernel-internal fixmap range +ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole Architecture defines a 64-bit virtual address. Implementations can support less. Currently supported are 48- and 57-bit virtual addresses. Bits 63 -through to the most-significant implemented bit are set to either all ones -or all zero. This causes hole between user space and kernel addresses. +through to the most-significant implemented bit are sign extended. +This causes hole between user space and kernel addresses if you interpret them +as unsigned. The direct mapping covers all memory in the system up to the highest memory address (this means in some cases it can also include PCI memory @@ -58,19 +65,15 @@ vmalloc space is lazily synchronized into the different PML4/PML5 pages of the processes using the page fault handler, with init_top_pgt as reference. -Current X86-64 implementations support up to 46 bits of address space (64 TB), -which is our current limit. This expands into MBZ space in the page tables. - We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual memory window (this size is arbitrary, it can be raised later if needed). The mappings are not part of any other kernel PGD and are only available during EFI runtime calls. -The module mapping space size changes based on the CONFIG requirements for the -following fixmap section. - Note that if CONFIG_RANDOMIZE_MEMORY is enabled, the direct mapping of all physical memory, vmalloc/ioremap space and virtual memory map are randomized. Their order is preserved but their base will be offset early at boot time. --Andi Kleen, Jul 2004 +Be very careful vs. KASLR when changing anything here. The KASLR address +range must not overlap with anything except the KASAN shadow area, which is +correct as KASAN disables KASLR. diff --git a/Makefile b/Makefile index ccd981892ef26..90a4bffa84467 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 0 +SUBLEVEL = 16 EXTRAVERSION = -NAME = Fearless Coyote +NAME = Petit Gorille # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -373,9 +373,6 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = LDFLAGS_vmlinux = -CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disable-warning,maybe-uninitialized,) -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) - # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ @@ -394,21 +391,19 @@ LINUXINCLUDE := \ -I$(objtree)/include \ $(USERINCLUDE) -KBUILD_CPPFLAGS := -D__KERNEL__ - +KBUILD_AFLAGS := -D__ASSEMBLY__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common -fshort-wchar \ -Werror-implicit-function-declaration \ -Wno-format-security \ - -std=gnu89 $(call cc-option,-fno-PIE) - - + -std=gnu89 +KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_AFLAGS_KERNEL := KBUILD_CFLAGS_KERNEL := -KBUILD_AFLAGS := -D__ASSEMBLY__ $(call cc-option,-fno-PIE) KBUILD_AFLAGS_MODULE := -DMODULE KBUILD_CFLAGS_MODULE := -DMODULE KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds +GCC_PLUGINS_CFLAGS := # Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) @@ -421,7 +416,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN +export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_KASAN CFLAGS_UBSAN export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL @@ -622,6 +617,12 @@ endif # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux +KBUILD_CFLAGS += $(call cc-option,-fno-PIE) +KBUILD_AFLAGS += $(call cc-option,-fno-PIE) +CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disable-warning,maybe-uninitialized,) +CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) +export CFLAGS_GCOV CFLAGS_KCOV + # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default # values of the respective KBUILD_* variables ARCH_CPPFLAGS := @@ -801,6 +802,9 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# Make sure -fstack-check isn't enabled (like gentoo apparently did) +KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) + # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) @@ -934,8 +938,8 @@ ifdef CONFIG_STACK_VALIDATION ifeq ($(has_libelf),1) objtool_target := tools/objtool FORCE else - ifdef CONFIG_ORC_UNWINDER - $(error "Cannot generate ORC metadata for CONFIG_ORC_UNWINDER=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel") + ifdef CONFIG_UNWINDER_ORC + $(error "Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel") else $(warning "Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel") endif diff --git a/README b/README index b2ba4aaa3a710..d1033febb8a54 100644 --- a/README +++ b/README @@ -1,3 +1,30 @@ +Kernel 4.14 for BananaPi R2 + + - checkout main branch + - run "./build.sh importconfig" to import my config for bpi-r2 + - run "./build.sh config" to configure the kernel (menuconfig) + - run "./build.sh" to start building kernel + +internal Wifi-driver (MT6625L) included + +to use it: + + copy firmware and tools to SD-Card from https://github.com/BPI-SINOVOIP/BPI-R2-bsp/tree/master/vendor/mediatek/connectivity or folder "utils" + + make a clean boot of bpi-r2 + remove wpasupplicant if installed: "apt-get remove wpasupplicant" + run the following commands: + wmt_loader + stp_uart_launcher -p /etc/firmware & + echo A >/dev/wmtWifi #(activate AP-Mode) + + if you type "ip a" you should see a ap0-device + now you can add an IP-address, start a dhcp-server and start hostapd on it + + more information: http://www.fw-web.de/dokuwiki/doku.php?id=en/bpi-r2/wlan + +Master-Branch + Linux kernel ============ diff --git a/arch/Kconfig b/arch/Kconfig index 057370a0ac4ec..400b9e1b2f275 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -91,7 +91,7 @@ config STATIC_KEYS_SELFTEST config OPTPROBES def_bool y depends on KPROBES && HAVE_OPTPROBES - depends on !PREEMPT + select TASKS_RCU if PREEMPT config KPROBES_ON_FTRACE def_bool y diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index 37bd6d9b8eb96..a6bdc1da47adb 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -102,6 +102,15 @@ sio_pci_route(void) alpha_mv.sys.sio.route_tab); } +static bool sio_pci_dev_irq_needs_level(const struct pci_dev *dev) +{ + if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + return false; + + return true; +} + static unsigned int __init sio_collect_irq_levels(void) { @@ -110,8 +119,7 @@ sio_collect_irq_levels(void) /* Iterate through the devices, collecting IRQ levels. */ for_each_pci_dev(dev) { - if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && - (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + if (!sio_pci_dev_irq_needs_level(dev)) continue; if (dev->irq) @@ -120,8 +128,7 @@ sio_collect_irq_levels(void) return level_bits; } -static void __init -sio_fixup_irq_levels(unsigned int level_bits) +static void __sio_fixup_irq_levels(unsigned int level_bits, bool reset) { unsigned int old_level_bits; @@ -139,12 +146,21 @@ sio_fixup_irq_levels(unsigned int level_bits) */ old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8); - level_bits |= (old_level_bits & 0x71ff); + if (reset) + old_level_bits &= 0x71ff; + + level_bits |= old_level_bits; outb((level_bits >> 0) & 0xff, 0x4d0); outb((level_bits >> 8) & 0xff, 0x4d1); } +static inline void +sio_fixup_irq_levels(unsigned int level_bits) +{ + __sio_fixup_irq_levels(level_bits, true); +} + static inline int noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { @@ -181,7 +197,14 @@ noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP, tmp; tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); - return irq >= 0 ? tmp : -1; + + irq = irq >= 0 ? tmp : -1; + + /* Fixup IRQ level if an actual IRQ mapping is detected */ + if (sio_pci_dev_irq_needs_level(dev) && irq >= 0) + __sio_fixup_irq_levels(1 << irq, false); + + return irq; } static inline int diff --git a/arch/arc/include/asm/uaccess.h b/arch/arc/include/asm/uaccess.h index f35974ee7264a..c9173c02081c0 100644 --- a/arch/arc/include/asm/uaccess.h +++ b/arch/arc/include/asm/uaccess.h @@ -668,6 +668,7 @@ __arc_strncpy_from_user(char *dst, const char __user *src, long count) return 0; __asm__ __volatile__( + " mov lp_count, %5 \n" " lp 3f \n" "1: ldb.ab %3, [%2, 1] \n" " breq.d %3, 0, 3f \n" @@ -684,8 +685,8 @@ __arc_strncpy_from_user(char *dst, const char __user *src, long count) " .word 1b, 4b \n" " .previous \n" : "+r"(res), "+r"(dst), "+r"(src), "=r"(val) - : "g"(-EFAULT), "l"(count) - : "memory"); + : "g"(-EFAULT), "r"(count) + : "lp_count", "lp_start", "lp_end", "memory"); return res; } diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 8bf0d89cdd355..2e516f4985e4c 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -433,15 +433,6 @@ clock-names = "ipg", "per"; }; - srtc: srtc@53fa4000 { - compatible = "fsl,imx53-rtc", "fsl,imx25-rtc"; - reg = <0x53fa4000 0x4000>; - interrupts = <24>; - interrupt-parent = <&tzic>; - clocks = <&clks IMX5_CLK_SRTC_GATE>; - clock-names = "ipg"; - }; - iomuxc: iomuxc@53fa8000 { compatible = "fsl,imx53-iomuxc"; reg = <0x53fa8000 0x4000>; diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts index cf2f5240e176d..27cc913ca0f56 100644 --- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts +++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts @@ -53,7 +53,8 @@ }; pinctrl: pin-controller@10000 { - pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>; + pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header + &pmx_gpio_header_gpo>; pinctrl-names = "default"; pmx_uart0: pmx-uart0 { @@ -85,11 +86,16 @@ * ground. */ pmx_gpio_header: pmx-gpio-header { - marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28", + marvell,pins = "mpp17", "mpp29", "mpp28", "mpp35", "mpp34", "mpp40"; marvell,function = "gpio"; }; + pmx_gpio_header_gpo: pxm-gpio-header-gpo { + marvell,pins = "mpp7"; + marvell,function = "gpo"; + }; + pmx_gpio_init: pmx-init { marvell,pins = "mpp38"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index ec8a07415cb38..bdfd22bbf7fda 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -263,6 +263,8 @@ compatible = "mediatek,mt7623-wdt", "mediatek,mt6589-wdt"; reg = <0 0x10007000 0 0x100>; + interrupts = ; + #reset-cells = <1>; }; timer: timer@10008000 { @@ -351,6 +353,17 @@ #io-channel-cells = <1>; }; + uart2: serial@11004000 { + compatible = "mediatek,mt7623-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11004000 0 0x400>; + interrupts = ; + clocks = <&pericfg CLK_PERI_UART2_SEL>, + <&pericfg CLK_PERI_UART2>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + uart0: serial@11002000 { compatible = "mediatek,mt7623-uart", "mediatek,mt6577-uart"; @@ -373,17 +386,6 @@ status = "disabled"; }; - uart2: serial@11004000 { - compatible = "mediatek,mt7623-uart", - "mediatek,mt6577-uart"; - reg = <0 0x11004000 0 0x400>; - interrupts = ; - clocks = <&pericfg CLK_PERI_UART2_SEL>, - <&pericfg CLK_PERI_UART2>; - clock-names = "baud", "bus"; - status = "disabled"; - }; - uart3: serial@11005000 { compatible = "mediatek,mt7623-uart", "mediatek,mt6577-uart"; @@ -486,6 +488,29 @@ nvmem-cell-names = "calibration-data"; }; + btif_tx: btif_tx@11000780 { + compatible = "mediatek,btif_tx"; + reg = <0 0x11000780 0 0x80>; + interrupts = ; + status = "okay"; + }; + + btif_rx: btif_rx@11000800 { + compatible = "mediatek,btif_rx"; + reg = <0 0x11000800 0 0x80>; + interrupts = ; + status = "okay"; + }; + + btif: btif@1100c000 { + compatible = "mediatek,btif"; + reg = <0 0x1100c000 0 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_BTIF>, <&pericfg CLK_PERI_AP_DMA>; + clock-names = "btifc", "apdmac"; + status = "okay"; + }; + nandc: nfi@1100d000 { compatible = "mediatek,mt7623-nfc", "mediatek,mt2701-nfc"; @@ -638,9 +663,20 @@ "top_syspll_d5"; }; + mmc1: mmc@11240000 { + compatible = "mediatek,mt7623-mmc", + "mediatek,mt2701-mmc"; + reg = <0 0x11240000 0 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_MSDC30_1>, + <&topckgen CLK_TOP_MSDC30_1_SEL>; + clock-names = "source", "hclk"; + status = "disabled"; + }; + mmc0: mmc@11230000 { compatible = "mediatek,mt7623-mmc", - "mediatek,mt8135-mmc"; + "mediatek,mt2701-mmc"; reg = <0 0x11230000 0 0x1000>; interrupts = ; clocks = <&pericfg CLK_PERI_MSDC30_0>, @@ -649,15 +685,27 @@ status = "disabled"; }; - mmc1: mmc@11240000 { - compatible = "mediatek,mt7623-mmc", - "mediatek,mt8135-mmc"; - reg = <0 0x11240000 0 0x1000>; - interrupts = ; - clocks = <&pericfg CLK_PERI_MSDC30_1>, - <&topckgen CLK_TOP_MSDC30_1_SEL>; - clock-names = "source", "hclk"; - status = "disabled"; + consys: consys@18070000 { + compatible = "mediatek,mt7623-consys"; + reg = <0 0x18070000 0 0x0200>, /*CONN_MCU_CONFIG_BASE */ + <0 0x10001000 0 0x1600>; /*TOPCKGEN_BASE */ + clocks = <&infracfg CLK_INFRA_CONNMCU>; + clock-names = "consysbus"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_CONN>; + interrupts = , /* BGF_EINT */ + ; /* WDT_EINT */ + resets = <&watchdog MT2701_TOPRGU_CONN_MCU_RST>; + reset-names = "connsys"; + status="disabled"; + }; + + wifi:wifi@180f0000 { + compatible = "mediatek,mt7623-wifi", + "mediatek,wifi"; + reg = <0 0x180f0000 0 0x005c>; + interrupts = ; + clocks = <&pericfg CLK_PERI_AP_DMA>; + clock-names = "wifi-dma"; }; hifsys: syscon@1a000000 { @@ -669,6 +717,114 @@ #reset-cells = <1>; }; + pcie: pcie-controller@1a140000 { + compatible = "mediatek,mt7623-pcie"; + device_type = "pci"; + reg = <0 0x1a140000 0 0x1000>, /* PCIe shared registers */ + <0 0x1a142000 0 0x1000>, /* Port0 registers */ + <0 0x1a143000 0 0x1000>, /* Port1 registers */ + <0 0x1a144000 0 0x1000>; /* Port2 registers */ + reg-names = "subsys", "port0", "port1", "port2"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 0>; + interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>, + <0x0800 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>, + <0x1000 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <&hifsys CLK_HIFSYS_PCIE0>, + <&hifsys CLK_HIFSYS_PCIE1>, + <&hifsys CLK_HIFSYS_PCIE2>; + clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2"; + resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>, + <&hifsys MT2701_HIFSYS_PCIE1_RST>, + <&hifsys MT2701_HIFSYS_PCIE2_RST>; + reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2"; + phys = <&pcie0_port PHY_TYPE_PCIE>, + <&pcie1_port PHY_TYPE_PCIE>, + <&u3port1 PHY_TYPE_PCIE>; + phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>; + bus-range = <0x00 0xff>; + status = "disabled"; + ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 + 0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; + + pcie@0,0 { + device_type = "pci"; + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + + pcie@1,0 { + device_type = "pci"; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + + pcie@2,0 { + device_type = "pci"; + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + }; + + pcie0_phy: pcie-phy@1a149000 { + compatible = "mediatek,generic-tphy-v1"; + reg = <0 0x1a149000 0 0x0700>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + pcie0_port: pcie-phy@1a149900 { + reg = <0 0x1a149900 0 0x0700>; + clocks = <&clk26m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + + pcie1_phy: pcie-phy@1a14a000 { + compatible = "mediatek,generic-tphy-v1"; + reg = <0 0x1a14a000 0 0x0700>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + pcie1_port: pcie-phy@1a14a900 { + reg = <0 0x1a14a900 0 0x0700>; + clocks = <&clk26m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + usb1: usb@1a1c0000 { compatible = "mediatek,mt7623-xhci", "mediatek,mt8173-xhci"; diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts index 688a86378ceef..4eea2bb613f11 100644 --- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts @@ -57,6 +57,18 @@ }; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + consys-reserve-memory { + compatible = "mediatek,consys-reserve-memory"; + no-map; + size = <0 0x100000>; + alignment = <0 0x100000>; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -204,11 +216,33 @@ bus-width = <4>; max-frequency = <50000000>; cap-sd-highspeed; - cd-gpios = <&pio 261 0>; + cd-gpios = <&pio 261 GPIO_ACTIVE_LOW>; vmmc-supply = <&mt6323_vmch_reg>; vqmmc-supply = <&mt6323_vio18_reg>; }; +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_default>; + status = "okay"; + + pcie@0,0 { + status = "okay"; + }; + + pcie@1,0 { + status = "okay"; + }; +}; + +&pcie0_phy { + status = "okay"; +}; + +&pcie1_phy { + status = "okay"; +}; + &pio { cir_pins_a:cir@0 { pins_cir { @@ -376,6 +410,14 @@ }; }; + pcie_default: pcie_pin_default { + pins_cmd_dat { + pinmux = , + ; + bias-disable; + }; + }; + pwm_pins_a: pwm@0 { pins_pwm { pinmux = , @@ -409,6 +451,31 @@ ; }; }; + + uart3_pins_a: uart@3 { + pins_dat { + pinmux = , + ; + }; + }; + + consys_pins_default: consys_pins_default { + adie { + pinmux = , + , + , + , + , + , + , + , + , + , + , + ; + bias-disable; + }; + }; }; &pwm { @@ -442,9 +509,239 @@ default-state = "off"; }; }; + + mt6323regulator: mt6323regulator{ + compatible = "mediatek,mt6323-regulator"; + + mt6323_vproc_reg: buck_vproc{ + regulator-name = "vproc"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vsys_reg: buck_vsys{ + regulator-name = "vsys"; + regulator-min-microvolt = <1400000>; + regulator-max-microvolt = <2987500>; + regulator-ramp-delay = <25000>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vpa_reg: buck_vpa{ + regulator-name = "vpa"; + regulator-min-microvolt = < 500000>; + regulator-max-microvolt = <3650000>; + }; + + mt6323_vtcxo_reg: ldo_vtcxo{ + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcn28_reg: ldo_vcn28{ + regulator-name = "vcn28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_vcn33_bt_reg: ldo_vcn33_bt{ + regulator-name = "vcn33_bt"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{ + regulator-name = "vcn33_wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_va_reg: ldo_va{ + regulator-name = "va"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcama_reg: ldo_vcama{ + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vio28_reg: ldo_vio28{ + regulator-name = "vio28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vusb_reg: ldo_vusb{ + regulator-name = "vusb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + regulator-boot-on; + }; + + mt6323_vmc_reg: ldo_vmc{ + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vmch_reg: ldo_vmch{ + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vemc3v3_reg: ldo_vemc3v3{ + regulator-name = "vemc3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vgp1_reg: ldo_vgp1{ + regulator-name = "vgp1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vgp2_reg: ldo_vgp2{ + regulator-name = "vgp2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vgp3_reg: ldo_vgp3{ + regulator-name = "vgp3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vcn18_reg: ldo_vcn18{ + regulator-name = "vcn18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vsim1_reg: ldo_vsim1{ + regulator-name = "vsim1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vsim2_reg: ldo_vsim2{ + regulator-name = "vsim2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vrtc_reg: ldo_vrtc{ + regulator-name = "vrtc"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcamaf_reg: ldo_vcamaf{ + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vibr_reg: ldo_vibr{ + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + }; + + mt6323_vrf18_reg: ldo_vrf18{ + regulator-name = "vrf18"; + regulator-min-microvolt = <1825000>; + regulator-max-microvolt = <1825000>; + regulator-enable-ramp-delay = <187>; + }; + + mt6323_vm_reg: ldo_vm{ + regulator-name = "vm"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vio18_reg: ldo_vio18{ + regulator-name = "vio18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcamd_reg: ldo_vcamd{ + regulator-name = "vcamd"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vcamio_reg: ldo_vcamio{ + regulator-name = "vcamio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + }; + }; }; +&consys { + mediatek,pwrap-regmap = <&pwrap>; + pinctrl-names = "default"; + pinctrl-0 = <&consys_pins_default>; + vcn18-supply = <&mt6323_vcn18_reg>; + vcn28-supply = <&mt6323_vcn28_reg>; + vcn33_bt-supply = <&mt6323_vcn33_bt_reg>; + vcn33_wifi-supply = <&mt6323_vcn33_wifi_reg>; + status = "okay"; +}; + &spi0 { pinctrl-names = "default"; pinctrl-0 = <&spi0_pins_a>; @@ -454,19 +751,25 @@ &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; - status = "disabled"; + status = "okay"; }; &uart1 { pinctrl-names = "default"; pinctrl-0 = <&uart1_pins_a>; - status = "disabled"; + status = "okay"; }; &uart2 { status = "okay"; }; +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins_a>; + status = "okay"; +}; + &usb1 { vusb33-supply = <&mt6323_vusb_reg>; status = "okay"; @@ -485,3 +788,7 @@ status = "okay"; }; +&watchdog { + status = "okay"; +}; + diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 8c2a2619971b1..f1d7834990ece 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -244,7 +244,7 @@ CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_CYPRESS_ATACB=m CONFIG_USB_STORAGE_ENE_UB6250=m -CONFIG_USB_UAS=m +CONFIG_USB_UAS=y CONFIG_USB_DWC3=y CONFIG_USB_DWC2=y CONFIG_USB_HSIC_USB3503=y diff --git a/arch/arm/configs/mt7623n_evb_fwu_defconfig b/arch/arm/configs/mt7623n_evb_fwu_defconfig new file mode 100644 index 0000000000000..fff098131183e --- /dev/null +++ b/arch/arm/configs/mt7623n_evb_fwu_defconfig @@ -0,0 +1,393 @@ +CONFIG_LOCALVERSION="-bpi-r2" +CONFIG_LOCALVERSION_AUTO=n + +#spectre/meltdown +CONFIG_PAGE_TABLE_ISOLATION=y + +CONFIG_SYSVIPC=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_CGROUPS=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_ARM_ERRATA_798181=y + +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_PL310_ERRATA_769419=y + +CONFIG_PCI=y +CONFIG_SMP=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_NR_CPUS=16 +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_FORCE_MAX_ZONEORDER=12 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 vmalloc=496M debug=7 no_console_suspend" +#CONFIG_CMDLINE_FORCE=y + +CONFIG_KEXEC=y + +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_ARM_MEDIATEK_CPUFREQ=y + +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_APM_EMULATION=y + +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_BRIDGE=y +CONFIG_NET_DSA=y +CONFIG_VLAN_8021Q=y +CONFIG_NETLINK_DIAG=y + +CONFIG_IPV6=m +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_NF_LOG_IPV4=m +CONFIG_NF_REJECT_IPV4=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_NF_LOG_IPV6=m +CONFIG_NF_REJECT_IPV6=m +CONFIG_IP_NF_NAT=m +CONFIG_IP6_NF_NAT=m +CONFIG_NF_NAT_MASQUERADE_IPV4=m +CONFIG_NF_NAT_MASQUERADE_IPV6=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP6_NF_MANGLE=m + + +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_ARM_CCI400_PMU=y +CONFIG_MTD=y +CONFIG_OF_OVERLAY=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_SRAM=y +CONFIG_EEPROM_93CX6=y +CONFIG_IDE=y +CONFIG_BLK_DEV_SD=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_AHCI_MTK=m + +CONFIG_NETDEVICES=y +CONFIG_NET_DSA_MT7530=y +CONFIG_NET_VENDOR_MEDIATEK=y +CONFIG_NET_MEDIATEK_SOC=y + +CONFIG_ICPLUS_PHY=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y +CONFIG_KEYBOARD_MATRIX=y +CONFIG_KEYBOARD_SAMSUNG=y +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_SERIO_SERPORT is not set +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_BTIF=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_MT65XX=y +CONFIG_PINCTRL_MT2701=y +# CONFIG_PINCTRL_MT6397 is not set +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_MEDIATEK_WATCHDOG=y +CONFIG_MFD_MT6397=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_MT6323=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_RC_DEVICES=y +CONFIG_IR_MTK=y +CONFIG_MMC=y +CONFIG_MMC_MTK=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_MT6323=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PCA963X=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_DMADEVICES=y +CONFIG_DMATEST=m +CONFIG_COMMON_CLK_MT2701_HIFSYS=y +CONFIG_COMMON_CLK_MT2701_ETHSYS=y +CONFIG_ARM_TIMER_SP804=y +CONFIG_MTK_IOMMU_V1=y +CONFIG_MTK_PMIC_WRAP=y +CONFIG_IIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_PHY_MT65XX_USB3=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_FTRACE=y +CONFIG_PSTORE_RAM=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEBUG_LIST=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_UART_PHYS=0x11002000 +CONFIG_DEBUG_UART_VIRT=0xf1002000 +CONFIG_KEYS=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRYPTO_DEV_MEDIATEK=y + +#LVM +CONFIG_BLK_DEV_DM=y +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_MIRROR=y +CONFIG_DM_MULTIPATH=y +CONFIG_DM_MULTIPATH_QL=y +CONFIG_DM_MULTIPATH_ST=y +CONFIG_DAX=y +CONFIG_CRYPTO_CBC=y + +#RamFS +#CONFIG_INITRAMFS_SOURCE="../rootfs_ttys0_rng.cpio.gz" +#CONFIG_INITRAMFS_FORCE=y + +#Filesystem +CONFIG_EXT4_FS=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_CIFS=m + +#GPIO +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +#wlan +CONFIG_MAC80211=y +CONFIG_CFG80211=y + +#internal wlan (not working yet) +# CONFIG_MTK_CONN_LTE_IDC_SUPPORT is not set +CONFIG_MTK_COMBO=y +CONFIG_MTK_COMBO_CHIP_CONSYS_7623=y +#used in 4.4, but should be set in Kconfig by selecting mt7623 COMBO +CONFIG_MTK_PLATFORM="mt7623" + +CONFIG_MTK_COMBO_COMM=y +CONFIG_MTK_COMBO_WIFI=y +CONFIG_NL80211_TESTMODE=y + +#internal Bluetooth (also not working yet) +CONFIG_BT=y +CONFIG_MTK_COMBO_BT=y +CONFIG_MTK_COMBO_BT_HCI=y +#needed for BT? +#Bluetooth Classic (BR/EDR) features +CONFIG_BT_BREDR=y +#Bluetooth High Speed (HS) features +CONFIG_BT_HS=y +#Bluetooth Low Energy (LE) features +CONFIG_BT_LE=y +#Export Bluetooth internals in debugfs +CONFIG_BT_DEBUGFS=y + +#to run bluetoothd rfkill needed +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=y + + +#if you use a mt76x2 or mt76x3 pcie-card +CONFIG_MT76=m + +#pcie +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PHY_MTK_TPHY=y + +CONFIG_I2C_CHARDEV=m +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m + +CONFIG_PWM=y +CONFIG_PWM_MEDIATEK=m + +#Temperature sensor driver for mediatek SoCs +CONFIG_MEDIATEK_MT6577_AUXADC=m +CONFIG_THERMAL=m +CONFIG_MTK_THERMAL=m + +#HDMI +##CONFIG_HDMI=y +#CONFIG_DRM=m +#CONFIG_DRM_MEDIATEK=m +#CONFIG_DRM_MEDIATEK_HDMI=m + +#CONFIG_FB=y +#CONFIG_FB_CMDLINE=y +#CONFIG_FRAMEBUFFER_CONSOLE=y +#CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y + +#Sound +CONFIG_SOUND=y +CONFIG_SND=y #alsa core +CONFIG_SND_SOC=y + +#CONFIG_SOUND_OSS_CORE=y +#CONFIG_SOUND_OSS_CORE_PRECLAIM=y +#CONFIG_SND_OSSEMUL=y +#CONFIG_SND_MIXER_OSS=m +#CONFIG_SND_PCM_OSS=m #alsa The PCM OSS emulation module. + +#USB/HID +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +#CONFIG_NOP_USB_XCEIV=y +#CONFIG_USB_GPIO_VBUS=y +#CONFIG_USB_GADGET=y +#CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +#CONFIG_USB_CONFIGFS_ACM=y +#CONFIG_USB_CONFIGFS_OBEX=y +#CONFIG_USB_CONFIGFS_NCM=y +#CONFIG_USB_CONFIGFS_ECM=y +#CONFIG_USB_CONFIGFS_ECM_SUBSET=y +#CONFIG_USB_CONFIGFS_RNDIS=y +#CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y + +CONFIG_HID=y +CONFIG_HIDRAW=y +#CONFIG_UHID=m +CONFIG_HID_GENERIC=y + +CONFIG_USB_HID=y +#CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y + +# CONFIG_USB_OHCI_LITTLE_ENDIAN=y ? +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +# CONFIG_USB_ARCH_HAS_HCD=y ? + +#additional NET (e.g. tunneling incl. openvpn,vlan-base-support) +CONFIG_TUN=m +#vlan +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_IPVLAN=m +CONFIG_MACVLAN=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_SCHED=y +CONFIG_NET_CLS_ACT=y + +#unused drivers which are set by default +CONFIG_WLAN_VENDOR_ADMTEK=n +CONFIG_WLAN_VENDOR_ATH=n +CONFIG_WLAN_VENDOR_ATMEL=n +CONFIG_WLAN_VENDOR_BROADCOM=n +CONFIG_WLAN_VENDOR_CISCO=n +CONFIG_WLAN_VENDOR_INTEL=n +CONFIG_WLAN_VENDOR_INTERSIL=n +CONFIG_WLAN_VENDOR_MARVELL=n +CONFIG_WLAN_VENDOR_REALTEK=n +CONFIG_WLAN_VENDOR_RALINK=n +CONFIG_WLAN_VENDOR_RSI=n +CONFIG_WLAN_VENDOR_ST=n +CONFIG_WLAN_VENDOR_TI=n +CONFIG_WLAN_VENDOR_ZYDAS=n +CONFIG_WLAN_VENDOR_QUANTENNA=n diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index 5caaf971fb500..df433abfcb028 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -10,6 +10,7 @@ CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_AEABI=y CONFIG_HIGHMEM=y +CONFIG_CMA=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CPU_FREQ=y @@ -33,6 +34,7 @@ CONFIG_CAN_SUN4I=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_AHCI_SUNXI=y diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index ad301f107dd28..bc8d4bbd82e27 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -518,4 +518,22 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm + .macro bug, msg, line +#ifdef CONFIG_THUMB2_KERNEL +1: .inst 0xde02 +#else +1: .inst 0xe7f001f2 +#endif +#ifdef CONFIG_DEBUG_BUGVERBOSE + .pushsection .rodata.str, "aMS", %progbits, 1 +2: .asciz "\msg" + .popsection + .pushsection __bug_table, "aw" + .align 2 + .word 1b, 2b + .hword \line + .popsection +#endif + .endm + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index c8781450905be..3ab8b3781bfec 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h @@ -161,8 +161,7 @@ #else #define VTTBR_X (5 - KVM_T0SZ) #endif -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT _AC(48, ULL) #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT) diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index e9c9a117bd25d..c7cdbb43ae7c4 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -126,8 +126,7 @@ extern unsigned long profile_pc(struct pt_regs *regs); /* * kprobe-based event tracer support */ -#include -#include +#include #define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) extern int regs_query_register_offset(const char *name); diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index d523cd8439a3d..0f07579af472c 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -300,6 +300,8 @@ mov r2, sp ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr ldr lr, [r2, #\offset + S_PC]! @ get pc + tst r1, #PSR_I_BIT | 0x0f + bne 1f msr spsr_cxsf, r1 @ save in spsr_svc #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) @ We must avoid clrex due to Cortex-A15 erratum #830321 @@ -314,6 +316,7 @@ @ after ldm {}^ add sp, sp, #\offset + PT_REGS_SIZE movs pc, lr @ return & move spsr_svc into cpsr +1: bug "Returning to usermode but unexpected PSR bits set?", \@ #elif defined(CONFIG_CPU_V7M) @ V7M restore. @ Note that we don't need to do clrex here as clearing the local @@ -329,6 +332,8 @@ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr ldr lr, [sp, #\offset + S_PC] @ get pc add sp, sp, #\offset + S_SP + tst r1, #PSR_I_BIT | 0x0f + bne 1f msr spsr_cxsf, r1 @ save in spsr_svc @ We must avoid clrex due to Cortex-A15 erratum #830321 @@ -341,6 +346,7 @@ .endif add sp, sp, #PT_REGS_SIZE - S_SP movs pc, lr @ return & move spsr_svc into cpsr +1: bug "Returning to usermode but unexpected PSR bits set?", \@ #endif /* !CONFIG_THUMB2_KERNEL */ .endm diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index c3276436b0aea..c12e7b572a419 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1656,6 +1656,7 @@ static struct omap_hwmod omap3xxx_mmc3_hwmod = { .main_clk = "mmchs3_fck", .prcm = { .omap2 = { + .module_offs = CORE_MOD, .prcm_reg_id = 1, .module_bit = OMAP3430_EN_MMC3_SHIFT, .idlest_reg_id = 1, diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c index 35ff45470dbfd..fc3b44028cfb2 100644 --- a/arch/arm/mm/dump.c +++ b/arch/arm/mm/dump.c @@ -129,8 +129,8 @@ static const struct prot_bits section_bits[] = { .val = PMD_SECT_USER, .set = "USR", }, { - .mask = L_PMD_SECT_RDONLY, - .val = L_PMD_SECT_RDONLY, + .mask = L_PMD_SECT_RDONLY | PMD_SECT_AP2, + .val = L_PMD_SECT_RDONLY | PMD_SECT_AP2, .set = "ro", .clear = "RW", #elif __LINUX_ARM_ARCH__ >= 6 diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index ad80548325fe9..0f6d1537f3301 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -639,8 +639,8 @@ static struct section_perm ro_perms[] = { .start = (unsigned long)_stext, .end = (unsigned long)__init_begin, #ifdef CONFIG_ARM_LPAE - .mask = ~L_PMD_SECT_RDONLY, - .prot = L_PMD_SECT_RDONLY, + .mask = ~(L_PMD_SECT_RDONLY | PMD_SECT_AP2), + .prot = L_PMD_SECT_RDONLY | PMD_SECT_AP2, #else .mask = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE), .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index c199990e12b62..323a4df59a6c0 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -27,14 +27,58 @@ int bpf_jit_enable __read_mostly; +/* + * eBPF prog stack layout: + * + * high + * original ARM_SP => +-----+ + * | | callee saved registers + * +-----+ <= (BPF_FP + SCRATCH_SIZE) + * | ... | eBPF JIT scratch space + * eBPF fp register => +-----+ + * (BPF_FP) | ... | eBPF prog stack + * +-----+ + * |RSVD | JIT scratchpad + * current ARM_SP => +-----+ <= (BPF_FP - STACK_SIZE + SCRATCH_SIZE) + * | | + * | ... | Function call stack + * | | + * +-----+ + * low + * + * The callee saved registers depends on whether frame pointers are enabled. + * With frame pointers (to be compliant with the ABI): + * + * high + * original ARM_SP => +------------------+ \ + * | pc | | + * current ARM_FP => +------------------+ } callee saved registers + * |r4-r8,r10,fp,ip,lr| | + * +------------------+ / + * low + * + * Without frame pointers: + * + * high + * original ARM_SP => +------------------+ + * | r4-r8,r10,fp,lr | callee saved registers + * current ARM_FP => +------------------+ + * low + * + * When popping registers off the stack at the end of a BPF function, we + * reference them via the current ARM_FP register. + */ +#define CALLEE_MASK (1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \ + 1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R10 | \ + 1 << ARM_FP) +#define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR) +#define CALLEE_POP_MASK (CALLEE_MASK | 1 << ARM_PC) + #define STACK_OFFSET(k) (k) #define TMP_REG_1 (MAX_BPF_JIT_REG + 0) /* TEMP Register 1 */ #define TMP_REG_2 (MAX_BPF_JIT_REG + 1) /* TEMP Register 2 */ #define TCALL_CNT (MAX_BPF_JIT_REG + 2) /* Tail Call Count */ -/* Flags used for JIT optimization */ -#define SEEN_CALL (1 << 0) - #define FLAG_IMM_OVERFLOW (1 << 0) /* @@ -95,7 +139,6 @@ static const u8 bpf2a32[][2] = { * idx : index of current last JITed instruction. * prologue_bytes : bytes used in prologue. * epilogue_offset : offset of epilogue starting. - * seen : bit mask used for JIT optimization. * offsets : array of eBPF instruction offsets in * JITed code. * target : final JITed code. @@ -110,7 +153,6 @@ struct jit_ctx { unsigned int idx; unsigned int prologue_bytes; unsigned int epilogue_offset; - u32 seen; u32 flags; u32 *offsets; u32 *target; @@ -179,8 +221,13 @@ static void jit_fill_hole(void *area, unsigned int size) *ptr++ = __opcode_to_mem_arm(ARM_INST_UDF); } -/* Stack must be multiples of 16 Bytes */ -#define STACK_ALIGN(sz) (((sz) + 3) & ~3) +#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) +/* EABI requires the stack to be aligned to 64-bit boundaries */ +#define STACK_ALIGNMENT 8 +#else +/* Stack must be aligned to 32-bit boundaries */ +#define STACK_ALIGNMENT 4 +#endif /* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4, * BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9, @@ -194,7 +241,7 @@ static void jit_fill_hole(void *area, unsigned int size) + SCRATCH_SIZE + \ + 4 /* extra for skb_copy_bits buffer */) -#define STACK_SIZE STACK_ALIGN(_STACK_SIZE) +#define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT) /* Get the offset of eBPF REGISTERs stored on scratch space. */ #define STACK_VAR(off) (STACK_SIZE-off-4) @@ -285,16 +332,19 @@ static inline void emit_mov_i(const u8 rd, u32 val, struct jit_ctx *ctx) emit_mov_i_no8m(rd, val, ctx); } -static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) +static void emit_bx_r(u8 tgt_reg, struct jit_ctx *ctx) { - ctx->seen |= SEEN_CALL; -#if __LINUX_ARM_ARCH__ < 5 - emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); - if (elf_hwcap & HWCAP_THUMB) emit(ARM_BX(tgt_reg), ctx); else emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx); +} + +static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) +{ +#if __LINUX_ARM_ARCH__ < 5 + emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); + emit_bx_r(tgt_reg, ctx); #else emit(ARM_BLX_R(tgt_reg), ctx); #endif @@ -354,7 +404,6 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op) } /* Call appropriate function */ - ctx->seen |= SEEN_CALL; emit_mov_i(ARM_IP, op == BPF_DIV ? (u32)jit_udiv32 : (u32)jit_mod32, ctx); emit_blx_r(ARM_IP, ctx); @@ -620,8 +669,6 @@ static inline void emit_a32_lsh_r64(const u8 dst[], const u8 src[], bool dstk, /* Do LSH operation */ emit(ARM_SUB_I(ARM_IP, rt, 32), ctx); emit(ARM_RSB_I(tmp2[0], rt, 32), ctx); - /* As we are using ARM_LR */ - ctx->seen |= SEEN_CALL; emit(ARM_MOV_SR(ARM_LR, rm, SRTYPE_ASL, rt), ctx); emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd, SRTYPE_ASL, ARM_IP), ctx); emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd, SRTYPE_LSR, tmp2[0]), ctx); @@ -656,8 +703,6 @@ static inline void emit_a32_arsh_r64(const u8 dst[], const u8 src[], bool dstk, /* Do the ARSH operation */ emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); - /* As we are using ARM_LR */ - ctx->seen |= SEEN_CALL; emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx); emit(ARM_ORR_SR(ARM_LR, ARM_LR, rm, SRTYPE_ASL, ARM_IP), ctx); _emit(ARM_COND_MI, ARM_B(0), ctx); @@ -692,8 +737,6 @@ static inline void emit_a32_lsr_r64(const u8 dst[], const u8 src[], bool dstk, /* Do LSH operation */ emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); - /* As we are using ARM_LR */ - ctx->seen |= SEEN_CALL; emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx); emit(ARM_ORR_SR(ARM_LR, ARM_LR, rm, SRTYPE_ASL, ARM_IP), ctx); emit(ARM_ORR_SR(ARM_LR, ARM_LR, rm, SRTYPE_LSR, tmp2[0]), ctx); @@ -828,8 +871,6 @@ static inline void emit_a32_mul_r64(const u8 dst[], const u8 src[], bool dstk, /* Do Multiplication */ emit(ARM_MUL(ARM_IP, rd, rn), ctx); emit(ARM_MUL(ARM_LR, rm, rt), ctx); - /* As we are using ARM_LR */ - ctx->seen |= SEEN_CALL; emit(ARM_ADD_R(ARM_LR, ARM_IP, ARM_LR), ctx); emit(ARM_UMULL(ARM_IP, rm, rd, rt), ctx); @@ -872,33 +913,53 @@ static inline void emit_str_r(const u8 dst, const u8 src, bool dstk, } /* dst = *(size*)(src + off) */ -static inline void emit_ldx_r(const u8 dst, const u8 src, bool dstk, - const s32 off, struct jit_ctx *ctx, const u8 sz){ +static inline void emit_ldx_r(const u8 dst[], const u8 src, bool dstk, + s32 off, struct jit_ctx *ctx, const u8 sz){ const u8 *tmp = bpf2a32[TMP_REG_1]; - u8 rd = dstk ? tmp[1] : dst; + const u8 *rd = dstk ? tmp : dst; u8 rm = src; + s32 off_max; - if (off) { + if (sz == BPF_H) + off_max = 0xff; + else + off_max = 0xfff; + + if (off < 0 || off > off_max) { emit_a32_mov_i(tmp[0], off, false, ctx); emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx); rm = tmp[0]; + off = 0; + } else if (rd[1] == rm) { + emit(ARM_MOV_R(tmp[0], rm), ctx); + rm = tmp[0]; } switch (sz) { - case BPF_W: - /* Load a Word */ - emit(ARM_LDR_I(rd, rm, 0), ctx); + case BPF_B: + /* Load a Byte */ + emit(ARM_LDRB_I(rd[1], rm, off), ctx); + emit_a32_mov_i(dst[0], 0, dstk, ctx); break; case BPF_H: /* Load a HalfWord */ - emit(ARM_LDRH_I(rd, rm, 0), ctx); + emit(ARM_LDRH_I(rd[1], rm, off), ctx); + emit_a32_mov_i(dst[0], 0, dstk, ctx); break; - case BPF_B: - /* Load a Byte */ - emit(ARM_LDRB_I(rd, rm, 0), ctx); + case BPF_W: + /* Load a Word */ + emit(ARM_LDR_I(rd[1], rm, off), ctx); + emit_a32_mov_i(dst[0], 0, dstk, ctx); + break; + case BPF_DW: + /* Load a Double Word */ + emit(ARM_LDR_I(rd[1], rm, off), ctx); + emit(ARM_LDR_I(rd[0], rm, off + 4), ctx); break; } if (dstk) - emit(ARM_STR_I(rd, ARM_SP, STACK_VAR(dst)), ctx); + emit(ARM_STR_I(rd[1], ARM_SP, STACK_VAR(dst[1])), ctx); + if (dstk && sz == BPF_DW) + emit(ARM_STR_I(rd[0], ARM_SP, STACK_VAR(dst[0])), ctx); } /* Arithmatic Operation */ @@ -906,7 +967,6 @@ static inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm, const u8 rn, struct jit_ctx *ctx, u8 op) { switch (op) { case BPF_JSET: - ctx->seen |= SEEN_CALL; emit(ARM_AND_R(ARM_IP, rt, rn), ctx); emit(ARM_AND_R(ARM_LR, rd, rm), ctx); emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); @@ -945,7 +1005,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) const u8 *tcc = bpf2a32[TCALL_CNT]; const int idx0 = ctx->idx; #define cur_offset (ctx->idx - idx0) -#define jmp_offset (out_offset - (cur_offset)) +#define jmp_offset (out_offset - (cur_offset) - 2) u32 off, lo, hi; /* if (index >= array->map.max_entries) @@ -956,7 +1016,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) emit_a32_mov_i(tmp[1], off, false, ctx); emit(ARM_LDR_I(tmp2[1], ARM_SP, STACK_VAR(r2[1])), ctx); emit(ARM_LDR_R(tmp[1], tmp2[1], tmp[1]), ctx); - /* index (64 bit) */ + /* index is 32-bit for arrays */ emit(ARM_LDR_I(tmp2[1], ARM_SP, STACK_VAR(r3[1])), ctx); /* index >= array->map.max_entries */ emit(ARM_CMP_R(tmp2[1], tmp[1]), ctx); @@ -997,7 +1057,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) emit_a32_mov_i(tmp2[1], off, false, ctx); emit(ARM_LDR_R(tmp[1], tmp[1], tmp2[1]), ctx); emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx); - emit(ARM_BX(tmp[1]), ctx); + emit_bx_r(tmp[1], ctx); /* out: */ if (out_offset == -1) @@ -1070,54 +1130,22 @@ static void build_prologue(struct jit_ctx *ctx) const u8 r2 = bpf2a32[BPF_REG_1][1]; const u8 r3 = bpf2a32[BPF_REG_1][0]; const u8 r4 = bpf2a32[BPF_REG_6][1]; - const u8 r5 = bpf2a32[BPF_REG_6][0]; - const u8 r6 = bpf2a32[TMP_REG_1][1]; - const u8 r7 = bpf2a32[TMP_REG_1][0]; - const u8 r8 = bpf2a32[TMP_REG_2][1]; - const u8 r10 = bpf2a32[TMP_REG_2][0]; const u8 fplo = bpf2a32[BPF_REG_FP][1]; const u8 fphi = bpf2a32[BPF_REG_FP][0]; - const u8 sp = ARM_SP; const u8 *tcc = bpf2a32[TCALL_CNT]; - u16 reg_set = 0; - - /* - * eBPF prog stack layout - * - * high - * original ARM_SP => +-----+ eBPF prologue - * |FP/LR| - * current ARM_FP => +-----+ - * | ... | callee saved registers - * eBPF fp register => +-----+ <= (BPF_FP) - * | ... | eBPF JIT scratch space - * | | eBPF prog stack - * +-----+ - * |RSVD | JIT scratchpad - * current A64_SP => +-----+ <= (BPF_FP - STACK_SIZE) - * | | - * | ... | Function call stack - * | | - * +-----+ - * low - */ - /* Save callee saved registers. */ - reg_set |= (1<seen & SEEN_CALL) - reg_set |= (1<stack_size = imm8m(STACK_SIZE); @@ -1140,33 +1168,19 @@ static void build_prologue(struct jit_ctx *ctx) /* end of prologue */ } +/* restore callee saved registers. */ static void build_epilogue(struct jit_ctx *ctx) { - const u8 r4 = bpf2a32[BPF_REG_6][1]; - const u8 r5 = bpf2a32[BPF_REG_6][0]; - const u8 r6 = bpf2a32[TMP_REG_1][1]; - const u8 r7 = bpf2a32[TMP_REG_1][0]; - const u8 r8 = bpf2a32[TMP_REG_2][1]; - const u8 r10 = bpf2a32[TMP_REG_2][0]; - u16 reg_set = 0; - - /* unwind function call stack */ - emit(ARM_ADD_I(ARM_SP, ARM_SP, ctx->stack_size), ctx); - - /* restore callee saved registers. */ - reg_set |= (1<seen & SEEN_CALL) - reg_set |= (1<seen & SEEN_CALL)) - emit(ARM_BX(ARM_LR), ctx); + emit(ARM_MOV_R(ARM_SP, ARM_FP), ctx); + emit(ARM_POP(CALLEE_POP_MASK), ctx); #endif } @@ -1394,8 +1408,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) emit_rev32(rt, rt, ctx); goto emit_bswap_uxt; case 64: - /* Because of the usage of ARM_LR */ - ctx->seen |= SEEN_CALL; emit_rev32(ARM_LR, rt, ctx); emit_rev32(rt, rd, ctx); emit(ARM_MOV_R(rd, ARM_LR), ctx); @@ -1448,22 +1460,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) rn = sstk ? tmp2[1] : src_lo; if (sstk) emit(ARM_LDR_I(rn, ARM_SP, STACK_VAR(src_lo)), ctx); - switch (BPF_SIZE(code)) { - case BPF_W: - /* Load a Word */ - case BPF_H: - /* Load a Half-Word */ - case BPF_B: - /* Load a Byte */ - emit_ldx_r(dst_lo, rn, dstk, off, ctx, BPF_SIZE(code)); - emit_a32_mov_i(dst_hi, 0, dstk, ctx); - break; - case BPF_DW: - /* Load a double word */ - emit_ldx_r(dst_lo, rn, dstk, off, ctx, BPF_W); - emit_ldx_r(dst_hi, rn, dstk, off+4, ctx, BPF_W); - break; - } + emit_ldx_r(dst, rn, dstk, off, ctx, BPF_SIZE(code)); break; /* R0 = ntohx(*(size *)(((struct sk_buff *)R6)->data + imm)) */ case BPF_LD | BPF_ABS | BPF_W: diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 939b310913cf3..7318165cfc90b 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -14,8 +14,12 @@ LDFLAGS_vmlinux :=-p --no-undefined -X CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) GZFLAGS :=-9 -ifneq ($(CONFIG_RELOCATABLE),) -LDFLAGS_vmlinux += -pie -shared -Bsymbolic +ifeq ($(CONFIG_RELOCATABLE), y) +# Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour +# for relative relocs, since this leads to better Image compression +# with the relocation offsets always being zero. +LDFLAGS_vmlinux += -pie -shared -Bsymbolic \ + $(call ld-option, --no-apply-dynamic-relocs) endif ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) @@ -77,9 +81,6 @@ endif ifeq ($(CONFIG_ARM64_MODULE_PLTS),y) KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/arm64/kernel/module.lds -ifeq ($(CONFIG_DYNAMIC_FTRACE),y) -KBUILD_LDFLAGS_MODULE += $(objtree)/arch/arm64/kernel/ftrace-mod.o -endif endif # Default value diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index 1ffa1c238a725..08b7bb7f5b749 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -301,6 +301,7 @@ &usb1_phy { status = "okay"; + phy-supply = <&usb_otg_pwr>; }; &usb0 { diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi index d8dd3298b15cf..fb8d76a17bc5d 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi @@ -49,6 +49,14 @@ / { compatible = "amlogic,meson-gxl"; + + reserved-memory { + /* Alternate 3 MiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved_alt: secmon@05000000 { + reg = <0x0 0x05000000 0x0 0x300000>; + no-map; + }; + }; }; ðmac { diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi index f2aa2a81de4dd..32690107c1cce 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi @@ -63,8 +63,10 @@ cpm_ethernet: ethernet@0 { compatible = "marvell,armada-7k-pp22"; reg = <0x0 0x100000>, <0x129000 0xb000>; - clocks = <&cpm_clk 1 3>, <&cpm_clk 1 9>, <&cpm_clk 1 5>; - clock-names = "pp_clk", "gop_clk", "mg_clk"; + clocks = <&cpm_clk 1 3>, <&cpm_clk 1 9>, + <&cpm_clk 1 5>, <&cpm_clk 1 18>; + clock-names = "pp_clk", "gop_clk", + "mg_clk","axi_clk"; marvell,system-controller = <&cpm_syscon0>; status = "disabled"; dma-coherent; @@ -114,7 +116,8 @@ #size-cells = <0>; compatible = "marvell,orion-mdio"; reg = <0x12a200 0x10>; - clocks = <&cpm_clk 1 9>, <&cpm_clk 1 5>; + clocks = <&cpm_clk 1 9>, <&cpm_clk 1 5>, + <&cpm_clk 1 6>, <&cpm_clk 1 18>; status = "disabled"; }; @@ -295,8 +298,8 @@ compatible = "marvell,armada-cp110-sdhci"; reg = <0x780000 0x300>; interrupts = ; - clock-names = "core"; - clocks = <&cpm_clk 1 4>; + clock-names = "core","axi"; + clocks = <&cpm_clk 1 4>, <&cpm_clk 1 18>; dma-coherent; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi index 4fe70323abb3a..14e47c5c38161 100644 --- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi @@ -63,8 +63,10 @@ cps_ethernet: ethernet@0 { compatible = "marvell,armada-7k-pp22"; reg = <0x0 0x100000>, <0x129000 0xb000>; - clocks = <&cps_clk 1 3>, <&cps_clk 1 9>, <&cps_clk 1 5>; - clock-names = "pp_clk", "gop_clk", "mg_clk"; + clocks = <&cps_clk 1 3>, <&cps_clk 1 9>, + <&cps_clk 1 5>, <&cps_clk 1 18>; + clock-names = "pp_clk", "gop_clk", + "mg_clk", "axi_clk"; marvell,system-controller = <&cps_syscon0>; status = "disabled"; dma-coherent; @@ -114,7 +116,8 @@ #size-cells = <0>; compatible = "marvell,orion-mdio"; reg = <0x12a200 0x10>; - clocks = <&cps_clk 1 9>, <&cps_clk 1 5>; + clocks = <&cps_clk 1 9>, <&cps_clk 1 5>, + <&cps_clk 1 6>, <&cps_clk 1 18>; status = "disabled"; }; diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index e39d487bf7243..a3c7f271ad4c7 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -215,7 +215,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL /* * A pointer passed in from user mode. This should not diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 650344d011249..c4cd5081d78bc 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -132,11 +132,9 @@ static inline void efi_set_pgd(struct mm_struct *mm) * Defer the switch to the current thread's TTBR0_EL1 * until uaccess_enable(). Restore the current * thread's saved ttbr0 corresponding to its active_mm - * (if different from init_mm). */ cpu_set_reserved_ttbr0(); - if (current->active_mm != &init_mm) - update_saved_ttbr0(current, current->active_mm); + update_saved_ttbr0(current, current->active_mm); } } } diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index caf86be815ba2..4052ec39e8dbb 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -51,6 +51,13 @@ enum fixed_addresses { FIX_EARLYCON_MEM_BASE, FIX_TEXT_POKE0, + +#ifdef CONFIG_ACPI_APEI_GHES + /* Used for GHES mapping from assorted contexts */ + FIX_APEI_GHES_IRQ, + FIX_APEI_GHES_NMI, +#endif /* CONFIG_ACPI_APEI_GHES */ + __end_of_permanent_fixed_addresses, /* diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 61d694c2eae5b..555d463c0eaad 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -170,8 +170,7 @@ #define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN_FLAGS) #define VTTBR_X (VTTBR_X_TGRAN_MAGIC - VTCR_EL2_T0SZ_IPA) -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT (UL(48)) #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 3257895a9b5e4..9d155fa9a5079 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -156,29 +156,21 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu); #define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; }) -/* - * This is called when "tsk" is about to enter lazy TLB mode. - * - * mm: describes the currently active mm context - * tsk: task which is entering lazy tlb - * cpu: cpu number which is entering lazy tlb - * - * tsk->mm will be NULL - */ -static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -{ -} - #ifdef CONFIG_ARM64_SW_TTBR0_PAN static inline void update_saved_ttbr0(struct task_struct *tsk, struct mm_struct *mm) { - if (system_uses_ttbr0_pan()) { - BUG_ON(mm->pgd == swapper_pg_dir); - task_thread_info(tsk)->ttbr0 = - virt_to_phys(mm->pgd) | ASID(mm) << 48; - } + u64 ttbr; + + if (!system_uses_ttbr0_pan()) + return; + + if (mm == &init_mm) + ttbr = __pa_symbol(empty_zero_page); + else + ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48; + + task_thread_info(tsk)->ttbr0 = ttbr; } #else static inline void update_saved_ttbr0(struct task_struct *tsk, @@ -187,6 +179,16 @@ static inline void update_saved_ttbr0(struct task_struct *tsk, } #endif +static inline void +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ + /* + * We don't actually care about the ttbr0 mapping, so point it at the + * zero page. + */ + update_saved_ttbr0(tsk, &init_mm); +} + static inline void __switch_mm(struct mm_struct *next) { unsigned int cpu = smp_processor_id(); @@ -214,11 +216,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, * Update the saved TTBR0_EL1 of the scheduled-in task as the previous * value may have not been initialised yet (activate_mm caller) or the * ASID has changed since the last run (following the context switch - * of another thread of the same process). Avoid setting the reserved - * TTBR0_EL1 to swapper_pg_dir (init_mm; e.g. via idle_task_exit). + * of another thread of the same process). */ - if (next != &init_mm) - update_saved_ttbr0(tsk, next); + update_saved_ttbr0(tsk, next); } #define deactivate_mm(tsk,mm) do { } while (0) diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index 19bd97671bb8d..4f766178fa6ff 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -32,7 +32,7 @@ struct mod_arch_specific { struct mod_plt_sec init; /* for CONFIG_DYNAMIC_FTRACE */ - void *ftrace_trampoline; + struct plt_entry *ftrace_trampoline; }; #endif @@ -45,4 +45,48 @@ extern u64 module_alloc_base; #define module_alloc_base ((u64)_etext - MODULES_VSIZE) #endif +struct plt_entry { + /* + * A program that conforms to the AArch64 Procedure Call Standard + * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or + * IP1 (x17) may be inserted at any branch instruction that is + * exposed to a relocation that supports long branches. Since that + * is exactly what we are dealing with here, we are free to use x16 + * as a scratch register in the PLT veneers. + */ + __le32 mov0; /* movn x16, #0x.... */ + __le32 mov1; /* movk x16, #0x...., lsl #16 */ + __le32 mov2; /* movk x16, #0x...., lsl #32 */ + __le32 br; /* br x16 */ +}; + +static inline struct plt_entry get_plt_entry(u64 val) +{ + /* + * MOVK/MOVN/MOVZ opcode: + * +--------+------------+--------+-----------+-------------+---------+ + * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] | + * +--------+------------+--------+-----------+-------------+---------+ + * + * Rd := 0x10 (x16) + * hw := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32) + * opc := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ) + * sf := 1 (64-bit variant) + */ + return (struct plt_entry){ + cpu_to_le32(0x92800010 | (((~val ) & 0xffff)) << 5), + cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5), + cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5), + cpu_to_le32(0xd61f0200) + }; +} + +static inline bool plt_entries_equal(const struct plt_entry *a, + const struct plt_entry *b) +{ + return a->mov0 == b->mov0 && + a->mov1 == b->mov1 && + a->mov2 == b->mov2; +} + #endif /* __ASM_MODULE_H */ diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index b46e54c2399b5..960d05c8816af 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -98,6 +98,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN)) #define pte_valid_young(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF)) +#define pte_valid_user(pte) \ + ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) /* * Could the pte be present in the TLB? We must check mm_tlb_flush_pending @@ -107,6 +109,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_accessible(mm, pte) \ (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte)) +/* + * p??_access_permitted() is true for valid user mappings (subject to the + * write permission check) other than user execute-only which do not have the + * PTE_USER bit set. PROT_NONE mappings do not have the PTE_VALID bit set. + */ +#define pte_access_permitted(pte, write) \ + (pte_valid_user(pte) && (!(write) || pte_write(pte))) +#define pmd_access_permitted(pmd, write) \ + (pte_access_permitted(pmd_pte(pmd), (write))) +#define pud_access_permitted(pud, write) \ + (pte_access_permitted(pud_pte(pud), (write))) + static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot) { pte_val(pte) &= ~pgprot_val(prot); @@ -135,12 +149,20 @@ static inline pte_t pte_mkwrite(pte_t pte) static inline pte_t pte_mkclean(pte_t pte) { - return clear_pte_bit(pte, __pgprot(PTE_DIRTY)); + pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY)); + pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); + + return pte; } static inline pte_t pte_mkdirty(pte_t pte) { - return set_pte_bit(pte, __pgprot(PTE_DIRTY)); + pte = set_pte_bit(pte, __pgprot(PTE_DIRTY)); + + if (pte_write(pte)) + pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY)); + + return pte; } static inline pte_t pte_mkold(pte_t pte) @@ -628,28 +650,23 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /* - * ptep_set_wrprotect - mark read-only while preserving the hardware update of - * the Access Flag. + * ptep_set_wrprotect - mark read-only while trasferring potential hardware + * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit. */ #define __HAVE_ARCH_PTEP_SET_WRPROTECT static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) { pte_t old_pte, pte; - /* - * ptep_set_wrprotect() is only called on CoW mappings which are - * private (!VM_SHARED) with the pte either read-only (!PTE_WRITE && - * PTE_RDONLY) or writable and software-dirty (PTE_WRITE && - * !PTE_RDONLY && PTE_DIRTY); see is_cow_mapping() and - * protection_map[]. There is no race with the hardware update of the - * dirty state: clearing of PTE_RDONLY when PTE_WRITE (a.k.a. PTE_DBM) - * is set. - */ - VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(*ptep), - "%s: potential race with hardware DBM", __func__); pte = READ_ONCE(*ptep); do { old_pte = pte; + /* + * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY + * clear), set the PTE_DIRTY bit. + */ + if (pte_hw_dirty(pte)) + pte = pte_mkdirty(pte); pte = pte_wrprotect(pte); pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), pte_val(old_pte), pte_val(pte)); diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 0029e13adb596..2f5ff2a65db3f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -63,6 +63,3 @@ extra-y += $(head-y) vmlinux.lds ifeq ($(CONFIG_DEBUG_EFI),y) AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\"" endif - -# will be included by each individual module but not by the core kernel itself -extra-$(CONFIG_DYNAMIC_FTRACE) += ftrace-mod.o diff --git a/arch/arm64/kernel/ftrace-mod.S b/arch/arm64/kernel/ftrace-mod.S deleted file mode 100644 index 00c4025be4ff8..0000000000000 --- a/arch/arm64/kernel/ftrace-mod.S +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2017 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include - - .section ".text.ftrace_trampoline", "ax" - .align 3 -0: .quad 0 -__ftrace_trampoline: - ldr x16, 0b - br x16 -ENDPROC(__ftrace_trampoline) diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index c13b1fca0e5ba..50986e388d2b2 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -76,7 +76,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) if (offset < -SZ_128M || offset >= SZ_128M) { #ifdef CONFIG_ARM64_MODULE_PLTS - unsigned long *trampoline; + struct plt_entry trampoline; struct module *mod; /* @@ -104,22 +104,24 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) * is added in the future, but for now, the pr_err() below * deals with a theoretical issue only. */ - trampoline = (unsigned long *)mod->arch.ftrace_trampoline; - if (trampoline[0] != addr) { - if (trampoline[0] != 0) { + trampoline = get_plt_entry(addr); + if (!plt_entries_equal(mod->arch.ftrace_trampoline, + &trampoline)) { + if (!plt_entries_equal(mod->arch.ftrace_trampoline, + &(struct plt_entry){})) { pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n"); return -EINVAL; } /* point the trampoline to our ftrace entry point */ module_disable_ro(mod); - trampoline[0] = addr; + *mod->arch.ftrace_trampoline = trampoline; module_enable_ro(mod, true); /* update trampoline before patching in the branch */ smp_wmb(); } - addr = (unsigned long)&trampoline[1]; + addr = (unsigned long)(void *)mod->arch.ftrace_trampoline; #else /* CONFIG_ARM64_MODULE_PLTS */ return -EINVAL; #endif /* CONFIG_ARM64_MODULE_PLTS */ diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index d05dbe658409b..ea640f92fe5ad 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -11,21 +11,6 @@ #include #include -struct plt_entry { - /* - * A program that conforms to the AArch64 Procedure Call Standard - * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or - * IP1 (x17) may be inserted at any branch instruction that is - * exposed to a relocation that supports long branches. Since that - * is exactly what we are dealing with here, we are free to use x16 - * as a scratch register in the PLT veneers. - */ - __le32 mov0; /* movn x16, #0x.... */ - __le32 mov1; /* movk x16, #0x...., lsl #16 */ - __le32 mov2; /* movk x16, #0x...., lsl #32 */ - __le32 br; /* br x16 */ -}; - static bool in_init(const struct module *mod, void *loc) { return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; @@ -40,33 +25,14 @@ u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela, int i = pltsec->plt_num_entries; u64 val = sym->st_value + rela->r_addend; - /* - * MOVK/MOVN/MOVZ opcode: - * +--------+------------+--------+-----------+-------------+---------+ - * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] | - * +--------+------------+--------+-----------+-------------+---------+ - * - * Rd := 0x10 (x16) - * hw := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32) - * opc := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ) - * sf := 1 (64-bit variant) - */ - plt[i] = (struct plt_entry){ - cpu_to_le32(0x92800010 | (((~val ) & 0xffff)) << 5), - cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5), - cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5), - cpu_to_le32(0xd61f0200) - }; + plt[i] = get_plt_entry(val); /* * Check if the entry we just created is a duplicate. Given that the * relocations are sorted, this will be the last entry we allocated. * (if one exists). */ - if (i > 0 && - plt[i].mov0 == plt[i - 1].mov0 && - plt[i].mov1 == plt[i - 1].mov1 && - plt[i].mov2 == plt[i - 1].mov2) + if (i > 0 && plt_entries_equal(plt + i, plt + i - 1)) return (u64)&plt[i - 1]; pltsec->plt_num_entries++; @@ -154,6 +120,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, unsigned long core_plts = 0; unsigned long init_plts = 0; Elf64_Sym *syms = NULL; + Elf_Shdr *tramp = NULL; int i; /* @@ -165,6 +132,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.core.plt = sechdrs + i; else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt")) mod->arch.init.plt = sechdrs + i; + else if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) && + !strcmp(secstrings + sechdrs[i].sh_name, + ".text.ftrace_trampoline")) + tramp = sechdrs + i; else if (sechdrs[i].sh_type == SHT_SYMTAB) syms = (Elf64_Sym *)sechdrs[i].sh_addr; } @@ -215,5 +186,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt_num_entries = 0; mod->arch.init.plt_max_entries = init_plts; + if (tramp) { + tramp->sh_type = SHT_NOBITS; + tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + tramp->sh_addralign = __alignof__(struct plt_entry); + tramp->sh_size = sizeof(struct plt_entry); + } + return 0; } diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds index f7c9781a9d48b..22e36a21c1134 100644 --- a/arch/arm64/kernel/module.lds +++ b/arch/arm64/kernel/module.lds @@ -1,4 +1,5 @@ SECTIONS { .plt (NOLOAD) : { BYTE(0) } .init.plt (NOLOAD) : { BYTE(0) } + .text.ftrace_trampoline (NOLOAD) : { BYTE(0) } } diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 2dc0f84822109..bcd22d7ee5902 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -258,6 +258,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); + /* + * In case p was allocated the same task_struct pointer as some + * other recently-exited task, make sure p is disassociated from + * any cpu that may have run that now-exited task recently. + * Otherwise we could erroneously skip reloading the FPSIMD + * registers for p. + */ + fpsimd_flush_task_state(p); + if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7debb74843a05..380261e258ef8 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -44,7 +44,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_psci_call(vcpu); if (ret < 0) { - kvm_inject_undefined(vcpu); + vcpu_set_reg(vcpu, 0, ~0UL); return 1; } @@ -53,7 +53,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - kvm_inject_undefined(vcpu); + vcpu_set_reg(vcpu, 0, ~0UL); return 1; } diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c index f5154ed3da6c9..2add22699764b 100644 --- a/arch/arm64/kvm/hyp/debug-sr.c +++ b/arch/arm64/kvm/hyp/debug-sr.c @@ -84,6 +84,9 @@ static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1) { u64 reg; + /* Clear pmscr in case of early return */ + *pmscr_el1 = 0; + /* SPE present on this CPU? */ if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), ID_AA64DFR0_PMSVER_SHIFT)) diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index ca74a2aace425..7b60d62ac5939 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -389,7 +389,7 @@ void ptdump_check_wx(void) .check_wx = true, }; - walk_pgd(&st, &init_mm, 0); + walk_pgd(&st, &init_mm, VA_START); note_page(&st, 0, 0, 0); if (st.wx_pages || st.uxn_pages) pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n", diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 5960bef0170df..00e7b900ca419 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -476,6 +476,8 @@ void __init arm64_memblock_init(void) reserve_elfcorehdr(); + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + dma_contiguous_reserve(arm64_dma_phys_limit); memblock_allow_resize(); @@ -502,7 +504,6 @@ void __init bootmem_init(void) sparse_init(); zone_sizes_init(min, max); - high_memory = __va((max << PAGE_SHIFT) - 1) + 1; memblock_dump_all(); } diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index ba38d403abb2f..bb32f7f6dd0f9 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -148,7 +148,8 @@ static inline int epilogue_offset(const struct jit_ctx *ctx) /* Stack must be multiples of 16B */ #define STACK_ALIGN(sz) (((sz) + 15) & ~15) -#define PROLOGUE_OFFSET 8 +/* Tail call offset to jump into */ +#define PROLOGUE_OFFSET 7 static int build_prologue(struct jit_ctx *ctx) { @@ -200,19 +201,19 @@ static int build_prologue(struct jit_ctx *ctx) /* Initialize tail_call_cnt */ emit(A64_MOVZ(1, tcc, 0, 0), ctx); - /* 4 byte extra for skb_copy_bits buffer */ - ctx->stack_size = prog->aux->stack_depth + 4; - ctx->stack_size = STACK_ALIGN(ctx->stack_size); - - /* Set up function call stack */ - emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); - cur_offset = ctx->idx - idx0; if (cur_offset != PROLOGUE_OFFSET) { pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n", cur_offset, PROLOGUE_OFFSET); return -1; } + + /* 4 byte extra for skb_copy_bits buffer */ + ctx->stack_size = prog->aux->stack_depth + 4; + ctx->stack_size = STACK_ALIGN(ctx->stack_size); + + /* Set up function call stack */ + emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); return 0; } @@ -260,11 +261,12 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) emit(A64_LDR64(prg, tmp, prg), ctx); emit(A64_CBZ(1, prg, jmp_offset), ctx); - /* goto *(prog->bpf_func + prologue_size); */ + /* goto *(prog->bpf_func + prologue_offset); */ off = offsetof(struct bpf_prog, bpf_func); emit_a64_mov_i64(tmp, off, ctx); emit(A64_LDR64(tmp, prg, tmp), ctx); emit(A64_ADD_I(1, tmp, tmp, sizeof(u32) * PROLOGUE_OFFSET), ctx); + emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); emit(A64_BR(tmp), ctx); /* out: */ diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index af5369422032b..d9c2866ba618c 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -321,11 +321,14 @@ config BF53x config GPIO_ADI def_bool y + depends on !PINCTRL depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561) -config PINCTRL +config PINCTRL_BLACKFIN_ADI2 def_bool y - depends on BF54x || BF60x + depends on (BF54x || BF60x) + select PINCTRL + select PINCTRL_ADI2 config MEM_MT48LC64M4A2FB_7E bool diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index 4ddd1b73ee3e5..c8d957274cc20 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -18,6 +18,7 @@ config DEBUG_VERBOSE config DEBUG_MMRS tristate "Generate Blackfin MMR tree" + depends on !PINCTRL select DEBUG_FS help Create a tree of Blackfin MMRs via the debugfs tree. If diff --git a/arch/m68k/mm/mcfmmu.c b/arch/m68k/mm/mcfmmu.c index 8d1408583cf42..b523a604cb87b 100644 --- a/arch/m68k/mm/mcfmmu.c +++ b/arch/m68k/mm/mcfmmu.c @@ -170,7 +170,7 @@ void __init cf_bootmem_alloc(void) max_pfn = max_low_pfn = PFN_DOWN(_ramend); high_memory = (void *)_ramend; - m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6; + m68k_virt_to_node_shift = fls(_ramend - 1) - 6; module_fixup(NULL, __start_fixup, __stop_fixup); /* setup bootmem data */ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5d3284d20678a..c3d798b440307 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -65,7 +65,7 @@ config MIPS select HAVE_PERF_EVENTS select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_SYSCALL_TRACEPOINTS - select HAVE_VIRT_CPU_ACCOUNTING_GEN + select HAVE_VIRT_CPU_ACCOUNTING_GEN if 64BIT || !SMP select IRQ_FORCED_THREADING select MODULES_USE_ELF_RELA if MODULES && 64BIT select MODULES_USE_ELF_REL if MODULES diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 4674f1efbe7a5..e1675c25d5d48 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -575,7 +575,7 @@ static int __init ar7_register_uarts(void) uart_port.type = PORT_AR7; uart_port.uartclk = clk_get_rate(bus_clk) / 2; uart_port.iotype = UPIO_MEM32; - uart_port.flags = UPF_FIXED_TYPE; + uart_port.flags = UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF; uart_port.regshift = 2; uart_port.line = 0; diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c index d4f2407a42c60..8307a8a026672 100644 --- a/arch/mips/bcm47xx/leds.c +++ b/arch/mips/bcm47xx/leds.c @@ -331,7 +331,7 @@ bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = { /* Verified on: WRT54GS V1.0 */ static const struct gpio_led bcm47xx_leds_linksys_wrt54g_type_0101[] __initconst = { - BCM47XX_GPIO_LED(0, "green", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(0, "green", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), BCM47XX_GPIO_LED(1, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), BCM47XX_GPIO_LED(7, "green", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), }; diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index 9e09cc4556b38..3989943123613 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -23,7 +23,6 @@ dtb-$(CONFIG_DT_NONE) += \ bcm63268-comtrend-vr-3032u.dtb \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ - bcm96358nb4ser.dtb \ bcm96368mvwg.dtb \ bcm9ejtagprb.dtb \ bcm97125cbmb.dtb \ diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 7c8aab23bce8d..b1f66699677db 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -16,7 +16,6 @@ generic-y += qrwlock.h generic-y += qspinlock.h generic-y += sections.h generic-y += segment.h -generic-y += serial.h generic-y += trace_clock.h generic-y += unaligned.h generic-y += user.h diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 83054f79f72aa..feb069cbf44e8 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -19,6 +19,9 @@ #include #endif +/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ +#undef fp + /* * Helper macros for generating raw instruction encodings. */ @@ -105,6 +108,7 @@ .macro fpu_save_16odd thread .set push .set mips64r2 + .set fp=64 SET_HARDFLOAT sdc1 $f1, THREAD_FPR1(\thread) sdc1 $f3, THREAD_FPR3(\thread) @@ -126,8 +130,8 @@ .endm .macro fpu_save_double thread status tmp -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) sll \tmp, \status, 5 bgez \tmp, 10f fpu_save_16odd \thread @@ -163,6 +167,7 @@ .macro fpu_restore_16odd thread .set push .set mips64r2 + .set fp=64 SET_HARDFLOAT ldc1 $f1, THREAD_FPR1(\thread) ldc1 $f3, THREAD_FPR3(\thread) @@ -184,8 +189,8 @@ .endm .macro fpu_restore_double thread status tmp -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) sll \tmp, \status, 5 bgez \tmp, 10f # 16 register mode? @@ -234,9 +239,6 @@ .endm #ifdef TOOLCHAIN_SUPPORTS_MSA -/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ -#undef fp - .macro _cfcmsa rd, cs .set push .set mips32r2 diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h index 7e25c5cc353a8..89e9fb7976fe6 100644 --- a/arch/mips/include/asm/cmpxchg.h +++ b/arch/mips/include/asm/cmpxchg.h @@ -204,8 +204,10 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #else #include #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) +#ifndef CONFIG_SMP #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) #endif +#endif #undef __scbeqz diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index 8e2b5b5564886..49691331ada4c 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -200,7 +200,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL /* * A pointer passed in from user mode. This should not diff --git a/arch/mips/include/asm/serial.h b/arch/mips/include/asm/serial.h new file mode 100644 index 0000000000000..1d830c6666c27 --- /dev/null +++ b/arch/mips/include/asm/serial.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 MIPS Tech, LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __ASM__SERIAL_H +#define __ASM__SERIAL_H + +#ifdef CONFIG_MIPS_GENERIC +/* + * Generic kernels cannot know a correct value for all platforms at + * compile time. Set it to 0 to prevent 8250_early using it + */ +#define BASE_BAUD 0 +#else +#include +#endif + +#endif /* __ASM__SERIAL_H */ diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index dd5567b1e3055..8f5bd04f320a9 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -292,7 +292,6 @@ void mips_cm_lock_other(unsigned int cluster, unsigned int core, *this_cpu_ptr(&cm_core_lock_flags)); } else { WARN_ON(cluster != 0); - WARN_ON(vp != 0); WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); /* diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index c5ff6bfe2825b..2f2d176396aa5 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -705,6 +705,18 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) struct task_struct *t; int max_users; + /* If nothing to change, return right away, successfully. */ + if (value == mips_get_process_fp_mode(task)) + return 0; + + /* Only accept a mode change if 64-bit FP enabled for o32. */ + if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT)) + return -EOPNOTSUPP; + + /* And only for o32 tasks. */ + if (IS_ENABLED(CONFIG_64BIT) && !test_thread_flag(TIF_32BIT_REGS)) + return -EOPNOTSUPP; + /* Check the value is valid */ if (value & ~known_bits) return -EOPNOTSUPP; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 1395654cfc8d8..c552c20237d4f 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -410,63 +410,160 @@ static int gpr64_set(struct task_struct *target, #endif /* CONFIG_64BIT */ +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots + * correspond 1:1 to buffer slots. Only general registers are copied. + */ +static int fpr_get_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) +{ + return user_regset_copyout(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's + * general register slots are copied to buffer slots. Only general + * registers are copied. + */ +static int fpr_get_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS; i++) { + fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); + err = user_regset_copyout(pos, count, kbuf, ubuf, + &fpr_val, i * sizeof(elf_fpreg_t), + (i + 1) * sizeof(elf_fpreg_t)); + if (err) + return err; + } + + return 0; +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + */ static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - unsigned i; + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); int err; - u64 fpr_val; - /* XXX fcr31 */ + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); - for (i = 0; i < NUM_FPU_REGS; i++) { - fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); - err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fpr_val, i * sizeof(elf_fpreg_t), - (i + 1) * sizeof(elf_fpreg_t)); + return err; +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP + * context's general register slots. Only general registers are copied. + */ +static int fpr_set_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + return user_regset_copyin(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64 + * bits only of FP context's general register slots. Only general + * registers are copied. + */ +static int fpr_set_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { + err = user_regset_copyin(pos, count, kbuf, ubuf, + &fpr_val, i * sizeof(elf_fpreg_t), + (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; + set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); } return 0; } +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + * + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', + * which is supposed to have been guaranteed by the kernel before + * calling us, e.g. in `ptrace_regset'. We enforce that requirement, + * so that we can safely avoid preinitializing temporaries for + * partial register writes. + */ static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - unsigned i; + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + u32 fcr31; int err; - u64 fpr_val; - /* XXX fcr31 */ + BUG_ON(count % sizeof(elf_fpreg_t)); + + if (pos + count > sizeof(elf_fpregset_t)) + return -EIO; init_fp_ctx(target); - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; - BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); - for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) { + if (count > 0) { err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpr_val, i * sizeof(elf_fpreg_t), - (i + 1) * sizeof(elf_fpreg_t)); + &fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); if (err) return err; - set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); + + ptrace_setfcr31(target, fcr31); } - return 0; + return err; } enum mips_regset { @@ -618,6 +715,19 @@ static const struct user_regset_view user_mips64_view = { .n = ARRAY_SIZE(mips64_regsets), }; +#ifdef CONFIG_MIPS32_N32 + +static const struct user_regset_view user_mipsn32_view = { + .name = "mipsn32", + .e_flags = EF_MIPS_ABI2, + .e_machine = ELF_ARCH, + .ei_osabi = ELF_OSABI, + .regsets = mips64_regsets, + .n = ARRAY_SIZE(mips64_regsets), +}; + +#endif /* CONFIG_MIPS32_N32 */ + #endif /* CONFIG_64BIT */ const struct user_regset_view *task_user_regset_view(struct task_struct *task) @@ -628,6 +738,10 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #ifdef CONFIG_MIPS32_O32 if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) return &user_mips_view; +#endif +#ifdef CONFIG_MIPS32_N32 + if (test_tsk_thread_flag(task, TIF_32BIT_ADDR)) + return &user_mipsn32_view; #endif return &user_mips64_view; #endif diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 0a83b1708b3cb..8e3a6020c6134 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -40,8 +40,8 @@ */ LEAF(_save_fp) EXPORT_SYMBOL(_save_fp) -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) mfc0 t0, CP0_STATUS #endif fpu_save_double a0 t0 t1 # clobbers t1 @@ -52,8 +52,8 @@ EXPORT_SYMBOL(_save_fp) * Restore a thread's fp context. */ LEAF(_restore_fp) -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) mfc0 t0, CP0_STATUS #endif fpu_restore_double a0 t0 t1 # clobbers t1 @@ -246,11 +246,11 @@ LEAF(_save_fp_context) cfc1 t1, fcr31 .set pop -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) .set push SET_HARDFLOAT -#ifdef CONFIG_CPU_MIPS32_R2 +#ifdef CONFIG_CPU_MIPSR2 .set mips32r2 .set fp=64 mfc0 t0, CP0_STATUS @@ -314,11 +314,11 @@ LEAF(_save_fp_context) LEAF(_restore_fp_context) EX lw t1, 0(a1) -#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ - defined(CONFIG_CPU_MIPS32_R6) +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPSR2) || \ + defined(CONFIG_CPU_MIPSR6) .set push SET_HARDFLOAT -#ifdef CONFIG_CPU_MIPS32_R2 +#ifdef CONFIG_CPU_MIPSR2 .set mips32r2 .set fp=64 mfc0 t0, CP0_STATUS diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 16d9ef5a78c57..6f57212f56594 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1795,7 +1795,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); rv.s = ieee754sp_maddf(fd, fs, ft); - break; + goto copcsr; } case fmsubf_op: { @@ -1809,7 +1809,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); rv.s = ieee754sp_msubf(fd, fs, ft); - break; + goto copcsr; } case frint_op: { @@ -1834,7 +1834,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754sp_2008class(fs); rfmt = w_fmt; - break; + goto copcsr; } case fmin_op: { @@ -1847,7 +1847,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmin(fs, ft); - break; + goto copcsr; } case fmina_op: { @@ -1860,7 +1860,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmina(fs, ft); - break; + goto copcsr; } case fmax_op: { @@ -1873,7 +1873,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmax(fs, ft); - break; + goto copcsr; } case fmaxa_op: { @@ -1886,7 +1886,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmaxa(fs, ft); - break; + goto copcsr; } case fabs_op: @@ -2165,7 +2165,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); rv.d = ieee754dp_maddf(fd, fs, ft); - break; + goto copcsr; } case fmsubf_op: { @@ -2179,7 +2179,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); rv.d = ieee754dp_msubf(fd, fs, ft); - break; + goto copcsr; } case frint_op: { @@ -2204,7 +2204,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754dp_2008class(fs); rfmt = l_fmt; - break; + goto copcsr; } case fmin_op: { @@ -2217,7 +2217,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmin(fs, ft); - break; + goto copcsr; } case fmina_op: { @@ -2230,7 +2230,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmina(fs, ft); - break; + goto copcsr; } case fmax_op: { @@ -2243,7 +2243,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmax(fs, ft); - break; + goto copcsr; } case fmaxa_op: { @@ -2256,7 +2256,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmaxa(fs, ft); - break; + goto copcsr; } case fabs_op: diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 90fba9bf98da7..27ac00c36bc05 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -121,7 +121,7 @@ static int wait_pciephy_busy(void) else break; if (retry++ > WAITRETRY_MAX) { - printk(KERN_WARN "PCIE-PHY retry failed.\n"); + pr_warn("PCIE-PHY retry failed.\n"); return -1; } } diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 9be8b08ae46b7..41b71c4352c25 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -145,8 +145,8 @@ static struct rt2880_pmx_func i2c_grp_mt7628[] = { FUNC("i2c", 0, 4, 2), }; -static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) }; -static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) }; +static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("refclk", 0, 37, 1) }; +static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 36, 1) }; static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) }; static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) }; diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c index 9345b44b86f03..f57118e1f6b42 100644 --- a/arch/parisc/boot/compressed/misc.c +++ b/arch/parisc/boot/compressed/misc.c @@ -123,8 +123,8 @@ int puts(const char *s) while ((nuline = strchr(s, '\n')) != NULL) { if (nuline != s) pdc_iodc_print(s, nuline - s); - pdc_iodc_print("\r\n", 2); - s = nuline + 1; + pdc_iodc_print("\r\n", 2); + s = nuline + 1; } if (*s != '\0') pdc_iodc_print(s, strlen(s)); diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index 07f48827afdae..acf8aa07cbe09 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -195,7 +195,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL struct compat_ipc64_perm { compat_key_t key; diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h index dd5a08aaa4da7..3eb4bfc1fb365 100644 --- a/arch/parisc/include/asm/ldcw.h +++ b/arch/parisc/include/asm/ldcw.h @@ -12,6 +12,7 @@ for the semaphore. */ #define __PA_LDCW_ALIGNMENT 16 +#define __PA_LDCW_ALIGN_ORDER 4 #define __ldcw_align(a) ({ \ unsigned long __ret = (unsigned long) &(a)->lock[0]; \ __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) \ @@ -29,6 +30,7 @@ ldcd). */ #define __PA_LDCW_ALIGNMENT 4 +#define __PA_LDCW_ALIGN_ORDER 2 #define __ldcw_align(a) (&(a)->slock) #define __LDCW "ldcw,co" diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index a4fd296c958e8..e95207c0565eb 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,14 @@ #endif .import pa_tlb_lock,data + .macro load_pa_tlb_lock reg +#if __PA_LDCW_ALIGNMENT > 4 + load32 PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg + depi 0,31,__PA_LDCW_ALIGN_ORDER, \reg +#else + load32 PA(pa_tlb_lock), \reg +#endif + .endm /* space_to_prot macro creates a prot id from a space id */ @@ -457,7 +466,7 @@ .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault #ifdef CONFIG_SMP cmpib,COND(=),n 0,\spc,2f - load32 PA(pa_tlb_lock),\tmp + load_pa_tlb_lock \tmp 1: LDCW 0(\tmp),\tmp1 cmpib,COND(=) 0,\tmp1,1b nop @@ -480,7 +489,7 @@ /* Release pa_tlb_lock lock. */ .macro tlb_unlock1 spc,tmp #ifdef CONFIG_SMP - load32 PA(pa_tlb_lock),\tmp + load_pa_tlb_lock \tmp tlb_unlock0 \spc,\tmp #endif .endm @@ -878,9 +887,6 @@ ENTRY_CFI(syscall_exit_rfi) STREG %r19,PT_SR7(%r16) intr_return: - /* NOTE: Need to enable interrupts incase we schedule. */ - ssm PSW_SM_I, %r0 - /* check for reschedule */ mfctl %cr30,%r1 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ @@ -907,6 +913,11 @@ intr_check_sig: LDREG PT_IASQ1(%r16), %r20 cmpib,COND(=),n 0,%r20,intr_restore /* backward */ + /* NOTE: We need to enable interrupts if we have to deliver + * signals. We used to do this earlier but it caused kernel + * stack overflows. */ + ssm PSW_SM_I, %r0 + copy %r0, %r25 /* long in_syscall = 0 */ #ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ @@ -958,6 +969,10 @@ intr_do_resched: cmpib,COND(=) 0, %r20, intr_do_preempt nop + /* NOTE: We need to enable interrupts if we schedule. We used + * to do this earlier but it caused kernel stack overflows. */ + ssm PSW_SM_I, %r0 + #ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index e3a8e5e4d5de7..8d072c44f300c 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -305,6 +305,7 @@ ENDPROC_CFI(os_hpmc) __INITRODATA + .align 4 .export os_hpmc_size os_hpmc_size: .word .os_hpmc_end-.os_hpmc diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index adf7187f89515..2d40c4ff3f691 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -36,6 +36,7 @@ #include #include #include +#include #include .text @@ -333,8 +334,12 @@ ENDPROC_CFI(flush_data_cache_local) .macro tlb_lock la,flags,tmp #ifdef CONFIG_SMP - ldil L%pa_tlb_lock,%r1 - ldo R%pa_tlb_lock(%r1),\la +#if __PA_LDCW_ALIGNMENT > 4 + load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la + depi 0,31,__PA_LDCW_ALIGN_ORDER, \la +#else + load32 pa_tlb_lock, \la +#endif rsm PSW_SM_I,\flags 1: LDCW 0(\la),\tmp cmpib,<>,n 0,\tmp,3f diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 30f92391a93ef..cad3e8661cd6c 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,44 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) return 1; } +/* + * Idle thread support + * + * Detect when running on QEMU with SeaBIOS PDC Firmware and let + * QEMU idle the host too. + */ + +int running_on_qemu __read_mostly; + +void __cpuidle arch_cpu_idle_dead(void) +{ + /* nop on real hardware, qemu will offline CPU. */ + asm volatile("or %%r31,%%r31,%%r31\n":::); +} + +void __cpuidle arch_cpu_idle(void) +{ + local_irq_enable(); + + /* nop on real hardware, qemu will idle sleep. */ + asm volatile("or %%r10,%%r10,%%r10\n":::); +} + +static int __init parisc_idle_init(void) +{ + const char *marker; + + /* check QEMU/SeaBIOS marker in PAGE0 */ + marker = (char *) &PAGE0->pad0; + running_on_qemu = (memcmp(marker, "SeaBIOS", 8) == 0); + + if (!running_on_qemu) + cpu_idle_poll_ctrl(1); + + return 0; +} +arch_initcall(parisc_idle_init); + /* * Copy architecture-specific thread state */ diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 41e60a9c7db23..e775f80ae28c5 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -690,15 +690,15 @@ cas_action: /* ELF32 Process entry path */ lws_compare_and_swap_2: #ifdef CONFIG_64BIT - /* Clip the input registers */ + /* Clip the input registers. We don't need to clip %r23 as we + only use it for word operations */ depdi 0, 31, 32, %r26 depdi 0, 31, 32, %r25 depdi 0, 31, 32, %r24 - depdi 0, 31, 32, %r23 #endif /* Check the validity of the size pointer */ - subi,>>= 4, %r23, %r0 + subi,>>= 3, %r23, %r0 b,n lws_exit_nosys /* Jump to the functions which will load the old and new values into diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index a035b1e5dfa7c..8a2aecfe9b024 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -185,7 +185,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL /* * A pointer passed in from user mode. This should not diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h index a703452d67b62..555e22d5e07f9 100644 --- a/arch/powerpc/include/asm/exception-64e.h +++ b/arch/powerpc/include/asm/exception-64e.h @@ -209,5 +209,11 @@ exc_##label##_book3e: ori r3,r3,vector_offset@l; \ mtspr SPRN_IVOR##vector_number,r3; +#define RFI_TO_KERNEL \ + rfi + +#define RFI_TO_USER \ + rfi + #endif /* _ASM_POWERPC_EXCEPTION_64E_H */ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 9a318973af054..ccf10c2f8899f 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -69,6 +69,59 @@ */ #define EX_R3 EX_DAR +/* + * Macros for annotating the expected destination of (h)rfid + * + * The nop instructions allow us to insert one or more instructions to flush the + * L1-D cache when returning to userspace or a guest. + */ +#define RFI_FLUSH_SLOT \ + RFI_FLUSH_FIXUP_SECTION; \ + nop; \ + nop; \ + nop + +#define RFI_TO_KERNEL \ + rfid + +#define RFI_TO_USER \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback + +#define RFI_TO_USER_OR_KERNEL \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback + +#define RFI_TO_GUEST \ + RFI_FLUSH_SLOT; \ + rfid; \ + b rfi_flush_fallback + +#define HRFI_TO_KERNEL \ + hrfid + +#define HRFI_TO_USER \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + +#define HRFI_TO_USER_OR_KERNEL \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + +#define HRFI_TO_GUEST \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + +#define HRFI_TO_UNKNOWN \ + RFI_FLUSH_SLOT; \ + hrfid; \ + b hrfi_flush_fallback + #ifdef CONFIG_RELOCATABLE #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ @@ -213,7 +266,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) mtspr SPRN_##h##SRR0,r12; \ mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ mtspr SPRN_##h##SRR1,r10; \ - h##rfid; \ + h##RFI_TO_KERNEL; \ b . /* prevent speculative execution */ #define EXCEPTION_PROLOG_PSERIES_1(label, h) \ __EXCEPTION_PROLOG_PSERIES_1(label, h) @@ -227,7 +280,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) mtspr SPRN_##h##SRR0,r12; \ mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ mtspr SPRN_##h##SRR1,r10; \ - h##rfid; \ + h##RFI_TO_KERNEL; \ b . /* prevent speculative execution */ #define EXCEPTION_PROLOG_PSERIES_1_NORI(label, h) \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 8f88f771cc55c..1e82eb3caabd1 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -187,7 +187,20 @@ label##3: \ FTR_ENTRY_OFFSET label##1b-label##3b; \ .popsection; +#define RFI_FLUSH_FIXUP_SECTION \ +951: \ + .pushsection __rfi_flush_fixup,"a"; \ + .align 2; \ +952: \ + FTR_ENTRY_OFFSET 951b-952b; \ + .popsection; + + #ifndef __ASSEMBLY__ +#include + +extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; + void apply_feature_fixups(void); void setup_feature_keys(void); #endif diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index a409177be8bdf..f0461618bf7be 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -241,6 +241,7 @@ #define H_GET_HCA_INFO 0x1B8 #define H_GET_PERF_COUNT 0x1BC #define H_MANAGE_TRACE 0x1C0 +#define H_GET_CPU_CHARACTERISTICS 0x1C8 #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 #define H_QUERY_INT_STATE 0x1E4 #define H_POLL_PENDING 0x1D8 @@ -330,6 +331,17 @@ #define H_SIGNAL_SYS_RESET_ALL_OTHERS -2 /* >= 0 values are CPU number */ +/* H_GET_CPU_CHARACTERISTICS return values */ +#define H_CPU_CHAR_SPEC_BAR_ORI31 (1ull << 63) // IBM bit 0 +#define H_CPU_CHAR_BCCTRL_SERIALISED (1ull << 62) // IBM bit 1 +#define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 +#define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 +#define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 + +#define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 +#define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 +#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ull << 61) // IBM bit 2 + /* Flag values used in H_REGISTER_PROC_TBL hcall */ #define PROC_TABLE_OP_MASK 0x18 #define PROC_TABLE_DEREG 0x10 @@ -436,6 +448,11 @@ static inline unsigned int get_longbusy_msecs(int longbusy_rc) } } +struct h_cpu_char_result { + u64 character; + u64 behaviour; +}; + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HVCALL_H */ diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 73b92017b6d7b..cd2fc1cc1cc7c 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -76,6 +76,7 @@ struct machdep_calls { void __noreturn (*restart)(char *cmd); void __noreturn (*halt)(void); + void (*panic)(char *str); void (*cpu_die)(void); long (*time_init)(void); /* Optional, may be NULL */ diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 492d8140a395f..44fdf4786638b 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -114,9 +114,10 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, #endif } -static inline void arch_dup_mmap(struct mm_struct *oldmm, - struct mm_struct *mm) +static inline int arch_dup_mmap(struct mm_struct *oldmm, + struct mm_struct *mm) { + return 0; } static inline void arch_exit_mmap(struct mm_struct *mm) diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 04b60af027ae3..b8366df50d195 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -231,6 +231,16 @@ struct paca_struct { struct sibling_subcore_state *sibling_subcore_state; #endif #endif +#ifdef CONFIG_PPC_BOOK3S_64 + /* + * rfi fallback flush must be in its own cacheline to prevent + * other paca data leaking into the L1d + */ + u64 exrfi[EX_SIZE] __aligned(0x80); + void *rfi_flush_fallback_area; + u64 l1d_flush_congruence; + u64 l1d_flush_sets; +#endif }; extern void copy_mm_to_paca(struct mm_struct *mm); diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h index 7f01b22fa6cb0..55eddf50d1498 100644 --- a/arch/powerpc/include/asm/plpar_wrappers.h +++ b/arch/powerpc/include/asm/plpar_wrappers.h @@ -326,4 +326,18 @@ static inline long plapr_signal_sys_reset(long cpu) return plpar_hcall_norets(H_SIGNAL_SYS_RESET, cpu); } +static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + long rc; + + rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf); + if (rc == H_SUCCESS) { + p->character = retbuf[0]; + p->behaviour = retbuf[1]; + } + + return rc; +} + #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index 257d23dbf55dc..469b7fdc9be41 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -24,6 +24,7 @@ extern void reloc_got2(unsigned long); void check_for_initrd(void); void initmem_init(void); +void setup_panic(void); #define ARCH_PANIC_TIMEOUT 180 #ifdef CONFIG_PPC_PSERIES @@ -38,6 +39,19 @@ static inline void pseries_big_endian_exceptions(void) {} static inline void pseries_little_endian_exceptions(void) {} #endif /* CONFIG_PPC_PSERIES */ +void rfi_flush_enable(bool enable); + +/* These are bit flags */ +enum l1d_flush_type { + L1D_FLUSH_NONE = 0x1, + L1D_FLUSH_FALLBACK = 0x2, + L1D_FLUSH_ORI = 0x4, + L1D_FLUSH_MTTRIG = 0x8, +}; + +void __init setup_rfi_flush(enum l1d_flush_type, bool enable); +void do_rfi_flush_fixups(enum l1d_flush_type types); + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_SETUP_H */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 8cfb20e38cfe9..748cdc4bb89ab 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -237,6 +237,11 @@ int main(void) OFFSET(PACA_NMI_EMERG_SP, paca_struct, nmi_emergency_sp); OFFSET(PACA_IN_MCE, paca_struct, in_mce); OFFSET(PACA_IN_NMI, paca_struct, in_nmi); + OFFSET(PACA_RFI_FLUSH_FALLBACK_AREA, paca_struct, rfi_flush_fallback_area); + OFFSET(PACA_EXRFI, paca_struct, exrfi); + OFFSET(PACA_L1D_FLUSH_CONGRUENCE, paca_struct, l1d_flush_congruence); + OFFSET(PACA_L1D_FLUSH_SETS, paca_struct, l1d_flush_sets); + #endif OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id); OFFSET(PACAKEXECSTATE, paca_struct, kexec_state); diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 610955fe8b81c..679bbe714e856 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -102,6 +102,7 @@ _GLOBAL(__setup_cpu_power9) li r0,0 mtspr SPRN_PSSCR,r0 mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC) or r3, r3, r4 @@ -126,6 +127,7 @@ _GLOBAL(__restore_cpu_power9) li r0,0 mtspr SPRN_PSSCR,r0 mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC) or r3, r3, r4 diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 4a0fd4f402453..8a8a6d7ddcc6e 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -37,6 +37,11 @@ #include #include #include +#ifdef CONFIG_PPC_BOOK3S +#include +#else +#include +#endif /* * System calls. @@ -262,13 +267,23 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r13,GPR13(r1) /* only restore r13 if returning to usermode */ + ld r2,GPR2(r1) + ld r1,GPR1(r1) + mtlr r4 + mtcr r5 + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r8 + RFI_TO_USER + b . /* prevent speculative execution */ + + /* exit to kernel */ 1: ld r2,GPR2(r1) ld r1,GPR1(r1) mtlr r4 mtcr r5 mtspr SPRN_SRR0,r7 mtspr SPRN_SRR1,r8 - RFI + RFI_TO_KERNEL b . /* prevent speculative execution */ .Lsyscall_error: @@ -397,8 +412,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) mtmsrd r10, 1 mtspr SPRN_SRR0, r11 mtspr SPRN_SRR1, r12 - - rfid + RFI_TO_USER b . /* prevent speculative execution */ #endif _ASM_NOKPROBE_SYMBOL(system_call_common); @@ -878,7 +892,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ACCOUNT_CPU_USER_EXIT(r13, r2, r4) REST_GPR(13, r1) -1: + mtspr SPRN_SRR1,r3 ld r2,_CCR(r1) @@ -891,8 +905,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r3,GPR3(r1) ld r4,GPR4(r1) ld r1,GPR1(r1) + RFI_TO_USER + b . /* prevent speculative execution */ - rfid +1: mtspr SPRN_SRR1,r3 + + ld r2,_CCR(r1) + mtcrf 0xFF,r2 + ld r2,_NIP(r1) + mtspr SPRN_SRR0,r2 + + ld r0,GPR0(r1) + ld r2,GPR2(r1) + ld r3,GPR3(r1) + ld r4,GPR4(r1) + ld r1,GPR1(r1) + RFI_TO_KERNEL b . /* prevent speculative execution */ #endif /* CONFIG_PPC_BOOK3E */ @@ -1073,7 +1101,7 @@ __enter_rtas: mtspr SPRN_SRR0,r5 mtspr SPRN_SRR1,r6 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ rtas_return_loc: @@ -1098,7 +1126,7 @@ rtas_return_loc: mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ _ASM_NOKPROBE_SYMBOL(__enter_rtas) _ASM_NOKPROBE_SYMBOL(rtas_return_loc) @@ -1171,7 +1199,7 @@ _GLOBAL(enter_prom) LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE) andc r11,r11,r12 mtsrr1 r11 - rfid + RFI_TO_KERNEL #endif /* CONFIG_PPC_BOOK3E */ 1: /* Return from OF */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 1c80bd292e481..e9f72abc52b72 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -254,7 +254,7 @@ BEGIN_FTR_SECTION LOAD_HANDLER(r12, machine_check_handle_early) 1: mtspr SPRN_SRR0,r12 mtspr SPRN_SRR1,r11 - rfid + RFI_TO_KERNEL b . /* prevent speculative execution */ 2: /* Stack overflow. Stay on emergency stack and panic. @@ -443,7 +443,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early) li r3,MSR_ME andc r10,r10,r3 /* Turn off MSR_ME */ mtspr SPRN_SRR1,r10 - rfid + RFI_TO_KERNEL b . 2: /* @@ -461,7 +461,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early) */ bl machine_check_queue_event MACHINE_CHECK_HANDLER_WINDUP - rfid + RFI_TO_USER_OR_KERNEL 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP @@ -542,7 +542,7 @@ EXC_COMMON_BEGIN(instruction_access_common) RECONCILE_IRQ_STATE(r10, r11) ld r12,_MSR(r1) ld r3,_NIP(r1) - andis. r4,r12,DSISR_BAD_FAULT_64S@h + andis. r4,r12,DSISR_SRR1_MATCH_64S@h li r5,0x400 std r3,_DAR(r1) std r4,_DSISR(r1) @@ -596,6 +596,9 @@ EXC_COMMON_BEGIN(slb_miss_common) stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ + andi. r9,r11,MSR_PR // Check for exception from userspace + cmpdi cr4,r9,MSR_PR // And save the result in CR4 for later + /* * Test MSR_RI before calling slb_allocate_realmode, because the * MSR in r11 gets clobbered. However we still want to allocate @@ -622,9 +625,12 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) /* All done -- return from exception. */ + bne cr4,1f /* returning to kernel */ + .machine push .machine "power4" mtcrf 0x80,r9 + mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ mtcrf 0x02,r9 /* I/D indication is in cr6 */ mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ @@ -638,9 +644,30 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) ld r11,PACA_EXSLB+EX_R11(r13) ld r12,PACA_EXSLB+EX_R12(r13) ld r13,PACA_EXSLB+EX_R13(r13) - rfid + RFI_TO_USER + b . /* prevent speculative execution */ +1: +.machine push +.machine "power4" + mtcrf 0x80,r9 + mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ + mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ + mtcrf 0x02,r9 /* I/D indication is in cr6 */ + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ +.machine pop + + RESTORE_CTR(r9, PACA_EXSLB) + RESTORE_PPR_PACA(PACA_EXSLB, r9) + mr r3,r12 + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + RFI_TO_KERNEL b . /* prevent speculative execution */ + 2: std r3,PACA_EXSLB+EX_DAR(r13) mr r3,r12 mfspr r11,SPRN_SRR0 @@ -649,7 +676,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) mtspr SPRN_SRR1,r10 - rfid + RFI_TO_KERNEL b . 8: std r3,PACA_EXSLB+EX_DAR(r13) @@ -660,7 +687,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) mtspr SPRN_SRR1,r10 - rfid + RFI_TO_KERNEL b . EXC_COMMON_BEGIN(unrecov_slb) @@ -905,7 +932,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ mtspr SPRN_SRR0,r10 ; \ ld r10,PACAKMSR(r13) ; \ mtspr SPRN_SRR1,r10 ; \ - rfid ; \ + RFI_TO_KERNEL ; \ b . ; /* prevent speculative execution */ #define SYSCALL_FASTENDIAN \ @@ -914,7 +941,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ xori r12,r12,MSR_LE ; \ mtspr SPRN_SRR1,r12 ; \ mr r13,r9 ; \ - rfid ; /* return to userspace */ \ + RFI_TO_USER ; /* return to userspace */ \ b . ; /* prevent speculative execution */ #if defined(CONFIG_RELOCATABLE) @@ -1299,7 +1326,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) ld r11,PACA_EXGEN+EX_R11(r13) ld r12,PACA_EXGEN+EX_R12(r13) ld r13,PACA_EXGEN+EX_R13(r13) - HRFID + HRFI_TO_UNKNOWN b . #endif @@ -1403,10 +1430,94 @@ masked_##_H##interrupt: \ ld r10,PACA_EXGEN+EX_R10(r13); \ ld r11,PACA_EXGEN+EX_R11(r13); \ /* returns to kernel where r13 must be set up, so don't restore it */ \ - ##_H##rfid; \ + ##_H##RFI_TO_KERNEL; \ b .; \ MASKED_DEC_HANDLER(_H) +TRAMP_REAL_BEGIN(rfi_flush_fallback) + SET_SCRATCH0(r13); + GET_PACA(r13); + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + std r11,PACA_EXRFI+EX_R11(r13) + std r12,PACA_EXRFI+EX_R12(r13) + std r8,PACA_EXRFI+EX_R13(r13) + mfctr r9 + ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) + ld r11,PACA_L1D_FLUSH_SETS(r13) + ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ + addi r12,r12,8 + mtctr r11 + DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ + + /* order ld/st prior to dcbt stop all streams with flushing */ + sync +1: li r8,0 + .rept 8 /* 8-way set associative */ + ldx r11,r10,r8 + add r8,r8,r12 + xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not + add r8,r8,r11 // Add 0, this creates a dependency on the ldx + .endr + addi r10,r10,128 /* 128 byte cache line */ + bdnz 1b + + mtctr r9 + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ld r11,PACA_EXRFI+EX_R11(r13) + ld r12,PACA_EXRFI+EX_R12(r13) + ld r8,PACA_EXRFI+EX_R13(r13) + GET_SCRATCH0(r13); + rfid + +TRAMP_REAL_BEGIN(hrfi_flush_fallback) + SET_SCRATCH0(r13); + GET_PACA(r13); + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + std r11,PACA_EXRFI+EX_R11(r13) + std r12,PACA_EXRFI+EX_R12(r13) + std r8,PACA_EXRFI+EX_R13(r13) + mfctr r9 + ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) + ld r11,PACA_L1D_FLUSH_SETS(r13) + ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ + addi r12,r12,8 + mtctr r11 + DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ + + /* order ld/st prior to dcbt stop all streams with flushing */ + sync +1: li r8,0 + .rept 8 /* 8-way set associative */ + ldx r11,r10,r8 + add r8,r8,r12 + xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not + add r8,r8,r11 // Add 0, this creates a dependency on the ldx + .endr + addi r10,r10,128 /* 128 byte cache line */ + bdnz 1b + + mtctr r9 + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ld r11,PACA_EXRFI+EX_R11(r13) + ld r12,PACA_EXRFI+EX_R12(r13) + ld r8,PACA_EXRFI+EX_R13(r13) + GET_SCRATCH0(r13); + hrfid + /* * Real mode exceptions actually use this too, but alternate * instruction code patches (which end up in the common .text area) @@ -1426,7 +1537,7 @@ TRAMP_REAL_BEGIN(kvmppc_skip_interrupt) addi r13, r13, 4 mtspr SPRN_SRR0, r13 GET_SCRATCH0(r13) - rfid + RFI_TO_KERNEL b . TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt) @@ -1438,7 +1549,7 @@ TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt) addi r13, r13, 4 mtspr SPRN_HSRR0, r13 GET_SCRATCH0(r13) - hrfid + HRFI_TO_KERNEL b . #endif diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index e1431800bfb9f..29d2b60501408 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1453,25 +1453,6 @@ static void fadump_init_files(void) return; } -static int fadump_panic_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - /* - * If firmware-assisted dump has been registered then trigger - * firmware-assisted dump and let firmware handle everything - * else. If this returns, then fadump was not registered, so - * go through the rest of the panic path. - */ - crash_fadump(NULL, ptr); - - return NOTIFY_DONE; -} - -static struct notifier_block fadump_panic_block = { - .notifier_call = fadump_panic_event, - .priority = INT_MIN /* may not return; must be done last */ -}; - /* * Prepare for firmware-assisted dump. */ @@ -1504,9 +1485,6 @@ int __init setup_fadump(void) init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); fadump_init_files(); - atomic_notifier_chain_register(&panic_notifier_list, - &fadump_panic_block); - return 1; } subsys_initcall(setup_fadump); diff --git a/arch/powerpc/kernel/kprobes-ftrace.c b/arch/powerpc/kernel/kprobes-ftrace.c index 6c089d9757c9c..2d81404f818c7 100644 --- a/arch/powerpc/kernel/kprobes-ftrace.c +++ b/arch/powerpc/kernel/kprobes-ftrace.c @@ -65,6 +65,7 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip, /* Disable irq for emulating a breakpoint and avoiding preempt */ local_irq_save(flags); hard_irq_disable(); + preempt_disable(); p = get_kprobe((kprobe_opcode_t *)nip); if (unlikely(!p) || kprobe_disabled(p)) @@ -86,12 +87,18 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip, kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (!p->pre_handler || !p->pre_handler(p, regs)) __skip_singlestep(p, regs, kcb, orig_nip); - /* - * If pre_handler returns !0, it sets regs->nip and - * resets current kprobe. - */ + else { + /* + * If pre_handler returns !0, it sets regs->nip and + * resets current kprobe. In this case, we still need + * to restore irq, but not preemption. + */ + local_irq_restore(flags); + return; + } } end: + preempt_enable_no_resched(); local_irq_restore(flags); } NOKPROBE_SYMBOL(kprobe_ftrace_handler); diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 8ac0bd2bddb0c..3280953a82cf6 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -623,7 +623,9 @@ BEGIN_FTR_SECTION * NOTE, we rely on r0 being 0 from above. */ mtspr SPRN_IAMR,r0 +BEGIN_FTR_SECTION_NESTED(42) mtspr SPRN_AMOR,r0 +END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) /* save regs for local vars on new stack. diff --git a/arch/powerpc/kernel/optprobes.c b/arch/powerpc/kernel/optprobes.c index 91e037ab20a19..60ba7f1370a80 100644 --- a/arch/powerpc/kernel/optprobes.c +++ b/arch/powerpc/kernel/optprobes.c @@ -115,7 +115,6 @@ static unsigned long can_optimize(struct kprobe *p) static void optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) { - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); unsigned long flags; /* This is possible if op is under delayed unoptimizing */ @@ -124,13 +123,14 @@ static void optimized_callback(struct optimized_kprobe *op, local_irq_save(flags); hard_irq_disable(); + preempt_disable(); if (kprobe_running()) { kprobes_inc_nmissed_count(&op->kp); } else { __this_cpu_write(current_kprobe, &op->kp); regs->nip = (unsigned long)op->kp.addr; - kcb->kprobe_status = KPROBE_HIT_ACTIVE; + get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; opt_pre_handler(&op->kp, regs); __this_cpu_write(current_kprobe, NULL); } @@ -140,6 +140,7 @@ static void optimized_callback(struct optimized_kprobe *op, * local_irq_restore() will re-enable interrupts, * if they were hard disabled. */ + preempt_enable_no_resched(); local_irq_restore(flags); } NOKPROBE_SYMBOL(optimized_callback); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 2e3bc16d02b28..90bc20efb4c7b 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -704,6 +704,30 @@ int check_legacy_ioport(unsigned long base_port) } EXPORT_SYMBOL(check_legacy_ioport); +static int ppc_panic_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + /* + * If firmware-assisted dump has been registered then trigger + * firmware-assisted dump and let firmware handle everything else. + */ + crash_fadump(NULL, ptr); + ppc_md.panic(ptr); /* May not return */ + return NOTIFY_DONE; +} + +static struct notifier_block ppc_panic_block = { + .notifier_call = ppc_panic_event, + .priority = INT_MIN /* may not return; must be done last */ +}; + +void __init setup_panic(void) +{ + if (!ppc_md.panic) + return; + atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block); +} + #ifdef CONFIG_CHECK_CACHE_COHERENCY /* * For platforms that have configurable cache-coherency. This function @@ -848,6 +872,9 @@ void __init setup_arch(char **cmdline_p) /* Probe the machine type, establish ppc_md. */ probe_machine(); + /* Setup panic notifier if requested by the platform. */ + setup_panic(); + /* * Configure ppc_md.power_save (ppc32 only, 64-bit machines do * it from their respective probe() function. diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index b89c6aac48c9b..935059cb9e403 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -784,3 +784,104 @@ static int __init disable_hardlockup_detector(void) return 0; } early_initcall(disable_hardlockup_detector); + +#ifdef CONFIG_PPC_BOOK3S_64 +static enum l1d_flush_type enabled_flush_types; +static void *l1d_flush_fallback_area; +static bool no_rfi_flush; +bool rfi_flush; + +static int __init handle_no_rfi_flush(char *p) +{ + pr_info("rfi-flush: disabled on command line."); + no_rfi_flush = true; + return 0; +} +early_param("no_rfi_flush", handle_no_rfi_flush); + +/* + * The RFI flush is not KPTI, but because users will see doco that says to use + * nopti we hijack that option here to also disable the RFI flush. + */ +static int __init handle_no_pti(char *p) +{ + pr_info("rfi-flush: disabling due to 'nopti' on command line.\n"); + handle_no_rfi_flush(NULL); + return 0; +} +early_param("nopti", handle_no_pti); + +static void do_nothing(void *unused) +{ + /* + * We don't need to do the flush explicitly, just enter+exit kernel is + * sufficient, the RFI exit handlers will do the right thing. + */ +} + +void rfi_flush_enable(bool enable) +{ + if (rfi_flush == enable) + return; + + if (enable) { + do_rfi_flush_fixups(enabled_flush_types); + on_each_cpu(do_nothing, NULL, 1); + } else + do_rfi_flush_fixups(L1D_FLUSH_NONE); + + rfi_flush = enable; +} + +static void init_fallback_flush(void) +{ + u64 l1d_size, limit; + int cpu; + + l1d_size = ppc64_caches.l1d.size; + limit = min(safe_stack_limit(), ppc64_rma_size); + + /* + * Align to L1d size, and size it at 2x L1d size, to catch possible + * hardware prefetch runoff. We don't have a recipe for load patterns to + * reliably avoid the prefetcher. + */ + l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit)); + memset(l1d_flush_fallback_area, 0, l1d_size * 2); + + for_each_possible_cpu(cpu) { + /* + * The fallback flush is currently coded for 8-way + * associativity. Different associativity is possible, but it + * will be treated as 8-way and may not evict the lines as + * effectively. + * + * 128 byte lines are mandatory. + */ + u64 c = l1d_size / 8; + + paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area; + paca[cpu].l1d_flush_congruence = c; + paca[cpu].l1d_flush_sets = c / 128; + } +} + +void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) +{ + if (types & L1D_FLUSH_FALLBACK) { + pr_info("rfi-flush: Using fallback displacement flush\n"); + init_fallback_flush(); + } + + if (types & L1D_FLUSH_ORI) + pr_info("rfi-flush: Using ori type flush\n"); + + if (types & L1D_FLUSH_MTTRIG) + pr_info("rfi-flush: Using mttrig type flush\n"); + + enabled_flush_types = types; + + if (!no_rfi_flush) + rfi_flush_enable(enable); +} +#endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index e9436c5e1e094..3d7539b90010c 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -103,7 +103,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, static void do_signal(struct task_struct *tsk) { sigset_t *oldset = sigmask_to_save(); - struct ksignal ksig; + struct ksignal ksig = { .sig = 0 }; int ret; int is32 = is_32bit_task(); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 0494e1566ee2a..307843d23682a 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -132,6 +132,15 @@ SECTIONS /* Read-only data */ RO_DATA(PAGE_SIZE) +#ifdef CONFIG_PPC64 + . = ALIGN(8); + __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { + __start___rfi_flush_fixup = .; + *(__rfi_flush_fixup) + __stop___rfi_flush_fixup = .; + } +#endif + EXCEPTION_TABLE(0) NOTES :kernel :notes diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c index 57190f384f633..ce848ff84eddf 100644 --- a/arch/powerpc/kernel/watchdog.c +++ b/arch/powerpc/kernel/watchdog.c @@ -276,9 +276,12 @@ void arch_touch_nmi_watchdog(void) { unsigned long ticks = tb_ticks_per_usec * wd_timer_period_ms * 1000; int cpu = smp_processor_id(); + u64 tb = get_tb(); - if (get_tb() - per_cpu(wd_timer_tb, cpu) >= ticks) - watchdog_timer_interrupt(cpu); + if (tb - per_cpu(wd_timer_tb, cpu) >= ticks) { + per_cpu(wd_timer_tb, cpu) = tb; + wd_smp_clear_cpu_pending(cpu, tb); + } } EXPORT_SYMBOL(arch_touch_nmi_watchdog); diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c index 29ebe2fd58674..a93d719edc906 100644 --- a/arch/powerpc/kvm/book3s_64_mmu.c +++ b/arch/powerpc/kvm/book3s_64_mmu.c @@ -235,6 +235,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, gpte->may_read = true; gpte->may_write = true; gpte->page_size = MMU_PAGE_4K; + gpte->wimg = HPTE_R_M; return 0; } diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 59247af5fd450..2645d484e945b 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -65,11 +65,17 @@ struct kvm_resize_hpt { u32 order; /* These fields protected by kvm->lock */ + + /* Possible values and their usage: + * <0 an error occurred during allocation, + * -EBUSY allocation is in the progress, + * 0 allocation made successfuly. + */ int error; - bool prepare_done; - /* Private to the work thread, until prepare_done is true, - * then protected by kvm->resize_hpt_sem */ + /* Private to the work thread, until error != -EBUSY, + * then protected by kvm->lock. + */ struct kvm_hpt_info hpt; }; @@ -159,8 +165,6 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) * Reset all the reverse-mapping chains for all memslots */ kvmppc_rmap_reset(kvm); - /* Ensure that each vcpu will flush its TLB on next entry. */ - cpumask_setall(&kvm->arch.need_tlb_flush); err = 0; goto out; } @@ -176,6 +180,10 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) kvmppc_set_hpt(kvm, &info); out: + if (err == 0) + /* Ensure that each vcpu will flush its TLB on next entry. */ + cpumask_setall(&kvm->arch.need_tlb_flush); + mutex_unlock(&kvm->lock); return err; } @@ -1424,16 +1432,20 @@ static void resize_hpt_pivot(struct kvm_resize_hpt *resize) static void resize_hpt_release(struct kvm *kvm, struct kvm_resize_hpt *resize) { - BUG_ON(kvm->arch.resize_hpt != resize); + if (WARN_ON(!mutex_is_locked(&kvm->lock))) + return; if (!resize) return; - if (resize->hpt.virt) - kvmppc_free_hpt(&resize->hpt); + if (resize->error != -EBUSY) { + if (resize->hpt.virt) + kvmppc_free_hpt(&resize->hpt); + kfree(resize); + } - kvm->arch.resize_hpt = NULL; - kfree(resize); + if (kvm->arch.resize_hpt == resize) + kvm->arch.resize_hpt = NULL; } static void resize_hpt_prepare_work(struct work_struct *work) @@ -1442,17 +1454,41 @@ static void resize_hpt_prepare_work(struct work_struct *work) struct kvm_resize_hpt, work); struct kvm *kvm = resize->kvm; - int err; + int err = 0; - resize_hpt_debug(resize, "resize_hpt_prepare_work(): order = %d\n", - resize->order); - - err = resize_hpt_allocate(resize); + if (WARN_ON(resize->error != -EBUSY)) + return; mutex_lock(&kvm->lock); + /* Request is still current? */ + if (kvm->arch.resize_hpt == resize) { + /* We may request large allocations here: + * do not sleep with kvm->lock held for a while. + */ + mutex_unlock(&kvm->lock); + + resize_hpt_debug(resize, "resize_hpt_prepare_work(): order = %d\n", + resize->order); + + err = resize_hpt_allocate(resize); + + /* We have strict assumption about -EBUSY + * when preparing for HPT resize. + */ + if (WARN_ON(err == -EBUSY)) + err = -EINPROGRESS; + + mutex_lock(&kvm->lock); + /* It is possible that kvm->arch.resize_hpt != resize + * after we grab kvm->lock again. + */ + } + resize->error = err; - resize->prepare_done = true; + + if (kvm->arch.resize_hpt != resize) + resize_hpt_release(kvm, resize); mutex_unlock(&kvm->lock); } @@ -1477,14 +1513,12 @@ long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, if (resize) { if (resize->order == shift) { - /* Suitable resize in progress */ - if (resize->prepare_done) { - ret = resize->error; - if (ret != 0) - resize_hpt_release(kvm, resize); - } else { + /* Suitable resize in progress? */ + ret = resize->error; + if (ret == -EBUSY) ret = 100; /* estimated time in ms */ - } + else if (ret) + resize_hpt_release(kvm, resize); goto out; } @@ -1504,6 +1538,8 @@ long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, ret = -ENOMEM; goto out; } + + resize->error = -EBUSY; resize->order = shift; resize->kvm = kvm; INIT_WORK(&resize->work, resize_hpt_prepare_work); @@ -1558,16 +1594,12 @@ long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, if (!resize || (resize->order != shift)) goto out; - ret = -EBUSY; - if (!resize->prepare_done) - goto out; - ret = resize->error; - if (ret != 0) + if (ret) goto out; ret = resize_hpt_rehash(resize); - if (ret != 0) + if (ret) goto out; resize_hpt_pivot(resize); diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 90644db9d38e2..8e0cf8f186dfd 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -529,6 +529,8 @@ static inline bool is_rm(void) unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; if (xive_enabled()) { if (is_rm()) return xive_rm_h_xirr(vcpu); @@ -541,6 +543,8 @@ unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu) unsigned long kvmppc_rm_h_xirr_x(struct kvm_vcpu *vcpu) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; vcpu->arch.gpr[5] = get_tb(); if (xive_enabled()) { if (is_rm()) @@ -554,6 +558,8 @@ unsigned long kvmppc_rm_h_xirr_x(struct kvm_vcpu *vcpu) unsigned long kvmppc_rm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; if (xive_enabled()) { if (is_rm()) return xive_rm_h_ipoll(vcpu, server); @@ -567,6 +573,8 @@ unsigned long kvmppc_rm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server) int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, unsigned long mfrr) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; if (xive_enabled()) { if (is_rm()) return xive_rm_h_ipi(vcpu, server, mfrr); @@ -579,6 +587,8 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; if (xive_enabled()) { if (is_rm()) return xive_rm_h_cppr(vcpu, cppr); @@ -591,6 +601,8 @@ int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) { + if (!kvmppc_xics_enabled(vcpu)) + return H_TOO_HARD; if (xive_enabled()) { if (is_rm()) return xive_rm_h_eoi(vcpu, xirr); diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 42639fba89e88..c85ac5c83bd4f 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -78,7 +78,7 @@ _GLOBAL_TOC(kvmppc_hv_entry_trampoline) mtmsrd r0,1 /* clear RI in MSR */ mtsrr0 r5 mtsrr1 r6 - RFI + RFI_TO_KERNEL kvmppc_call_hv_entry: ld r4, HSTATE_KVM_VCPU(r13) @@ -187,7 +187,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300) mtmsrd r6, 1 /* Clear RI in MSR */ mtsrr0 r8 mtsrr1 r7 - RFI + RFI_TO_KERNEL /* Virtual-mode return */ .Lvirt_return: @@ -1131,8 +1131,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) ld r0, VCPU_GPR(R0)(r4) ld r4, VCPU_GPR(R4)(r4) - - hrfid + HRFI_TO_GUEST b . secondary_too_late: diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 69a09444d46e6..e2ef161984561 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -60,6 +60,7 @@ static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac); #define MSR_USER32 MSR_USER #define MSR_USER64 MSR_USER #define HW_PAGE_SIZE PAGE_SIZE +#define HPTE_R_M _PAGE_COHERENT #endif static bool kvmppc_is_split_real(struct kvm_vcpu *vcpu) @@ -557,6 +558,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, pte.eaddr = eaddr; pte.vpage = eaddr >> 12; pte.page_size = MMU_PAGE_64K; + pte.wimg = HPTE_R_M; } switch (kvmppc_get_msr(vcpu) & (MSR_DR|MSR_IR)) { diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 42a4b237df5f5..34a5adeff0840 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -46,6 +46,9 @@ #define FUNC(name) name +#define RFI_TO_KERNEL RFI +#define RFI_TO_GUEST RFI + .macro INTERRUPT_TRAMPOLINE intno .global kvmppc_trampoline_\intno @@ -141,7 +144,7 @@ kvmppc_handler_skip_ins: GET_SCRATCH0(r13) /* And get back into the code */ - RFI + RFI_TO_KERNEL #endif /* @@ -164,6 +167,6 @@ _GLOBAL_TOC(kvmppc_entry_trampoline) ori r5, r5, MSR_EE mtsrr0 r7 mtsrr1 r6 - RFI + RFI_TO_KERNEL #include "book3s_segment.S" diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index 2a2b96d539991..93a180ceefad0 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -156,7 +156,7 @@ no_dcbz32_on: PPC_LL r9, SVCPU_R9(r3) PPC_LL r3, (SVCPU_R3)(r3) - RFI + RFI_TO_GUEST kvmppc_handler_trampoline_enter_end: @@ -407,5 +407,5 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) cmpwi r12, BOOK3S_INTERRUPT_DOORBELL beqa BOOK3S_INTERRUPT_DOORBELL - RFI + RFI_TO_KERNEL kvmppc_handler_trampoline_exit_end: diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c index bf457843e0321..0d750d274c4e2 100644 --- a/arch/powerpc/kvm/book3s_xive.c +++ b/arch/powerpc/kvm/book3s_xive.c @@ -725,7 +725,8 @@ u64 kvmppc_xive_get_icp(struct kvm_vcpu *vcpu) /* Return the per-cpu state for state saving/migration */ return (u64)xc->cppr << KVM_REG_PPC_ICP_CPPR_SHIFT | - (u64)xc->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT; + (u64)xc->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT | + (u64)0xff << KVM_REG_PPC_ICP_PPRI_SHIFT; } int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) @@ -1558,7 +1559,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr) /* * Restore P and Q. If the interrupt was pending, we - * force both P and Q, which will trigger a resend. + * force Q and !P, which will trigger a resend. * * That means that a guest that had both an interrupt * pending (queued) and Q set will restore with only @@ -1566,7 +1567,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr) * is perfectly fine as coalescing interrupts that haven't * been presented yet is always allowed. */ - if (val & KVM_XICS_PRESENTED || val & KVM_XICS_PENDING) + if (val & KVM_XICS_PRESENTED && !(val & KVM_XICS_PENDING)) state->old_p = true; if (val & KVM_XICS_QUEUED || val & KVM_XICS_PENDING) state->old_q = true; diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index c9de03e0c1f12..d469224c4ada8 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -21,6 +21,7 @@ #include #include #include +#include static int __patch_instruction(unsigned int *addr, unsigned int instr) { @@ -146,11 +147,8 @@ int patch_instruction(unsigned int *addr, unsigned int instr) * During early early boot patch_instruction is called * when text_poke_area is not ready, but we still need * to allow patching. We just do the plain old patching - * We use slab_is_available and per cpu read * via this_cpu_read - * of text_poke_area. Per-CPU areas might not be up early - * this can create problems with just using this_cpu_read() */ - if (!slab_is_available() || !this_cpu_read(text_poke_area)) + if (!this_cpu_read(*PTRRELOC(&text_poke_area))) return __patch_instruction(addr, instr); local_irq_save(flags); diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 41cf5ae273cf7..a95ea007d654d 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -116,6 +116,47 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) } } +#ifdef CONFIG_PPC_BOOK3S_64 +void do_rfi_flush_fixups(enum l1d_flush_type types) +{ + unsigned int instrs[3], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___rfi_flush_fixup), + end = PTRRELOC(&__stop___rfi_flush_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + + if (types & L1D_FLUSH_FALLBACK) + /* b .+16 to fallback flush */ + instrs[0] = 0x48000010; + + i = 0; + if (types & L1D_FLUSH_ORI) { + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/ + } + + if (types & L1D_FLUSH_MTTRIG) + instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */ + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + patch_instruction(dest + 1, instrs[1]); + patch_instruction(dest + 2, instrs[2]); + } + + printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); +} +#endif /* CONFIG_PPC_BOOK3S_64 */ + void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) { long *start, *end; diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 4797d08581cec..6e1e390353806 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -145,6 +145,11 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address) return __bad_area(regs, address, SEGV_MAPERR); } +static noinline int bad_access(struct pt_regs *regs, unsigned long address) +{ + return __bad_area(regs, address, SEGV_ACCERR); +} + static int do_sigbus(struct pt_regs *regs, unsigned long address, unsigned int fault) { @@ -490,7 +495,7 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address, good_area: if (unlikely(access_error(is_write, is_exec, vma))) - return bad_area(regs, address); + return bad_access(regs, address); /* * If for any reason at all we couldn't handle the fault, diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 3848af167df9d..640cf566e9865 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -47,7 +47,8 @@ DEFINE_RAW_SPINLOCK(native_tlbie_lock); -static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) +static inline unsigned long ___tlbie(unsigned long vpn, int psize, + int apsize, int ssize) { unsigned long va; unsigned int penc; @@ -100,7 +101,15 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) : "memory"); break; } - trace_tlbie(0, 0, va, 0, 0, 0, 0); + return va; +} + +static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) +{ + unsigned long rb; + + rb = ___tlbie(vpn, psize, apsize, ssize); + trace_tlbie(0, 0, rb, 0, 0, 0, 0); } static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize) @@ -652,7 +661,7 @@ static void native_hpte_clear(void) if (hpte_v & HPTE_V_VALID) { hpte_decode(hptep, slot, &psize, &apsize, &ssize, &vpn); hptep->v = 0; - __tlbie(vpn, psize, apsize, ssize); + ___tlbie(vpn, psize, apsize, ssize); } } diff --git a/arch/powerpc/mm/hugetlbpage-radix.c b/arch/powerpc/mm/hugetlbpage-radix.c index 558e9d3891bfc..bd022d16745c2 100644 --- a/arch/powerpc/mm/hugetlbpage-radix.c +++ b/arch/powerpc/mm/hugetlbpage-radix.c @@ -49,17 +49,28 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr, struct mm_struct *mm = current->mm; struct vm_area_struct *vma; struct hstate *h = hstate_file(file); + int fixed = (flags & MAP_FIXED); + unsigned long high_limit; struct vm_unmapped_area_info info; - if (unlikely(addr > mm->context.addr_limit && addr < TASK_SIZE)) - mm->context.addr_limit = TASK_SIZE; + high_limit = DEFAULT_MAP_WINDOW; + if (addr >= high_limit || (fixed && (addr + len > high_limit))) + high_limit = TASK_SIZE; if (len & ~huge_page_mask(h)) return -EINVAL; - if (len > mm->task_size) + if (len > high_limit) return -ENOMEM; + if (fixed) { + if (addr > high_limit - len) + return -ENOMEM; + } - if (flags & MAP_FIXED) { + if (unlikely(addr > mm->context.addr_limit && + mm->context.addr_limit != TASK_SIZE)) + mm->context.addr_limit = TASK_SIZE; + + if (fixed) { if (prepare_hugepage_range(file, addr, len)) return -EINVAL; return addr; @@ -68,7 +79,7 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (addr) { addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); - if (mm->task_size - len >= addr && + if (high_limit - len >= addr && (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -79,12 +90,9 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr, info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; info.low_limit = PAGE_SIZE; - info.high_limit = current->mm->mmap_base; + info.high_limit = mm->mmap_base + (high_limit - DEFAULT_MAP_WINDOW); info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; - if (addr > DEFAULT_MAP_WINDOW) - info.high_limit += mm->context.addr_limit - DEFAULT_MAP_WINDOW; - return vm_unmapped_area(&info); } diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c index 5d78b193fec41..6d476a7b56112 100644 --- a/arch/powerpc/mm/mmap.c +++ b/arch/powerpc/mm/mmap.c @@ -106,22 +106,32 @@ radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + int fixed = (flags & MAP_FIXED); + unsigned long high_limit; struct vm_unmapped_area_info info; + high_limit = DEFAULT_MAP_WINDOW; + if (addr >= high_limit || (fixed && (addr + len > high_limit))) + high_limit = TASK_SIZE; + + if (len > high_limit) + return -ENOMEM; + if (fixed) { + if (addr > high_limit - len) + return -ENOMEM; + } + if (unlikely(addr > mm->context.addr_limit && mm->context.addr_limit != TASK_SIZE)) mm->context.addr_limit = TASK_SIZE; - if (len > mm->task_size - mmap_min_addr) - return -ENOMEM; - - if (flags & MAP_FIXED) + if (fixed) return addr; if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (mm->task_size - len >= addr && addr >= mmap_min_addr && + if (high_limit - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -129,13 +139,9 @@ radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, info.flags = 0; info.length = len; info.low_limit = mm->mmap_base; + info.high_limit = high_limit; info.align_mask = 0; - if (unlikely(addr > DEFAULT_MAP_WINDOW)) - info.high_limit = mm->context.addr_limit; - else - info.high_limit = DEFAULT_MAP_WINDOW; - return vm_unmapped_area(&info); } @@ -149,37 +155,42 @@ radix__arch_get_unmapped_area_topdown(struct file *filp, struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr = addr0; + int fixed = (flags & MAP_FIXED); + unsigned long high_limit; struct vm_unmapped_area_info info; + high_limit = DEFAULT_MAP_WINDOW; + if (addr >= high_limit || (fixed && (addr + len > high_limit))) + high_limit = TASK_SIZE; + + if (len > high_limit) + return -ENOMEM; + if (fixed) { + if (addr > high_limit - len) + return -ENOMEM; + } + if (unlikely(addr > mm->context.addr_limit && mm->context.addr_limit != TASK_SIZE)) mm->context.addr_limit = TASK_SIZE; - /* requested length too big for entire address space */ - if (len > mm->task_size - mmap_min_addr) - return -ENOMEM; - - if (flags & MAP_FIXED) + if (fixed) return addr; - /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (mm->task_size - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) + if (high_limit - len >= addr && addr >= mmap_min_addr && + (!vma || addr + len <= vm_start_gap(vma))) return addr; } info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; info.low_limit = max(PAGE_SIZE, mmap_min_addr); - info.high_limit = mm->mmap_base; + info.high_limit = mm->mmap_base + (high_limit - DEFAULT_MAP_WINDOW); info.align_mask = 0; - if (addr > DEFAULT_MAP_WINDOW) - info.high_limit += mm->context.addr_limit - DEFAULT_MAP_WINDOW; - addr = vm_unmapped_area(&info); if (!(addr & ~PAGE_MASK)) return addr; diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index 05e15386d4cb3..b94fb62e60fde 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -93,11 +93,11 @@ static int hash__init_new_context(struct mm_struct *mm) return index; /* - * We do switch_slb() early in fork, even before we setup the - * mm->context.addr_limit. Default to max task size so that we copy the - * default values to paca which will help us to handle slb miss early. + * In the case of exec, use the default limit, + * otherwise inherit it from the mm we are duplicating. */ - mm->context.addr_limit = DEFAULT_MAP_WINDOW_USER64; + if (!mm->context.addr_limit) + mm->context.addr_limit = DEFAULT_MAP_WINDOW_USER64; /* * The old code would re-promote on fork, we don't do that when using diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index 39c252b54d161..cfbbee941a76b 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c @@ -169,6 +169,16 @@ void radix__mark_rodata_ro(void) { unsigned long start, end; + /* + * mark_rodata_ro() will mark itself as !writable at some point. + * Due to DD1 workaround in radix__pte_update(), we'll end up with + * an invalid pte and the system will crash quite severly. + */ + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { + pr_warn("Warning: Unable to mark rodata read only on P9 DD1\n"); + return; + } + start = (unsigned long)_stext; end = (unsigned long)__init_begin; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 45f6740dd407d..a4f93699194b6 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -96,7 +96,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, { struct vm_area_struct *vma; - if ((mm->task_size - len) < addr) + if ((mm->context.addr_limit - len) < addr) return 0; vma = find_vma(mm, addr); return (!vma || (addr + len) <= vm_start_gap(vma)); @@ -133,7 +133,7 @@ static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret) if (!slice_low_has_vma(mm, i)) ret->low_slices |= 1u << i; - if (mm->task_size <= SLICE_LOW_TOP) + if (mm->context.addr_limit <= SLICE_LOW_TOP) return; for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.addr_limit); i++) @@ -412,25 +412,31 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, struct slice_mask compat_mask; int fixed = (flags & MAP_FIXED); int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT); + unsigned long page_size = 1UL << pshift; struct mm_struct *mm = current->mm; unsigned long newaddr; unsigned long high_limit; - /* - * Check if we need to expland slice area. - */ - if (unlikely(addr > mm->context.addr_limit && - mm->context.addr_limit != TASK_SIZE)) { - mm->context.addr_limit = TASK_SIZE; + high_limit = DEFAULT_MAP_WINDOW; + if (addr >= high_limit || (fixed && (addr + len > high_limit))) + high_limit = TASK_SIZE; + + if (len > high_limit) + return -ENOMEM; + if (len & (page_size - 1)) + return -EINVAL; + if (fixed) { + if (addr & (page_size - 1)) + return -EINVAL; + if (addr > high_limit - len) + return -ENOMEM; + } + + if (high_limit > mm->context.addr_limit) { + mm->context.addr_limit = high_limit; on_each_cpu(slice_flush_segments, mm, 1); } - /* - * This mmap request can allocate upt to 512TB - */ - if (addr > DEFAULT_MAP_WINDOW) - high_limit = mm->context.addr_limit; - else - high_limit = DEFAULT_MAP_WINDOW; + /* * init different masks */ @@ -446,27 +452,19 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, /* Sanity checks */ BUG_ON(mm->task_size == 0); + BUG_ON(mm->context.addr_limit == 0); VM_BUG_ON(radix_enabled()); slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize); slice_dbg(" addr=%lx, len=%lx, flags=%lx, topdown=%d\n", addr, len, flags, topdown); - if (len > mm->task_size) - return -ENOMEM; - if (len & ((1ul << pshift) - 1)) - return -EINVAL; - if (fixed && (addr & ((1ul << pshift) - 1))) - return -EINVAL; - if (fixed && addr > (mm->task_size - len)) - return -ENOMEM; - /* If hint, make sure it matches our alignment restrictions */ if (!fixed && addr) { - addr = _ALIGN_UP(addr, 1ul << pshift); + addr = _ALIGN_UP(addr, page_size); slice_dbg(" aligned addr=%lx\n", addr); /* Ignore hint if it's too large or overlaps a VMA */ - if (addr > mm->task_size - len || + if (addr > high_limit - len || !slice_area_is_free(mm, addr, len)) addr = 0; } diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index a66e64b0b251f..5d115bd325391 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -762,7 +762,8 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, func = (u8 *) __bpf_call_base + imm; /* Save skb pointer if we need to re-cache skb data */ - if (bpf_helper_changes_pkt_data(func)) + if ((ctx->seen & SEEN_SKB) && + bpf_helper_changes_pkt_data(func)) PPC_BPF_STL(3, 1, bpf_jit_stack_local(ctx)); bpf_jit_emit_func_call(image, ctx, (u64)func); @@ -771,7 +772,8 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, PPC_MR(b2p[BPF_REG_0], 3); /* refresh skb cache */ - if (bpf_helper_changes_pkt_data(func)) { + if ((ctx->seen & SEEN_SKB) && + bpf_helper_changes_pkt_data(func)) { /* reload skb pointer to r3 */ PPC_BPF_LL(3, 1, bpf_jit_stack_local(ctx)); bpf_jit_emit_skb_loads(image, ctx); diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 9e3da168d54cd..b4209a68b85da 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -410,8 +410,12 @@ static __u64 power_pmu_bhrb_to(u64 addr) int ret; __u64 target; - if (is_kernel_addr(addr)) - return branch_target((unsigned int *)addr); + if (is_kernel_addr(addr)) { + if (probe_kernel_read(&instr, (void *)addr, sizeof(instr))) + return 0; + + return branch_target(&instr); + } /* Userspace: need copy instruction here then translate it */ pagefault_disable(); diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 9c88b82f62293..72238eedc360f 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -540,7 +540,7 @@ static int memord(const void *d1, size_t s1, const void *d2, size_t s2) { if (s1 < s2) return 1; - if (s2 > s1) + if (s1 > s2) return -1; return memcmp(d1, d2, s1); diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index 36344117c680b..cf64e16f92c25 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -467,7 +467,7 @@ static int nest_imc_event_init(struct perf_event *event) * Nest HW counter memory resides in a per-chip reserve-memory (HOMER). * Get the base memory addresss for this cpu. */ - chip_id = topology_physical_package_id(event->cpu); + chip_id = cpu_to_chip_id(event->cpu); pcni = pmu->mem_info; do { if (pcni->id == chip_id) { @@ -524,19 +524,19 @@ static int nest_imc_event_init(struct perf_event *event) */ static int core_imc_mem_init(int cpu, int size) { - int phys_id, rc = 0, core_id = (cpu / threads_per_core); + int nid, rc = 0, core_id = (cpu / threads_per_core); struct imc_mem_info *mem_info; /* * alloc_pages_node() will allocate memory for core in the * local node only. */ - phys_id = topology_physical_package_id(cpu); + nid = cpu_to_node(cpu); mem_info = &core_imc_pmu->mem_info[core_id]; mem_info->id = core_id; /* We need only vbase for core counters */ - mem_info->vbase = page_address(alloc_pages_node(phys_id, + mem_info->vbase = page_address(alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE | __GFP_NOWARN, get_order(size))); if (!mem_info->vbase) @@ -797,14 +797,14 @@ static int core_imc_event_init(struct perf_event *event) static int thread_imc_mem_alloc(int cpu_id, int size) { u64 ldbar_value, *local_mem = per_cpu(thread_imc_mem, cpu_id); - int phys_id = topology_physical_package_id(cpu_id); + int nid = cpu_to_node(cpu_id); if (!local_mem) { /* * This case could happen only once at start, since we dont * free the memory in cpu offline path. */ - local_mem = page_address(alloc_pages_node(phys_id, + local_mem = page_address(alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE | __GFP_NOWARN, get_order(size))); if (!local_mem) diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c index cf33769a7b725..45b3feb8aa2f7 100644 --- a/arch/powerpc/platforms/powernv/opal-async.c +++ b/arch/powerpc/platforms/powernv/opal-async.c @@ -39,18 +39,18 @@ int __opal_async_get_token(void) int token; spin_lock_irqsave(&opal_async_comp_lock, flags); - token = find_first_bit(opal_async_complete_map, opal_max_async_tokens); + token = find_first_zero_bit(opal_async_token_map, opal_max_async_tokens); if (token >= opal_max_async_tokens) { token = -EBUSY; goto out; } - if (__test_and_set_bit(token, opal_async_token_map)) { + if (!__test_and_clear_bit(token, opal_async_complete_map)) { token = -EBUSY; goto out; } - __clear_bit(token, opal_async_complete_map); + __set_bit(token, opal_async_token_map); out: spin_unlock_irqrestore(&opal_async_comp_lock, flags); diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c index 21f6531fae20f..b150f4deaccfc 100644 --- a/arch/powerpc/platforms/powernv/opal-imc.c +++ b/arch/powerpc/platforms/powernv/opal-imc.c @@ -191,8 +191,10 @@ static int opal_imc_counters_probe(struct platform_device *pdev) break; } - if (!imc_pmu_create(imc_dev, pmu_count, domain)) - pmu_count++; + if (!imc_pmu_create(imc_dev, pmu_count, domain)) { + if (domain == IMC_DOMAIN_NEST) + pmu_count++; + } } return 0; diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index bbb73aa0eb8f0..7966a314d93ab 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -36,13 +36,62 @@ #include #include #include +#include #include "powernv.h" +static void pnv_setup_rfi_flush(void) +{ + struct device_node *np, *fw_features; + enum l1d_flush_type type; + int enable; + + /* Default to fallback in case fw-features are not available */ + type = L1D_FLUSH_FALLBACK; + enable = 1; + + np = of_find_node_by_name(NULL, "ibm,opal"); + fw_features = of_get_child_by_name(np, "fw-features"); + of_node_put(np); + + if (fw_features) { + np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); + if (np && of_property_read_bool(np, "enabled")) + type = L1D_FLUSH_MTTRIG; + + of_node_put(np); + + np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); + if (np && of_property_read_bool(np, "enabled")) + type = L1D_FLUSH_ORI; + + of_node_put(np); + + /* Enable unless firmware says NOT to */ + enable = 2; + np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); + if (np && of_property_read_bool(np, "disabled")) + enable--; + + of_node_put(np); + + np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); + if (np && of_property_read_bool(np, "disabled")) + enable--; + + of_node_put(np); + of_node_put(fw_features); + } + + setup_rfi_flush(type, enable > 0); +} + static void __init pnv_setup_arch(void) { set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); + pnv_setup_rfi_flush(); + /* Initialize SMP */ pnv_smp_init(); @@ -319,7 +368,7 @@ static unsigned long pnv_get_proc_freq(unsigned int cpu) { unsigned long ret_freq; - ret_freq = cpufreq_quick_get(cpu) * 1000ul; + ret_freq = cpufreq_get(cpu) * 1000ul; /* * If the backend cpufreq driver does not exist, diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 9dabea6e14439..6244bc849469e 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -104,6 +104,20 @@ static void __noreturn ps3_halt(void) ps3_sys_manager_halt(); /* never returns */ } +static void ps3_panic(char *str) +{ + DBG("%s:%d %s\n", __func__, __LINE__, str); + + smp_send_stop(); + printk("\n"); + printk(" System does not reboot automatically.\n"); + printk(" Please press POWER button.\n"); + printk("\n"); + + while(1) + lv1_pause(1); +} + #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \ defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) static void __init prealloc(struct ps3_prealloc *p) @@ -255,6 +269,7 @@ define_machine(ps3) { .probe = ps3_probe, .setup_arch = ps3_setup_arch, .init_IRQ = ps3_init_IRQ, + .panic = ps3_panic, .get_boot_time = ps3_get_boot_time, .set_dabr = ps3_set_dabr, .calibrate_decr = ps3_calibrate_decr, diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 5f1beb8367aca..ae4f596273b51 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -459,6 +459,39 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } +static void pseries_setup_rfi_flush(void) +{ + struct h_cpu_char_result result; + enum l1d_flush_type types; + bool enable; + long rc; + + /* Enable by default */ + enable = true; + + rc = plpar_get_cpu_characteristics(&result); + if (rc == H_SUCCESS) { + types = L1D_FLUSH_NONE; + + if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) + types |= L1D_FLUSH_MTTRIG; + if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) + types |= L1D_FLUSH_ORI; + + /* Use fallback if nothing set in hcall */ + if (types == L1D_FLUSH_NONE) + types = L1D_FLUSH_FALLBACK; + + if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) + enable = false; + } else { + /* Default to fallback if case hcall is not available */ + types = L1D_FLUSH_FALLBACK; + } + + setup_rfi_flush(types, enable); +} + static void __init pSeries_setup_arch(void) { set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); @@ -476,6 +509,8 @@ static void __init pSeries_setup_arch(void) fwnmi_init(); + pseries_setup_rfi_flush(); + /* By default, only probe PCI (can be overridden by rtas_pci) */ pci_add_flags(PCI_PROBE_ONLY); @@ -726,6 +761,7 @@ define_machine(pseries) { .pcibios_fixup = pSeries_final_fixup, .restart = rtas_restart, .halt = rtas_halt, + .panic = rtas_os_term, .get_boot_time = rtas_get_boot_time, .get_rtc_time = rtas_get_rtc_time, .set_rtc_time = rtas_set_rtc_time, diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 12277bc9fd9eb..d86938260a867 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1592,6 +1592,8 @@ ATTRIBUTE_GROUPS(vio_dev); void vio_unregister_device(struct vio_dev *viodev) { device_unregister(&viodev->dev); + if (viodev->family == VDEVICE) + irq_dispose_mapping(viodev->irq); } EXPORT_SYMBOL(vio_unregister_device); diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 16f1edd78c40e..535cf1f6941c0 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -846,12 +846,12 @@ void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) u32 ipic_get_mcp_status(void) { - return ipic_read(primary_ipic->regs, IPIC_SERMR); + return ipic_read(primary_ipic->regs, IPIC_SERSR); } void ipic_clear_mcp_status(u32 mask) { - ipic_write(primary_ipic->regs, IPIC_SERMR, mask); + ipic_write(primary_ipic->regs, IPIC_SERSR, mask); } /* Return an interrupt vector or 0 if no interrupt is pending. */ diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 33351c6704b1d..2c8b325591cc2 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -530,14 +530,19 @@ static int xmon_core(struct pt_regs *regs, int fromipi) waiting: secondary = 1; + spin_begin(); while (secondary && !xmon_gate) { if (in_xmon == 0) { - if (fromipi) + if (fromipi) { + spin_end(); goto leave; + } secondary = test_and_set_bit(0, &in_xmon); } - barrier(); + spin_cpu_relax(); + touch_nmi_watchdog(); } + spin_end(); if (!secondary && !xmon_gate) { /* we are the first cpu to come in */ @@ -568,21 +573,25 @@ static int xmon_core(struct pt_regs *regs, int fromipi) mb(); xmon_gate = 1; barrier(); + touch_nmi_watchdog(); } cmdloop: while (in_xmon) { if (secondary) { + spin_begin(); if (cpu == xmon_owner) { if (!test_and_set_bit(0, &xmon_taken)) { secondary = 0; + spin_end(); continue; } /* missed it */ while (cpu == xmon_owner) - barrier(); + spin_cpu_relax(); } - barrier(); + spin_cpu_relax(); + touch_nmi_watchdog(); } else { cmd = cmds(regs); if (cmd != 0) { @@ -2475,6 +2484,11 @@ static void dump_xives(void) unsigned long num; int c; + if (!xive_enabled()) { + printf("Xive disabled on this system\n"); + return; + } + c = inchar(); if (c == 'a') { dump_all_xives(); diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 1b60eb3676d55..5e6a63641a5f1 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -263,7 +263,6 @@ typedef struct compat_siginfo { #define si_overrun _sifields._timer._overrun #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL /* * A pointer passed in from user mode. This should not diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 9a3cb3983c014..1a61b1b997f2a 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -194,13 +194,14 @@ struct arch_elf_state { #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE PAGE_SIZE -/* - * This is the base location for PIE (ET_DYN with INTERP) loads. On - * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ -#define ELF_ET_DYN_BASE (is_compat_task() ? 0x000400000UL : \ - 0x100000000UL) +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. 64-bit + tasks are aligned to 4GB. */ +#define ELF_ET_DYN_BASE (is_compat_task() ? \ + (STACK_TOP / 3 * 2) : \ + (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1)) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h index 419e83fa47217..ba22a6ea51a14 100644 --- a/arch/s390/include/asm/pci_insn.h +++ b/arch/s390/include/asm/pci_insn.h @@ -82,6 +82,6 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range); int zpci_load(u64 *data, u64 req, u64 offset); int zpci_store(u64 data, u64 req, u64 offset); int zpci_store_block(const u64 *data, u64 req, u64 offset); -void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc); +int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc); #endif diff --git a/arch/s390/include/asm/runtime_instr.h b/arch/s390/include/asm/runtime_instr.h index ea8896ba5afc7..2502d05403ef4 100644 --- a/arch/s390/include/asm/runtime_instr.h +++ b/arch/s390/include/asm/runtime_instr.h @@ -86,6 +86,8 @@ static inline void restore_ri_cb(struct runtime_instr_cb *cb_next, load_runtime_instr_cb(&runtime_instr_empty_cb); } -void exit_thread_runtime_instr(void); +struct task_struct; + +void runtime_instr_release(struct task_struct *tsk); #endif /* _RUNTIME_INSTR_H */ diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index c21fe1d57c009..c61b2cc1a8a86 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h @@ -30,21 +30,20 @@ static inline void restore_access_regs(unsigned int *acrs) asm volatile("lam 0,15,%0" : : "Q" (*(acrstype *)acrs)); } -#define switch_to(prev,next,last) do { \ - if (prev->mm) { \ - save_fpu_regs(); \ - save_access_regs(&prev->thread.acrs[0]); \ - save_ri_cb(prev->thread.ri_cb); \ - save_gs_cb(prev->thread.gs_cb); \ - } \ - if (next->mm) { \ - update_cr_regs(next); \ - set_cpu_flag(CIF_FPU); \ - restore_access_regs(&next->thread.acrs[0]); \ - restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ - restore_gs_cb(next->thread.gs_cb); \ - } \ - prev = __switch_to(prev,next); \ +#define switch_to(prev, next, last) do { \ + /* save_fpu_regs() sets the CIF_FPU flag, which enforces \ + * a restore of the floating point / vector registers as \ + * soon as the next task returns to user space \ + */ \ + save_fpu_regs(); \ + save_access_regs(&prev->thread.acrs[0]); \ + save_ri_cb(prev->thread.ri_cb); \ + save_gs_cb(prev->thread.gs_cb); \ + update_cr_regs(next); \ + restore_access_regs(&next->thread.acrs[0]); \ + restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ + restore_gs_cb(next->thread.gs_cb); \ + prev = __switch_to(prev, next); \ } while (0) #endif /* __ASM_SWITCH_TO_H */ diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index f04db3779b345..59eea9c65d3e9 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplis return retval; } + groups_sort(group_info); retval = set_current_groups(group_info); put_group_info(group_info); diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index f7e82302a71ef..2394557653d57 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1548,6 +1548,7 @@ static struct s390_insn opcode_e7[] = { { "vfsq", 0xce, INSTR_VRR_VV000MM }, { "vfs", 0xe2, INSTR_VRR_VVV00MM }, { "vftci", 0x4a, INSTR_VRI_VVIMM }, + { "", 0, INSTR_INVALID } }; static struct s390_insn opcode_eb[] = { @@ -1953,7 +1954,7 @@ void show_code(struct pt_regs *regs) { char *mode = user_mode(regs) ? "User" : "Krnl"; unsigned char code[64]; - char buffer[64], *ptr; + char buffer[128], *ptr; mm_segment_t old_fs; unsigned long addr; int start, end, opsize, hops, i; @@ -2016,7 +2017,7 @@ void show_code(struct pt_regs *regs) start += opsize; pr_cont("%s", buffer); ptr = buffer; - ptr += sprintf(ptr, "\n "); + ptr += sprintf(ptr, "\n\t "); hops++; } pr_cont("\n"); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index b945448b9eae8..f7b280f0ab168 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -375,8 +375,10 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; if (test_facility(40)) S390_lowcore.machine_flags |= MACHINE_FLAG_LPP; - if (test_facility(50) && test_facility(73)) + if (test_facility(50) && test_facility(73)) { S390_lowcore.machine_flags |= MACHINE_FLAG_TE; + __ctl_set_bit(0, 55); + } if (test_facility(51)) S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; if (test_facility(129)) { diff --git a/arch/s390/kernel/guarded_storage.c b/arch/s390/kernel/guarded_storage.c index bff39b66c9ffd..9ee794e14f33e 100644 --- a/arch/s390/kernel/guarded_storage.c +++ b/arch/s390/kernel/guarded_storage.c @@ -14,9 +14,11 @@ void exit_thread_gs(void) { + preempt_disable(); kfree(current->thread.gs_cb); kfree(current->thread.gs_bc_cb); current->thread.gs_cb = current->thread.gs_bc_cb = NULL; + preempt_enable(); } static int gs_enable(void) diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index b0ba2c26b45e4..d6f7782e75c93 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -269,6 +269,7 @@ static void __do_machine_kexec(void *data) s390_reset_system(); data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); + __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */ /* Call the moving routine */ (*data_mover)(&image->head, image->start); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index a4a84fb080468..7d4c5500c6c21 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -49,10 +49,8 @@ extern void kernel_thread_starter(void); */ void exit_thread(struct task_struct *tsk) { - if (tsk == current) { - exit_thread_runtime_instr(); + if (tsk == current) exit_thread_gs(); - } } void flush_thread(void) @@ -65,6 +63,7 @@ void release_thread(struct task_struct *dead_task) void arch_release_task_struct(struct task_struct *tsk) { + runtime_instr_release(tsk); } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) @@ -100,6 +99,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp, memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); clear_tsk_thread_flag(p, TIF_SINGLE_STEP); + p->thread.per_flags = 0; /* Initialize per thread user and system timer values */ p->thread.user_timer = 0; p->thread.guest_timer = 0; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 1427d60ce628c..56e0190d6e651 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -1172,26 +1172,37 @@ static int s390_gs_cb_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct gs_cb *data = target->thread.gs_cb; + struct gs_cb gs_cb = { }, *data = NULL; int rc; if (!MACHINE_HAS_GS) return -ENODEV; - if (!data) { + if (!target->thread.gs_cb) { data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->gsd = 25; - target->thread.gs_cb = data; - if (target == current) - __ctl_set_bit(2, 4); - } else if (target == current) { - save_gs_cb(data); } + if (!target->thread.gs_cb) + gs_cb.gsd = 25; + else if (target == current) + save_gs_cb(&gs_cb); + else + gs_cb = *target->thread.gs_cb; rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - data, 0, sizeof(struct gs_cb)); - if (target == current) - restore_gs_cb(data); + &gs_cb, 0, sizeof(gs_cb)); + if (rc) { + kfree(data); + return -EFAULT; + } + preempt_disable(); + if (!target->thread.gs_cb) + target->thread.gs_cb = data; + *target->thread.gs_cb = gs_cb; + if (target == current) { + __ctl_set_bit(2, 4); + restore_gs_cb(target->thread.gs_cb); + } + preempt_enable(); return rc; } diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index ca37e5d5b40cc..9c2c96da23d02 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S @@ -29,7 +29,6 @@ ENTRY(relocate_kernel) basr %r13,0 # base address .base: - stnsm sys_msk-.base(%r13),0xfb # disable DAT stctg %c0,%c15,ctlregs-.base(%r13) stmg %r0,%r15,gprregs-.base(%r13) lghi %r0,3 @@ -103,8 +102,6 @@ ENTRY(relocate_kernel) .align 8 load_psw: .long 0x00080000,0x80000000 - sys_msk: - .quad 0 ctlregs: .rept 16 .quad 0 diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c index 32aefb215e59f..94c9ba72cf835 100644 --- a/arch/s390/kernel/runtime_instr.c +++ b/arch/s390/kernel/runtime_instr.c @@ -21,11 +21,24 @@ /* empty control block to disable RI by loading it */ struct runtime_instr_cb runtime_instr_empty_cb; +void runtime_instr_release(struct task_struct *tsk) +{ + kfree(tsk->thread.ri_cb); +} + static void disable_runtime_instr(void) { - struct pt_regs *regs = task_pt_regs(current); + struct task_struct *task = current; + struct pt_regs *regs; + if (!task->thread.ri_cb) + return; + regs = task_pt_regs(task); + preempt_disable(); load_runtime_instr_cb(&runtime_instr_empty_cb); + kfree(task->thread.ri_cb); + task->thread.ri_cb = NULL; + preempt_enable(); /* * Make sure the RI bit is deleted from the PSW. If the user did not @@ -46,17 +59,6 @@ static void init_runtime_instr_cb(struct runtime_instr_cb *cb) cb->valid = 1; } -void exit_thread_runtime_instr(void) -{ - struct task_struct *task = current; - - if (!task->thread.ri_cb) - return; - disable_runtime_instr(); - kfree(task->thread.ri_cb); - task->thread.ri_cb = NULL; -} - SYSCALL_DEFINE1(s390_runtime_instr, int, command) { struct runtime_instr_cb *cb; @@ -65,9 +67,7 @@ SYSCALL_DEFINE1(s390_runtime_instr, int, command) return -EOPNOTSUPP; if (command == S390_RUNTIME_INSTR_STOP) { - preempt_disable(); - exit_thread_runtime_instr(); - preempt_enable(); + disable_runtime_instr(); return 0; } diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index d39f121e67a98..bc905ae1d5c8d 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -370,10 +370,10 @@ SYSCALL(sys_recvmmsg,compat_sys_recvmmsg) SYSCALL(sys_sendmmsg,compat_sys_sendmmsg) SYSCALL(sys_socket,sys_socket) SYSCALL(sys_socketpair,compat_sys_socketpair) /* 360 */ -SYSCALL(sys_bind,sys_bind) -SYSCALL(sys_connect,sys_connect) +SYSCALL(sys_bind,compat_sys_bind) +SYSCALL(sys_connect,compat_sys_connect) SYSCALL(sys_listen,sys_listen) -SYSCALL(sys_accept4,sys_accept4) +SYSCALL(sys_accept4,compat_sys_accept4) SYSCALL(sys_getsockopt,compat_sys_getsockopt) /* 365 */ SYSCALL(sys_setsockopt,compat_sys_setsockopt) SYSCALL(sys_getsockname,compat_sys_getsockname) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 40d0a1a97889b..6c88cb18ace2e 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -768,7 +768,7 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req) /* * Must be called with kvm->srcu held to avoid races on memslots, and with - * kvm->lock to avoid races with ourselves and kvm_s390_vm_stop_migration. + * kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration. */ static int kvm_s390_vm_start_migration(struct kvm *kvm) { @@ -794,11 +794,12 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm) if (kvm->arch.use_cmma) { /* - * Get the last slot. They should be sorted by base_gfn, so the - * last slot is also the one at the end of the address space. - * We have verified above that at least one slot is present. + * Get the first slot. They are reverse sorted by base_gfn, so + * the first slot is also the one at the end of the address + * space. We have verified above that at least one slot is + * present. */ - ms = slots->memslots + slots->used_slots - 1; + ms = slots->memslots; /* round up so we only use full longs */ ram_pages = roundup(ms->base_gfn + ms->npages, BITS_PER_LONG); /* allocate enough bytes to store all the bits */ @@ -823,7 +824,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm) } /* - * Must be called with kvm->lock to avoid races with ourselves and + * Must be called with kvm->slots_lock to avoid races with ourselves and * kvm_s390_vm_start_migration. */ static int kvm_s390_vm_stop_migration(struct kvm *kvm) @@ -838,6 +839,8 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm) if (kvm->arch.use_cmma) { kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION); + /* We have to wait for the essa emulation to finish */ + synchronize_srcu(&kvm->srcu); vfree(mgs->pgste_bitmap); } kfree(mgs); @@ -847,14 +850,12 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm) static int kvm_s390_vm_set_migration(struct kvm *kvm, struct kvm_device_attr *attr) { - int idx, res = -ENXIO; + int res = -ENXIO; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->slots_lock); switch (attr->attr) { case KVM_S390_VM_MIGRATION_START: - idx = srcu_read_lock(&kvm->srcu); res = kvm_s390_vm_start_migration(kvm); - srcu_read_unlock(&kvm->srcu, idx); break; case KVM_S390_VM_MIGRATION_STOP: res = kvm_s390_vm_stop_migration(kvm); @@ -862,7 +863,7 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm, default: break; } - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->slots_lock); return res; } @@ -1752,7 +1753,9 @@ long kvm_arch_vm_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&args, argp, sizeof(args))) break; + mutex_lock(&kvm->slots_lock); r = kvm_s390_get_cmma_bits(kvm, &args); + mutex_unlock(&kvm->slots_lock); if (!r) { r = copy_to_user(argp, &args, sizeof(args)); if (r) @@ -1766,7 +1769,9 @@ long kvm_arch_vm_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&args, argp, sizeof(args))) break; + mutex_lock(&kvm->slots_lock); r = kvm_s390_set_cmma_bits(kvm, &args); + mutex_unlock(&kvm->slots_lock); break; } default: diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index c954ac49eee47..7bd3a59232f01 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -235,8 +235,6 @@ static int try_handle_skey(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); return -EAGAIN; } - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) - return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return 0; } @@ -247,6 +245,9 @@ static int handle_iske(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; @@ -276,6 +277,9 @@ static int handle_rrbe(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; @@ -311,6 +315,9 @@ static int handle_sske(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; @@ -1002,7 +1009,7 @@ static inline int do_essa(struct kvm_vcpu *vcpu, const int orc) cbrlo[entries] = gfn << PAGE_SHIFT; } - if (orc) { + if (orc && gfn < ms->bitmap_size) { /* increment only if we are really flipping the bit to 1 */ if (!test_and_set_bit(gfn, ms->pgste_bitmap)) atomic64_inc(&ms->dirty_pages); diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index cc2faffa7d6ef..334b6d103cbd1 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -85,8 +85,6 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long end) /* upgrade should only happen from 3 to 4, 3 to 5, or 4 to 5 levels */ VM_BUG_ON(mm->context.asce_limit < _REGION2_SIZE); - if (end >= TASK_SIZE_MAX) - return -ENOMEM; rc = 0; notify = 0; while (mm->context.asce_limit < end) { diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index b15cd2f0320f8..33e2785f68428 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -55,8 +55,7 @@ struct bpf_jit { #define SEEN_LITERAL 8 /* code uses literals */ #define SEEN_FUNC 16 /* calls C functions */ #define SEEN_TAIL_CALL 32 /* code uses tail calls */ -#define SEEN_SKB_CHANGE 64 /* code changes skb data */ -#define SEEN_REG_AX 128 /* code uses constant blinding */ +#define SEEN_REG_AX 64 /* code uses constant blinding */ #define SEEN_STACK (SEEN_FUNC | SEEN_MEM | SEEN_SKB) /* @@ -448,12 +447,12 @@ static void bpf_jit_prologue(struct bpf_jit *jit) EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, 152); } - if (jit->seen & SEEN_SKB) + if (jit->seen & SEEN_SKB) { emit_load_skb_data_hlen(jit); - if (jit->seen & SEEN_SKB_CHANGE) /* stg %b1,ST_OFF_SKBP(%r0,%r15) */ EMIT6_DISP_LH(0xe3000000, 0x0024, BPF_REG_1, REG_0, REG_15, STK_OFF_SKBP); + } } /* @@ -983,8 +982,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i EMIT2(0x0d00, REG_14, REG_W1); /* lgr %b0,%r2: load return value into %b0 */ EMIT4(0xb9040000, BPF_REG_0, REG_2); - if (bpf_helper_changes_pkt_data((void *)func)) { - jit->seen |= SEEN_SKB_CHANGE; + if ((jit->seen & SEEN_SKB) && + bpf_helper_changes_pkt_data((void *)func)) { /* lg %b1,ST_OFF_SKBP(%r15) */ EMIT6_DISP_LH(0xe3000000, 0x0004, BPF_REG_1, REG_0, REG_15, STK_OFF_SKBP); diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index a25d95a6612dd..0fe649c0d5423 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -368,7 +368,8 @@ static void zpci_irq_handler(struct airq_struct *airq) /* End of second scan with interrupts on. */ break; /* First scan complete, reenable interrupts. */ - zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); + if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC)) + break; si = 0; continue; } @@ -956,7 +957,7 @@ static int __init pci_base_init(void) if (!s390_pci_probe) return 0; - if (!test_facility(69) || !test_facility(71) || !test_facility(72)) + if (!test_facility(69) || !test_facility(71)) return 0; rc = zpci_debug_init(); diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index ea34086c86744..81b840bc6e4e7 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -91,11 +92,14 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range) } /* Set Interruption Controls */ -void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) +int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) { + if (!test_facility(72)) + return -EIO; asm volatile ( " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); + return 0; } /* PCI Load */ diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index 3e3823db303e7..c73b5a3ab7b91 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h @@ -63,6 +63,9 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size) (unsigned long)_n_, sizeof(*(ptr))); \ }) +u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new); +#define cmpxchg64(ptr, old, new) __cmpxchg_u64(ptr, old, new) + #include /* diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index 977c3f280ba19..fa38c78de0f00 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -209,7 +209,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL /* * A pointer passed in from user mode. This should not diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index e25d25b0a34b5..b361702ef52a7 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -8,9 +8,11 @@ #include #include +#include #include #include +#include static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index 6a339a78f4f42..71dd82b43cc57 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -7,6 +7,7 @@ #if defined(__sparc__) && defined(__arch64__) #ifndef __ASSEMBLY__ +#include #include #include diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index 25b6abdb39083..522a677e050d7 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h @@ -217,7 +217,7 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; sllx REG2, 32, REG2; \ andcc REG1, REG2, %g0; \ be,pt %xcc, 700f; \ - sethi %hi(0x1ffc0000), REG2; \ + sethi %hi(0xffe00000), REG2; \ sllx REG2, 1, REG2; \ brgez,pn REG1, FAIL_LABEL; \ andn REG1, REG2, REG1; \ diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 5010df4973879..465a901a0ada7 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -173,6 +173,20 @@ unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new) } EXPORT_SYMBOL(__cmpxchg_u32); +u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new) +{ + unsigned long flags; + u64 prev; + + spin_lock_irqsave(ATOMIC_HASH(ptr), flags); + if ((prev = *ptr) == old) + *ptr = new; + spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags); + + return prev; +} +EXPORT_SYMBOL(__cmpxchg_u64); + unsigned long __xchg_u32(volatile u32 *ptr, u32 new) { unsigned long flags; diff --git a/arch/sparc/lib/hweight.S b/arch/sparc/lib/hweight.S index e5547b22cd183..0ddbbb0318223 100644 --- a/arch/sparc/lib/hweight.S +++ b/arch/sparc/lib/hweight.S @@ -44,8 +44,8 @@ EXPORT_SYMBOL(__arch_hweight32) .previous ENTRY(__arch_hweight64) - sethi %hi(__sw_hweight16), %g1 - jmpl %g1 + %lo(__sw_hweight16), %g0 + sethi %hi(__sw_hweight64), %g1 + jmpl %g1 + %lo(__sw_hweight64), %g0 nop ENDPROC(__arch_hweight64) EXPORT_SYMBOL(__arch_hweight64) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 61bdc1270d195..a0cc1be767c8f 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -2540,9 +2540,16 @@ void __init mem_init(void) { high_memory = __va(last_valid_pfn << PAGE_SHIFT); - register_page_bootmem_info(); free_all_bootmem(); + /* + * Must be done after boot memory is put on freelist, because here we + * might set fields in deferred struct pages that have not yet been + * initialized, and free_all_bootmem() initializes all the reserved + * deferred pages for us. + */ + register_page_bootmem_info(); + /* * Set up the zero page, mark it reserved, so that page count * is not manipulated when freeing the page from user ptes. diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c index 5765e7e711f78..ff5f9cb3039af 100644 --- a/arch/sparc/net/bpf_jit_comp_64.c +++ b/arch/sparc/net/bpf_jit_comp_64.c @@ -1245,14 +1245,16 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) u8 *func = ((u8 *)__bpf_call_base) + imm; ctx->saw_call = true; + if (ctx->saw_ld_abs_ind && bpf_helper_changes_pkt_data(func)) + emit_reg_move(bpf2sparc[BPF_REG_1], L7, ctx); emit_call((u32 *)func, ctx); emit_nop(ctx); emit_reg_move(O0, bpf2sparc[BPF_REG_0], ctx); - if (bpf_helper_changes_pkt_data(func) && ctx->saw_ld_abs_ind) - load_skb_regs(ctx, bpf2sparc[BPF_REG_6]); + if (ctx->saw_ld_abs_ind && bpf_helper_changes_pkt_data(func)) + load_skb_regs(ctx, L7); break; } diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index c14e36f008c8f..62a7b83025dd2 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -173,7 +173,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL struct compat_ipc64_perm { compat_key_t key; diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index 50a32c33d729b..73c57f614c9e0 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -1,4 +1,5 @@ generic-y += barrier.h +generic-y += bpf_perf_event.h generic-y += bug.h generic-y += clkdev.h generic-y += current.h diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h index b668e351fd6c2..fca34b2177e28 100644 --- a/arch/um/include/asm/mmu_context.h +++ b/arch/um/include/asm/mmu_context.h @@ -15,9 +15,10 @@ extern void uml_setup_stubs(struct mm_struct *mm); /* * Needed since we do not use the asm-generic/mm_hooks.h: */ -static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { uml_setup_stubs(mm); + return 0; } extern void arch_exit_mmap(struct mm_struct *mm); static inline void arch_unmap(struct mm_struct *mm, diff --git a/arch/um/include/shared/init.h b/arch/um/include/shared/init.h index 390572daa40de..b3f5865a92c91 100644 --- a/arch/um/include/shared/init.h +++ b/arch/um/include/shared/init.h @@ -41,7 +41,7 @@ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void); -#include +#include /* These are for everybody (although not all archs will actually discard it in modules) */ diff --git a/arch/unicore32/include/asm/mmu_context.h b/arch/unicore32/include/asm/mmu_context.h index 59b06b48f27d7..5c205a9cb5a6a 100644 --- a/arch/unicore32/include/asm/mmu_context.h +++ b/arch/unicore32/include/asm/mmu_context.h @@ -81,9 +81,10 @@ do { \ } \ } while (0) -static inline void arch_dup_mmap(struct mm_struct *oldmm, - struct mm_struct *mm) +static inline int arch_dup_mmap(struct mm_struct *oldmm, + struct mm_struct *mm) { + return 0; } static inline void arch_unmap(struct mm_struct *mm, diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2fdb23313dd55..17de6acc0eab6 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -56,7 +56,7 @@ config X86 select ARCH_HAS_KCOV if X86_64 select ARCH_HAS_PMEM_API if X86_64 # Causing hangs/crashes, see the commit that added this change for details. - select ARCH_HAS_REFCOUNT if BROKEN + select ARCH_HAS_REFCOUNT select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_SET_MEMORY select ARCH_HAS_SG_CHAIN @@ -89,6 +89,7 @@ config X86 select GENERIC_CLOCKEVENTS_MIN_ADJUST select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_FIND_FIRST_BIT select GENERIC_IOMAP @@ -108,7 +109,7 @@ config X86 select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE select HAVE_ARCH_JUMP_LABEL - select HAVE_ARCH_KASAN if X86_64 && SPARSEMEM_VMEMMAP + select HAVE_ARCH_KASAN if X86_64 select HAVE_ARCH_KGDB select HAVE_ARCH_KMEMCHECK select HAVE_ARCH_MMAP_RND_BITS if MMU @@ -171,7 +172,7 @@ config X86 select HAVE_PERF_USER_STACK_DUMP select HAVE_RCU_TABLE_FREE select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_RELIABLE_STACKTRACE if X86_64 && FRAME_POINTER_UNWINDER && STACK_VALIDATION + select HAVE_RELIABLE_STACKTRACE if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION select HAVE_STACK_VALIDATION if X86_64 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UNSTABLE_SCHED_CLOCK @@ -303,7 +304,6 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC config KASAN_SHADOW_OFFSET hex depends on KASAN - default 0xdff8000000000000 if X86_5LEVEL default 0xdffffc0000000000 config HAVE_INTEL_TXT @@ -429,6 +429,19 @@ config GOLDFISH def_bool y depends on X86_GOLDFISH +config RETPOLINE + bool "Avoid speculative indirect branches in kernel" + default y + help + Compile kernel with the retpoline compiler options to guard against + kernel-to-user data leaks by avoiding speculative indirect + branches. Requires a compiler with -mindirect-branch=thunk-extern + support for full protection. The kernel may run slower. + + Without compiler support, at least indirect branches in assembler + code are eliminated. Since this includes the syscall entry path, + it is not entirely pointless. + config INTEL_RDT bool "Intel Resource Director Technology support" default n @@ -926,7 +939,8 @@ config MAXSMP config NR_CPUS int "Maximum number of CPUs" if SMP && !MAXSMP range 2 8 if SMP && X86_32 && !X86_BIGSMP - range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK + range 2 64 if SMP && X86_32 && X86_BIGSMP + range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK && X86_64 range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64 default "1" if !SMP default "8192" if MAXSMP diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 90b123056f4b3..6293a8768a912 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -359,28 +359,14 @@ config PUNIT_ATOM_DEBUG choice prompt "Choose kernel unwinder" - default FRAME_POINTER_UNWINDER + default UNWINDER_ORC if X86_64 + default UNWINDER_FRAME_POINTER if X86_32 ---help--- This determines which method will be used for unwinding kernel stack traces for panics, oopses, bugs, warnings, perf, /proc//stack, livepatch, lockdep, and more. -config FRAME_POINTER_UNWINDER - bool "Frame pointer unwinder" - select FRAME_POINTER - ---help--- - This option enables the frame pointer unwinder for unwinding kernel - stack traces. - - The unwinder itself is fast and it uses less RAM than the ORC - unwinder, but the kernel text size will grow by ~3% and the kernel's - overall performance will degrade by roughly 5-10%. - - This option is recommended if you want to use the livepatch - consistency model, as this is currently the only way to get a - reliable stack trace (CONFIG_HAVE_RELIABLE_STACKTRACE). - -config ORC_UNWINDER +config UNWINDER_ORC bool "ORC unwinder" depends on X86_64 select STACK_VALIDATION @@ -396,7 +382,22 @@ config ORC_UNWINDER Enabling this option will increase the kernel's runtime memory usage by roughly 2-4MB, depending on your kernel config. -config GUESS_UNWINDER +config UNWINDER_FRAME_POINTER + bool "Frame pointer unwinder" + select FRAME_POINTER + ---help--- + This option enables the frame pointer unwinder for unwinding kernel + stack traces. + + The unwinder itself is fast and it uses less RAM than the ORC + unwinder, but the kernel text size will grow by ~3% and the kernel's + overall performance will degrade by roughly 5-10%. + + This option is recommended if you want to use the livepatch + consistency model, as this is currently the only way to get a + reliable stack trace (CONFIG_HAVE_RELIABLE_STACKTRACE). + +config UNWINDER_GUESS bool "Guess unwinder" depends on EXPERT ---help--- @@ -411,7 +412,7 @@ config GUESS_UNWINDER endchoice config FRAME_POINTER - depends on !ORC_UNWINDER && !GUESS_UNWINDER + depends on !UNWINDER_ORC && !UNWINDER_GUESS bool endmenu diff --git a/arch/x86/Makefile b/arch/x86/Makefile index a20eacd9c7e9a..504b1a4535aca 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -235,6 +235,14 @@ KBUILD_CFLAGS += -Wno-sign-compare # KBUILD_CFLAGS += -fno-asynchronous-unwind-tables +# Avoid indirect branches in kernel to deal with Spectre +ifdef CONFIG_RETPOLINE + RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) + ifneq ($(RETPOLINE_CFLAGS),) + KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE + endif +endif + archscripts: scripts_basic $(Q)$(MAKE) $(build)=arch/x86/tools relocs diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 4b7575b005631..98018a621f6b0 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -78,6 +78,7 @@ vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o ifdef CONFIG_X86_64 vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/pagetable.o + vmlinux-objs-y += $(obj)/pgtable_64.o endif $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index beb255b66447a..4b3d92a37c801 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -289,10 +289,18 @@ ENTRY(startup_64) leaq boot_stack_end(%rbx), %rsp #ifdef CONFIG_X86_5LEVEL - /* Check if 5-level paging has already enabled */ - movq %cr4, %rax - testl $X86_CR4_LA57, %eax - jnz lvl5 + /* + * Check if we need to enable 5-level paging. + * RSI holds real mode data and need to be preserved across + * a function call. + */ + pushq %rsi + call l5_paging_required + popq %rsi + + /* If l5_paging_required() returned zero, we're done here. */ + cmpq $0, %rax + je lvl5 /* * At this point we are in long mode with 4-level paging enabled, diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index b50c42455e252..98761a1576ceb 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -169,6 +169,16 @@ void __puthex(unsigned long value) } } +static bool l5_supported(void) +{ + /* Check if leaf 7 is supported. */ + if (native_cpuid_eax(0) < 7) + return 0; + + /* Check if la57 is supported. */ + return native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)); +} + #if CONFIG_X86_NEED_RELOCS static void handle_relocations(void *output, unsigned long output_len, unsigned long virt_addr) @@ -362,6 +372,12 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, console_init(); debug_putstr("early console in extract_kernel\n"); + if (IS_ENABLED(CONFIG_X86_5LEVEL) && !l5_supported()) { + error("This linux kernel as configured requires 5-level paging\n" + "This CPU does not support the required 'cr4.la57' feature\n" + "Unable to boot - please use a kernel appropriate for your CPU\n"); + } + free_mem_ptr = heap; /* Heap */ free_mem_end_ptr = heap + BOOT_HEAP_SIZE; diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c index 972319ff5b019..e691ff734cb5a 100644 --- a/arch/x86/boot/compressed/pagetable.c +++ b/arch/x86/boot/compressed/pagetable.c @@ -23,6 +23,9 @@ */ #undef CONFIG_AMD_MEM_ENCRYPT +/* No PAGE_TABLE_ISOLATION support needed either: */ +#undef CONFIG_PAGE_TABLE_ISOLATION + #include "misc.h" /* These actually do the work of building the kernel identity maps. */ diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c new file mode 100644 index 0000000000000..b4469a37e9a16 --- /dev/null +++ b/arch/x86/boot/compressed/pgtable_64.c @@ -0,0 +1,28 @@ +#include + +/* + * __force_order is used by special_insns.h asm code to force instruction + * serialization. + * + * It is not referenced from the code, but GCC < 5 with -fPIE would fail + * due to an undefined symbol. Define it to make these ancient GCCs work. + */ +unsigned long __force_order; + +int l5_paging_required(void) +{ + /* Check if leaf 7 is supported. */ + + if (native_cpuid_eax(0) < 7) + return 0; + + /* Check if la57 is supported. */ + if (!(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31)))) + return 0; + + /* Check if 5-level paging has already been enabled. */ + if (native_read_cr4() & X86_CR4_LA57) + return 0; + + return 1; +} diff --git a/arch/x86/configs/tiny.config b/arch/x86/configs/tiny.config index 550cd5012b735..66c9e2aab16cc 100644 --- a/arch/x86/configs/tiny.config +++ b/arch/x86/configs/tiny.config @@ -1,5 +1,5 @@ CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set -CONFIG_GUESS_UNWINDER=y -# CONFIG_FRAME_POINTER_UNWINDER is not set +CONFIG_UNWINDER_GUESS=y +# CONFIG_UNWINDER_FRAME_POINTER is not set diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 4a4b16e56d354..e32fc1f274d85 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -299,6 +299,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_RODATA_TEST is not set CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y +CONFIG_UNWINDER_ORC=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 16627fec80b26..3d09e3aca18da 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -32,6 +32,7 @@ #include #include #include +#include /* * The following macros are used to move an (un)aligned 16 byte value to/from @@ -2884,7 +2885,7 @@ ENTRY(aesni_xts_crypt8) pxor INC, STATE4 movdqu IV, 0x30(OUTP) - call *%r11 + CALL_NOSPEC %r11 movdqu 0x00(OUTP), INC pxor INC, STATE1 @@ -2929,7 +2930,7 @@ ENTRY(aesni_xts_crypt8) _aesni_gf128mul_x_ble() movups IV, (IVP) - call *%r11 + CALL_NOSPEC %r11 movdqu 0x40(OUTP), INC pxor INC, STATE1 diff --git a/arch/x86/crypto/camellia-aesni-avx-asm_64.S b/arch/x86/crypto/camellia-aesni-avx-asm_64.S index f7c495e2863cb..a14af6eb09cb0 100644 --- a/arch/x86/crypto/camellia-aesni-avx-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx-asm_64.S @@ -17,6 +17,7 @@ #include #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -1227,7 +1228,7 @@ camellia_xts_crypt_16way: vpxor 14 * 16(%rax), %xmm15, %xmm14; vpxor 15 * 16(%rax), %xmm15, %xmm15; - call *%r9; + CALL_NOSPEC %r9; addq $(16 * 16), %rsp; diff --git a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S index eee5b3982cfd3..b66bbfa62f50d 100644 --- a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S @@ -12,6 +12,7 @@ #include #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -1343,7 +1344,7 @@ camellia_xts_crypt_32way: vpxor 14 * 32(%rax), %ymm15, %ymm14; vpxor 15 * 32(%rax), %ymm15, %ymm15; - call *%r9; + CALL_NOSPEC %r9; addq $(16 * 32), %rsp; diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index 7a7de27c6f415..d9b734d0c8cc7 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -45,6 +45,7 @@ #include #include +#include ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction @@ -172,7 +173,7 @@ continue_block: movzxw (bufp, %rax, 2), len lea crc_array(%rip), bufp lea (bufp, len, 1), bufp - jmp *bufp + JMP_NOSPEC bufp ################################################################ ## 2a) PROCESS FULL BLOCKS: diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index 399a29d067d63..cb91a64a99e7c 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -59,13 +59,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.src.virt.addr, - walk.dst.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.src.virt.addr, walk.dst.virt.addr, diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 6e160031cfea1..3f48f695d5e6a 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h @@ -1,6 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include #include +#include +#include +#include +#include +#include /* @@ -142,56 +147,25 @@ For 32-bit we have the following conventions - kernel is built with UNWIND_HINT_REGS offset=\offset .endm - .macro RESTORE_EXTRA_REGS offset=0 - movq 0*8+\offset(%rsp), %r15 - movq 1*8+\offset(%rsp), %r14 - movq 2*8+\offset(%rsp), %r13 - movq 3*8+\offset(%rsp), %r12 - movq 4*8+\offset(%rsp), %rbp - movq 5*8+\offset(%rsp), %rbx - UNWIND_HINT_REGS offset=\offset extra=0 - .endm - - .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 - .if \rstor_r11 - movq 6*8(%rsp), %r11 - .endif - .if \rstor_r8910 - movq 7*8(%rsp), %r10 - movq 8*8(%rsp), %r9 - movq 9*8(%rsp), %r8 - .endif - .if \rstor_rax - movq 10*8(%rsp), %rax - .endif - .if \rstor_rcx - movq 11*8(%rsp), %rcx - .endif - .if \rstor_rdx - movq 12*8(%rsp), %rdx - .endif - movq 13*8(%rsp), %rsi - movq 14*8(%rsp), %rdi - UNWIND_HINT_IRET_REGS offset=16*8 - .endm - .macro RESTORE_C_REGS - RESTORE_C_REGS_HELPER 1,1,1,1,1 - .endm - .macro RESTORE_C_REGS_EXCEPT_RAX - RESTORE_C_REGS_HELPER 0,1,1,1,1 - .endm - .macro RESTORE_C_REGS_EXCEPT_RCX - RESTORE_C_REGS_HELPER 1,0,1,1,1 - .endm - .macro RESTORE_C_REGS_EXCEPT_R11 - RESTORE_C_REGS_HELPER 1,1,0,1,1 - .endm - .macro RESTORE_C_REGS_EXCEPT_RCX_R11 - RESTORE_C_REGS_HELPER 1,0,0,1,1 + .macro POP_EXTRA_REGS + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx .endm - .macro REMOVE_PT_GPREGS_FROM_STACK addskip=0 - subq $-(15*8+\addskip), %rsp + .macro POP_C_REGS + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rcx + popq %rdx + popq %rsi + popq %rdi .endm .macro icebp @@ -218,6 +192,148 @@ For 32-bit we have the following conventions - kernel is built with #endif .endm +#ifdef CONFIG_PAGE_TABLE_ISOLATION + +/* + * PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two + * halves: + */ +#define PTI_USER_PGTABLE_BIT PAGE_SHIFT +#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) +#define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT +#define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT) +#define PTI_USER_PGTABLE_AND_PCID_MASK (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK) + +.macro SET_NOFLUSH_BIT reg:req + bts $X86_CR3_PCID_NOFLUSH_BIT, \reg +.endm + +.macro ADJUST_KERNEL_CR3 reg:req + ALTERNATIVE "", "SET_NOFLUSH_BIT \reg", X86_FEATURE_PCID + /* Clear PCID and "PAGE_TABLE_ISOLATION bit", point CR3 at kernel pagetables: */ + andq $(~PTI_USER_PGTABLE_AND_PCID_MASK), \reg +.endm + +.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI + mov %cr3, \scratch_reg + ADJUST_KERNEL_CR3 \scratch_reg + mov \scratch_reg, %cr3 +.Lend_\@: +.endm + +#define THIS_CPU_user_pcid_flush_mask \ + PER_CPU_VAR(cpu_tlbstate) + TLB_STATE_user_pcid_flush_mask + +.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI + mov %cr3, \scratch_reg + + ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID + + /* + * Test if the ASID needs a flush. + */ + movq \scratch_reg, \scratch_reg2 + andq $(0x7FF), \scratch_reg /* mask ASID */ + bt \scratch_reg, THIS_CPU_user_pcid_flush_mask + jnc .Lnoflush_\@ + + /* Flush needed, clear the bit */ + btr \scratch_reg, THIS_CPU_user_pcid_flush_mask + movq \scratch_reg2, \scratch_reg + jmp .Lwrcr3_pcid_\@ + +.Lnoflush_\@: + movq \scratch_reg2, \scratch_reg + SET_NOFLUSH_BIT \scratch_reg + +.Lwrcr3_pcid_\@: + /* Flip the ASID to the user version */ + orq $(PTI_USER_PCID_MASK), \scratch_reg + +.Lwrcr3_\@: + /* Flip the PGD to the user version */ + orq $(PTI_USER_PGTABLE_MASK), \scratch_reg + mov \scratch_reg, %cr3 +.Lend_\@: +.endm + +.macro SWITCH_TO_USER_CR3_STACK scratch_reg:req + pushq %rax + SWITCH_TO_USER_CR3_NOSTACK scratch_reg=\scratch_reg scratch_reg2=%rax + popq %rax +.endm + +.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req + ALTERNATIVE "jmp .Ldone_\@", "", X86_FEATURE_PTI + movq %cr3, \scratch_reg + movq \scratch_reg, \save_reg + /* + * Test the user pagetable bit. If set, then the user page tables + * are active. If clear CR3 already has the kernel page table + * active. + */ + bt $PTI_USER_PGTABLE_BIT, \scratch_reg + jnc .Ldone_\@ + + ADJUST_KERNEL_CR3 \scratch_reg + movq \scratch_reg, %cr3 + +.Ldone_\@: +.endm + +.macro RESTORE_CR3 scratch_reg:req save_reg:req + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI + + ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID + + /* + * KERNEL pages can always resume with NOFLUSH as we do + * explicit flushes. + */ + bt $PTI_USER_PGTABLE_BIT, \save_reg + jnc .Lnoflush_\@ + + /* + * Check if there's a pending flush for the user ASID we're + * about to set. + */ + movq \save_reg, \scratch_reg + andq $(0x7FF), \scratch_reg + bt \scratch_reg, THIS_CPU_user_pcid_flush_mask + jnc .Lnoflush_\@ + + btr \scratch_reg, THIS_CPU_user_pcid_flush_mask + jmp .Lwrcr3_\@ + +.Lnoflush_\@: + SET_NOFLUSH_BIT \save_reg + +.Lwrcr3_\@: + /* + * The CR3 write could be avoided when not changing its value, + * but would require a CR3 read *and* a scratch register. + */ + movq \save_reg, %cr3 +.Lend_\@: +.endm + +#else /* CONFIG_PAGE_TABLE_ISOLATION=n: */ + +.macro SWITCH_TO_KERNEL_CR3 scratch_reg:req +.endm +.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req +.endm +.macro SWITCH_TO_USER_CR3_STACK scratch_reg:req +.endm +.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req +.endm +.macro RESTORE_CR3 scratch_reg:req save_reg:req +.endm + +#endif + #endif /* CONFIG_X86_64 */ /* diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 4838037f97f6e..60c4c342316cd 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -44,6 +44,7 @@ #include #include #include +#include .section .entry.text, "ax" @@ -243,6 +244,17 @@ ENTRY(__switch_to_asm) movl %ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset #endif +#ifdef CONFIG_RETPOLINE + /* + * When switching from a shallower to a deeper call stack + * the RSB may either underflow or use entries populated + * with userspace addresses. On CPUs where those concerns + * exist, overwrite the RSB with entries which capture + * speculative execution to prevent attack. + */ + FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW +#endif + /* restore callee-saved registers */ popl %esi popl %edi @@ -290,7 +302,7 @@ ENTRY(ret_from_fork) /* kernel thread */ 1: movl %edi, %eax - call *%ebx + CALL_NOSPEC %ebx /* * A kernel thread is allowed to return here after successfully * calling do_execve(). Exit to userspace to complete the execve() @@ -919,7 +931,7 @@ common_exception: movl %ecx, %es TRACE_IRQS_OFF movl %esp, %eax # pt_regs pointer - call *%edi + CALL_NOSPEC %edi jmp ret_from_exception END(common_exception) @@ -941,9 +953,10 @@ ENTRY(debug) movl %esp, %eax # pt_regs pointer /* Are we currently on the SYSENTER stack? */ - PER_CPU(cpu_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx) - subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */ - cmpl $SIZEOF_SYSENTER_stack, %ecx + movl PER_CPU_VAR(cpu_entry_area), %ecx + addl $CPU_ENTRY_AREA_entry_stack + SIZEOF_entry_stack, %ecx + subl %eax, %ecx /* ecx = (end of entry_stack) - esp */ + cmpl $SIZEOF_entry_stack, %ecx jb .Ldebug_from_sysenter_stack TRACE_IRQS_OFF @@ -984,9 +997,10 @@ ENTRY(nmi) movl %esp, %eax # pt_regs pointer /* Are we currently on the SYSENTER stack? */ - PER_CPU(cpu_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx) - subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */ - cmpl $SIZEOF_SYSENTER_stack, %ecx + movl PER_CPU_VAR(cpu_entry_area), %ecx + addl $CPU_ENTRY_AREA_entry_stack + SIZEOF_entry_stack, %ecx + subl %eax, %ecx /* ecx = (end of entry_stack) - esp */ + cmpl $SIZEOF_entry_stack, %ecx jb .Lnmi_from_sysenter_stack /* Not on SYSENTER stack. */ diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index bcfc5668dcb22..be6b66464f6a7 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -23,7 +23,6 @@ #include #include #include -#include "calling.h" #include #include #include @@ -38,8 +37,11 @@ #include #include #include +#include #include +#include "calling.h" + .code64 .section .entry.text, "ax" @@ -136,6 +138,67 @@ END(native_usergs_sysret64) * with them due to bugs in both AMD and Intel CPUs. */ + .pushsection .entry_trampoline, "ax" + +/* + * The code in here gets remapped into cpu_entry_area's trampoline. This means + * that the assembler and linker have the wrong idea as to where this code + * lives (and, in fact, it's mapped more than once, so it's not even at a + * fixed address). So we can't reference any symbols outside the entry + * trampoline and expect it to work. + * + * Instead, we carefully abuse %rip-relative addressing. + * _entry_trampoline(%rip) refers to the start of the remapped) entry + * trampoline. We can thus find cpu_entry_area with this macro: + */ + +#define CPU_ENTRY_AREA \ + _entry_trampoline - CPU_ENTRY_AREA_entry_trampoline(%rip) + +/* The top word of the SYSENTER stack is hot and is usable as scratch space. */ +#define RSP_SCRATCH CPU_ENTRY_AREA_entry_stack + \ + SIZEOF_entry_stack - 8 + CPU_ENTRY_AREA + +ENTRY(entry_SYSCALL_64_trampoline) + UNWIND_HINT_EMPTY + swapgs + + /* Stash the user RSP. */ + movq %rsp, RSP_SCRATCH + + /* Note: using %rsp as a scratch reg. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp + + /* Load the top of the task stack into RSP */ + movq CPU_ENTRY_AREA_tss + TSS_sp1 + CPU_ENTRY_AREA, %rsp + + /* Start building the simulated IRET frame. */ + pushq $__USER_DS /* pt_regs->ss */ + pushq RSP_SCRATCH /* pt_regs->sp */ + pushq %r11 /* pt_regs->flags */ + pushq $__USER_CS /* pt_regs->cs */ + pushq %rcx /* pt_regs->ip */ + + /* + * x86 lacks a near absolute jump, and we can't jump to the real + * entry text with a relative jump. We could push the target + * address and then use retq, but this destroys the pipeline on + * many CPUs (wasting over 20 cycles on Sandy Bridge). Instead, + * spill RDI and restore it in a second-stage trampoline. + */ + pushq %rdi + movq $entry_SYSCALL_64_stage2, %rdi + JMP_NOSPEC %rdi +END(entry_SYSCALL_64_trampoline) + + .popsection + +ENTRY(entry_SYSCALL_64_stage2) + UNWIND_HINT_EMPTY + popq %rdi + jmp entry_SYSCALL_64_after_hwframe +END(entry_SYSCALL_64_stage2) + ENTRY(entry_SYSCALL_64) UNWIND_HINT_EMPTY /* @@ -145,11 +208,13 @@ ENTRY(entry_SYSCALL_64) */ swapgs + /* + * This path is not taken when PAGE_TABLE_ISOLATION is disabled so it + * is not required to switch CR3. + */ movq %rsp, PER_CPU_VAR(rsp_scratch) movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp - TRACE_IRQS_OFF - /* Construct struct pt_regs on stack */ pushq $__USER_DS /* pt_regs->ss */ pushq PER_CPU_VAR(rsp_scratch) /* pt_regs->sp */ @@ -170,6 +235,8 @@ GLOBAL(entry_SYSCALL_64_after_hwframe) sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ UNWIND_HINT_REGS extra=0 + TRACE_IRQS_OFF + /* * If we need to do entry work or if we guess we'll need to do * exit work, go straight to the slow path. @@ -200,7 +267,12 @@ entry_SYSCALL_64_fastpath: * It might end up jumping to the slow path. If it jumps, RAX * and all argument registers are clobbered. */ +#ifdef CONFIG_RETPOLINE + movq sys_call_table(, %rax, 8), %rax + call __x86_indirect_thunk_rax +#else call *sys_call_table(, %rax, 8) +#endif .Lentry_SYSCALL_64_after_fastpath_call: movq %rax, RAX(%rsp) @@ -221,10 +293,9 @@ entry_SYSCALL_64_fastpath: TRACE_IRQS_ON /* user mode is traced as IRQs on */ movq RIP(%rsp), %rcx movq EFLAGS(%rsp), %r11 - RESTORE_C_REGS_EXCEPT_RCX_R11 - movq RSP(%rsp), %rsp + addq $6*8, %rsp /* skip extra regs -- they were preserved */ UNWIND_HINT_EMPTY - USERGS_SYSRET64 + jmp .Lpop_c_regs_except_rcx_r11_and_sysret 1: /* @@ -246,17 +317,18 @@ entry_SYSCALL64_slow_path: call do_syscall_64 /* returns with IRQs disabled */ return_from_SYSCALL_64: - RESTORE_EXTRA_REGS TRACE_IRQS_IRETQ /* we're about to change IF */ /* * Try to use SYSRET instead of IRET if we're returning to - * a completely clean 64-bit userspace context. + * a completely clean 64-bit userspace context. If we're not, + * go to the slow exit path. */ movq RCX(%rsp), %rcx movq RIP(%rsp), %r11 - cmpq %rcx, %r11 /* RCX == RIP */ - jne opportunistic_sysret_failed + + cmpq %rcx, %r11 /* SYSRET requires RCX == RIP */ + jne swapgs_restore_regs_and_return_to_usermode /* * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP @@ -274,14 +346,14 @@ return_from_SYSCALL_64: /* If this changed %rcx, it was not canonical */ cmpq %rcx, %r11 - jne opportunistic_sysret_failed + jne swapgs_restore_regs_and_return_to_usermode cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */ - jne opportunistic_sysret_failed + jne swapgs_restore_regs_and_return_to_usermode movq R11(%rsp), %r11 cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */ - jne opportunistic_sysret_failed + jne swapgs_restore_regs_and_return_to_usermode /* * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot @@ -302,12 +374,12 @@ return_from_SYSCALL_64: * would never get past 'stuck_here'. */ testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11 - jnz opportunistic_sysret_failed + jnz swapgs_restore_regs_and_return_to_usermode /* nothing to check for RSP */ cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */ - jne opportunistic_sysret_failed + jne swapgs_restore_regs_and_return_to_usermode /* * We win! This label is here just for ease of understanding @@ -315,14 +387,37 @@ return_from_SYSCALL_64: */ syscall_return_via_sysret: /* rcx and r11 are already restored (see code above) */ - RESTORE_C_REGS_EXCEPT_RCX_R11 - movq RSP(%rsp), %rsp UNWIND_HINT_EMPTY - USERGS_SYSRET64 + POP_EXTRA_REGS +.Lpop_c_regs_except_rcx_r11_and_sysret: + popq %rsi /* skip r11 */ + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rsi /* skip rcx */ + popq %rdx + popq %rsi -opportunistic_sysret_failed: - SWAPGS - jmp restore_c_regs_and_iret + /* + * Now all regs are restored except RSP and RDI. + * Save old stack pointer and switch to trampoline stack. + */ + movq %rsp, %rdi + movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp + + pushq RSP-RDI(%rdi) /* RSP */ + pushq (%rdi) /* RDI */ + + /* + * We are on the trampoline stack. All regs except RDI are live. + * We can do future final exit work right here. + */ + SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi + + popq %rdi + popq %rsp + USERGS_SYSRET64 END(entry_SYSCALL_64) ENTRY(stub_ptregs_64) @@ -349,7 +444,7 @@ ENTRY(stub_ptregs_64) jmp entry_SYSCALL64_slow_path 1: - jmp *%rax /* Called from C */ + JMP_NOSPEC %rax /* Called from C */ END(stub_ptregs_64) .macro ptregs_stub func @@ -392,6 +487,17 @@ ENTRY(__switch_to_asm) movq %rbx, PER_CPU_VAR(irq_stack_union)+stack_canary_offset #endif +#ifdef CONFIG_RETPOLINE + /* + * When switching from a shallower to a deeper call stack + * the RSB may either underflow or use entries populated + * with userspace addresses. On CPUs where those concerns + * exist, overwrite the RSB with entries which capture + * speculative execution to prevent attack. + */ + FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW +#endif + /* restore callee-saved registers */ popq %r15 popq %r14 @@ -423,13 +529,12 @@ ENTRY(ret_from_fork) movq %rsp, %rdi call syscall_return_slowpath /* returns with IRQs disabled */ TRACE_IRQS_ON /* user mode is traced as IRQS on */ - SWAPGS - jmp restore_regs_and_iret + jmp swapgs_restore_regs_and_return_to_usermode 1: /* kernel thread */ movq %r12, %rdi - call *%rbx + CALL_NOSPEC %rbx /* * A kernel thread is allowed to return here after successfully * calling do_execve(). Exit to userspace to complete the execve() @@ -457,12 +562,13 @@ END(irq_entries_start) .macro DEBUG_ENTRY_ASSERT_IRQS_OFF #ifdef CONFIG_DEBUG_ENTRY - pushfq - testl $X86_EFLAGS_IF, (%rsp) + pushq %rax + SAVE_FLAGS(CLBR_RAX) + testl $X86_EFLAGS_IF, %eax jz .Lokay_\@ ud2 .Lokay_\@: - addq $8, %rsp + popq %rax #endif .endm @@ -554,6 +660,13 @@ END(irq_entries_start) /* 0(%rsp): ~(interrupt number) */ .macro interrupt func cld + + testb $3, CS-ORIG_RAX(%rsp) + jz 1f + SWAPGS + call switch_to_thread_stack +1: + ALLOC_PT_GPREGS_ON_STACK SAVE_C_REGS SAVE_EXTRA_REGS @@ -563,12 +676,8 @@ END(irq_entries_start) jz 1f /* - * IRQ from user mode. Switch to kernel gsbase and inform context - * tracking that we're in kernel mode. - */ - SWAPGS - - /* + * IRQ from user mode. + * * We need to tell lockdep that IRQs are off. We can't do this until * we fix gsbase, and we should do it before enter_from_user_mode * (which can take locks). Since TRACE_IRQS_OFF idempotent, @@ -612,8 +721,54 @@ GLOBAL(retint_user) mov %rsp,%rdi call prepare_exit_to_usermode TRACE_IRQS_IRETQ + +GLOBAL(swapgs_restore_regs_and_return_to_usermode) +#ifdef CONFIG_DEBUG_ENTRY + /* Assert that pt_regs indicates user mode. */ + testb $3, CS(%rsp) + jnz 1f + ud2 +1: +#endif + POP_EXTRA_REGS + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rcx + popq %rdx + popq %rsi + + /* + * The stack is now user RDI, orig_ax, RIP, CS, EFLAGS, RSP, SS. + * Save old stack pointer and switch to trampoline stack. + */ + movq %rsp, %rdi + movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp + + /* Copy the IRET frame to the trampoline stack. */ + pushq 6*8(%rdi) /* SS */ + pushq 5*8(%rdi) /* RSP */ + pushq 4*8(%rdi) /* EFLAGS */ + pushq 3*8(%rdi) /* CS */ + pushq 2*8(%rdi) /* RIP */ + + /* Push user RDI on the trampoline stack. */ + pushq (%rdi) + + /* + * We are on the trampoline stack. All regs except RDI are live. + * We can do future final exit work right here. + */ + + SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi + + /* Restore RDI. */ + popq %rdi SWAPGS - jmp restore_regs_and_iret + INTERRUPT_RETURN + /* Returning to kernel space */ retint_kernel: @@ -633,15 +788,17 @@ retint_kernel: */ TRACE_IRQS_IRETQ -/* - * At this label, code paths which return to kernel and to user, - * which come from interrupts/exception and from syscalls, merge. - */ -GLOBAL(restore_regs_and_iret) - RESTORE_EXTRA_REGS -restore_c_regs_and_iret: - RESTORE_C_REGS - REMOVE_PT_GPREGS_FROM_STACK 8 +GLOBAL(restore_regs_and_return_to_kernel) +#ifdef CONFIG_DEBUG_ENTRY + /* Assert that pt_regs indicates kernel mode. */ + testb $3, CS(%rsp) + jz 1f + ud2 +1: +#endif + POP_EXTRA_REGS + POP_C_REGS + addq $8, %rsp /* skip regs->orig_ax */ INTERRUPT_RETURN ENTRY(native_iret) @@ -689,7 +846,9 @@ native_irq_return_ldt: */ pushq %rdi /* Stash user RDI */ - SWAPGS + SWAPGS /* to kernel GS */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi /* to kernel CR3 */ + movq PER_CPU_VAR(espfix_waddr), %rdi movq %rax, (0*8)(%rdi) /* user RAX */ movq (1*8)(%rsp), %rax /* user RIP */ @@ -705,7 +864,6 @@ native_irq_return_ldt: /* Now RAX == RSP. */ andl $0xffff0000, %eax /* RAX = (RSP & 0xffff0000) */ - popq %rdi /* Restore user RDI */ /* * espfix_stack[31:16] == 0. The page tables are set up such that @@ -716,7 +874,11 @@ native_irq_return_ldt: * still points to an RO alias of the ESPFIX stack. */ orq PER_CPU_VAR(espfix_stack), %rax - SWAPGS + + SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi + SWAPGS /* to user GS */ + popq %rdi /* Restore user RDI */ + movq %rax, %rsp UNWIND_HINT_IRET_REGS offset=8 @@ -805,7 +967,35 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt /* * Exception entry points. */ -#define CPU_TSS_IST(x) PER_CPU_VAR(cpu_tss) + (TSS_ist + ((x) - 1) * 8) +#define CPU_TSS_IST(x) PER_CPU_VAR(cpu_tss_rw) + (TSS_ist + ((x) - 1) * 8) + +/* + * Switch to the thread stack. This is called with the IRET frame and + * orig_ax on the stack. (That is, RDI..R12 are not on the stack and + * space has not been allocated for them.) + */ +ENTRY(switch_to_thread_stack) + UNWIND_HINT_FUNC + + pushq %rdi + /* Need to switch before accessing the thread stack. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi + movq %rsp, %rdi + movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp + UNWIND_HINT sp_offset=16 sp_reg=ORC_REG_DI + + pushq 7*8(%rdi) /* regs->ss */ + pushq 6*8(%rdi) /* regs->rsp */ + pushq 5*8(%rdi) /* regs->eflags */ + pushq 4*8(%rdi) /* regs->cs */ + pushq 3*8(%rdi) /* regs->ip */ + pushq 2*8(%rdi) /* regs->orig_ax */ + pushq 8(%rdi) /* return address */ + UNWIND_HINT_FUNC + + movq (%rdi), %rdi + ret +END(switch_to_thread_stack) .macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ENTRY(\sym) @@ -818,17 +1008,18 @@ ENTRY(\sym) ASM_CLAC - .ifeq \has_error_code + .if \has_error_code == 0 pushq $-1 /* ORIG_RAX: no syscall to restart */ .endif ALLOC_PT_GPREGS_ON_STACK - .if \paranoid - .if \paranoid == 1 + .if \paranoid < 2 testb $3, CS(%rsp) /* If coming from userspace, switch stacks */ - jnz 1f + jnz .Lfrom_usermode_switch_stack_\@ .endif + + .if \paranoid call paranoid_entry .else call error_entry @@ -870,20 +1061,15 @@ ENTRY(\sym) jmp error_exit .endif - .if \paranoid == 1 + .if \paranoid < 2 /* - * Paranoid entry from userspace. Switch stacks and treat it + * Entry from userspace. Switch stacks and treat it * as a normal entry. This means that paranoid handlers * run in real process context if user_mode(regs). */ -1: +.Lfrom_usermode_switch_stack_\@: call error_entry - - movq %rsp, %rdi /* pt_regs pointer */ - call sync_regs - movq %rax, %rsp /* switch stack */ - movq %rsp, %rdi /* pt_regs pointer */ .if \has_error_code @@ -1059,6 +1245,7 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN +idtentry xennmi do_nmi has_error_code=0 idtentry xendebug do_debug has_error_code=0 idtentry xenint3 do_int3 has_error_code=0 #endif @@ -1071,7 +1258,7 @@ idtentry async_page_fault do_async_page_fault has_error_code=1 #endif #ifdef CONFIG_X86_MCE -idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(%rip) +idtentry machine_check do_mce has_error_code=0 paranoid=1 #endif /* @@ -1092,7 +1279,11 @@ ENTRY(paranoid_entry) js 1f /* negative -> in kernel */ SWAPGS xorl %ebx, %ebx -1: ret + +1: + SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14 + + ret END(paranoid_entry) /* @@ -1112,17 +1303,15 @@ ENTRY(paranoid_exit) DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF_DEBUG testl %ebx, %ebx /* swapgs needed? */ - jnz paranoid_exit_no_swapgs + jnz .Lparanoid_exit_no_swapgs TRACE_IRQS_IRETQ + RESTORE_CR3 scratch_reg=%rbx save_reg=%r14 SWAPGS_UNSAFE_STACK - jmp paranoid_exit_restore -paranoid_exit_no_swapgs: + jmp .Lparanoid_exit_restore +.Lparanoid_exit_no_swapgs: TRACE_IRQS_IRETQ_DEBUG -paranoid_exit_restore: - RESTORE_EXTRA_REGS - RESTORE_C_REGS - REMOVE_PT_GPREGS_FROM_STACK 8 - INTERRUPT_RETURN +.Lparanoid_exit_restore: + jmp restore_regs_and_return_to_kernel END(paranoid_exit) /* @@ -1144,8 +1333,18 @@ ENTRY(error_entry) * from user mode due to an IRET fault. */ SWAPGS + /* We have user CR3. Change to kernel CR3. */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax .Lerror_entry_from_usermode_after_swapgs: + /* Put us onto the real thread stack. */ + popq %r12 /* save return addr in %12 */ + movq %rsp, %rdi /* arg0 = pt_regs pointer */ + call sync_regs + movq %rax, %rsp /* switch stack */ + ENCODE_FRAME_POINTER + pushq %r12 + /* * We need to tell lockdep that IRQs are off. We can't do this until * we fix gsbase, and we should do it before enter_from_user_mode @@ -1182,6 +1381,7 @@ ENTRY(error_entry) * .Lgs_change's error handler with kernel gsbase. */ SWAPGS + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax jmp .Lerror_entry_done .Lbstep_iret: @@ -1191,10 +1391,11 @@ ENTRY(error_entry) .Lerror_bad_iret: /* - * We came from an IRET to user mode, so we have user gsbase. - * Switch to kernel gsbase: + * We came from an IRET to user mode, so we have user + * gsbase and CR3. Switch to kernel gsbase and CR3: */ SWAPGS + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax /* * Pretend that the exception came from user mode: set up pt_regs @@ -1223,10 +1424,17 @@ ENTRY(error_exit) jmp retint_user END(error_exit) -/* Runs on exception stack */ -/* XXX: broken on Xen PV */ +/* + * Runs on exception stack. Xen PV does not go through this path at all, + * so we can use real assembly here. + * + * Registers: + * %r14: Used to save/restore the CR3 of the interrupted context + * when PAGE_TABLE_ISOLATION is in use. Do not clobber. + */ ENTRY(nmi) UNWIND_HINT_IRET_REGS + /* * We allow breakpoints in NMIs. If a breakpoint occurs, then * the iretq it performs will take us out of NMI context. @@ -1284,8 +1492,9 @@ ENTRY(nmi) * stacks lest we corrupt the "NMI executing" variable. */ - SWAPGS_UNSAFE_STACK + swapgs cld + SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx movq %rsp, %rdx movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp UNWIND_HINT_IRET_REGS base=%rdx offset=8 @@ -1328,8 +1537,7 @@ ENTRY(nmi) * Return back to user mode. We must *not* do the normal exit * work, because we don't want to enable interrupts. */ - SWAPGS - jmp restore_regs_and_iret + jmp swapgs_restore_regs_and_return_to_usermode .Lnmi_from_kernel: /* @@ -1450,7 +1658,7 @@ nested_nmi_out: popq %rdx /* We are returning to kernel mode, so this cannot result in a fault. */ - INTERRUPT_RETURN + iretq first_nmi: /* Restore rdx. */ @@ -1481,7 +1689,7 @@ first_nmi: pushfq /* RFLAGS */ pushq $__KERNEL_CS /* CS */ pushq $1f /* RIP */ - INTERRUPT_RETURN /* continues at repeat_nmi below */ + iretq /* continues at repeat_nmi below */ UNWIND_HINT_IRET_REGS 1: #endif @@ -1539,34 +1747,41 @@ end_repeat_nmi: movq $-1, %rsi call do_nmi + RESTORE_CR3 scratch_reg=%r15 save_reg=%r14 + testl %ebx, %ebx /* swapgs needed? */ jnz nmi_restore nmi_swapgs: SWAPGS_UNSAFE_STACK nmi_restore: - RESTORE_EXTRA_REGS - RESTORE_C_REGS + POP_EXTRA_REGS + POP_C_REGS - /* Point RSP at the "iret" frame. */ - REMOVE_PT_GPREGS_FROM_STACK 6*8 + /* + * Skip orig_ax and the "outermost" frame to point RSP at the "iret" + * at the "iret" frame. + */ + addq $6*8, %rsp /* * Clear "NMI executing". Set DF first so that we can easily * distinguish the remaining code between here and IRET from - * the SYSCALL entry and exit paths. On a native kernel, we - * could just inspect RIP, but, on paravirt kernels, - * INTERRUPT_RETURN can translate into a jump into a - * hypercall page. + * the SYSCALL entry and exit paths. + * + * We arguably should just inspect RIP instead, but I (Andy) wrote + * this code when I had the misapprehension that Xen PV supported + * NMIs, and Xen PV would break that approach. */ std movq $0, 5*8(%rsp) /* clear "NMI executing" */ /* - * INTERRUPT_RETURN reads the "iret" frame and exits the NMI - * stack in a single instruction. We are returning to kernel - * mode, so this cannot result in a fault. + * iretq reads the "iret" frame and exits the NMI stack in a + * single instruction. We are returning to kernel mode, so this + * cannot result in a fault. Similarly, we don't need to worry + * about espfix64 on the way back to kernel mode. */ - INTERRUPT_RETURN + iretq END(nmi) ENTRY(ignore_sysret) diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index b5c7a56ed256d..98d5358e4041a 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -48,7 +48,11 @@ */ ENTRY(entry_SYSENTER_compat) /* Interrupts are off on entry. */ - SWAPGS_UNSAFE_STACK + SWAPGS + + /* We are about to clobber %rsp anyway, clobbering here is OK */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp + movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /* @@ -186,8 +190,13 @@ ENTRY(entry_SYSCALL_compat) /* Interrupts are off on entry. */ swapgs - /* Stash user ESP and switch to the kernel stack. */ + /* Stash user ESP */ movl %esp, %r8d + + /* Use %rsp as scratch reg. User ESP is stashed in r8 */ + SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp + + /* Switch to the kernel stack */ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /* Construct struct pt_regs on stack */ @@ -256,10 +265,22 @@ sysret32_from_system_call: * when the system call started, which is already known to user * code. We zero R8-R10 to avoid info leaks. */ + movq RSP-ORIG_RAX(%rsp), %rsp + + /* + * The original userspace %rsp (RSP-ORIG_RAX(%rsp)) is stored + * on the process stack which is not mapped to userspace and + * not readable after we SWITCH_TO_USER_CR3. Delay the CR3 + * switch until after after the last reference to the process + * stack. + * + * %r8/%r9 are zeroed before the sysret, thus safe to clobber. + */ + SWITCH_TO_USER_CR3_NOSTACK scratch_reg=%r8 scratch_reg2=%r9 + xorq %r8, %r8 xorq %r9, %r9 xorq %r10, %r10 - movq RSP-ORIG_RAX(%rsp), %rsp swapgs sysretl END(entry_SYSCALL_compat) @@ -306,8 +327,11 @@ ENTRY(entry_INT80_compat) */ movl %eax, %eax - /* Construct struct pt_regs on stack (iret frame is already on stack) */ pushq %rax /* pt_regs->orig_ax */ + + /* switch to thread stack expects orig_ax to be pushed */ + call switch_to_thread_stack + pushq %rdi /* pt_regs->di */ pushq %rsi /* pt_regs->si */ pushq %rdx /* pt_regs->dx */ @@ -337,8 +361,7 @@ ENTRY(entry_INT80_compat) /* Go back to user mode. */ TRACE_IRQS_ON - SWAPGS - jmp restore_regs_and_iret + jmp swapgs_restore_regs_and_return_to_usermode END(entry_INT80_compat) ENTRY(stub32_clone) diff --git a/arch/x86/entry/syscalls/Makefile b/arch/x86/entry/syscalls/Makefile index 331f1dca50854..6fb9b57ed5ba0 100644 --- a/arch/x86/entry/syscalls/Makefile +++ b/arch/x86/entry/syscalls/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -out := $(obj)/../../include/generated/asm -uapi := $(obj)/../../include/generated/uapi/asm +out := arch/$(SRCARCH)/include/generated/asm +uapi := arch/$(SRCARCH)/include/generated/uapi/asm # Create output directory if not already present _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') \ diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index f279ba2643dc8..577fa8adb785b 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -37,6 +37,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "vsyscall_trace.h" @@ -138,6 +139,10 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) WARN_ON_ONCE(address != regs->ip); + /* This should be unreachable in NATIVE mode. */ + if (WARN_ON(vsyscall_mode == NATIVE)) + return false; + if (vsyscall_mode == NONE) { warn_bad_vsyscall(KERN_INFO, regs, "vsyscall attempted with vsyscall=none"); @@ -329,16 +334,47 @@ int in_gate_area_no_mm(unsigned long addr) return vsyscall_mode != NONE && (addr & PAGE_MASK) == VSYSCALL_ADDR; } +/* + * The VSYSCALL page is the only user-accessible page in the kernel address + * range. Normally, the kernel page tables can have _PAGE_USER clear, but + * the tables covering VSYSCALL_ADDR need _PAGE_USER set if vsyscalls + * are enabled. + * + * Some day we may create a "minimal" vsyscall mode in which we emulate + * vsyscalls but leave the page not present. If so, we skip calling + * this. + */ +void __init set_vsyscall_pgtable_user_bits(pgd_t *root) +{ + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset_pgd(root, VSYSCALL_ADDR); + set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER)); + p4d = p4d_offset(pgd, VSYSCALL_ADDR); +#if CONFIG_PGTABLE_LEVELS >= 5 + p4d->p4d |= _PAGE_USER; +#endif + pud = pud_offset(p4d, VSYSCALL_ADDR); + set_pud(pud, __pud(pud_val(*pud) | _PAGE_USER)); + pmd = pmd_offset(pud, VSYSCALL_ADDR); + set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_USER)); +} + void __init map_vsyscall(void) { extern char __vsyscall_page; unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page); - if (vsyscall_mode != NONE) + if (vsyscall_mode != NONE) { __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, vsyscall_mode == NATIVE ? PAGE_KERNEL_VSYSCALL : PAGE_KERNEL_VVAR); + set_vsyscall_pgtable_user_bits(swapper_pg_dir); + } BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) != (unsigned long)VSYSCALL_ADDR); diff --git a/arch/x86/events/amd/power.c b/arch/x86/events/amd/power.c index a6eee5ac4f581..2aefacf5c5b2a 100644 --- a/arch/x86/events/amd/power.c +++ b/arch/x86/events/amd/power.c @@ -277,7 +277,7 @@ static int __init amd_power_pmu_init(void) int ret; if (!x86_match_cpu(cpu_match)) - return 0; + return -ENODEV; if (!boot_cpu_has(X86_FEATURE_ACC_POWER)) return -ENODEV; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 80534d3c24800..589af1eec7c1c 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2371,7 +2371,7 @@ static unsigned long get_segment_base(unsigned int segment) struct ldt_struct *ldt; /* IRQs are off, so this synchronizes with smp_store_release */ - ldt = lockless_dereference(current->active_mm->context.ldt); + ldt = READ_ONCE(current->active_mm->context.ldt); if (!ldt || idx >= ldt->nr_entries) return 0; diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 141e07b062168..24ffa1e88cf94 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -582,6 +582,24 @@ static __init int bts_init(void) if (!boot_cpu_has(X86_FEATURE_DTES64) || !x86_pmu.bts) return -ENODEV; + if (boot_cpu_has(X86_FEATURE_PTI)) { + /* + * BTS hardware writes through a virtual memory map we must + * either use the kernel physical map, or the user mapping of + * the AUX buffer. + * + * However, since this driver supports per-CPU and per-task inherit + * we cannot use the user mapping since it will not be availble + * if we're not running the owning process. + * + * With PTI we can't use the kernal map either, because its not + * there when we run userspace. + * + * For now, disable this driver when using PTI. + */ + return -ENODEV; + } + bts_pmu.capabilities = PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_ITRACE | PERF_PMU_CAP_EXCLUSIVE; bts_pmu.task_ctx_nr = perf_sw_context; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 9fb9a1f1e47bd..09c26a4f139c1 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2958,6 +2958,10 @@ static unsigned long intel_pmu_free_running_flags(struct perf_event *event) if (event->attr.use_clockid) flags &= ~PERF_SAMPLE_TIME; + if (!event->attr.exclude_kernel) + flags &= ~PERF_SAMPLE_REGS_USER; + if (event->attr.sample_regs_user & ~PEBS_REGS) + flags &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_REGS_INTR); return flags; } @@ -3730,6 +3734,19 @@ EVENT_ATTR_STR(cycles-t, cycles_t, "event=0x3c,in_tx=1"); EVENT_ATTR_STR(cycles-ct, cycles_ct, "event=0x3c,in_tx=1,in_tx_cp=1"); static struct attribute *hsw_events_attrs[] = { + EVENT_PTR(mem_ld_hsw), + EVENT_PTR(mem_st_hsw), + EVENT_PTR(td_slots_issued), + EVENT_PTR(td_slots_retired), + EVENT_PTR(td_fetch_bubbles), + EVENT_PTR(td_total_slots), + EVENT_PTR(td_total_slots_scale), + EVENT_PTR(td_recovery_bubbles), + EVENT_PTR(td_recovery_bubbles_scale), + NULL +}; + +static struct attribute *hsw_tsx_events_attrs[] = { EVENT_PTR(tx_start), EVENT_PTR(tx_commit), EVENT_PTR(tx_abort), @@ -3742,18 +3759,16 @@ static struct attribute *hsw_events_attrs[] = { EVENT_PTR(el_conflict), EVENT_PTR(cycles_t), EVENT_PTR(cycles_ct), - EVENT_PTR(mem_ld_hsw), - EVENT_PTR(mem_st_hsw), - EVENT_PTR(td_slots_issued), - EVENT_PTR(td_slots_retired), - EVENT_PTR(td_fetch_bubbles), - EVENT_PTR(td_total_slots), - EVENT_PTR(td_total_slots_scale), - EVENT_PTR(td_recovery_bubbles), - EVENT_PTR(td_recovery_bubbles_scale), NULL }; +static __init struct attribute **get_hsw_events_attrs(void) +{ + return boot_cpu_has(X86_FEATURE_RTM) ? + merge_attr(hsw_events_attrs, hsw_tsx_events_attrs) : + hsw_events_attrs; +} + static ssize_t freeze_on_smi_show(struct device *cdev, struct device_attribute *attr, char *buf) @@ -4182,7 +4197,7 @@ __init int intel_pmu_init(void) x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints; - x86_pmu.cpu_events = hsw_events_attrs; + x86_pmu.cpu_events = get_hsw_events_attrs(); x86_pmu.lbr_double_abort = true; extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? hsw_format_attr : nhm_format_attr; @@ -4221,7 +4236,7 @@ __init int intel_pmu_init(void) x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints; - x86_pmu.cpu_events = hsw_events_attrs; + x86_pmu.cpu_events = get_hsw_events_attrs(); x86_pmu.limit_period = bdw_limit_period; extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? hsw_format_attr : nhm_format_attr; @@ -4279,7 +4294,7 @@ __init int intel_pmu_init(void) extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? hsw_format_attr : nhm_format_attr; extra_attr = merge_attr(extra_attr, skl_format_attr); - x86_pmu.cpu_events = hsw_events_attrs; + x86_pmu.cpu_events = get_hsw_events_attrs(); intel_pmu_pebs_data_source_skl( boot_cpu_data.x86_model == INTEL_FAM6_SKYLAKE_X); pr_cont("Skylake events, "); diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 3674a4b6f8bd0..8156e47da7ba4 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -3,16 +3,19 @@ #include #include +#include #include +#include #include #include "../perf_event.h" +/* Waste a full page so it can be mapped into the cpu_entry_area */ +DEFINE_PER_CPU_PAGE_ALIGNED(struct debug_store, cpu_debug_store); + /* The size of a BTS record in bytes: */ #define BTS_RECORD_SIZE 24 -#define BTS_BUFFER_SIZE (PAGE_SIZE << 4) -#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4) #define PEBS_FIXUP_SIZE PAGE_SIZE /* @@ -279,17 +282,67 @@ void fini_debug_store_on_cpu(int cpu) static DEFINE_PER_CPU(void *, insn_buffer); -static int alloc_pebs_buffer(int cpu) +static void ds_update_cea(void *cea, void *addr, size_t size, pgprot_t prot) { - struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; + unsigned long start = (unsigned long)cea; + phys_addr_t pa; + size_t msz = 0; + + pa = virt_to_phys(addr); + + preempt_disable(); + for (; msz < size; msz += PAGE_SIZE, pa += PAGE_SIZE, cea += PAGE_SIZE) + cea_set_pte(cea, pa, prot); + + /* + * This is a cross-CPU update of the cpu_entry_area, we must shoot down + * all TLB entries for it. + */ + flush_tlb_kernel_range(start, start + size); + preempt_enable(); +} + +static void ds_clear_cea(void *cea, size_t size) +{ + unsigned long start = (unsigned long)cea; + size_t msz = 0; + + preempt_disable(); + for (; msz < size; msz += PAGE_SIZE, cea += PAGE_SIZE) + cea_set_pte(cea, 0, PAGE_NONE); + + flush_tlb_kernel_range(start, start + size); + preempt_enable(); +} + +static void *dsalloc_pages(size_t size, gfp_t flags, int cpu) +{ + unsigned int order = get_order(size); int node = cpu_to_node(cpu); - int max; - void *buffer, *ibuffer; + struct page *page; + + page = __alloc_pages_node(node, flags | __GFP_ZERO, order); + return page ? page_address(page) : NULL; +} + +static void dsfree_pages(const void *buffer, size_t size) +{ + if (buffer) + free_pages((unsigned long)buffer, get_order(size)); +} + +static int alloc_pebs_buffer(int cpu) +{ + struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); + struct debug_store *ds = hwev->ds; + size_t bsiz = x86_pmu.pebs_buffer_size; + int max, node = cpu_to_node(cpu); + void *buffer, *ibuffer, *cea; if (!x86_pmu.pebs) return 0; - buffer = kzalloc_node(x86_pmu.pebs_buffer_size, GFP_KERNEL, node); + buffer = dsalloc_pages(bsiz, GFP_KERNEL, cpu); if (unlikely(!buffer)) return -ENOMEM; @@ -300,25 +353,27 @@ static int alloc_pebs_buffer(int cpu) if (x86_pmu.intel_cap.pebs_format < 2) { ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node); if (!ibuffer) { - kfree(buffer); + dsfree_pages(buffer, bsiz); return -ENOMEM; } per_cpu(insn_buffer, cpu) = ibuffer; } - - max = x86_pmu.pebs_buffer_size / x86_pmu.pebs_record_size; - - ds->pebs_buffer_base = (u64)(unsigned long)buffer; + hwev->ds_pebs_vaddr = buffer; + /* Update the cpu entry area mapping */ + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.pebs_buffer; + ds->pebs_buffer_base = (unsigned long) cea; + ds_update_cea(cea, buffer, bsiz, PAGE_KERNEL); ds->pebs_index = ds->pebs_buffer_base; - ds->pebs_absolute_maximum = ds->pebs_buffer_base + - max * x86_pmu.pebs_record_size; - + max = x86_pmu.pebs_record_size * (bsiz / x86_pmu.pebs_record_size); + ds->pebs_absolute_maximum = ds->pebs_buffer_base + max; return 0; } static void release_pebs_buffer(int cpu) { - struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; + struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); + struct debug_store *ds = hwev->ds; + void *cea; if (!ds || !x86_pmu.pebs) return; @@ -326,73 +381,70 @@ static void release_pebs_buffer(int cpu) kfree(per_cpu(insn_buffer, cpu)); per_cpu(insn_buffer, cpu) = NULL; - kfree((void *)(unsigned long)ds->pebs_buffer_base); + /* Clear the fixmap */ + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.pebs_buffer; + ds_clear_cea(cea, x86_pmu.pebs_buffer_size); ds->pebs_buffer_base = 0; + dsfree_pages(hwev->ds_pebs_vaddr, x86_pmu.pebs_buffer_size); + hwev->ds_pebs_vaddr = NULL; } static int alloc_bts_buffer(int cpu) { - struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; - int node = cpu_to_node(cpu); - int max, thresh; - void *buffer; + struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); + struct debug_store *ds = hwev->ds; + void *buffer, *cea; + int max; if (!x86_pmu.bts) return 0; - buffer = kzalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node); + buffer = dsalloc_pages(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, cpu); if (unlikely(!buffer)) { WARN_ONCE(1, "%s: BTS buffer allocation failure\n", __func__); return -ENOMEM; } - - max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE; - thresh = max / 16; - - ds->bts_buffer_base = (u64)(unsigned long)buffer; + hwev->ds_bts_vaddr = buffer; + /* Update the fixmap */ + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.bts_buffer; + ds->bts_buffer_base = (unsigned long) cea; + ds_update_cea(cea, buffer, BTS_BUFFER_SIZE, PAGE_KERNEL); ds->bts_index = ds->bts_buffer_base; - ds->bts_absolute_maximum = ds->bts_buffer_base + - max * BTS_RECORD_SIZE; - ds->bts_interrupt_threshold = ds->bts_absolute_maximum - - thresh * BTS_RECORD_SIZE; - + max = BTS_RECORD_SIZE * (BTS_BUFFER_SIZE / BTS_RECORD_SIZE); + ds->bts_absolute_maximum = ds->bts_buffer_base + max; + ds->bts_interrupt_threshold = ds->bts_absolute_maximum - (max / 16); return 0; } static void release_bts_buffer(int cpu) { - struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; + struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); + struct debug_store *ds = hwev->ds; + void *cea; if (!ds || !x86_pmu.bts) return; - kfree((void *)(unsigned long)ds->bts_buffer_base); + /* Clear the fixmap */ + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.bts_buffer; + ds_clear_cea(cea, BTS_BUFFER_SIZE); ds->bts_buffer_base = 0; + dsfree_pages(hwev->ds_bts_vaddr, BTS_BUFFER_SIZE); + hwev->ds_bts_vaddr = NULL; } static int alloc_ds_buffer(int cpu) { - int node = cpu_to_node(cpu); - struct debug_store *ds; - - ds = kzalloc_node(sizeof(*ds), GFP_KERNEL, node); - if (unlikely(!ds)) - return -ENOMEM; + struct debug_store *ds = &get_cpu_entry_area(cpu)->cpu_debug_store; + memset(ds, 0, sizeof(*ds)); per_cpu(cpu_hw_events, cpu).ds = ds; - return 0; } static void release_ds_buffer(int cpu) { - struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; - - if (!ds) - return; - per_cpu(cpu_hw_events, cpu).ds = NULL; - kfree(ds); } void release_ds_buffers(void) diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 4196f81ec0e1b..8e4ea143ed964 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -14,6 +14,8 @@ #include +#include + /* To enable MSR tracing please use the generic trace points. */ /* @@ -77,38 +79,41 @@ struct amd_nb { struct event_constraint event_constraints[X86_PMC_IDX_MAX]; }; -/* The maximal number of PEBS events: */ -#define MAX_PEBS_EVENTS 8 #define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1) /* * Flags PEBS can handle without an PMI. * * TID can only be handled by flushing at context switch. + * REGS_USER can be handled for events limited to ring 3. * */ #define PEBS_FREERUNNING_FLAGS \ (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | \ PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \ PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \ - PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR) - -/* - * A debug store configuration. - * - * We only support architectures that use 64bit fields. - */ -struct debug_store { - u64 bts_buffer_base; - u64 bts_index; - u64 bts_absolute_maximum; - u64 bts_interrupt_threshold; - u64 pebs_buffer_base; - u64 pebs_index; - u64 pebs_absolute_maximum; - u64 pebs_interrupt_threshold; - u64 pebs_event_reset[MAX_PEBS_EVENTS]; -}; + PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | \ + PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER) + +#define PEBS_REGS \ + (PERF_REG_X86_AX | \ + PERF_REG_X86_BX | \ + PERF_REG_X86_CX | \ + PERF_REG_X86_DX | \ + PERF_REG_X86_DI | \ + PERF_REG_X86_SI | \ + PERF_REG_X86_SP | \ + PERF_REG_X86_BP | \ + PERF_REG_X86_IP | \ + PERF_REG_X86_FLAGS | \ + PERF_REG_X86_R8 | \ + PERF_REG_X86_R9 | \ + PERF_REG_X86_R10 | \ + PERF_REG_X86_R11 | \ + PERF_REG_X86_R12 | \ + PERF_REG_X86_R13 | \ + PERF_REG_X86_R14 | \ + PERF_REG_X86_R15) /* * Per register state. @@ -194,6 +199,8 @@ struct cpu_hw_events { * Intel DebugStore bits */ struct debug_store *ds; + void *ds_pebs_vaddr; + void *ds_bts_vaddr; u64 pebs_enabled; int n_pebs; int n_large_pebs; diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index a5db63f728a2f..a0b86cf486e0a 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -113,7 +113,7 @@ void hyperv_init(void) u64 guest_id; union hv_x64_msr_hypercall_contents hypercall_msr; - if (x86_hyper != &x86_hyper_ms_hyperv) + if (x86_hyper_type != X86_HYPER_MS_HYPERV) return; /* Allocate percpu VP index */ diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index dbfd0854651fe..cf5961ca86774 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -140,7 +140,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ".popsection\n" \ ".pushsection .altinstr_replacement, \"ax\"\n" \ ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ - ".popsection" + ".popsection\n" #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ OLDINSTR_2(oldinstr, 1, 2) \ @@ -151,7 +151,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ".pushsection .altinstr_replacement, \"ax\"\n" \ ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ - ".popsection" + ".popsection\n" /* * Alternative instructions for different CPU types or capabilities. diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index 5b0579abb3982..3ac991d81e74d 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -45,7 +45,7 @@ static inline bool rdrand_long(unsigned long *v) bool ok; unsigned int retry = RDRAND_RETRY_LOOPS; do { - asm volatile(RDRAND_LONG "\n\t" + asm volatile(RDRAND_LONG CC_SET(c) : CC_OUT(c) (ok), "=a" (*v)); if (ok) @@ -59,7 +59,7 @@ static inline bool rdrand_int(unsigned int *v) bool ok; unsigned int retry = RDRAND_RETRY_LOOPS; do { - asm volatile(RDRAND_INT "\n\t" + asm volatile(RDRAND_INT CC_SET(c) : CC_OUT(c) (ok), "=a" (*v)); if (ok) @@ -71,7 +71,7 @@ static inline bool rdrand_int(unsigned int *v) static inline bool rdseed_long(unsigned long *v) { bool ok; - asm volatile(RDSEED_LONG "\n\t" + asm volatile(RDSEED_LONG CC_SET(c) : CC_OUT(c) (ok), "=a" (*v)); return ok; @@ -80,7 +80,7 @@ static inline bool rdseed_long(unsigned long *v) static inline bool rdseed_int(unsigned int *v) { bool ok; - asm volatile(RDSEED_INT "\n\t" + asm volatile(RDSEED_INT CC_SET(c) : CC_OUT(c) (ok), "=a" (*v)); return ok; diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h index ff700d81e91ef..0927cdc4f9460 100644 --- a/arch/x86/include/asm/asm-prototypes.h +++ b/arch/x86/include/asm/asm-prototypes.h @@ -11,7 +11,32 @@ #include #include #include +#include #ifndef CONFIG_X86_CMPXCHG64 extern void cmpxchg8b_emu(void); #endif + +#ifdef CONFIG_RETPOLINE +#ifdef CONFIG_X86_32 +#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void); +#else +#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void); +INDIRECT_THUNK(8) +INDIRECT_THUNK(9) +INDIRECT_THUNK(10) +INDIRECT_THUNK(11) +INDIRECT_THUNK(12) +INDIRECT_THUNK(13) +INDIRECT_THUNK(14) +INDIRECT_THUNK(15) +#endif +INDIRECT_THUNK(ax) +INDIRECT_THUNK(bx) +INDIRECT_THUNK(cx) +INDIRECT_THUNK(dx) +INDIRECT_THUNK(si) +INDIRECT_THUNK(di) +INDIRECT_THUNK(bp) +INDIRECT_THUNK(sp) +#endif /* CONFIG_RETPOLINE */ diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 2bcf473149595..3fa039855b8f7 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -143,7 +143,7 @@ static __always_inline void __clear_bit(long nr, volatile unsigned long *addr) static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr) { bool negative; - asm volatile(LOCK_PREFIX "andb %2,%1\n\t" + asm volatile(LOCK_PREFIX "andb %2,%1" CC_SET(s) : CC_OUT(s) (negative), ADDR : "ir" ((char) ~(1 << nr)) : "memory"); @@ -246,7 +246,7 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long * { bool oldbit; - asm("bts %2,%1\n\t" + asm("bts %2,%1" CC_SET(c) : CC_OUT(c) (oldbit), ADDR : "Ir" (nr)); @@ -286,7 +286,7 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long { bool oldbit; - asm volatile("btr %2,%1\n\t" + asm volatile("btr %2,%1" CC_SET(c) : CC_OUT(c) (oldbit), ADDR : "Ir" (nr)); @@ -298,7 +298,7 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon { bool oldbit; - asm volatile("btc %2,%1\n\t" + asm volatile("btc %2,%1" CC_SET(c) : CC_OUT(c) (oldbit), ADDR : "Ir" (nr) : "memory"); @@ -329,7 +329,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l { bool oldbit; - asm volatile("bt %2,%1\n\t" + asm volatile("bt %2,%1" CC_SET(c) : CC_OUT(c) (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 9eef9cc64c684..2cbd75dd2fd35 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -209,7 +210,6 @@ typedef struct compat_siginfo { } compat_siginfo_t; #define COMPAT_OFF_T_MAX 0x7fffffff -#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL struct compat_ipc64_perm { compat_key_t key; diff --git a/arch/x86/include/asm/cpu_entry_area.h b/arch/x86/include/asm/cpu_entry_area.h new file mode 100644 index 0000000000000..4a7884b8dca55 --- /dev/null +++ b/arch/x86/include/asm/cpu_entry_area.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef _ASM_X86_CPU_ENTRY_AREA_H +#define _ASM_X86_CPU_ENTRY_AREA_H + +#include +#include +#include + +/* + * cpu_entry_area is a percpu region that contains things needed by the CPU + * and early entry/exit code. Real types aren't used for all fields here + * to avoid circular header dependencies. + * + * Every field is a virtual alias of some other allocated backing store. + * There is no direct allocation of a struct cpu_entry_area. + */ +struct cpu_entry_area { + char gdt[PAGE_SIZE]; + + /* + * The GDT is just below entry_stack and thus serves (on x86_64) as + * a a read-only guard page. + */ + struct entry_stack_page entry_stack_page; + + /* + * On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because + * we need task switches to work, and task switches write to the TSS. + */ + struct tss_struct tss; + + char entry_trampoline[PAGE_SIZE]; + +#ifdef CONFIG_X86_64 + /* + * Exception stacks used for IST entries. + * + * In the future, this should have a separate slot for each stack + * with guard pages between them. + */ + char exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]; +#endif +#ifdef CONFIG_CPU_SUP_INTEL + /* + * Per CPU debug store for Intel performance monitoring. Wastes a + * full page at the moment. + */ + struct debug_store cpu_debug_store; + /* + * The actual PEBS/BTS buffers must be mapped to user space + * Reserve enough fixmap PTEs. + */ + struct debug_store_buffers cpu_debug_buffers; +#endif +}; + +#define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area)) +#define CPU_ENTRY_AREA_TOT_SIZE (CPU_ENTRY_AREA_SIZE * NR_CPUS) + +DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area); + +extern void setup_cpu_entry_areas(void); +extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags); + +#define CPU_ENTRY_AREA_RO_IDT CPU_ENTRY_AREA_BASE +#define CPU_ENTRY_AREA_PER_CPU (CPU_ENTRY_AREA_RO_IDT + PAGE_SIZE) + +#define CPU_ENTRY_AREA_RO_IDT_VADDR ((void *)CPU_ENTRY_AREA_RO_IDT) + +#define CPU_ENTRY_AREA_MAP_SIZE \ + (CPU_ENTRY_AREA_PER_CPU + CPU_ENTRY_AREA_TOT_SIZE - CPU_ENTRY_AREA_BASE) + +extern struct cpu_entry_area *get_cpu_entry_area(int cpu); + +static inline struct entry_stack *cpu_entry_stack(int cpu) +{ + return &get_cpu_entry_area(cpu)->entry_stack_page.stack; +} + +#endif diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 0dfa68438e80e..ea9a7dde62e5c 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -126,16 +126,17 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) -#define clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability)) -#define setup_clear_cpu_cap(bit) do { \ - clear_cpu_cap(&boot_cpu_data, bit); \ - set_bit(bit, (unsigned long *)cpu_caps_cleared); \ -} while (0) + +extern void setup_clear_cpu_cap(unsigned int bit); +extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); + #define setup_force_cpu_cap(bit) do { \ set_cpu_cap(&boot_cpu_data, bit); \ set_bit(bit, (unsigned long *)cpu_caps_set); \ } while (0) +#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit) + #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_X86_FAST_FEATURE_TESTS) /* * Static testing of CPU features. Used the same as boot_cpu_has(). diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 793690fbda362..25b9375c1484b 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -13,173 +13,176 @@ /* * Defines x86 CPU feature bits */ -#define NCAPINTS 18 /* N 32-bit words worth of info */ -#define NBUGINTS 1 /* N 32-bit bug flags */ +#define NCAPINTS 18 /* N 32-bit words worth of info */ +#define NBUGINTS 1 /* N 32-bit bug flags */ /* * Note: If the comment begins with a quoted string, that string is used * in /proc/cpuinfo instead of the macro name. If the string is "", * this feature bit is not displayed in /proc/cpuinfo at all. + * + * When adding new features here that depend on other features, + * please update the table in kernel/cpu/cpuid-deps.c as well. */ -/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ -#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */ -#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */ -#define X86_FEATURE_DE ( 0*32+ 2) /* Debugging Extensions */ -#define X86_FEATURE_PSE ( 0*32+ 3) /* Page Size Extensions */ -#define X86_FEATURE_TSC ( 0*32+ 4) /* Time Stamp Counter */ -#define X86_FEATURE_MSR ( 0*32+ 5) /* Model-Specific Registers */ -#define X86_FEATURE_PAE ( 0*32+ 6) /* Physical Address Extensions */ -#define X86_FEATURE_MCE ( 0*32+ 7) /* Machine Check Exception */ -#define X86_FEATURE_CX8 ( 0*32+ 8) /* CMPXCHG8 instruction */ -#define X86_FEATURE_APIC ( 0*32+ 9) /* Onboard APIC */ -#define X86_FEATURE_SEP ( 0*32+11) /* SYSENTER/SYSEXIT */ -#define X86_FEATURE_MTRR ( 0*32+12) /* Memory Type Range Registers */ -#define X86_FEATURE_PGE ( 0*32+13) /* Page Global Enable */ -#define X86_FEATURE_MCA ( 0*32+14) /* Machine Check Architecture */ -#define X86_FEATURE_CMOV ( 0*32+15) /* CMOV instructions */ - /* (plus FCMOVcc, FCOMI with FPU) */ -#define X86_FEATURE_PAT ( 0*32+16) /* Page Attribute Table */ -#define X86_FEATURE_PSE36 ( 0*32+17) /* 36-bit PSEs */ -#define X86_FEATURE_PN ( 0*32+18) /* Processor serial number */ -#define X86_FEATURE_CLFLUSH ( 0*32+19) /* CLFLUSH instruction */ -#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */ -#define X86_FEATURE_ACPI ( 0*32+22) /* ACPI via MSR */ -#define X86_FEATURE_MMX ( 0*32+23) /* Multimedia Extensions */ -#define X86_FEATURE_FXSR ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ -#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */ -#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */ -#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */ -#define X86_FEATURE_HT ( 0*32+28) /* Hyper-Threading */ -#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */ -#define X86_FEATURE_IA64 ( 0*32+30) /* IA-64 processor */ -#define X86_FEATURE_PBE ( 0*32+31) /* Pending Break Enable */ +/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */ +#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */ +#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */ +#define X86_FEATURE_DE ( 0*32+ 2) /* Debugging Extensions */ +#define X86_FEATURE_PSE ( 0*32+ 3) /* Page Size Extensions */ +#define X86_FEATURE_TSC ( 0*32+ 4) /* Time Stamp Counter */ +#define X86_FEATURE_MSR ( 0*32+ 5) /* Model-Specific Registers */ +#define X86_FEATURE_PAE ( 0*32+ 6) /* Physical Address Extensions */ +#define X86_FEATURE_MCE ( 0*32+ 7) /* Machine Check Exception */ +#define X86_FEATURE_CX8 ( 0*32+ 8) /* CMPXCHG8 instruction */ +#define X86_FEATURE_APIC ( 0*32+ 9) /* Onboard APIC */ +#define X86_FEATURE_SEP ( 0*32+11) /* SYSENTER/SYSEXIT */ +#define X86_FEATURE_MTRR ( 0*32+12) /* Memory Type Range Registers */ +#define X86_FEATURE_PGE ( 0*32+13) /* Page Global Enable */ +#define X86_FEATURE_MCA ( 0*32+14) /* Machine Check Architecture */ +#define X86_FEATURE_CMOV ( 0*32+15) /* CMOV instructions (plus FCMOVcc, FCOMI with FPU) */ +#define X86_FEATURE_PAT ( 0*32+16) /* Page Attribute Table */ +#define X86_FEATURE_PSE36 ( 0*32+17) /* 36-bit PSEs */ +#define X86_FEATURE_PN ( 0*32+18) /* Processor serial number */ +#define X86_FEATURE_CLFLUSH ( 0*32+19) /* CLFLUSH instruction */ +#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */ +#define X86_FEATURE_ACPI ( 0*32+22) /* ACPI via MSR */ +#define X86_FEATURE_MMX ( 0*32+23) /* Multimedia Extensions */ +#define X86_FEATURE_FXSR ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ +#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */ +#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */ +#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */ +#define X86_FEATURE_HT ( 0*32+28) /* Hyper-Threading */ +#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */ +#define X86_FEATURE_IA64 ( 0*32+30) /* IA-64 processor */ +#define X86_FEATURE_PBE ( 0*32+31) /* Pending Break Enable */ /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ /* Don't duplicate feature flags which are redundant with Intel! */ -#define X86_FEATURE_SYSCALL ( 1*32+11) /* SYSCALL/SYSRET */ -#define X86_FEATURE_MP ( 1*32+19) /* MP Capable. */ -#define X86_FEATURE_NX ( 1*32+20) /* Execute Disable */ -#define X86_FEATURE_MMXEXT ( 1*32+22) /* AMD MMX extensions */ -#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */ -#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */ -#define X86_FEATURE_RDTSCP ( 1*32+27) /* RDTSCP */ -#define X86_FEATURE_LM ( 1*32+29) /* Long Mode (x86-64) */ -#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* AMD 3DNow! extensions */ -#define X86_FEATURE_3DNOW ( 1*32+31) /* 3DNow! */ +#define X86_FEATURE_SYSCALL ( 1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP ( 1*32+19) /* MP Capable */ +#define X86_FEATURE_NX ( 1*32+20) /* Execute Disable */ +#define X86_FEATURE_MMXEXT ( 1*32+22) /* AMD MMX extensions */ +#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */ +#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */ +#define X86_FEATURE_RDTSCP ( 1*32+27) /* RDTSCP */ +#define X86_FEATURE_LM ( 1*32+29) /* Long Mode (x86-64, 64-bit support) */ +#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* AMD 3DNow extensions */ +#define X86_FEATURE_3DNOW ( 1*32+31) /* 3DNow */ /* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */ -#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* CPU in recovery mode */ -#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* Longrun power control */ -#define X86_FEATURE_LRTI ( 2*32+ 3) /* LongRun table interface */ +#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* CPU in recovery mode */ +#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* Longrun power control */ +#define X86_FEATURE_LRTI ( 2*32+ 3) /* LongRun table interface */ /* Other features, Linux-defined mapping, word 3 */ /* This range is used for feature bits which conflict or are synthesized */ -#define X86_FEATURE_CXMMX ( 3*32+ 0) /* Cyrix MMX extensions */ -#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ -#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ -#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ -/* cpu types for specific tunings: */ -#define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ -#define X86_FEATURE_K7 ( 3*32+ 5) /* "" Athlon */ -#define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ -#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ -#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ -#define X86_FEATURE_UP ( 3*32+ 9) /* smp kernel running on up */ -#define X86_FEATURE_ART ( 3*32+10) /* Platform has always running timer (ART) */ -#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */ -#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */ -#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */ -#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in ia32 userspace */ -#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in ia32 userspace */ -#define X86_FEATURE_REP_GOOD ( 3*32+16) /* rep microcode works well */ -#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */ -#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */ -#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ -#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ -#define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ -#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ -#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ -#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ -#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */ -#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ -#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ -#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ -#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */ +#define X86_FEATURE_CXMMX ( 3*32+ 0) /* Cyrix MMX extensions */ +#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ +#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ +#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ + +/* CPU types for specific tunings: */ +#define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ +#define X86_FEATURE_K7 ( 3*32+ 5) /* "" Athlon */ +#define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ +#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ +#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ +#define X86_FEATURE_UP ( 3*32+ 9) /* SMP kernel running on UP */ +#define X86_FEATURE_ART ( 3*32+10) /* Always running timer (ART) */ +#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */ +#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */ +#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */ +#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in IA32 userspace */ +#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */ +#define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */ +#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" MFENCE synchronizes RDTSC */ +#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" LFENCE synchronizes RDTSC */ +#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ +#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ +#define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ +#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* CPU topology enum extensions */ +#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ +#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ +#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */ +#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* Extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM ( 3*32+27) /* AMD multi-node processor */ +#define X86_FEATURE_APERFMPERF ( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */ +#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ +#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */ -/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ -#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ -#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* PCLMULQDQ instruction */ -#define X86_FEATURE_DTES64 ( 4*32+ 2) /* 64-bit Debug Store */ -#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" Monitor/Mwait support */ -#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */ -#define X86_FEATURE_VMX ( 4*32+ 5) /* Hardware virtualization */ -#define X86_FEATURE_SMX ( 4*32+ 6) /* Safer mode */ -#define X86_FEATURE_EST ( 4*32+ 7) /* Enhanced SpeedStep */ -#define X86_FEATURE_TM2 ( 4*32+ 8) /* Thermal Monitor 2 */ -#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* Supplemental SSE-3 */ -#define X86_FEATURE_CID ( 4*32+10) /* Context ID */ -#define X86_FEATURE_SDBG ( 4*32+11) /* Silicon Debug */ -#define X86_FEATURE_FMA ( 4*32+12) /* Fused multiply-add */ -#define X86_FEATURE_CX16 ( 4*32+13) /* CMPXCHG16B */ -#define X86_FEATURE_XTPR ( 4*32+14) /* Send Task Priority Messages */ -#define X86_FEATURE_PDCM ( 4*32+15) /* Performance Capabilities */ -#define X86_FEATURE_PCID ( 4*32+17) /* Process Context Identifiers */ -#define X86_FEATURE_DCA ( 4*32+18) /* Direct Cache Access */ -#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */ -#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */ -#define X86_FEATURE_X2APIC ( 4*32+21) /* x2APIC */ -#define X86_FEATURE_MOVBE ( 4*32+22) /* MOVBE instruction */ -#define X86_FEATURE_POPCNT ( 4*32+23) /* POPCNT instruction */ -#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* Tsc deadline timer */ -#define X86_FEATURE_AES ( 4*32+25) /* AES instructions */ -#define X86_FEATURE_XSAVE ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ -#define X86_FEATURE_OSXSAVE ( 4*32+27) /* "" XSAVE enabled in the OS */ -#define X86_FEATURE_AVX ( 4*32+28) /* Advanced Vector Extensions */ -#define X86_FEATURE_F16C ( 4*32+29) /* 16-bit fp conversions */ -#define X86_FEATURE_RDRAND ( 4*32+30) /* The RDRAND instruction */ -#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */ +/* Intel-defined CPU features, CPUID level 0x00000001 (ECX), word 4 */ +#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ +#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* PCLMULQDQ instruction */ +#define X86_FEATURE_DTES64 ( 4*32+ 2) /* 64-bit Debug Store */ +#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" MONITOR/MWAIT support */ +#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL-qualified (filtered) Debug Store */ +#define X86_FEATURE_VMX ( 4*32+ 5) /* Hardware virtualization */ +#define X86_FEATURE_SMX ( 4*32+ 6) /* Safer Mode eXtensions */ +#define X86_FEATURE_EST ( 4*32+ 7) /* Enhanced SpeedStep */ +#define X86_FEATURE_TM2 ( 4*32+ 8) /* Thermal Monitor 2 */ +#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* Supplemental SSE-3 */ +#define X86_FEATURE_CID ( 4*32+10) /* Context ID */ +#define X86_FEATURE_SDBG ( 4*32+11) /* Silicon Debug */ +#define X86_FEATURE_FMA ( 4*32+12) /* Fused multiply-add */ +#define X86_FEATURE_CX16 ( 4*32+13) /* CMPXCHG16B instruction */ +#define X86_FEATURE_XTPR ( 4*32+14) /* Send Task Priority Messages */ +#define X86_FEATURE_PDCM ( 4*32+15) /* Perf/Debug Capabilities MSR */ +#define X86_FEATURE_PCID ( 4*32+17) /* Process Context Identifiers */ +#define X86_FEATURE_DCA ( 4*32+18) /* Direct Cache Access */ +#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */ +#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */ +#define X86_FEATURE_X2APIC ( 4*32+21) /* X2APIC */ +#define X86_FEATURE_MOVBE ( 4*32+22) /* MOVBE instruction */ +#define X86_FEATURE_POPCNT ( 4*32+23) /* POPCNT instruction */ +#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* TSC deadline timer */ +#define X86_FEATURE_AES ( 4*32+25) /* AES instructions */ +#define X86_FEATURE_XSAVE ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV instructions */ +#define X86_FEATURE_OSXSAVE ( 4*32+27) /* "" XSAVE instruction enabled in the OS */ +#define X86_FEATURE_AVX ( 4*32+28) /* Advanced Vector Extensions */ +#define X86_FEATURE_F16C ( 4*32+29) /* 16-bit FP conversions */ +#define X86_FEATURE_RDRAND ( 4*32+30) /* RDRAND instruction */ +#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ -#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */ -#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */ -#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ -#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */ -#define X86_FEATURE_ACE2 ( 5*32+ 8) /* Advanced Cryptography Engine v2 */ -#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* ACE v2 enabled */ -#define X86_FEATURE_PHE ( 5*32+10) /* PadLock Hash Engine */ -#define X86_FEATURE_PHE_EN ( 5*32+11) /* PHE enabled */ -#define X86_FEATURE_PMM ( 5*32+12) /* PadLock Montgomery Multiplier */ -#define X86_FEATURE_PMM_EN ( 5*32+13) /* PMM enabled */ +#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */ +#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */ +#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ +#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 ( 5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE ( 5*32+10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN ( 5*32+11) /* PHE enabled */ +#define X86_FEATURE_PMM ( 5*32+12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN ( 5*32+13) /* PMM enabled */ -/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ -#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* LAHF/SAHF in long mode */ -#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */ -#define X86_FEATURE_SVM ( 6*32+ 2) /* Secure virtual machine */ -#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* Extended APIC space */ -#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */ -#define X86_FEATURE_ABM ( 6*32+ 5) /* Advanced bit manipulation */ -#define X86_FEATURE_SSE4A ( 6*32+ 6) /* SSE-4A */ -#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */ -#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */ -#define X86_FEATURE_OSVW ( 6*32+ 9) /* OS Visible Workaround */ -#define X86_FEATURE_IBS ( 6*32+10) /* Instruction Based Sampling */ -#define X86_FEATURE_XOP ( 6*32+11) /* extended AVX instructions */ -#define X86_FEATURE_SKINIT ( 6*32+12) /* SKINIT/STGI instructions */ -#define X86_FEATURE_WDT ( 6*32+13) /* Watchdog timer */ -#define X86_FEATURE_LWP ( 6*32+15) /* Light Weight Profiling */ -#define X86_FEATURE_FMA4 ( 6*32+16) /* 4 operands MAC instructions */ -#define X86_FEATURE_TCE ( 6*32+17) /* translation cache extension */ -#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */ -#define X86_FEATURE_TBM ( 6*32+21) /* trailing bit manipulations */ -#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ -#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ -#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ -#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ -#define X86_FEATURE_PTSC ( 6*32+27) /* performance time-stamp counter */ -#define X86_FEATURE_PERFCTR_LLC ( 6*32+28) /* Last Level Cache performance counter extensions */ -#define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */ +/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */ +#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_SVM ( 6*32+ 2) /* Secure Virtual Machine */ +#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* Extended APIC space */ +#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */ +#define X86_FEATURE_ABM ( 6*32+ 5) /* Advanced bit manipulation */ +#define X86_FEATURE_SSE4A ( 6*32+ 6) /* SSE-4A */ +#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */ +#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */ +#define X86_FEATURE_OSVW ( 6*32+ 9) /* OS Visible Workaround */ +#define X86_FEATURE_IBS ( 6*32+10) /* Instruction Based Sampling */ +#define X86_FEATURE_XOP ( 6*32+11) /* extended AVX instructions */ +#define X86_FEATURE_SKINIT ( 6*32+12) /* SKINIT/STGI instructions */ +#define X86_FEATURE_WDT ( 6*32+13) /* Watchdog timer */ +#define X86_FEATURE_LWP ( 6*32+15) /* Light Weight Profiling */ +#define X86_FEATURE_FMA4 ( 6*32+16) /* 4 operands MAC instructions */ +#define X86_FEATURE_TCE ( 6*32+17) /* Translation Cache Extension */ +#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */ +#define X86_FEATURE_TBM ( 6*32+21) /* Trailing Bit Manipulations */ +#define X86_FEATURE_TOPOEXT ( 6*32+22) /* Topology extensions CPUID leafs */ +#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* Core performance counter extensions */ +#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT ( 6*32+26) /* Data breakpoint extension */ +#define X86_FEATURE_PTSC ( 6*32+27) /* Performance time-stamp counter */ +#define X86_FEATURE_PERFCTR_LLC ( 6*32+28) /* Last Level Cache performance counter extensions */ +#define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX instructions) */ /* * Auxiliary flags: Linux defined - For features scattered in various @@ -187,146 +190,162 @@ * * Reuse free bits when adding new feature flags! */ -#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT */ -#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */ -#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ -#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ -#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ -#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ -#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ +#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT instructions */ +#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */ +#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ +#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ +#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ +#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ +#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ +#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */ -#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ -#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ -#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ +#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ +#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ +#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ +#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */ +#define X86_FEATURE_RETPOLINE ( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ +#define X86_FEATURE_AVX512_4VNNIW ( 7*32+16) /* AVX-512 Neural Network Instructions */ +#define X86_FEATURE_AVX512_4FMAPS ( 7*32+17) /* AVX-512 Multiply Accumulation Single precision */ -#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ -#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ -#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ -#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ - -#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ +#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ +#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* Fill RSB on context switches */ /* Virtualization flags: Linux defined, word 8 */ -#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ -#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ -#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ -#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ +#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ -#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer vmmcall to vmcall */ -#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ +#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ +#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ -/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ -#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ -#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3b */ -#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ -#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ -#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ -#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ -#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ -#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */ -#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ -#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */ -#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */ -#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */ -#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */ -#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */ -#define X86_FEATURE_AVX512DQ ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ -#define X86_FEATURE_RDSEED ( 9*32+18) /* The RDSEED instruction */ -#define X86_FEATURE_ADX ( 9*32+19) /* The ADCX and ADOX instructions */ -#define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ -#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */ -#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ -#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ -#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ -#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ -#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ -#define X86_FEATURE_SHA_NI ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */ -#define X86_FEATURE_AVX512BW ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ -#define X86_FEATURE_AVX512VL ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ +#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ +#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3B */ +#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ +#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ +#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ +#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ +#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ +#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */ +#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ +#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */ +#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */ +#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */ +#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */ +#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */ +#define X86_FEATURE_AVX512DQ ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ +#define X86_FEATURE_RDSEED ( 9*32+18) /* RDSEED instruction */ +#define X86_FEATURE_ADX ( 9*32+19) /* ADCX and ADOX instructions */ +#define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ +#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */ +#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ +#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ +#define X86_FEATURE_INTEL_PT ( 9*32+25) /* Intel Processor Trace */ +#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ +#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ +#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ +#define X86_FEATURE_SHA_NI ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */ +#define X86_FEATURE_AVX512BW ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ +#define X86_FEATURE_AVX512VL ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ -/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */ -#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT */ -#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC */ -#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 */ -#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS */ +/* Extended state features, CPUID level 0x0000000d:1 (EAX), word 10 */ +#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT instruction */ +#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC instruction */ +#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */ +#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */ -/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 11 */ -#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */ +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */ +#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */ -/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 12 */ -#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 */ -#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ -#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */ +#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring */ +#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ +#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ -/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ -#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ -#define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ +/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */ +#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */ +#define X86_FEATURE_IRPERF (13*32+ 1) /* Instructions Retired Count */ +#define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* Always save/restore FP error pointers */ -/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ -#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ -#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ -#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ -#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ -#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ -#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ -#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ -#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ -#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ -#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ +/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ +#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ +#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ +#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ +#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ +#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ +#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ +#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ +#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ +#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ +#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ -/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */ -#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ -#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ -#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ -#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ -#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ -#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ -#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ -#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ -#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ -#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ -#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ -#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ -#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ +/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */ +#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ +#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ +#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ +#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ +#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ +#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ +#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ +#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ +#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ +#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ +#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ +#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ +#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ -/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ -#define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ -#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ -#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ -#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ -#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ -#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */ +#define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ +#define X86_FEATURE_UMIP (16*32+ 2) /* User Mode Instruction Protection */ +#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ +#define X86_FEATURE_AVX512_VBMI2 (16*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */ +#define X86_FEATURE_GFNI (16*32+ 8) /* Galois Field New Instructions */ +#define X86_FEATURE_VAES (16*32+ 9) /* Vector AES */ +#define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ +#define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ +#define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ +#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ +#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ +#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ -/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */ -#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */ -#define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ -#define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ +/* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */ +#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* MCA overflow recovery support */ +#define X86_FEATURE_SUCCOR (17*32+ 1) /* Uncorrectable error containment and recovery */ +#define X86_FEATURE_SMCA (17*32+ 3) /* Scalable MCA */ /* * BUG word(s) */ -#define X86_BUG(x) (NCAPINTS*32 + (x)) +#define X86_BUG(x) (NCAPINTS*32 + (x)) -#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */ -#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */ -#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */ -#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */ -#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */ -#define X86_BUG_11AP X86_BUG(5) /* Bad local APIC aka 11AP */ -#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ -#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ -#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ +#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */ +#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */ +#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */ +#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */ +#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */ +#define X86_BUG_11AP X86_BUG(5) /* Bad local APIC aka 11AP */ +#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ +#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ +#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ #ifdef CONFIG_X86_32 /* * 64-bit kernels don't use X86_BUG_ESPFIX. Make the define conditional * to avoid confusion. */ -#define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ +#define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ #endif -#define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ -#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ -#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ -#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ +#define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ +#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ +#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ +#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ +#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ +#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ +#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ + #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 0a3e808b91230..85e23bb7b34e3 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in desc->type = (info->read_exec_only ^ 1) << 1; desc->type |= info->contents << 2; + /* Set the ACCESS bit so it can be mapped RO */ + desc->type |= 1; desc->s = 1; desc->dpl = 0x3; @@ -60,17 +63,10 @@ static inline struct desc_struct *get_current_gdt_rw(void) return this_cpu_ptr(&gdt_page)->gdt; } -/* Get the fixmap index for a specific processor */ -static inline unsigned int get_cpu_gdt_ro_index(int cpu) -{ - return FIX_GDT_REMAP_BEGIN + cpu; -} - /* Provide the fixmap address of the remapped GDT */ static inline struct desc_struct *get_cpu_gdt_ro(int cpu) { - unsigned int idx = get_cpu_gdt_ro_index(cpu); - return (struct desc_struct *)__fix_to_virt(idx); + return (struct desc_struct *)&get_cpu_entry_area(cpu)->gdt; } /* Provide the current read-only GDT */ @@ -185,7 +181,7 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, #endif } -static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) +static inline void __set_tss_desc(unsigned cpu, unsigned int entry, struct x86_hw_tss *addr) { struct desc_struct *d = get_cpu_gdt_rw(cpu); tss_desc tss; diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index c10c9128f54e6..e428e16dd8224 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -44,6 +44,12 @@ # define DISABLE_LA57 (1<<(X86_FEATURE_LA57 & 31)) #endif +#ifdef CONFIG_PAGE_TABLE_ISOLATION +# define DISABLE_PTI 0 +#else +# define DISABLE_PTI (1 << (X86_FEATURE_PTI & 31)) +#endif + /* * Make sure to add features to the correct mask */ @@ -54,7 +60,7 @@ #define DISABLED_MASK4 (DISABLE_PCID) #define DISABLED_MASK5 0 #define DISABLED_MASK6 0 -#define DISABLED_MASK7 0 +#define DISABLED_MASK7 (DISABLE_PTI) #define DISABLED_MASK8 0 #define DISABLED_MASK9 (DISABLE_MPX) #define DISABLED_MASK10 0 diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h index 0211029076ea8..6777480d8a427 100644 --- a/arch/x86/include/asm/espfix.h +++ b/arch/x86/include/asm/espfix.h @@ -2,7 +2,7 @@ #ifndef _ASM_X86_ESPFIX_H #define _ASM_X86_ESPFIX_H -#ifdef CONFIG_X86_64 +#ifdef CONFIG_X86_ESPFIX64 #include @@ -11,7 +11,8 @@ DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); extern void init_espfix_bsp(void); extern void init_espfix_ap(int cpu); - -#endif /* CONFIG_X86_64 */ +#else +static inline void init_espfix_ap(int cpu) { } +#endif #endif /* _ASM_X86_ESPFIX_H */ diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index dcd9fb55e6799..64c4a30e0d396 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -44,7 +44,6 @@ extern unsigned long __FIXADDR_TOP; PAGE_SIZE) #endif - /* * Here we define all the compile-time 'special' virtual * addresses. The point is to have a constant address at @@ -84,7 +83,6 @@ enum fixed_addresses { FIX_IO_APIC_BASE_0, FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1, #endif - FIX_RO_IDT, /* Virtual mapping for read-only IDT */ #ifdef CONFIG_X86_32 FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, @@ -100,9 +98,12 @@ enum fixed_addresses { #ifdef CONFIG_X86_INTEL_MID FIX_LNW_VRTC, #endif - /* Fixmap entries to remap the GDTs, one per processor. */ - FIX_GDT_REMAP_BEGIN, - FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1, + +#ifdef CONFIG_ACPI_APEI_GHES + /* Used for GHES mapping from assorted contexts */ + FIX_APEI_GHES_IRQ, + FIX_APEI_GHES_NMI, +#endif __end_of_permanent_fixed_addresses, @@ -137,7 +138,7 @@ enum fixed_addresses { extern void reserve_top_address(unsigned long reserve); #define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) extern int fixmaps_set; diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index 0ead9dbb91301..96aa6b9884dc5 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h @@ -20,14 +20,22 @@ #ifndef _ASM_X86_HYPERVISOR_H #define _ASM_X86_HYPERVISOR_H +/* x86 hypervisor types */ +enum x86_hypervisor_type { + X86_HYPER_NATIVE = 0, + X86_HYPER_VMWARE, + X86_HYPER_MS_HYPERV, + X86_HYPER_XEN_PV, + X86_HYPER_XEN_HVM, + X86_HYPER_KVM, +}; + #ifdef CONFIG_HYPERVISOR_GUEST #include +#include #include -/* - * x86 hypervisor information - */ struct hypervisor_x86 { /* Hypervisor name */ const char *name; @@ -35,40 +43,27 @@ struct hypervisor_x86 { /* Detection routine */ uint32_t (*detect)(void); - /* Platform setup (run once per boot) */ - void (*init_platform)(void); - - /* X2APIC detection (run once per boot) */ - bool (*x2apic_available)(void); + /* Hypervisor type */ + enum x86_hypervisor_type type; - /* pin current vcpu to specified physical cpu (run rarely) */ - void (*pin_vcpu)(int); + /* init time callbacks */ + struct x86_hyper_init init; - /* called during init_mem_mapping() to setup early mappings. */ - void (*init_mem_mapping)(void); + /* runtime callbacks */ + struct x86_hyper_runtime runtime; }; -extern const struct hypervisor_x86 *x86_hyper; - -/* Recognized hypervisors */ -extern const struct hypervisor_x86 x86_hyper_vmware; -extern const struct hypervisor_x86 x86_hyper_ms_hyperv; -extern const struct hypervisor_x86 x86_hyper_xen_pv; -extern const struct hypervisor_x86 x86_hyper_xen_hvm; -extern const struct hypervisor_x86 x86_hyper_kvm; - +extern enum x86_hypervisor_type x86_hyper_type; extern void init_hypervisor_platform(void); -extern bool hypervisor_x2apic_available(void); -extern void hypervisor_pin_vcpu(int cpu); - -static inline void hypervisor_init_mem_mapping(void) +static inline bool hypervisor_is_type(enum x86_hypervisor_type type) { - if (x86_hyper && x86_hyper->init_mem_mapping) - x86_hyper->init_mem_mapping(); + return x86_hyper_type == type; } #else static inline void init_hypervisor_platform(void) { } -static inline bool hypervisor_x2apic_available(void) { return false; } -static inline void hypervisor_init_mem_mapping(void) { } +static inline bool hypervisor_is_type(enum x86_hypervisor_type type) +{ + return type == X86_HYPER_NATIVE; +} #endif /* CONFIG_HYPERVISOR_GUEST */ #endif /* _ASM_X86_HYPERVISOR_H */ diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h index 02aff08672115..1c78580e58bea 100644 --- a/arch/x86/include/asm/inat.h +++ b/arch/x86/include/asm/inat.h @@ -97,6 +97,16 @@ #define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) #define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) +/* Identifiers for segment registers */ +#define INAT_SEG_REG_IGNORE 0 +#define INAT_SEG_REG_DEFAULT 1 +#define INAT_SEG_REG_CS 2 +#define INAT_SEG_REG_SS 3 +#define INAT_SEG_REG_DS 4 +#define INAT_SEG_REG_ES 5 +#define INAT_SEG_REG_FS 6 +#define INAT_SEG_REG_GS 7 + /* Attribute search APIs */ extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); extern int inat_get_last_prefix_id(insn_byte_t last_pfx); diff --git a/arch/x86/include/asm/intel_ds.h b/arch/x86/include/asm/intel_ds.h new file mode 100644 index 0000000000000..62a9f4966b429 --- /dev/null +++ b/arch/x86/include/asm/intel_ds.h @@ -0,0 +1,36 @@ +#ifndef _ASM_INTEL_DS_H +#define _ASM_INTEL_DS_H + +#include + +#define BTS_BUFFER_SIZE (PAGE_SIZE << 4) +#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4) + +/* The maximal number of PEBS events: */ +#define MAX_PEBS_EVENTS 8 + +/* + * A debug store configuration. + * + * We only support architectures that use 64bit fields. + */ +struct debug_store { + u64 bts_buffer_base; + u64 bts_index; + u64 bts_absolute_maximum; + u64 bts_interrupt_threshold; + u64 pebs_buffer_base; + u64 pebs_index; + u64 pebs_absolute_maximum; + u64 pebs_interrupt_threshold; + u64 pebs_event_reset[MAX_PEBS_EVENTS]; +} __aligned(PAGE_SIZE); + +DECLARE_PER_CPU_PAGE_ALIGNED(struct debug_store, cpu_debug_store); + +struct debug_store_buffers { + char bts_buffer[BTS_BUFFER_SIZE]; + char pebs_buffer[PEBS_BUFFER_SIZE]; +}; + +#endif diff --git a/arch/x86/include/asm/invpcid.h b/arch/x86/include/asm/invpcid.h new file mode 100644 index 0000000000000..989cfa86de851 --- /dev/null +++ b/arch/x86/include/asm/invpcid.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_INVPCID +#define _ASM_X86_INVPCID + +static inline void __invpcid(unsigned long pcid, unsigned long addr, + unsigned long type) +{ + struct { u64 d[2]; } desc = { { pcid, addr } }; + + /* + * The memory clobber is because the whole point is to invalidate + * stale TLB entries and, especially if we're flushing global + * mappings, we don't want the compiler to reorder any subsequent + * memory accesses before the TLB flush. + * + * The hex opcode is invpcid (%ecx), %eax in 32-bit mode and + * invpcid (%rcx), %rax in long mode. + */ + asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01" + : : "m" (desc), "a" (type), "c" (&desc) : "memory"); +} + +#define INVPCID_TYPE_INDIV_ADDR 0 +#define INVPCID_TYPE_SINGLE_CTXT 1 +#define INVPCID_TYPE_ALL_INCL_GLOBAL 2 +#define INVPCID_TYPE_ALL_NON_GLOBAL 3 + +/* Flush all mappings for a given pcid and addr, not including globals. */ +static inline void invpcid_flush_one(unsigned long pcid, + unsigned long addr) +{ + __invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR); +} + +/* Flush all mappings for a given PCID, not including globals. */ +static inline void invpcid_flush_single_context(unsigned long pcid) +{ + __invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT); +} + +/* Flush all mappings, including globals, for all PCIDs. */ +static inline void invpcid_flush_all(void) +{ + __invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL); +} + +/* Flush all mappings for all PCIDs except globals. */ +static inline void invpcid_flush_all_nonglobals(void) +{ + __invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL); +} + +#endif /* _ASM_X86_INVPCID */ diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index c8ef23f2c28f1..89f08955fff73 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -142,6 +142,9 @@ static inline notrace unsigned long arch_local_irq_save(void) swapgs; \ sysretl +#ifdef CONFIG_DEBUG_ENTRY +#define SAVE_FLAGS(x) pushfq; popq %rax +#endif #else #define INTERRUPT_RETURN iret #define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h index f86a8caa561e8..395c9631e000a 100644 --- a/arch/x86/include/asm/kdebug.h +++ b/arch/x86/include/asm/kdebug.h @@ -26,6 +26,7 @@ extern void die(const char *, struct pt_regs *,long); extern int __must_check __die(const char *, struct pt_regs *, long); extern void show_stack_regs(struct pt_regs *regs); extern void __show_regs(struct pt_regs *regs, int all); +extern void show_iret_regs(struct pt_regs *regs); extern unsigned long oops_begin(void); extern void oops_end(unsigned long, struct pt_regs *, int signr); diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index c73e493adf074..eb38ac9d9a31c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1426,4 +1426,7 @@ static inline int kvm_cpu_get_apicid(int mps_cpu) #endif } +void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, + unsigned long start, unsigned long end); + #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h index 6a77c63540f75..e7d96c0766fe1 100644 --- a/arch/x86/include/asm/mem_encrypt.h +++ b/arch/x86/include/asm/mem_encrypt.h @@ -39,7 +39,7 @@ void __init sme_unmap_bootdata(char *real_mode_data); void __init sme_early_init(void); -void __init sme_encrypt_kernel(void); +void __init sme_encrypt_kernel(struct boot_params *bp); void __init sme_enable(struct boot_params *bp); /* Architecture __weak replacement functions */ @@ -61,7 +61,7 @@ static inline void __init sme_unmap_bootdata(char *real_mode_data) { } static inline void __init sme_early_init(void) { } -static inline void __init sme_encrypt_kernel(void) { } +static inline void __init sme_encrypt_kernel(struct boot_params *bp) { } static inline void __init sme_enable(struct boot_params *bp) { } #endif /* CONFIG_AMD_MEM_ENCRYPT */ diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 9ea26f1674970..5ff3e8af2c205 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -3,6 +3,7 @@ #define _ASM_X86_MMU_H #include +#include #include #include @@ -27,7 +28,8 @@ typedef struct { atomic64_t tlb_gen; #ifdef CONFIG_MODIFY_LDT_SYSCALL - struct ldt_struct *ldt; + struct rw_semaphore ldt_usr_sem; + struct ldt_struct *ldt; #endif #ifdef CONFIG_X86_64 diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 6699fc4416441..c931b88982a0f 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -50,22 +50,53 @@ struct ldt_struct { * call gates. On native, we could merge the ldt_struct and LDT * allocations, but it's not worth trying to optimize. */ - struct desc_struct *entries; - unsigned int nr_entries; + struct desc_struct *entries; + unsigned int nr_entries; + + /* + * If PTI is in use, then the entries array is not mapped while we're + * in user mode. The whole array will be aliased at the addressed + * given by ldt_slot_va(slot). We use two slots so that we can allocate + * and map, and enable a new LDT without invalidating the mapping + * of an older, still-in-use LDT. + * + * slot will be -1 if this LDT doesn't have an alias mapping. + */ + int slot; }; +/* This is a multiple of PAGE_SIZE. */ +#define LDT_SLOT_STRIDE (LDT_ENTRIES * LDT_ENTRY_SIZE) + +static inline void *ldt_slot_va(int slot) +{ +#ifdef CONFIG_X86_64 + return (void *)(LDT_BASE_ADDR + LDT_SLOT_STRIDE * slot); +#else + BUG(); +#endif +} + /* * Used for LDT copy/destruction. */ -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm); +static inline void init_new_context_ldt(struct mm_struct *mm) +{ + mm->context.ldt = NULL; + init_rwsem(&mm->context.ldt_usr_sem); +} +int ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm); void destroy_context_ldt(struct mm_struct *mm); +void ldt_arch_exit_mmap(struct mm_struct *mm); #else /* CONFIG_MODIFY_LDT_SYSCALL */ -static inline int init_new_context_ldt(struct task_struct *tsk, - struct mm_struct *mm) +static inline void init_new_context_ldt(struct mm_struct *mm) { } +static inline int ldt_dup_context(struct mm_struct *oldmm, + struct mm_struct *mm) { return 0; } -static inline void destroy_context_ldt(struct mm_struct *mm) {} +static inline void destroy_context_ldt(struct mm_struct *mm) { } +static inline void ldt_arch_exit_mmap(struct mm_struct *mm) { } #endif static inline void load_mm_ldt(struct mm_struct *mm) @@ -73,8 +104,8 @@ static inline void load_mm_ldt(struct mm_struct *mm) #ifdef CONFIG_MODIFY_LDT_SYSCALL struct ldt_struct *ldt; - /* lockless_dereference synchronizes with smp_store_release */ - ldt = lockless_dereference(mm->context.ldt); + /* READ_ONCE synchronizes with smp_store_release */ + ldt = READ_ONCE(mm->context.ldt); /* * Any change to mm->context.ldt is followed by an IPI to all @@ -90,10 +121,31 @@ static inline void load_mm_ldt(struct mm_struct *mm) * that we can see. */ - if (unlikely(ldt)) - set_ldt(ldt->entries, ldt->nr_entries); - else + if (unlikely(ldt)) { + if (static_cpu_has(X86_FEATURE_PTI)) { + if (WARN_ON_ONCE((unsigned long)ldt->slot > 1)) { + /* + * Whoops -- either the new LDT isn't mapped + * (if slot == -1) or is mapped into a bogus + * slot (if slot > 1). + */ + clear_LDT(); + return; + } + + /* + * If page table isolation is enabled, ldt->entries + * will not be mapped in the userspace pagetables. + * Tell the CPU to access the LDT through the alias + * at ldt_slot_va(ldt->slot). + */ + set_ldt(ldt_slot_va(ldt->slot), ldt->nr_entries); + } else { + set_ldt(ldt->entries, ldt->nr_entries); + } + } else { clear_LDT(); + } #else clear_LDT(); #endif @@ -132,18 +184,21 @@ void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk); static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + mutex_init(&mm->context.lock); + mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id); atomic64_set(&mm->context.tlb_gen, 0); - #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { /* pkey 0 is the default and always allocated */ mm->context.pkey_allocation_map = 0x1; /* -1 means unallocated or invalid */ mm->context.execute_only_pkey = -1; } - #endif - return init_new_context_ldt(tsk, mm); +#endif + init_new_context_ldt(mm); + return 0; } static inline void destroy_context(struct mm_struct *mm) { @@ -176,15 +231,16 @@ do { \ } while (0) #endif -static inline void arch_dup_mmap(struct mm_struct *oldmm, - struct mm_struct *mm) +static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { paravirt_arch_dup_mmap(oldmm, mm); + return ldt_dup_context(oldmm, mm); } static inline void arch_exit_mmap(struct mm_struct *mm) { paravirt_arch_exit_mmap(mm); + ldt_arch_exit_mmap(mm); } #ifdef CONFIG_X86_64 @@ -281,33 +337,6 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, return __pkru_allows_pkey(vma_pkey(vma), write); } -/* - * If PCID is on, ASID-aware code paths put the ASID+1 into the PCID - * bits. This serves two purposes. It prevents a nasty situation in - * which PCID-unaware code saves CR3, loads some other value (with PCID - * == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if - * the saved ASID was nonzero. It also means that any bugs involving - * loading a PCID-enabled CR3 with CR4.PCIDE off will trigger - * deterministically. - */ - -static inline unsigned long build_cr3(struct mm_struct *mm, u16 asid) -{ - if (static_cpu_has(X86_FEATURE_PCID)) { - VM_WARN_ON_ONCE(asid > 4094); - return __sme_pa(mm->pgd) | (asid + 1); - } else { - VM_WARN_ON_ONCE(asid != 0); - return __sme_pa(mm->pgd); - } -} - -static inline unsigned long build_cr3_noflush(struct mm_struct *mm, u16 asid) -{ - VM_WARN_ON_ONCE(asid > 4094); - return __sme_pa(mm->pgd) | (asid + 1) | CR3_NOFLUSH; -} - /* * This can be used from process context to figure out what the value of * CR3 is without needing to do a (slow) __read_cr3(). @@ -317,7 +346,7 @@ static inline unsigned long build_cr3_noflush(struct mm_struct *mm, u16 asid) */ static inline unsigned long __get_current_cr3_fast(void) { - unsigned long cr3 = build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm), + unsigned long cr3 = build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd, this_cpu_read(cpu_tlbstate.loaded_mm_asid)); /* For now, be very restrictive about when this can be called. */ diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 8546fafa21a91..7948a17febb4b 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -6,7 +6,7 @@ #include struct mod_arch_specific { -#ifdef CONFIG_ORC_UNWINDER +#ifdef CONFIG_UNWINDER_ORC unsigned int num_orcs; int *orc_unwind_ip; struct orc_entry *orc_unwind; diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 581bb54dd464e..5119e4b555cc5 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -7,6 +7,7 @@ #include #include #include +#include /* * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent @@ -186,10 +187,11 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) return U64_MAX; __asm__ __volatile__("mov %4, %%r8\n" - "call *%5" + CALL_NOSPEC : "=a" (hv_status), ASM_CALL_CONSTRAINT, "+c" (control), "+d" (input_address) - : "r" (output_address), "m" (hv_hypercall_pg) + : "r" (output_address), + THUNK_TARGET(hv_hypercall_pg) : "cc", "memory", "r8", "r9", "r10", "r11"); #else u32 input_address_hi = upper_32_bits(input_address); @@ -200,13 +202,13 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) if (!hv_hypercall_pg) return U64_MAX; - __asm__ __volatile__("call *%7" + __asm__ __volatile__(CALL_NOSPEC : "=A" (hv_status), "+c" (input_address_lo), ASM_CALL_CONSTRAINT : "A" (control), "b" (input_address_hi), "D"(output_address_hi), "S"(output_address_lo), - "m" (hv_hypercall_pg) + THUNK_TARGET(hv_hypercall_pg) : "cc", "memory"); #endif /* !x86_64 */ return hv_status; @@ -227,10 +229,10 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1) #ifdef CONFIG_X86_64 { - __asm__ __volatile__("call *%4" + __asm__ __volatile__(CALL_NOSPEC : "=a" (hv_status), ASM_CALL_CONSTRAINT, "+c" (control), "+d" (input1) - : "m" (hv_hypercall_pg) + : THUNK_TARGET(hv_hypercall_pg) : "cc", "r8", "r9", "r10", "r11"); } #else @@ -238,13 +240,13 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1) u32 input1_hi = upper_32_bits(input1); u32 input1_lo = lower_32_bits(input1); - __asm__ __volatile__ ("call *%5" + __asm__ __volatile__ (CALL_NOSPEC : "=A"(hv_status), "+c"(input1_lo), ASM_CALL_CONSTRAINT : "A" (control), "b" (input1_hi), - "m" (hv_hypercall_pg) + THUNK_TARGET(hv_hypercall_pg) : "cc", "edi", "esi"); } #endif diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index ab022618a50af..fa11fb1fa570e 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -352,6 +352,9 @@ #define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL #define FAM10H_MMIO_CONF_BASE_SHIFT 20 #define MSR_FAM10H_NODE_ID 0xc001100c +#define MSR_F10H_DECFG 0xc0011029 +#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1 +#define MSR_F10H_DECFG_LFENCE_SERIALIZE BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT) /* K8 MSRs */ #define MSR_K8_TOP_MEM1 0xc001001a diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h new file mode 100644 index 0000000000000..4ad41087ce0e7 --- /dev/null +++ b/arch/x86/include/asm/nospec-branch.h @@ -0,0 +1,222 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __NOSPEC_BRANCH_H__ +#define __NOSPEC_BRANCH_H__ + +#include +#include +#include + +/* + * Fill the CPU return stack buffer. + * + * Each entry in the RSB, if used for a speculative 'ret', contains an + * infinite 'pause; lfence; jmp' loop to capture speculative execution. + * + * This is required in various cases for retpoline and IBRS-based + * mitigations for the Spectre variant 2 vulnerability. Sometimes to + * eliminate potentially bogus entries from the RSB, and sometimes + * purely to ensure that it doesn't get empty, which on some CPUs would + * allow predictions from other (unwanted!) sources to be used. + * + * We define a CPP macro such that it can be used from both .S files and + * inline assembly. It's possible to do a .macro and then include that + * from C via asm(".include ") but let's not go there. + */ + +#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ +#define RSB_FILL_LOOPS 16 /* To avoid underflow */ + +/* + * Google experimented with loop-unrolling and this turned out to be + * the optimal version — two calls, each with their own speculation + * trap should their return address end up getting used, in a loop. + */ +#define __FILL_RETURN_BUFFER(reg, nr, sp) \ + mov $(nr/2), reg; \ +771: \ + call 772f; \ +773: /* speculation trap */ \ + pause; \ + lfence; \ + jmp 773b; \ +772: \ + call 774f; \ +775: /* speculation trap */ \ + pause; \ + lfence; \ + jmp 775b; \ +774: \ + dec reg; \ + jnz 771b; \ + add $(BITS_PER_LONG/8) * nr, sp; + +#ifdef __ASSEMBLY__ + +/* + * This should be used immediately before a retpoline alternative. It tells + * objtool where the retpolines are so that it can make sense of the control + * flow by just reading the original instruction(s) and ignoring the + * alternatives. + */ +.macro ANNOTATE_NOSPEC_ALTERNATIVE + .Lannotate_\@: + .pushsection .discard.nospec + .long .Lannotate_\@ - . + .popsection +.endm + +/* + * These are the bare retpoline primitives for indirect jmp and call. + * Do not use these directly; they only exist to make the ALTERNATIVE + * invocation below less ugly. + */ +.macro RETPOLINE_JMP reg:req + call .Ldo_rop_\@ +.Lspec_trap_\@: + pause + lfence + jmp .Lspec_trap_\@ +.Ldo_rop_\@: + mov \reg, (%_ASM_SP) + ret +.endm + +/* + * This is a wrapper around RETPOLINE_JMP so the called function in reg + * returns to the instruction after the macro. + */ +.macro RETPOLINE_CALL reg:req + jmp .Ldo_call_\@ +.Ldo_retpoline_jmp_\@: + RETPOLINE_JMP \reg +.Ldo_call_\@: + call .Ldo_retpoline_jmp_\@ +.endm + +/* + * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple + * indirect jmp/call which may be susceptible to the Spectre variant 2 + * attack. + */ +.macro JMP_NOSPEC reg:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE_2 __stringify(jmp *\reg), \ + __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ + __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD +#else + jmp *\reg +#endif +.endm + +.macro CALL_NOSPEC reg:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE_2 __stringify(call *\reg), \ + __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ + __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD +#else + call *\reg +#endif +.endm + + /* + * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP + * monstrosity above, manually. + */ +.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE "jmp .Lskip_rsb_\@", \ + __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ + \ftr +.Lskip_rsb_\@: +#endif +.endm + +#else /* __ASSEMBLY__ */ + +#define ANNOTATE_NOSPEC_ALTERNATIVE \ + "999:\n\t" \ + ".pushsection .discard.nospec\n\t" \ + ".long 999b - .\n\t" \ + ".popsection\n\t" + +#if defined(CONFIG_X86_64) && defined(RETPOLINE) + +/* + * Since the inline asm uses the %V modifier which is only in newer GCC, + * the 64-bit one is dependent on RETPOLINE not CONFIG_RETPOLINE. + */ +# define CALL_NOSPEC \ + ANNOTATE_NOSPEC_ALTERNATIVE \ + ALTERNATIVE( \ + "call *%[thunk_target]\n", \ + "call __x86_indirect_thunk_%V[thunk_target]\n", \ + X86_FEATURE_RETPOLINE) +# define THUNK_TARGET(addr) [thunk_target] "r" (addr) + +#elif defined(CONFIG_X86_32) && defined(CONFIG_RETPOLINE) +/* + * For i386 we use the original ret-equivalent retpoline, because + * otherwise we'll run out of registers. We don't care about CET + * here, anyway. + */ +# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \ + " jmp 904f;\n" \ + " .align 16\n" \ + "901: call 903f;\n" \ + "902: pause;\n" \ + " lfence;\n" \ + " jmp 902b;\n" \ + " .align 16\n" \ + "903: addl $4, %%esp;\n" \ + " pushl %[thunk_target];\n" \ + " ret;\n" \ + " .align 16\n" \ + "904: call 901b;\n", \ + X86_FEATURE_RETPOLINE) + +# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) +#else /* No retpoline for C / inline asm */ +# define CALL_NOSPEC "call *%[thunk_target]\n" +# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) +#endif + +/* The Spectre V2 mitigation variants */ +enum spectre_v2_mitigation { + SPECTRE_V2_NONE, + SPECTRE_V2_RETPOLINE_MINIMAL, + SPECTRE_V2_RETPOLINE_MINIMAL_AMD, + SPECTRE_V2_RETPOLINE_GENERIC, + SPECTRE_V2_RETPOLINE_AMD, + SPECTRE_V2_IBRS, +}; + +extern char __indirect_thunk_start[]; +extern char __indirect_thunk_end[]; + +/* + * On VMEXIT we must ensure that no RSB predictions learned in the guest + * can be followed in the host, by overwriting the RSB completely. Both + * retpoline and IBRS mitigations for Spectre v2 need this; only on future + * CPUs with IBRS_ATT *might* it be avoided. + */ +static inline void vmexit_fill_RSB(void) +{ +#ifdef CONFIG_RETPOLINE + unsigned long loops; + + asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE("jmp 910f", + __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)), + X86_FEATURE_RETPOLINE) + "910:" + : "=r" (loops), ASM_CALL_CONSTRAINT + : : "memory" ); +#endif +} + +#endif /* __ASSEMBLY__ */ +#endif /* __NOSPEC_BRANCH_H__ */ diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index fd81228e8037f..892df375b6155 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -16,10 +16,9 @@ #include #include -static inline void load_sp0(struct tss_struct *tss, - struct thread_struct *thread) +static inline void load_sp0(unsigned long sp0) { - PVOP_VCALL2(pv_cpu_ops.load_sp0, tss, thread); + PVOP_VCALL1(pv_cpu_ops.load_sp0, sp0); } /* The paravirtualized CPUID instruction. */ @@ -928,6 +927,15 @@ extern void default_banner(void); PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ CLBR_NONE, \ jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64)) + +#ifdef CONFIG_DEBUG_ENTRY +#define SAVE_FLAGS(clobbers) \ + PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_save_fl), clobbers, \ + PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ + call PARA_INDIRECT(pv_irq_ops+PV_IRQ_save_fl); \ + PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) +#endif + #endif /* CONFIG_X86_32 */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 10cc3b9709fe0..6ec54d01972dc 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -134,7 +134,7 @@ struct pv_cpu_ops { void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries); void (*free_ldt)(struct desc_struct *ldt, unsigned entries); - void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); + void (*load_sp0)(unsigned long sp0); void (*set_iopl_mask)(unsigned mask); diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 377f1ffd18be6..ba3c523aaf161 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -526,7 +526,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr, { bool oldbit; - asm volatile("bt "__percpu_arg(2)",%1\n\t" + asm volatile("bt "__percpu_arg(2)",%1" CC_SET(c) : CC_OUT(c) (oldbit) : "m" (*(unsigned long __percpu *)addr), "Ir" (nr)); diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h index 4b5e1eafada73..aff42e1da6ee1 100644 --- a/arch/x86/include/asm/pgalloc.h +++ b/arch/x86/include/asm/pgalloc.h @@ -30,6 +30,17 @@ static inline void paravirt_release_p4d(unsigned long pfn) {} */ extern gfp_t __userpte_alloc_gfp; +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * Instead of one PGD, we acquire two PGDs. Being order-1, it is + * both 8k in size and 8k-aligned. That lets us just flip bit 12 + * in a pointer to swap between the two 4k halves. + */ +#define PGD_ALLOCATION_ORDER 1 +#else +#define PGD_ALLOCATION_ORDER 0 +#endif + /* * Allocate and free page tables. */ diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index f735c30163252..211368922cad6 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -28,6 +28,7 @@ extern pgd_t early_top_pgt[PTRS_PER_PGD]; int __init __early_make_pgtable(unsigned long address, pmdval_t pmd); void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd); +void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user); void ptdump_walk_pgd_level_checkwx(void); #ifdef CONFIG_DEBUG_WX @@ -846,7 +847,12 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address) static inline int p4d_bad(p4d_t p4d) { - return (p4d_flags(p4d) & ~(_KERNPG_TABLE | _PAGE_USER)) != 0; + unsigned long ignore_flags = _KERNPG_TABLE | _PAGE_USER; + + if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) + ignore_flags |= _PAGE_NX; + + return (p4d_flags(p4d) & ~ignore_flags) != 0; } #endif /* CONFIG_PGTABLE_LEVELS > 3 */ @@ -880,7 +886,12 @@ static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) static inline int pgd_bad(pgd_t pgd) { - return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE; + unsigned long ignore_flags = _PAGE_USER; + + if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) + ignore_flags |= _PAGE_NX; + + return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE; } static inline int pgd_none(pgd_t pgd) @@ -909,7 +920,11 @@ static inline int pgd_none(pgd_t pgd) * pgd_offset() returns a (pgd_t *) * pgd_index() is used get the offset into the pgd page's array of pgd_t's; */ -#define pgd_offset(mm, address) ((mm)->pgd + pgd_index((address))) +#define pgd_offset_pgd(pgd, address) (pgd + pgd_index((address))) +/* + * a shortcut to get a pgd_t in a given mm + */ +#define pgd_offset(mm, address) pgd_offset_pgd((mm)->pgd, (address)) /* * a shortcut which implies the use of the kernel's pgd, instead * of a process's @@ -1093,6 +1108,12 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, clear_bit(_PAGE_BIT_RW, (unsigned long *)pmdp); } +#define pud_write pud_write +static inline int pud_write(pud_t pud) +{ + return pud_flags(pud) & _PAGE_RW; +} + /* * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); * @@ -1105,7 +1126,14 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, */ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) { - memcpy(dst, src, count * sizeof(pgd_t)); + memcpy(dst, src, count * sizeof(pgd_t)); +#ifdef CONFIG_PAGE_TABLE_ISOLATION + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + /* Clone the user space pgd as well */ + memcpy(kernel_to_user_pgdp(dst), kernel_to_user_pgdp(src), + count * sizeof(pgd_t)); +#endif } #define PTE_SHIFT ilog2(PTRS_PER_PTE) diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h index f2ca9b28fd683..ce245b0cdfcaa 100644 --- a/arch/x86/include/asm/pgtable_32_types.h +++ b/arch/x86/include/asm/pgtable_32_types.h @@ -38,13 +38,22 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */ #define LAST_PKMAP 1024 #endif -#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \ - & PMD_MASK) +/* + * Define this here and validate with BUILD_BUG_ON() in pgtable_32.c + * to avoid include recursion hell + */ +#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 40) + +#define CPU_ENTRY_AREA_BASE \ + ((FIXADDR_START - PAGE_SIZE * (CPU_ENTRY_AREA_PAGES + 1)) & PMD_MASK) + +#define PKMAP_BASE \ + ((CPU_ENTRY_AREA_BASE - PAGE_SIZE) & PMD_MASK) #ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE) #else -# define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE) +# define VMALLOC_END (CPU_ENTRY_AREA_BASE - 2 * PAGE_SIZE) #endif #define MODULES_VADDR VMALLOC_START diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index e9f05331e732a..81462e9a34f6a 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -131,9 +131,97 @@ static inline pud_t native_pudp_get_and_clear(pud_t *xp) #endif } +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * All top-level PAGE_TABLE_ISOLATION page tables are order-1 pages + * (8k-aligned and 8k in size). The kernel one is at the beginning 4k and + * the user one is in the last 4k. To switch between them, you + * just need to flip the 12th bit in their addresses. + */ +#define PTI_PGTABLE_SWITCH_BIT PAGE_SHIFT + +/* + * This generates better code than the inline assembly in + * __set_bit(). + */ +static inline void *ptr_set_bit(void *ptr, int bit) +{ + unsigned long __ptr = (unsigned long)ptr; + + __ptr |= BIT(bit); + return (void *)__ptr; +} +static inline void *ptr_clear_bit(void *ptr, int bit) +{ + unsigned long __ptr = (unsigned long)ptr; + + __ptr &= ~BIT(bit); + return (void *)__ptr; +} + +static inline pgd_t *kernel_to_user_pgdp(pgd_t *pgdp) +{ + return ptr_set_bit(pgdp, PTI_PGTABLE_SWITCH_BIT); +} + +static inline pgd_t *user_to_kernel_pgdp(pgd_t *pgdp) +{ + return ptr_clear_bit(pgdp, PTI_PGTABLE_SWITCH_BIT); +} + +static inline p4d_t *kernel_to_user_p4dp(p4d_t *p4dp) +{ + return ptr_set_bit(p4dp, PTI_PGTABLE_SWITCH_BIT); +} + +static inline p4d_t *user_to_kernel_p4dp(p4d_t *p4dp) +{ + return ptr_clear_bit(p4dp, PTI_PGTABLE_SWITCH_BIT); +} +#endif /* CONFIG_PAGE_TABLE_ISOLATION */ + +/* + * Page table pages are page-aligned. The lower half of the top + * level is used for userspace and the top half for the kernel. + * + * Returns true for parts of the PGD that map userspace and + * false for the parts that map the kernel. + */ +static inline bool pgdp_maps_userspace(void *__ptr) +{ + unsigned long ptr = (unsigned long)__ptr; + + return (ptr & ~PAGE_MASK) < (PAGE_SIZE / 2); +} + +#ifdef CONFIG_PAGE_TABLE_ISOLATION +pgd_t __pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd); + +/* + * Take a PGD location (pgdp) and a pgd value that needs to be set there. + * Populates the user and returns the resulting PGD that must be set in + * the kernel copy of the page tables. + */ +static inline pgd_t pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd) +{ + if (!static_cpu_has(X86_FEATURE_PTI)) + return pgd; + return __pti_set_user_pgd(pgdp, pgd); +} +#else +static inline pgd_t pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd) +{ + return pgd; +} +#endif + static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) { +#if defined(CONFIG_PAGE_TABLE_ISOLATION) && !defined(CONFIG_X86_5LEVEL) + p4dp->pgd = pti_set_user_pgd(&p4dp->pgd, p4d.pgd); +#else *p4dp = p4d; +#endif } static inline void native_p4d_clear(p4d_t *p4d) @@ -147,7 +235,11 @@ static inline void native_p4d_clear(p4d_t *p4d) static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) { +#ifdef CONFIG_PAGE_TABLE_ISOLATION + *pgdp = pti_set_user_pgd(pgdp, pgd); +#else *pgdp = pgd; +#endif } static inline void native_pgd_clear(pgd_t *pgd) diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index 6d5f45dcd4a13..6b8f73dcbc2c2 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -75,33 +75,52 @@ typedef struct { pteval_t pte; } pte_t; #define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE - 1)) -/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ -#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) +/* + * See Documentation/x86/x86_64/mm.txt for a description of the memory map. + * + * Be very careful vs. KASLR when changing anything here. The KASLR address + * range must not overlap with anything except the KASAN shadow area, which + * is correct as KASAN disables KASLR. + */ +#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) + #ifdef CONFIG_X86_5LEVEL -#define VMALLOC_SIZE_TB _AC(16384, UL) -#define __VMALLOC_BASE _AC(0xff92000000000000, UL) -#define __VMEMMAP_BASE _AC(0xffd4000000000000, UL) +# define VMALLOC_SIZE_TB _AC(12800, UL) +# define __VMALLOC_BASE _AC(0xffa0000000000000, UL) +# define __VMEMMAP_BASE _AC(0xffd4000000000000, UL) +# define LDT_PGD_ENTRY _AC(-112, UL) +# define LDT_BASE_ADDR (LDT_PGD_ENTRY << PGDIR_SHIFT) #else -#define VMALLOC_SIZE_TB _AC(32, UL) -#define __VMALLOC_BASE _AC(0xffffc90000000000, UL) -#define __VMEMMAP_BASE _AC(0xffffea0000000000, UL) +# define VMALLOC_SIZE_TB _AC(32, UL) +# define __VMALLOC_BASE _AC(0xffffc90000000000, UL) +# define __VMEMMAP_BASE _AC(0xffffea0000000000, UL) +# define LDT_PGD_ENTRY _AC(-3, UL) +# define LDT_BASE_ADDR (LDT_PGD_ENTRY << PGDIR_SHIFT) #endif + #ifdef CONFIG_RANDOMIZE_MEMORY -#define VMALLOC_START vmalloc_base -#define VMEMMAP_START vmemmap_base +# define VMALLOC_START vmalloc_base +# define VMEMMAP_START vmemmap_base #else -#define VMALLOC_START __VMALLOC_BASE -#define VMEMMAP_START __VMEMMAP_BASE +# define VMALLOC_START __VMALLOC_BASE +# define VMEMMAP_START __VMEMMAP_BASE #endif /* CONFIG_RANDOMIZE_MEMORY */ -#define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) + +#define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) + +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) /* The module sections ends with the start of the fixmap */ -#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) -#define MODULES_LEN (MODULES_END - MODULES_VADDR) -#define ESPFIX_PGD_ENTRY _AC(-2, UL) -#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << P4D_SHIFT) -#define EFI_VA_START ( -4 * (_AC(1, UL) << 30)) -#define EFI_VA_END (-68 * (_AC(1, UL) << 30)) +#define MODULES_END _AC(0xffffffffff000000, UL) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) + +#define ESPFIX_PGD_ENTRY _AC(-2, UL) +#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << P4D_SHIFT) + +#define CPU_ENTRY_AREA_PGD _AC(-4, UL) +#define CPU_ENTRY_AREA_BASE (CPU_ENTRY_AREA_PGD << P4D_SHIFT) + +#define EFI_VA_START ( -4 * (_AC(1, UL) << 30)) +#define EFI_VA_END (-68 * (_AC(1, UL) << 30)) #define EARLY_DYNAMIC_PAGE_TABLES 64 diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 59df7b47a4349..9e9b05fc4860e 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -200,10 +200,9 @@ enum page_cache_mode { #define _PAGE_ENC (_AT(pteval_t, sme_me_mask)) -#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ - _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_ENC) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | \ _PAGE_DIRTY | _PAGE_ENC) +#define _PAGE_TABLE (_KERNPG_TABLE | _PAGE_USER) #define __PAGE_KERNEL_ENC (__PAGE_KERNEL | _PAGE_ENC) #define __PAGE_KERNEL_ENC_WP (__PAGE_KERNEL_WP | _PAGE_ENC) diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h index 43212a43ee69f..625a52a5594f5 100644 --- a/arch/x86/include/asm/processor-flags.h +++ b/arch/x86/include/asm/processor-flags.h @@ -38,6 +38,11 @@ #define CR3_ADDR_MASK __sme_clr(0x7FFFFFFFFFFFF000ull) #define CR3_PCID_MASK 0xFFFull #define CR3_NOFLUSH BIT_ULL(63) + +#ifdef CONFIG_PAGE_TABLE_ISOLATION +# define X86_CR3_PTI_PCID_USER_BIT 11 +#endif + #else /* * CR3_ADDR_MASK needs at least bits 31:5 set on PAE systems, and we save diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index bdac19ab24888..9c18da64daa92 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -162,9 +162,9 @@ enum cpuid_regs_idx { extern struct cpuinfo_x86 boot_cpu_data; extern struct cpuinfo_x86 new_cpu_data; -extern struct tss_struct doublefault_tss; -extern __u32 cpu_caps_cleared[NCAPINTS]; -extern __u32 cpu_caps_set[NCAPINTS]; +extern struct x86_hw_tss doublefault_tss; +extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; +extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS]; #ifdef CONFIG_SMP DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info); @@ -252,6 +252,11 @@ static inline void load_cr3(pgd_t *pgdir) write_cr3(__sme_pa(pgdir)); } +/* + * Note that while the legacy 'TSS' name comes from 'Task State Segment', + * on modern x86 CPUs the TSS also holds information important to 64-bit mode, + * unrelated to the task-switch mechanism: + */ #ifdef CONFIG_X86_32 /* This is the TSS defined by the hardware. */ struct x86_hw_tss { @@ -304,7 +309,13 @@ struct x86_hw_tss { struct x86_hw_tss { u32 reserved1; u64 sp0; + + /* + * We store cpu_current_top_of_stack in sp1 so it's always accessible. + * Linux does not use ring 1, so sp1 is not otherwise needed. + */ u64 sp1; + u64 sp2; u64 reserved2; u64 ist[7]; @@ -322,12 +333,22 @@ struct x86_hw_tss { #define IO_BITMAP_BITS 65536 #define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) #define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) -#define IO_BITMAP_OFFSET offsetof(struct tss_struct, io_bitmap) +#define IO_BITMAP_OFFSET (offsetof(struct tss_struct, io_bitmap) - offsetof(struct tss_struct, x86_tss)) #define INVALID_IO_BITMAP_OFFSET 0x8000 +struct entry_stack { + unsigned long words[64]; +}; + +struct entry_stack_page { + struct entry_stack stack; +} __aligned(PAGE_SIZE); + struct tss_struct { /* - * The hardware state: + * The fixed hardware portion. This must not cross a page boundary + * at risk of violating the SDM's advice and potentially triggering + * errata. */ struct x86_hw_tss x86_tss; @@ -338,18 +359,9 @@ struct tss_struct { * be within the limit. */ unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; +} __aligned(PAGE_SIZE); -#ifdef CONFIG_X86_32 - /* - * Space for the temporary SYSENTER stack. - */ - unsigned long SYSENTER_stack_canary; - unsigned long SYSENTER_stack[64]; -#endif - -} ____cacheline_aligned; - -DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss); +DECLARE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw); /* * sizeof(unsigned long) coming from an extra "long" at the end @@ -363,6 +375,9 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss); #ifdef CONFIG_X86_32 DECLARE_PER_CPU(unsigned long, cpu_current_top_of_stack); +#else +/* The RO copy can't be accessed with this_cpu_xyz(), so use the RW copy. */ +#define cpu_current_top_of_stack cpu_tss_rw.x86_tss.sp1 #endif /* @@ -431,7 +446,9 @@ typedef struct { struct thread_struct { /* Cached TLS descriptors: */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; +#ifdef CONFIG_X86_32 unsigned long sp0; +#endif unsigned long sp; #ifdef CONFIG_X86_32 unsigned long sysenter_cs; @@ -518,16 +535,9 @@ static inline void native_set_iopl_mask(unsigned mask) } static inline void -native_load_sp0(struct tss_struct *tss, struct thread_struct *thread) +native_load_sp0(unsigned long sp0) { - tss->x86_tss.sp0 = thread->sp0; -#ifdef CONFIG_X86_32 - /* Only happens when SEP is enabled, no need to test "SEP"arately: */ - if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) { - tss->x86_tss.ss1 = thread->sysenter_cs; - wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); - } -#endif + this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0); } static inline void native_swapgs(void) @@ -539,12 +549,18 @@ static inline void native_swapgs(void) static inline unsigned long current_top_of_stack(void) { -#ifdef CONFIG_X86_64 - return this_cpu_read_stable(cpu_tss.x86_tss.sp0); -#else - /* sp0 on x86_32 is special in and around vm86 mode. */ + /* + * We can't read directly from tss.sp0: sp0 on x86_32 is special in + * and around vm86 mode and sp0 on x86_64 is special because of the + * entry trampoline. + */ return this_cpu_read_stable(cpu_current_top_of_stack); -#endif +} + +static inline bool on_thread_stack(void) +{ + return (unsigned long)(current_top_of_stack() - + current_stack_pointer) < THREAD_SIZE; } #ifdef CONFIG_PARAVIRT @@ -552,10 +568,9 @@ static inline unsigned long current_top_of_stack(void) #else #define __cpuid native_cpuid -static inline void load_sp0(struct tss_struct *tss, - struct thread_struct *thread) +static inline void load_sp0(unsigned long sp0) { - native_load_sp0(tss, thread); + native_load_sp0(sp0); } #define set_iopl_mask native_set_iopl_mask @@ -804,6 +819,15 @@ static inline void spin_lock_prefetch(const void *x) #define TOP_OF_INIT_STACK ((unsigned long)&init_stack + sizeof(init_stack) - \ TOP_OF_KERNEL_STACK_PADDING) +#define task_top_of_stack(task) ((unsigned long)(task_pt_regs(task) + 1)) + +#define task_pt_regs(task) \ +({ \ + unsigned long __ptr = (unsigned long)task_stack_page(task); \ + __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; \ + ((struct pt_regs *)__ptr) - 1; \ +}) + #ifdef CONFIG_X86_32 /* * User space process size: 3GB (default). @@ -823,34 +847,26 @@ static inline void spin_lock_prefetch(const void *x) .addr_limit = KERNEL_DS, \ } -/* - * TOP_OF_KERNEL_STACK_PADDING reserves 8 bytes on top of the ring0 stack. - * This is necessary to guarantee that the entire "struct pt_regs" - * is accessible even if the CPU haven't stored the SS/ESP registers - * on the stack (interrupt gate does not save these registers - * when switching to the same priv ring). - * Therefore beware: accessing the ss/esp fields of the - * "struct pt_regs" is possible, but they may contain the - * completely wrong values. - */ -#define task_pt_regs(task) \ -({ \ - unsigned long __ptr = (unsigned long)task_stack_page(task); \ - __ptr += THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING; \ - ((struct pt_regs *)__ptr) - 1; \ -}) - #define KSTK_ESP(task) (task_pt_regs(task)->sp) #else /* - * User space process size. 47bits minus one guard page. The guard - * page is necessary on Intel CPUs: if a SYSCALL instruction is at - * the highest possible canonical userspace address, then that - * syscall will enter the kernel with a non-canonical return - * address, and SYSRET will explode dangerously. We avoid this - * particular problem by preventing anything from being mapped - * at the maximum canonical address. + * User space process size. This is the first address outside the user range. + * There are a few constraints that determine this: + * + * On Intel CPUs, if a SYSCALL instruction is at the highest canonical + * address, then that syscall will enter the kernel with a + * non-canonical return address, and SYSRET will explode dangerously. + * We avoid this particular problem by preventing anything executable + * from being mapped at the maximum canonical address. + * + * On AMD CPUs in the Ryzen family, there's a nasty bug in which the + * CPUs malfunction if they execute code from the highest canonical page. + * They'll speculate right off the end of the canonical space, and + * bad things happen. This is worked around in the same way as the + * Intel problem. + * + * With page table isolation enabled, we map the LDT in ... [stay tuned] */ #define TASK_SIZE_MAX ((1UL << __VIRTUAL_MASK_SHIFT) - PAGE_SIZE) @@ -873,11 +889,9 @@ static inline void spin_lock_prefetch(const void *x) #define STACK_TOP_MAX TASK_SIZE_MAX #define INIT_THREAD { \ - .sp0 = TOP_OF_INIT_STACK, \ .addr_limit = KERNEL_DS, \ } -#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.sp0 - 1) extern unsigned long KSTK_ESP(struct task_struct *task); #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/include/asm/pti.h b/arch/x86/include/asm/pti.h new file mode 100644 index 0000000000000..0b5ef05b2d2d9 --- /dev/null +++ b/arch/x86/include/asm/pti.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _ASM_X86_PTI_H +#define _ASM_X86_PTI_H +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_PAGE_TABLE_ISOLATION +extern void pti_init(void); +extern void pti_check_boottime_disable(void); +#else +static inline void pti_check_boottime_disable(void) { } +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_X86_PTI_H */ diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index c0e3c45cf6aba..14131dd06b290 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -136,9 +136,9 @@ static inline int v8086_mode(struct pt_regs *regs) #endif } -#ifdef CONFIG_X86_64 static inline bool user_64bit_mode(struct pt_regs *regs) { +#ifdef CONFIG_X86_64 #ifndef CONFIG_PARAVIRT /* * On non-paravirt systems, this is the only long mode CPL 3 @@ -149,8 +149,12 @@ static inline bool user_64bit_mode(struct pt_regs *regs) /* Headers are too twisted for this to go in paravirt.h. */ return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs; #endif +#else /* !CONFIG_X86_64 */ + return false; +#endif } +#ifdef CONFIG_X86_64 #define current_user_stack_pointer() current_pt_regs()->sp #define compat_user_stack_pointer() current_pt_regs()->sp #endif diff --git a/arch/x86/include/asm/refcount.h b/arch/x86/include/asm/refcount.h index ff871210b9f2f..4e44250e7d0d7 100644 --- a/arch/x86/include/asm/refcount.h +++ b/arch/x86/include/asm/refcount.h @@ -15,7 +15,7 @@ * back to the regular execution flow in .text. */ #define _REFCOUNT_EXCEPTION \ - ".pushsection .text.unlikely\n" \ + ".pushsection .text..refcount\n" \ "111:\tlea %[counter], %%" _ASM_CX "\n" \ "112:\t" ASM_UD0 "\n" \ ASM_UNREACHABLE \ diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index d8f3a6ae9f6c9..f91c365e57c36 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -29,7 +29,7 @@ cc_label: \ #define __GEN_RMWcc(fullop, var, cc, clobbers, ...) \ do { \ bool c; \ - asm volatile (fullop ";" CC_SET(cc) \ + asm volatile (fullop CC_SET(cc) \ : [counter] "+m" (var), CC_OUT(cc) (c) \ : __VA_ARGS__ : clobbers); \ return c; \ diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 8da111b3c342b..f737068787729 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h @@ -16,6 +16,7 @@ enum stack_type { STACK_TYPE_TASK, STACK_TYPE_IRQ, STACK_TYPE_SOFTIRQ, + STACK_TYPE_ENTRY, STACK_TYPE_EXCEPTION, STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1, }; @@ -28,6 +29,8 @@ struct stack_info { bool in_task_stack(unsigned long *stack, struct task_struct *task, struct stack_info *info); +bool in_entry_stack(unsigned long *stack, struct stack_info *info); + int get_stack_info(unsigned long *stack, struct task_struct *task, struct stack_info *info, unsigned long *visit_mask); diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index 899084b70412e..9b6df68d8fd1e 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_SWITCH_TO_H #define _ASM_X86_SWITCH_TO_H +#include + struct task_struct; /* one of the stranger aspects of C forward declarations */ struct task_struct *__switch_to_asm(struct task_struct *prev, @@ -73,4 +75,28 @@ do { \ ((last) = __switch_to_asm((prev), (next))); \ } while (0) +#ifdef CONFIG_X86_32 +static inline void refresh_sysenter_cs(struct thread_struct *thread) +{ + /* Only happens when SEP is enabled, no need to test "SEP"arately: */ + if (unlikely(this_cpu_read(cpu_tss_rw.x86_tss.ss1) == thread->sysenter_cs)) + return; + + this_cpu_write(cpu_tss_rw.x86_tss.ss1, thread->sysenter_cs); + wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); +} +#endif + +/* This is used when switching tasks or entering/exiting vm86 mode. */ +static inline void update_sp0(struct task_struct *task) +{ + /* On x86_64, sp0 always points to the entry trampoline stack, which is constant: */ +#ifdef CONFIG_X86_32 + load_sp0(task->thread.sp0); +#else + if (static_cpu_has(X86_FEATURE_XENPV)) + load_sp0(task_top_of_stack(task)); +#endif +} + #endif /* _ASM_X86_SWITCH_TO_H */ diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 91dfcafe27a66..bad25bb80679f 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -21,7 +21,7 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); asmlinkage long sys_iopl(unsigned int); /* kernel/ldt.c */ -asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); +asmlinkage long sys_modify_ldt(int, void __user *, unsigned long); /* kernel/signal.c */ asmlinkage long sys_rt_sigreturn(void); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 70f425947dc50..00223333821a9 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -207,7 +207,7 @@ static inline int arch_within_stack_frames(const void * const stack, #else /* !__ASSEMBLY__ */ #ifdef CONFIG_X86_64 -# define cpu_current_top_of_stack (cpu_tss + TSS_sp0) +# define cpu_current_top_of_stack (cpu_tss_rw + TSS_sp1) #endif #endif diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 509046cfa5ce8..3effd3c994afe 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -9,70 +9,130 @@ #include #include #include +#include +#include +#include -static inline void __invpcid(unsigned long pcid, unsigned long addr, - unsigned long type) -{ - struct { u64 d[2]; } desc = { { pcid, addr } }; +/* + * The x86 feature is called PCID (Process Context IDentifier). It is similar + * to what is traditionally called ASID on the RISC processors. + * + * We don't use the traditional ASID implementation, where each process/mm gets + * its own ASID and flush/restart when we run out of ASID space. + * + * Instead we have a small per-cpu array of ASIDs and cache the last few mm's + * that came by on this CPU, allowing cheaper switch_mm between processes on + * this CPU. + * + * We end up with different spaces for different things. To avoid confusion we + * use different names for each of them: + * + * ASID - [0, TLB_NR_DYN_ASIDS-1] + * the canonical identifier for an mm + * + * kPCID - [1, TLB_NR_DYN_ASIDS] + * the value we write into the PCID part of CR3; corresponds to the + * ASID+1, because PCID 0 is special. + * + * uPCID - [2048 + 1, 2048 + TLB_NR_DYN_ASIDS] + * for KPTI each mm has two address spaces and thus needs two + * PCID values, but we can still do with a single ASID denomination + * for each mm. Corresponds to kPCID + 2048. + * + */ - /* - * The memory clobber is because the whole point is to invalidate - * stale TLB entries and, especially if we're flushing global - * mappings, we don't want the compiler to reorder any subsequent - * memory accesses before the TLB flush. - * - * The hex opcode is invpcid (%ecx), %eax in 32-bit mode and - * invpcid (%rcx), %rax in long mode. - */ - asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01" - : : "m" (desc), "a" (type), "c" (&desc) : "memory"); -} +/* There are 12 bits of space for ASIDS in CR3 */ +#define CR3_HW_ASID_BITS 12 -#define INVPCID_TYPE_INDIV_ADDR 0 -#define INVPCID_TYPE_SINGLE_CTXT 1 -#define INVPCID_TYPE_ALL_INCL_GLOBAL 2 -#define INVPCID_TYPE_ALL_NON_GLOBAL 3 +/* + * When enabled, PAGE_TABLE_ISOLATION consumes a single bit for + * user/kernel switches + */ +#ifdef CONFIG_PAGE_TABLE_ISOLATION +# define PTI_CONSUMED_PCID_BITS 1 +#else +# define PTI_CONSUMED_PCID_BITS 0 +#endif -/* Flush all mappings for a given pcid and addr, not including globals. */ -static inline void invpcid_flush_one(unsigned long pcid, - unsigned long addr) -{ - __invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR); -} +#define CR3_AVAIL_PCID_BITS (X86_CR3_PCID_BITS - PTI_CONSUMED_PCID_BITS) + +/* + * ASIDs are zero-based: 0->MAX_AVAIL_ASID are valid. -1 below to account + * for them being zero-based. Another -1 is because PCID 0 is reserved for + * use by non-PCID-aware users. + */ +#define MAX_ASID_AVAILABLE ((1 << CR3_AVAIL_PCID_BITS) - 2) + +/* + * 6 because 6 should be plenty and struct tlb_state will fit in two cache + * lines. + */ +#define TLB_NR_DYN_ASIDS 6 -/* Flush all mappings for a given PCID, not including globals. */ -static inline void invpcid_flush_single_context(unsigned long pcid) +/* + * Given @asid, compute kPCID + */ +static inline u16 kern_pcid(u16 asid) { - __invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT); + VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE); + +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* + * Make sure that the dynamic ASID space does not confict with the + * bit we are using to switch between user and kernel ASIDs. + */ + BUILD_BUG_ON(TLB_NR_DYN_ASIDS >= (1 << X86_CR3_PTI_PCID_USER_BIT)); + + /* + * The ASID being passed in here should have respected the + * MAX_ASID_AVAILABLE and thus never have the switch bit set. + */ + VM_WARN_ON_ONCE(asid & (1 << X86_CR3_PTI_PCID_USER_BIT)); +#endif + /* + * The dynamically-assigned ASIDs that get passed in are small + * (context.tlb_gen); - smp_mb__after_atomic(); - - return new_tlb_gen; + VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE); + VM_WARN_ON_ONCE(!this_cpu_has(X86_FEATURE_PCID)); + return __sme_pa(pgd) | kern_pcid(asid) | CR3_NOFLUSH; } #ifdef CONFIG_PARAVIRT @@ -99,12 +159,6 @@ static inline bool tlb_defer_switch_to_init_mm(void) return !static_cpu_has(X86_FEATURE_PCID); } -/* - * 6 because 6 should be plenty and struct tlb_state will fit in - * two cache lines. - */ -#define TLB_NR_DYN_ASIDS 6 - struct tlb_context { u64 ctx_id; u64 tlb_gen; @@ -138,6 +192,24 @@ struct tlb_state { */ bool is_lazy; + /* + * If set we changed the page tables in such a way that we + * needed an invalidation of all contexts (aka. PCIDs / ASIDs). + * This tells us to go invalidate all the non-loaded ctxs[] + * on the next context switch. + * + * The current ctx was kept up-to-date as it ran and does not + * need to be invalidated. + */ + bool invalidate_other; + + /* + * Mask that contains TLB_NR_DYN_ASIDS+1 bits to indicate + * the corresponding user PCID needs a flush next time we + * switch to it; see SWITCH_TO_USER_CR3. + */ + unsigned short user_pcid_flush_mask; + /* * Access to this CR4 shadow and to H/W CR4 is protected by * disabling interrupts when modifying either one. @@ -215,6 +287,14 @@ static inline unsigned long cr4_read_shadow(void) return this_cpu_read(cpu_tlbstate.cr4); } +/* + * Mark all other ASIDs as invalid, preserves the current. + */ +static inline void invalidate_other_asid(void) +{ + this_cpu_write(cpu_tlbstate.invalidate_other, true); +} + /* * Save some of cr4 feature set we're using (e.g. Pentium 4MB * enable and PPro Global page enable), so that any CPU's that boot @@ -234,37 +314,63 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask) extern void initialize_tlbstate_and_flush(void); -static inline void __native_flush_tlb(void) +/* + * Given an ASID, flush the corresponding user ASID. We can delay this + * until the next time we switch to it. + * + * See SWITCH_TO_USER_CR3. + */ +static inline void invalidate_user_asid(u16 asid) { + /* There is no user ASID if address space separation is off */ + if (!IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) + return; + /* - * If current->mm == NULL then we borrow a mm which may change during a - * task switch and therefore we must not be preempted while we write CR3 - * back: + * We only have a single ASID if PCID is off and the CR3 + * write will have flushed it. */ - preempt_disable(); - native_write_cr3(__native_read_cr3()); - preempt_enable(); + if (!cpu_feature_enabled(X86_FEATURE_PCID)) + return; + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + __set_bit(kern_pcid(asid), + (unsigned long *)this_cpu_ptr(&cpu_tlbstate.user_pcid_flush_mask)); } -static inline void __native_flush_tlb_global_irq_disabled(void) +/* + * flush the entire current user mapping + */ +static inline void __native_flush_tlb(void) { - unsigned long cr4; + /* + * Preemption or interrupts must be disabled to protect the access + * to the per CPU variable and to prevent being preempted between + * read_cr3() and write_cr3(). + */ + WARN_ON_ONCE(preemptible()); - cr4 = this_cpu_read(cpu_tlbstate.cr4); - /* clear PGE */ - native_write_cr4(cr4 & ~X86_CR4_PGE); - /* write old PGE again and flush TLBs */ - native_write_cr4(cr4); + invalidate_user_asid(this_cpu_read(cpu_tlbstate.loaded_mm_asid)); + + /* If current->mm == NULL then the read_cr3() "borrows" an mm */ + native_write_cr3(__native_read_cr3()); } +/* + * flush everything + */ static inline void __native_flush_tlb_global(void) { - unsigned long flags; + unsigned long cr4, flags; if (static_cpu_has(X86_FEATURE_INVPCID)) { /* * Using INVPCID is considerably faster than a pair of writes * to CR4 sandwiched inside an IRQ flag save/restore. + * + * Note, this works with CR4.PCIDE=0 or 1. */ invpcid_flush_all(); return; @@ -277,36 +383,69 @@ static inline void __native_flush_tlb_global(void) */ raw_local_irq_save(flags); - __native_flush_tlb_global_irq_disabled(); + cr4 = this_cpu_read(cpu_tlbstate.cr4); + /* toggle PGE */ + native_write_cr4(cr4 ^ X86_CR4_PGE); + /* write old PGE again and flush TLBs */ + native_write_cr4(cr4); raw_local_irq_restore(flags); } +/* + * flush one page in the user mapping + */ static inline void __native_flush_tlb_single(unsigned long addr) { + u32 loaded_mm_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid); + asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + /* + * Some platforms #GP if we call invpcid(type=1/2) before CR4.PCIDE=1. + * Just use invalidate_user_asid() in case we are called early. + */ + if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE)) + invalidate_user_asid(loaded_mm_asid); + else + invpcid_flush_one(user_pcid(loaded_mm_asid), addr); } +/* + * flush everything + */ static inline void __flush_tlb_all(void) { - if (boot_cpu_has(X86_FEATURE_PGE)) + if (boot_cpu_has(X86_FEATURE_PGE)) { __flush_tlb_global(); - else + } else { + /* + * !PGE -> !PCID (setup_pcid()), thus every flush is total. + */ __flush_tlb(); - - /* - * Note: if we somehow had PCID but not PGE, then this wouldn't work -- - * we'd end up flushing kernel translations for the current ASID but - * we might fail to flush kernel translations for other cached ASIDs. - * - * To avoid this issue, we force PCID off if PGE is off. - */ + } } +/* + * flush one page in the kernel mapping + */ static inline void __flush_tlb_one(unsigned long addr) { count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE); __flush_tlb_single(addr); + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + /* + * __flush_tlb_single() will have cleared the TLB entry for this ASID, + * but since kernel space is replicated across all, we must also + * invalidate all others. + */ + invalidate_other_asid(); } #define TLB_FLUSH_ALL -1UL @@ -367,6 +506,17 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a) void native_flush_tlb_others(const struct cpumask *cpumask, const struct flush_tlb_info *info); +static inline u64 inc_mm_tlb_gen(struct mm_struct *mm) +{ + /* + * Bump the generation count. This also serves as a full barrier + * that synchronizes with switch_mm(): callers are required to order + * their read of mm_cpumask after their writes to the paging + * structures. + */ + return atomic64_inc_return(&mm->context.tlb_gen); +} + static inline void arch_tlbbatch_add_mm(struct arch_tlbflush_unmap_batch *batch, struct mm_struct *mm) { diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h index fa60398bbc3ac..069c04be15076 100644 --- a/arch/x86/include/asm/trace/fpu.h +++ b/arch/x86/include/asm/trace/fpu.h @@ -34,11 +34,6 @@ DECLARE_EVENT_CLASS(x86_fpu, ) ); -DEFINE_EVENT(x86_fpu, x86_fpu_state, - TP_PROTO(struct fpu *fpu), - TP_ARGS(fpu) -); - DEFINE_EVENT(x86_fpu, x86_fpu_before_save, TP_PROTO(struct fpu *fpu), TP_ARGS(fpu) @@ -74,11 +69,6 @@ DEFINE_EVENT(x86_fpu, x86_fpu_activate_state, TP_ARGS(fpu) ); -DEFINE_EVENT(x86_fpu, x86_fpu_deactivate_state, - TP_PROTO(struct fpu *fpu), - TP_ARGS(fpu) -); - DEFINE_EVENT(x86_fpu, x86_fpu_init_state, TP_PROTO(struct fpu *fpu), TP_ARGS(fpu) diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index b0cced97a6ce9..3de69330e6c50 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -38,9 +38,9 @@ asmlinkage void simd_coprocessor_error(void); #if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) asmlinkage void xen_divide_error(void); +asmlinkage void xen_xennmi(void); asmlinkage void xen_xendebug(void); asmlinkage void xen_xenint3(void); -asmlinkage void xen_nmi(void); asmlinkage void xen_overflow(void); asmlinkage void xen_bounds(void); asmlinkage void xen_invalid_op(void); @@ -75,7 +75,6 @@ dotraplinkage void do_segment_not_present(struct pt_regs *, long); dotraplinkage void do_stack_segment(struct pt_regs *, long); #ifdef CONFIG_X86_64 dotraplinkage void do_double_fault(struct pt_regs *, long); -asmlinkage struct pt_regs *sync_regs(struct pt_regs *); #endif dotraplinkage void do_general_protection(struct pt_regs *, long); dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); @@ -89,6 +88,7 @@ dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); #ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long); #endif +dotraplinkage void do_mce(struct pt_regs *, long); static inline int get_si_code(unsigned long condition) { @@ -145,4 +145,22 @@ enum { X86_TRAP_IRET = 32, /* 32, IRET Exception */ }; +/* + * Page fault error code bits: + * + * bit 0 == 0: no page found 1: protection fault + * bit 1 == 0: read access 1: write access + * bit 2 == 0: kernel-mode access 1: user-mode access + * bit 3 == 1: use of reserved bit detected + * bit 4 == 1: fault was an instruction fetch + * bit 5 == 1: protection keys block access + */ +enum x86_pf_error_code { + X86_PF_PROT = 1 << 0, + X86_PF_WRITE = 1 << 1, + X86_PF_USER = 1 << 2, + X86_PF_RSVD = 1 << 3, + X86_PF_INSTR = 1 << 4, + X86_PF_PK = 1 << 5, +}; #endif /* _ASM_X86_TRAPS_H */ diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h index 87adc0d38c4aa..1f86e1b0a5cdc 100644 --- a/arch/x86/include/asm/unwind.h +++ b/arch/x86/include/asm/unwind.h @@ -7,17 +7,20 @@ #include #include +#define IRET_FRAME_OFFSET (offsetof(struct pt_regs, ip)) +#define IRET_FRAME_SIZE (sizeof(struct pt_regs) - IRET_FRAME_OFFSET) + struct unwind_state { struct stack_info stack_info; unsigned long stack_mask; struct task_struct *task; int graph_idx; bool error; -#if defined(CONFIG_ORC_UNWINDER) +#if defined(CONFIG_UNWINDER_ORC) bool signal, full_regs; unsigned long sp, bp, ip; struct pt_regs *regs; -#elif defined(CONFIG_FRAME_POINTER_UNWINDER) +#elif defined(CONFIG_UNWINDER_FRAME_POINTER) bool got_irq; unsigned long *bp, *orig_sp, ip; struct pt_regs *regs; @@ -51,22 +54,35 @@ void unwind_start(struct unwind_state *state, struct task_struct *task, __unwind_start(state, task, regs, first_frame); } -#if defined(CONFIG_ORC_UNWINDER) || defined(CONFIG_FRAME_POINTER_UNWINDER) -static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state) +#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER) +/* + * If 'partial' returns true, only the iret frame registers are valid. + */ +static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state, + bool *partial) { if (unwind_done(state)) return NULL; + if (partial) { +#ifdef CONFIG_UNWINDER_ORC + *partial = !state->full_regs; +#else + *partial = false; +#endif + } + return state->regs; } #else -static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state) +static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state, + bool *partial) { return NULL; } #endif -#ifdef CONFIG_ORC_UNWINDER +#ifdef CONFIG_UNWINDER_ORC void unwind_init(void); void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size); diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h index d9a7c659009c9..b986b2ca688a0 100644 --- a/arch/x86/include/asm/vsyscall.h +++ b/arch/x86/include/asm/vsyscall.h @@ -7,6 +7,7 @@ #ifdef CONFIG_X86_VSYSCALL_EMULATION extern void map_vsyscall(void); +extern void set_vsyscall_pgtable_user_bits(pgd_t *root); /* * Called on instruction fetch fault in vsyscall page. diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 8a1ebf9540ddf..ad15a0fda9174 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -114,6 +114,18 @@ struct x86_init_pci { void (*fixup_irqs)(void); }; +/** + * struct x86_hyper_init - x86 hypervisor init functions + * @init_platform: platform setup + * @x2apic_available: X2APIC detection + * @init_mem_mapping: setup early mappings during init_mem_mapping() + */ +struct x86_hyper_init { + void (*init_platform)(void); + bool (*x2apic_available)(void); + void (*init_mem_mapping)(void); +}; + /** * struct x86_init_ops - functions for platform specific setup * @@ -127,6 +139,7 @@ struct x86_init_ops { struct x86_init_timers timers; struct x86_init_iommu iommu; struct x86_init_pci pci; + struct x86_hyper_init hyper; }; /** @@ -199,6 +212,15 @@ struct x86_legacy_features { struct x86_legacy_devices devices; }; +/** + * struct x86_hyper_runtime - x86 hypervisor specific runtime callbacks + * + * @pin_vcpu: pin current vcpu to specified physical cpu (run rarely) + */ +struct x86_hyper_runtime { + void (*pin_vcpu)(int cpu); +}; + /** * struct x86_platform_ops - platform specific runtime functions * @calibrate_cpu: calibrate CPU @@ -218,6 +240,7 @@ struct x86_legacy_features { * possible in x86_early_init_platform_quirks() by * only using the current x86_hardware_subarch * semantics. + * @hyper: x86 hypervisor specific runtime callbacks */ struct x86_platform_ops { unsigned long (*calibrate_cpu)(void); @@ -233,6 +256,7 @@ struct x86_platform_ops { void (*apic_post_init)(void); struct x86_legacy_features legacy; void (*set_legacy_features)(void); + struct x86_hyper_runtime hyper; }; struct pci_dev; diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index 7cb282e9e5877..bfd8826176139 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -217,9 +218,9 @@ privcmd_call(unsigned call, __HYPERCALL_5ARG(a1, a2, a3, a4, a5); stac(); - asm volatile("call *%[call]" + asm volatile(CALL_NOSPEC : __HYPERCALL_5PARAM - : [call] "a" (&hypercall_page[call]) + : [thunk_target] "a" (&hypercall_page[call]) : __HYPERCALL_CLOBBER5); clac(); diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h index 6f33553996650..97abdaab95357 100644 --- a/arch/x86/include/uapi/asm/processor-flags.h +++ b/arch/x86/include/uapi/asm/processor-flags.h @@ -78,7 +78,12 @@ #define X86_CR3_PWT _BITUL(X86_CR3_PWT_BIT) #define X86_CR3_PCD_BIT 4 /* Page Cache Disable */ #define X86_CR3_PCD _BITUL(X86_CR3_PCD_BIT) -#define X86_CR3_PCID_MASK _AC(0x00000fff,UL) /* PCID Mask */ + +#define X86_CR3_PCID_BITS 12 +#define X86_CR3_PCID_MASK (_AC((1UL << X86_CR3_PCID_BITS) - 1, UL)) + +#define X86_CR3_PCID_NOFLUSH_BIT 63 /* Preserve old PCID */ +#define X86_CR3_PCID_NOFLUSH _BITULL(X86_CR3_PCID_NOFLUSH_BIT) /* * Intel CPU features in CR4 @@ -152,5 +157,8 @@ #define CX86_ARR_BASE 0xc4 #define CX86_RCR_BASE 0xdc +#define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \ + X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \ + X86_CR0_PG) #endif /* _UAPI_ASM_X86_PROCESSOR_FLAGS_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 5f70044340ff1..295abaa58adde 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -25,9 +25,9 @@ endif KASAN_SANITIZE_head$(BITS).o := n KASAN_SANITIZE_dumpstack.o := n KASAN_SANITIZE_dumpstack_$(BITS).o := n -KASAN_SANITIZE_stacktrace.o := n +KASAN_SANITIZE_stacktrace.o := n +KASAN_SANITIZE_paravirt.o := n -OBJECT_FILES_NON_STANDARD_head_$(BITS).o := y OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y OBJECT_FILES_NON_STANDARD_test_nx.o := y @@ -128,9 +128,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_SCHED_MC_PRIO) += itmt.o -obj-$(CONFIG_ORC_UNWINDER) += unwind_orc.o -obj-$(CONFIG_FRAME_POINTER_UNWINDER) += unwind_frame.o -obj-$(CONFIG_GUESS_UNWINDER) += unwind_guess.o +obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o +obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o +obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o ### # 64 bit specific files diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 079535e53e2a6..9c2a002d9297c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -342,13 +342,12 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e #ifdef CONFIG_X86_IO_APIC #define MP_ISA_BUS 0 +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi); + static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) { - int ioapic; - int pin; - struct mpc_intsrc mp_irq; - /* * Check bus_irq boundary. */ @@ -357,14 +356,6 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, return; } - /* - * Convert 'gsi' to 'ioapic.pin'. - */ - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) - return; - pin = mp_find_ioapic_pin(ioapic, gsi); - /* * TBD: This check is for faulty timer entries, where the override * erroneously sets the trigger to level, resulting in a HUGE @@ -373,16 +364,8 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, if ((bus_irq == 0) && (trigger == 3)) trigger = 1; - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (trigger << 2) | polarity; - mp_irq.srcbus = MP_ISA_BUS; - mp_irq.srcbusirq = bus_irq; /* IRQ */ - mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */ - mp_irq.dstirq = pin; /* INTIN# */ - - mp_save_irq(&mp_irq); - + if (mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi) < 0) + return; /* * Reset default identity mapping if gsi is also an legacy IRQ, * otherwise there will be more than one entry with the same GSI @@ -429,6 +412,34 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, return 0; } +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi) +{ + struct mpc_intsrc mp_irq; + int ioapic, pin; + + /* Convert 'gsi' to 'ioapic.pin'(INTIN#) */ + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + pr_warn("Failed to find ioapic for gsi : %u\n", gsi); + return ioapic; + } + + pin = mp_find_ioapic_pin(ioapic, gsi); + + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger << 2) | polarity; + mp_irq.srcbus = MP_ISA_BUS; + mp_irq.srcbusirq = bus_irq; + mp_irq.dstapic = mpc_ioapic_id(ioapic); + mp_irq.dstirq = pin; + + mp_save_irq(&mp_irq); + + return 0; +} + static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { @@ -473,7 +484,11 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; - mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + if (bus_irq < NR_IRQS_LEGACY) + mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + else + mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi); + acpi_penalize_sci_irq(bus_irq, trigger, polarity); /* diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 3344d3382e913..e0b97e4d1db55 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -344,9 +344,12 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf) static void __init_or_module noinline optimize_nops(struct alt_instr *a, u8 *instr) { unsigned long flags; + int i; - if (instr[0] != 0x90) - return; + for (i = 0; i < a->padlen; i++) { + if (instr[i] != 0x90) + return; + } local_irq_save(flags); add_nops(instr + (a->instrlen - a->padlen), a->padlen); diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ff891772c9f86..89c7c8569e5e7 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1645,7 +1645,7 @@ static __init void try_to_enable_x2apic(int remap_mode) * under KVM */ if (max_physical_apicid > 255 || - !hypervisor_x2apic_available()) { + !x86_init.hyper.x2apic_available()) { pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); x2apic_disable(); return; diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 88c214e75a6be..2ce1c708b8ee3 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -369,8 +369,11 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, irq_data->hwirq = virq + i; err = assign_irq_vector_policy(virq + i, node, data, info, irq_data); - if (err) + if (err) { + irq_data->chip_data = NULL; + free_apic_chip_data(data); goto error; + } /* * If the apic destination mode is physical, then the * effective affinity is restricted to a single target @@ -383,7 +386,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, return 0; error: - x86_vector_free_irqs(domain, virq, i + 1); + x86_vector_free_irqs(domain, virq, i); return err; } diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 0d57bb9079c99..c0b694810ff45 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -920,9 +920,8 @@ static __init void uv_rtc_init(void) /* * percpu heartbeat timer */ -static void uv_heartbeat(unsigned long ignored) +static void uv_heartbeat(struct timer_list *timer) { - struct timer_list *timer = &uv_scir_info->timer; unsigned char bits = uv_scir_info->state; /* Flip heartbeat bit: */ @@ -947,7 +946,7 @@ static int uv_heartbeat_enable(unsigned int cpu) struct timer_list *timer = &uv_cpu_scir_info(cpu)->timer; uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); - setup_pinned_timer(timer, uv_heartbeat, cpu); + timer_setup(timer, uv_heartbeat, TIMER_PINNED); timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; add_timer_on(timer, cpu); uv_cpu_scir_info(cpu)->enabled = 1; diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 8ea78275480da..76417a9aab73c 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_XEN #include @@ -93,4 +94,13 @@ void common(void) { BLANK(); DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); + + /* TLB state for the entry code */ + OFFSET(TLB_STATE_user_pcid_flush_mask, tlb_state, user_pcid_flush_mask); + + /* Layout info for cpu_entry_area */ + OFFSET(CPU_ENTRY_AREA_tss, cpu_entry_area, tss); + OFFSET(CPU_ENTRY_AREA_entry_trampoline, cpu_entry_area, entry_trampoline); + OFFSET(CPU_ENTRY_AREA_entry_stack, cpu_entry_area, entry_stack_page); + DEFINE(SIZEOF_entry_stack, sizeof(struct entry_stack)); } diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index dedf428b20b68..fa1261eefa16e 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -47,13 +47,8 @@ void foo(void) BLANK(); /* Offset from the sysenter stack to tss.sp0 */ - DEFINE(TSS_sysenter_sp0, offsetof(struct tss_struct, x86_tss.sp0) - - offsetofend(struct tss_struct, SYSENTER_stack)); - - /* Offset from cpu_tss to SYSENTER_stack */ - OFFSET(CPU_TSS_SYSENTER_stack, tss_struct, SYSENTER_stack); - /* Size of SYSENTER_stack */ - DEFINE(SIZEOF_SYSENTER_stack, sizeof(((struct tss_struct *)0)->SYSENTER_stack)); + DEFINE(TSS_sysenter_sp0, offsetof(struct cpu_entry_area, tss.x86_tss.sp0) - + offsetofend(struct cpu_entry_area, entry_stack_page.stack)); #ifdef CONFIG_CC_STACKPROTECTOR BLANK(); diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index 630212fa9b9da..bf51e51d808dd 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -23,6 +23,9 @@ int main(void) #ifdef CONFIG_PARAVIRT OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64); OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs); +#ifdef CONFIG_DEBUG_ENTRY + OFFSET(PV_IRQ_save_fl, pv_irq_ops, save_fl); +#endif BLANK(); #endif @@ -63,6 +66,7 @@ int main(void) OFFSET(TSS_ist, tss_struct, x86_tss.ist); OFFSET(TSS_sp0, tss_struct, x86_tss.sp0); + OFFSET(TSS_sp1, tss_struct, x86_tss.sp1); BLANK(); #ifdef CONFIG_CC_STACKPROTECTOR diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index c60922a663857..570e8bb1f386d 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -22,7 +22,8 @@ obj-y += common.o obj-y += rdrand.o obj-y += match.o obj-y += bugs.o -obj-$(CONFIG_CPU_FREQ) += aperfmperf.o +obj-y += aperfmperf.o +obj-y += cpuid-deps.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index d58184b7cd443..ea831c8581958 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -804,8 +804,11 @@ static void init_amd(struct cpuinfo_x86 *c) case 0x17: init_amd_zn(c); break; } - /* Enable workaround for FXSAVE leak */ - if (c->x86 >= 6) + /* + * Enable workaround for FXSAVE leak on CPUs + * without a XSaveErPtr feature + */ + if ((c->x86 >= 6) && (!cpu_has(c, X86_FEATURE_XSAVEERPTR))) set_cpu_bug(c, X86_BUG_FXSAVE_LEAK); cpu_detect_cache_sizes(c); @@ -826,8 +829,32 @@ static void init_amd(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_K8); if (cpu_has(c, X86_FEATURE_XMM2)) { - /* MFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); + unsigned long long val; + int ret; + + /* + * A serializing LFENCE has less overhead than MFENCE, so + * use it for execution serialization. On families which + * don't have that MSR, LFENCE is already serializing. + * msr_set_bit() uses the safe accessors, too, even if the MSR + * is not present. + */ + msr_set_bit(MSR_F10H_DECFG, + MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT); + + /* + * Verify that the MSR write was successful (could be running + * under a hypervisor) and only then assume that LFENCE is + * serializing. + */ + ret = rdmsrl_safe(MSR_F10H_DECFG, &val); + if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) { + /* A serializing LFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); + } else { + /* MFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); + } } /* diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c index 0ee83321a3136..7eba34df54c3d 100644 --- a/arch/x86/kernel/cpu/aperfmperf.c +++ b/arch/x86/kernel/cpu/aperfmperf.c @@ -14,6 +14,8 @@ #include #include +#include "cpu.h" + struct aperfmperf_sample { unsigned int khz; ktime_t time; @@ -24,7 +26,7 @@ struct aperfmperf_sample { static DEFINE_PER_CPU(struct aperfmperf_sample, samples); #define APERFMPERF_CACHE_THRESHOLD_MS 10 -#define APERFMPERF_REFRESH_DELAY_MS 20 +#define APERFMPERF_REFRESH_DELAY_MS 10 #define APERFMPERF_STALE_THRESHOLD_MS 1000 /* @@ -38,14 +40,8 @@ static void aperfmperf_snapshot_khz(void *dummy) u64 aperf, aperf_delta; u64 mperf, mperf_delta; struct aperfmperf_sample *s = this_cpu_ptr(&samples); - ktime_t now = ktime_get(); - s64 time_delta = ktime_ms_delta(now, s->time); unsigned long flags; - /* Don't bother re-computing within the cache threshold time. */ - if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS) - return; - local_irq_save(flags); rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); @@ -61,31 +57,68 @@ static void aperfmperf_snapshot_khz(void *dummy) if (mperf_delta == 0) return; - s->time = now; + s->time = ktime_get(); s->aperf = aperf; s->mperf = mperf; + s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta); +} - /* If the previous iteration was too long ago, discard it. */ - if (time_delta > APERFMPERF_STALE_THRESHOLD_MS) - s->khz = 0; - else - s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta); +static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait) +{ + s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu)); + + /* Don't bother re-computing within the cache threshold time. */ + if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS) + return true; + + smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, wait); + + /* Return false if the previous iteration was too long ago. */ + return time_delta <= APERFMPERF_STALE_THRESHOLD_MS; } -unsigned int arch_freq_get_on_cpu(int cpu) +unsigned int aperfmperf_get_khz(int cpu) { - unsigned int khz; + if (!cpu_khz) + return 0; + + if (!static_cpu_has(X86_FEATURE_APERFMPERF)) + return 0; + aperfmperf_snapshot_cpu(cpu, ktime_get(), true); + return per_cpu(samples.khz, cpu); +} + +void arch_freq_prepare_all(void) +{ + ktime_t now = ktime_get(); + bool wait = false; + int cpu; + + if (!cpu_khz) + return; + + if (!static_cpu_has(X86_FEATURE_APERFMPERF)) + return; + + for_each_online_cpu(cpu) + if (!aperfmperf_snapshot_cpu(cpu, now, false)) + wait = true; + + if (wait) + msleep(APERFMPERF_REFRESH_DELAY_MS); +} + +unsigned int arch_freq_get_on_cpu(int cpu) +{ if (!cpu_khz) return 0; if (!static_cpu_has(X86_FEATURE_APERFMPERF)) return 0; - smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); - khz = per_cpu(samples.khz, cpu); - if (khz) - return khz; + if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true)) + return per_cpu(samples.khz, cpu); msleep(APERFMPERF_REFRESH_DELAY_MS); smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ba0b2424c9b05..390b3dc3d4382 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -10,6 +10,10 @@ */ #include #include +#include + +#include +#include #include #include #include @@ -19,6 +23,9 @@ #include #include #include +#include + +static void __init spectre_v2_select_mitigation(void); void __init check_bugs(void) { @@ -29,6 +36,9 @@ void __init check_bugs(void) print_cpu_info(&boot_cpu_data); } + /* Select the proper spectre mitigation before patching alternatives */ + spectre_v2_select_mitigation(); + #ifdef CONFIG_X86_32 /* * Check whether we are able to run this kernel safely on SMP. @@ -60,3 +70,214 @@ void __init check_bugs(void) set_memory_4k((unsigned long)__va(0), 1); #endif } + +/* The kernel command line selection */ +enum spectre_v2_mitigation_cmd { + SPECTRE_V2_CMD_NONE, + SPECTRE_V2_CMD_AUTO, + SPECTRE_V2_CMD_FORCE, + SPECTRE_V2_CMD_RETPOLINE, + SPECTRE_V2_CMD_RETPOLINE_GENERIC, + SPECTRE_V2_CMD_RETPOLINE_AMD, +}; + +static const char *spectre_v2_strings[] = { + [SPECTRE_V2_NONE] = "Vulnerable", + [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline", + [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline", + [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", + [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", +}; + +#undef pr_fmt +#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt + +static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; + +static void __init spec2_print_if_insecure(const char *reason) +{ + if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static void __init spec2_print_if_secure(const char *reason) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static inline bool retp_compiler(void) +{ + return __is_defined(RETPOLINE); +} + +static inline bool match_option(const char *arg, int arglen, const char *opt) +{ + int len = strlen(opt); + + return len == arglen && !strncmp(arg, opt, len); +} + +static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) +{ + char arg[20]; + int ret; + + ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, + sizeof(arg)); + if (ret > 0) { + if (match_option(arg, ret, "off")) { + goto disable; + } else if (match_option(arg, ret, "on")) { + spec2_print_if_secure("force enabled on command line."); + return SPECTRE_V2_CMD_FORCE; + } else if (match_option(arg, ret, "retpoline")) { + spec2_print_if_insecure("retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE; + } else if (match_option(arg, ret, "retpoline,amd")) { + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { + pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); + return SPECTRE_V2_CMD_AUTO; + } + spec2_print_if_insecure("AMD retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE_AMD; + } else if (match_option(arg, ret, "retpoline,generic")) { + spec2_print_if_insecure("generic retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE_GENERIC; + } else if (match_option(arg, ret, "auto")) { + return SPECTRE_V2_CMD_AUTO; + } + } + + if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) + return SPECTRE_V2_CMD_AUTO; +disable: + spec2_print_if_insecure("disabled on command line."); + return SPECTRE_V2_CMD_NONE; +} + +/* Check for Skylake-like CPUs (for RSB handling) */ +static bool __init is_skylake_era(void) +{ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6) { + switch (boot_cpu_data.x86_model) { + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE_X: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: + return true; + } + } + return false; +} + +static void __init spectre_v2_select_mitigation(void) +{ + enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); + enum spectre_v2_mitigation mode = SPECTRE_V2_NONE; + + /* + * If the CPU is not affected and the command line mode is NONE or AUTO + * then nothing to do. + */ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) && + (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO)) + return; + + switch (cmd) { + case SPECTRE_V2_CMD_NONE: + return; + + case SPECTRE_V2_CMD_FORCE: + /* FALLTRHU */ + case SPECTRE_V2_CMD_AUTO: + goto retpoline_auto; + + case SPECTRE_V2_CMD_RETPOLINE_AMD: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_amd; + break; + case SPECTRE_V2_CMD_RETPOLINE_GENERIC: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_generic; + break; + case SPECTRE_V2_CMD_RETPOLINE: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_auto; + break; + } + pr_err("kernel not compiled with retpoline; no mitigation available!"); + return; + +retpoline_auto: + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { + retpoline_amd: + if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { + pr_err("LFENCE not serializing. Switching to generic retpoline\n"); + goto retpoline_generic; + } + mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : + SPECTRE_V2_RETPOLINE_MINIMAL_AMD; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + } else { + retpoline_generic: + mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC : + SPECTRE_V2_RETPOLINE_MINIMAL; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + } + + spectre_v2_enabled = mode; + pr_info("%s\n", spectre_v2_strings[mode]); + + /* + * If neither SMEP or KPTI are available, there is a risk of + * hitting userspace addresses in the RSB after a context switch + * from a shallow call stack to a deeper one. To prevent this fill + * the entire RSB, even when using IBRS. + * + * Skylake era CPUs have a separate issue with *underflow* of the + * RSB, when they will predict 'ret' targets from the generic BTB. + * The proper mitigation for this is IBRS. If IBRS is not supported + * or deactivated in favour of retpolines the RSB fill on context + * switch is required. + */ + if ((!boot_cpu_has(X86_FEATURE_PTI) && + !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) { + setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); + pr_info("Filling RSB on context switch\n"); + } +} + +#undef pr_fmt + +#ifdef CONFIG_SYSFS +ssize_t cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + return sprintf(buf, "Not affected\n"); + if (boot_cpu_has(X86_FEATURE_PTI)) + return sprintf(buf, "Mitigation: PTI\n"); + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) + return sprintf(buf, "Not affected\n"); + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); +} +#endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c9176bae7fd8c..372ba3fb400fa 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -452,8 +452,8 @@ static const char *table_lookup_model(struct cpuinfo_x86 *c) return NULL; /* Not found */ } -__u32 cpu_caps_cleared[NCAPINTS]; -__u32 cpu_caps_set[NCAPINTS]; +__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; +__u32 cpu_caps_set[NCAPINTS + NBUGINTS]; void load_percpu_segment(int cpu) { @@ -466,28 +466,23 @@ void load_percpu_segment(int cpu) load_stack_canary_segment(); } -/* Setup the fixmap mapping only once per-processor */ -static inline void setup_fixmap_gdt(int cpu) -{ -#ifdef CONFIG_X86_64 - /* On 64-bit systems, we use a read-only fixmap GDT. */ - pgprot_t prot = PAGE_KERNEL_RO; -#else - /* - * On native 32-bit systems, the GDT cannot be read-only because - * our double fault handler uses a task gate, and entering through - * a task gate needs to change an available TSS to busy. If the GDT - * is read-only, that will triple fault. - * - * On Xen PV, the GDT must be read-only because the hypervisor requires - * it. - */ - pgprot_t prot = boot_cpu_has(X86_FEATURE_XENPV) ? - PAGE_KERNEL_RO : PAGE_KERNEL; +#ifdef CONFIG_X86_32 +/* The 32-bit entry code needs to find cpu_entry_area. */ +DEFINE_PER_CPU(struct cpu_entry_area *, cpu_entry_area); #endif - __set_fixmap(get_cpu_gdt_ro_index(cpu), get_cpu_gdt_paddr(cpu), prot); -} +#ifdef CONFIG_X86_64 +/* + * Special IST stacks which the CPU switches to when it calls + * an IST-marked descriptor entry. Up to 7 stacks (hardware + * limit), all of them are 4K, except the debug stack which + * is 8K. + */ +static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { + [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, + [DEBUG_STACK - 1] = DEBUG_STKSZ +}; +#endif /* Load the original GDT from the per-cpu structure */ void load_direct_gdt(int cpu) @@ -723,7 +718,7 @@ static void apply_forced_caps(struct cpuinfo_x86 *c) { int i; - for (i = 0; i < NCAPINTS; i++) { + for (i = 0; i < NCAPINTS + NBUGINTS; i++) { c->x86_capability[i] &= ~cpu_caps_cleared[i]; c->x86_capability[i] |= cpu_caps_set[i]; } @@ -903,6 +898,13 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) } setup_force_cpu_cap(X86_FEATURE_ALWAYS); + + if (c->x86_vendor != X86_VENDOR_AMD) + setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); + + setup_force_cpu_bug(X86_BUG_SPECTRE_V1); + setup_force_cpu_bug(X86_BUG_SPECTRE_V2); + fpu__init_system(c); #ifdef CONFIG_X86_32 @@ -1225,7 +1227,7 @@ void enable_sep_cpu(void) return; cpu = get_cpu(); - tss = &per_cpu(cpu_tss, cpu); + tss = &per_cpu(cpu_tss_rw, cpu); /* * We cache MSR_IA32_SYSENTER_CS's value in the TSS's ss1 field -- @@ -1234,11 +1236,7 @@ void enable_sep_cpu(void) tss->x86_tss.ss1 = __KERNEL_CS; wrmsr(MSR_IA32_SYSENTER_CS, tss->x86_tss.ss1, 0); - - wrmsr(MSR_IA32_SYSENTER_ESP, - (unsigned long)tss + offsetofend(struct tss_struct, SYSENTER_stack), - 0); - + wrmsr(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_entry_stack(cpu) + 1), 0); wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long)entry_SYSENTER_32, 0); put_cpu(); @@ -1301,18 +1299,16 @@ void print_cpu_info(struct cpuinfo_x86 *c) pr_cont(")\n"); } -static __init int setup_disablecpuid(char *arg) +/* + * clearcpuid= was already parsed in fpu__init_parse_early_param. + * But we need to keep a dummy __setup around otherwise it would + * show up as an environment variable for init. + */ +static __init int setup_clearcpuid(char *arg) { - int bit; - - if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32) - setup_clear_cpu_cap(bit); - else - return 0; - return 1; } -__setup("clearcpuid=", setup_disablecpuid); +__setup("clearcpuid=", setup_clearcpuid); #ifdef CONFIG_X86_64 DEFINE_PER_CPU_FIRST(union irq_stack_union, @@ -1334,25 +1330,22 @@ DEFINE_PER_CPU(unsigned int, irq_count) __visible = -1; DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT; EXPORT_PER_CPU_SYMBOL(__preempt_count); -/* - * Special IST stacks which the CPU switches to when it calls - * an IST-marked descriptor entry. Up to 7 stacks (hardware - * limit), all of them are 4K, except the debug stack which - * is 8K. - */ -static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { - [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, - [DEBUG_STACK - 1] = DEBUG_STKSZ -}; - -static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks - [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); - /* May not be marked __init: used by software suspend */ void syscall_init(void) { + extern char _entry_trampoline[]; + extern char entry_SYSCALL_64_trampoline[]; + + int cpu = smp_processor_id(); + unsigned long SYSCALL64_entry_trampoline = + (unsigned long)get_cpu_entry_area(cpu)->entry_trampoline + + (entry_SYSCALL_64_trampoline - _entry_trampoline); + wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS); - wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64); + if (static_cpu_has(X86_FEATURE_PTI)) + wrmsrl(MSR_LSTAR, SYSCALL64_entry_trampoline); + else + wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64); #ifdef CONFIG_IA32_EMULATION wrmsrl(MSR_CSTAR, (unsigned long)entry_SYSCALL_compat); @@ -1363,7 +1356,7 @@ void syscall_init(void) * AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit). */ wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); - wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); + wrmsrl_safe(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_entry_stack(cpu) + 1)); wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat); #else wrmsrl(MSR_CSTAR, (unsigned long)ignore_sysret); @@ -1507,7 +1500,7 @@ void cpu_init(void) if (cpu) load_ucode_ap(); - t = &per_cpu(cpu_tss, cpu); + t = &per_cpu(cpu_tss_rw, cpu); oist = &per_cpu(orig_ist, cpu); #ifdef CONFIG_NUMA @@ -1546,7 +1539,7 @@ void cpu_init(void) * set up and load the per-CPU TSS */ if (!oist->ist[0]) { - char *estacks = per_cpu(exception_stacks, cpu); + char *estacks = get_cpu_entry_area(cpu)->exception_stacks; for (v = 0; v < N_EXCEPTION_STACKS; v++) { estacks += exception_stack_sizes[v]; @@ -1557,7 +1550,7 @@ void cpu_init(void) } } - t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + t->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; /* * <= is required because the CPU will access up to @@ -1572,9 +1565,14 @@ void cpu_init(void) initialize_tlbstate_and_flush(); enter_lazy_tlb(&init_mm, me); - load_sp0(t, ¤t->thread); - set_tss_desc(cpu, t); + /* + * Initialize the TSS. sp0 points to the entry trampoline stack + * regardless of what task is running. + */ + set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss); load_TR_desc(); + load_sp0((unsigned long)(cpu_entry_stack(cpu) + 1)); + load_mm_ldt(&init_mm); clear_all_debug_regs(); @@ -1585,7 +1583,6 @@ void cpu_init(void) if (is_uv_system()) uv_cpu_init(); - setup_fixmap_gdt(cpu); load_fixmap_gdt(cpu); } @@ -1595,8 +1592,7 @@ void cpu_init(void) { int cpu = smp_processor_id(); struct task_struct *curr = current; - struct tss_struct *t = &per_cpu(cpu_tss, cpu); - struct thread_struct *thread = &curr->thread; + struct tss_struct *t = &per_cpu(cpu_tss_rw, cpu); wait_for_master_cpu(cpu); @@ -1627,12 +1623,16 @@ void cpu_init(void) initialize_tlbstate_and_flush(); enter_lazy_tlb(&init_mm, curr); - load_sp0(t, thread); - set_tss_desc(cpu, t); + /* + * Initialize the TSS. Don't bother initializing sp0, as the initial + * task never enters user mode. + */ + set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss); load_TR_desc(); + load_mm_ldt(&init_mm); - t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + t->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; #ifdef CONFIG_DOUBLEFAULT /* Set up doublefault TSS pointer in the GDT */ @@ -1644,7 +1644,6 @@ void cpu_init(void) fpu__init_cpu(); - setup_fixmap_gdt(cpu); load_fixmap_gdt(cpu); } #endif diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index f52a370b6c00f..e806b11a99af4 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -47,4 +47,7 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[], extern void get_cpu_cap(struct cpuinfo_x86 *c); extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c); + +unsigned int aperfmperf_get_khz(int cpu); + #endif /* ARCH_X86_CPU_H */ diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c new file mode 100644 index 0000000000000..904b0a3c4e53c --- /dev/null +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -0,0 +1,121 @@ +/* Declare dependencies between CPUIDs */ +#include +#include +#include +#include + +struct cpuid_dep { + unsigned int feature; + unsigned int depends; +}; + +/* + * Table of CPUID features that depend on others. + * + * This only includes dependencies that can be usefully disabled, not + * features part of the base set (like FPU). + * + * Note this all is not __init / __initdata because it can be + * called from cpu hotplug. It shouldn't do anything in this case, + * but it's difficult to tell that to the init reference checker. + */ +const static struct cpuid_dep cpuid_deps[] = { + { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE }, + { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE }, + { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE }, + { X86_FEATURE_AVX, X86_FEATURE_XSAVE }, + { X86_FEATURE_PKU, X86_FEATURE_XSAVE }, + { X86_FEATURE_MPX, X86_FEATURE_XSAVE }, + { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE }, + { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR }, + { X86_FEATURE_XMM, X86_FEATURE_FXSR }, + { X86_FEATURE_XMM2, X86_FEATURE_XMM }, + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 }, + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, + { X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 }, + { X86_FEATURE_SSSE3, X86_FEATURE_XMM2, }, + { X86_FEATURE_F16C, X86_FEATURE_XMM2, }, + { X86_FEATURE_AES, X86_FEATURE_XMM2 }, + { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 }, + { X86_FEATURE_FMA, X86_FEATURE_AVX }, + { X86_FEATURE_AVX2, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512F, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VBMI2, X86_FEATURE_AVX512VL }, + { X86_FEATURE_GFNI, X86_FEATURE_AVX512VL }, + { X86_FEATURE_VAES, X86_FEATURE_AVX512VL }, + { X86_FEATURE_VPCLMULQDQ, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_VNNI, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_BITALG, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F }, + {} +}; + +static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature) +{ + /* + * Note: This could use the non atomic __*_bit() variants, but the + * rest of the cpufeature code uses atomics as well, so keep it for + * consistency. Cleanup all of it separately. + */ + if (!c) { + clear_cpu_cap(&boot_cpu_data, feature); + set_bit(feature, (unsigned long *)cpu_caps_cleared); + } else { + clear_bit(feature, (unsigned long *)c->x86_capability); + } +} + +/* Take the capabilities and the BUG bits into account */ +#define MAX_FEATURE_BITS ((NCAPINTS + NBUGINTS) * sizeof(u32) * 8) + +static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) +{ + DECLARE_BITMAP(disable, MAX_FEATURE_BITS); + const struct cpuid_dep *d; + bool changed; + + if (WARN_ON(feature >= MAX_FEATURE_BITS)) + return; + + clear_feature(c, feature); + + /* Collect all features to disable, handling dependencies */ + memset(disable, 0, sizeof(disable)); + __set_bit(feature, disable); + + /* Loop until we get a stable state. */ + do { + changed = false; + for (d = cpuid_deps; d->feature; d++) { + if (!test_bit(d->depends, disable)) + continue; + if (__test_and_set_bit(d->feature, disable)) + continue; + + changed = true; + clear_feature(c, d->feature); + } + } while (changed); +} + +void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) +{ + do_clear_cpu_cap(c, feature); +} + +void setup_clear_cpu_cap(unsigned int feature) +{ + do_clear_cpu_cap(NULL, feature); +} diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index 4fa90006ac68c..bea8d3e24f508 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c @@ -26,6 +26,12 @@ #include #include +extern const struct hypervisor_x86 x86_hyper_vmware; +extern const struct hypervisor_x86 x86_hyper_ms_hyperv; +extern const struct hypervisor_x86 x86_hyper_xen_pv; +extern const struct hypervisor_x86 x86_hyper_xen_hvm; +extern const struct hypervisor_x86 x86_hyper_kvm; + static const __initconst struct hypervisor_x86 * const hypervisors[] = { #ifdef CONFIG_XEN_PV @@ -41,54 +47,52 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = #endif }; -const struct hypervisor_x86 *x86_hyper; -EXPORT_SYMBOL(x86_hyper); +enum x86_hypervisor_type x86_hyper_type; +EXPORT_SYMBOL(x86_hyper_type); -static inline void __init +static inline const struct hypervisor_x86 * __init detect_hypervisor_vendor(void) { - const struct hypervisor_x86 *h, * const *p; + const struct hypervisor_x86 *h = NULL, * const *p; uint32_t pri, max_pri = 0; for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { - h = *p; - pri = h->detect(); - if (pri != 0 && pri > max_pri) { + pri = (*p)->detect(); + if (pri > max_pri) { max_pri = pri; - x86_hyper = h; + h = *p; } } - if (max_pri) - pr_info("Hypervisor detected: %s\n", x86_hyper->name); + if (h) + pr_info("Hypervisor detected: %s\n", h->name); + + return h; } -void __init init_hypervisor_platform(void) +static void __init copy_array(const void *src, void *target, unsigned int size) { + unsigned int i, n = size / sizeof(void *); + const void * const *from = (const void * const *)src; + const void **to = (const void **)target; - detect_hypervisor_vendor(); - - if (!x86_hyper) - return; - - if (x86_hyper->init_platform) - x86_hyper->init_platform(); + for (i = 0; i < n; i++) + if (from[i]) + to[i] = from[i]; } -bool __init hypervisor_x2apic_available(void) +void __init init_hypervisor_platform(void) { - return x86_hyper && - x86_hyper->x2apic_available && - x86_hyper->x2apic_available(); -} + const struct hypervisor_x86 *h; -void hypervisor_pin_vcpu(int cpu) -{ - if (!x86_hyper) + h = detect_hypervisor_vendor(); + + if (!h) return; - if (x86_hyper->pin_vcpu) - x86_hyper->pin_vcpu(cpu); - else - WARN_ONCE(1, "vcpu pinning requested but not supported!\n"); + copy_array(&h->init, &x86_init.hyper, sizeof(h->init)); + copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime)); + + x86_hyper_type = h->type; + x86_init.hyper.init_platform(); } diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index cd5fc61ba4502..99442370de40d 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -267,6 +267,7 @@ static void rdt_get_cdp_l3_config(int type) r->num_closid = r_l3->num_closid / 2; r->cache.cbm_len = r_l3->cache.cbm_len; r->default_ctrl = r_l3->default_ctrl; + r->cache.shareable_bits = r_l3->cache.shareable_bits; r->data_width = (r->cache.cbm_len + 3) / 4; r->alloc_capable = true; /* @@ -524,10 +525,6 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) */ if (static_branch_unlikely(&rdt_mon_enable_key)) rmdir_mondata_subdir_allrdtgrp(r, d->id); - kfree(d->ctrl_val); - kfree(d->rmid_busy_llc); - kfree(d->mbm_total); - kfree(d->mbm_local); list_del(&d->list); if (is_mbm_enabled()) cancel_delayed_work(&d->mbm_over); @@ -544,6 +541,10 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) cancel_delayed_work(&d->cqm_limbo); } + kfree(d->ctrl_val); + kfree(d->rmid_busy_llc); + kfree(d->mbm_total); + kfree(d->mbm_local); kfree(d); return; } diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index a869d4a073c5c..7be35b6002998 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1081,6 +1081,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, struct dentry *dentry; int ret; + cpus_read_lock(); mutex_lock(&rdtgroup_mutex); /* * resctrl file system can only be mounted once. @@ -1130,12 +1131,12 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, goto out_mondata; if (rdt_alloc_capable) - static_branch_enable(&rdt_alloc_enable_key); + static_branch_enable_cpuslocked(&rdt_alloc_enable_key); if (rdt_mon_capable) - static_branch_enable(&rdt_mon_enable_key); + static_branch_enable_cpuslocked(&rdt_mon_enable_key); if (rdt_alloc_capable || rdt_mon_capable) - static_branch_enable(&rdt_enable_key); + static_branch_enable_cpuslocked(&rdt_enable_key); if (is_mbm_enabled()) { r = &rdt_resources_all[RDT_RESOURCE_L3]; @@ -1157,6 +1158,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, cdp_disable(); out: mutex_unlock(&rdtgroup_mutex); + cpus_read_unlock(); return dentry; } @@ -1295,9 +1297,7 @@ static void rmdir_all_sub(void) kfree(rdtgrp); } /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */ - get_online_cpus(); update_closid_rmid(cpu_online_mask, &rdtgroup_default); - put_online_cpus(); kernfs_remove(kn_info); kernfs_remove(kn_mongrp); @@ -1308,6 +1308,7 @@ static void rdt_kill_sb(struct super_block *sb) { struct rdt_resource *r; + cpus_read_lock(); mutex_lock(&rdtgroup_mutex); /*Put everything back to default values. */ @@ -1315,11 +1316,12 @@ static void rdt_kill_sb(struct super_block *sb) reset_all_ctrls(r); cdp_disable(); rmdir_all_sub(); - static_branch_disable(&rdt_alloc_enable_key); - static_branch_disable(&rdt_mon_enable_key); - static_branch_disable(&rdt_enable_key); + static_branch_disable_cpuslocked(&rdt_alloc_enable_key); + static_branch_disable_cpuslocked(&rdt_mon_enable_key); + static_branch_disable_cpuslocked(&rdt_enable_key); kernfs_kill_sb(sb); mutex_unlock(&rdtgroup_mutex); + cpus_read_unlock(); } static struct file_system_type rdt_fs_type = { diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 87cc9ab7a13cd..4b8187639c2df 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -245,6 +245,9 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc if (m->status & MCI_STATUS_UC) { + if (ctx == IN_KERNEL) + return MCE_PANIC_SEVERITY; + /* * On older systems where overflow_recov flag is not present, we * should simply panic if an error overflow occurs. If @@ -255,10 +258,6 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc if (mce_flags.smca) return mce_severity_amd_smca(m, ctx); - /* software can try to contain */ - if (!(m->mcgstatus & MCG_STATUS_RIPV) && (ctx == IN_KERNEL)) - return MCE_PANIC_SEVERITY; - /* kill current process */ return MCE_AR_SEVERITY; } else { diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 3b413065c6130..a9e898b71208f 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1788,6 +1788,11 @@ static void unexpected_machine_check(struct pt_regs *regs, long error_code) void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; +dotraplinkage void do_mce(struct pt_regs *regs, long error_code) +{ + machine_check_vector(regs, error_code); +} + /* * Called for each booted CPU to set up machine checks. * Must be called with preempt off: diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index c6daec4bdba5b..330b8462d426f 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -470,6 +470,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 #define F16H_MPB_MAX_SIZE 3458 +#define F17H_MPB_MAX_SIZE 3200 switch (family) { case 0x14: @@ -481,6 +482,9 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, case 0x16: max_size = F16H_MPB_MAX_SIZE; break; + case 0x17: + max_size = F17H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break; diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index c4fa4a85d4cb6..e4fc595cd6eaa 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -239,7 +239,7 @@ static int __init save_microcode_in_initrd(void) break; case X86_VENDOR_AMD: if (c->x86 >= 0x10) - return save_microcode_in_initrd_amd(cpuid_eax(1)); + ret = save_microcode_in_initrd_amd(cpuid_eax(1)); break; default: break; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 7dbcb7adf7975..f7c55b0e753ad 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -45,6 +45,9 @@ static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin"; /* Current microcode patch used in early patching on the APs. */ static struct microcode_intel *intel_ucode_patch; +/* last level cache size per core */ +static int llc_size_per_core; + static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1, unsigned int s2, unsigned int p2) { @@ -565,15 +568,6 @@ static void print_ucode(struct ucode_cpu_info *uci) } #else -/* - * Flush global tlb. We only do this in x86_64 where paging has been enabled - * already and PGE should be enabled as well. - */ -static inline void flush_tlb_early(void) -{ - __native_flush_tlb_global_irq_disabled(); -} - static inline void print_ucode(struct ucode_cpu_info *uci) { struct microcode_intel *mc; @@ -602,10 +596,6 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) if (rev != mc->hdr.rev) return -1; -#ifdef CONFIG_X86_64 - /* Flush global tlb. This is precaution. */ - flush_tlb_early(); -#endif uci->cpu_sig.rev = rev; if (early) @@ -923,8 +913,19 @@ static bool is_blacklisted(unsigned int cpu) { struct cpuinfo_x86 *c = &cpu_data(cpu); - if (c->x86 == 6 && c->x86_model == INTEL_FAM6_BROADWELL_X) { - pr_err_once("late loading on model 79 is disabled.\n"); + /* + * Late loading on model 79 with microcode revision less than 0x0b000021 + * and LLC size per core bigger than 2.5MB may result in a system hang. + * This behavior is documented in item BDF90, #334165 (Intel Xeon + * Processor E7-8800/4800 v4 Product Family). + */ + if (c->x86 == 6 && + c->x86_model == INTEL_FAM6_BROADWELL_X && + c->x86_mask == 0x01 && + llc_size_per_core > 2621440 && + c->microcode < 0x0b000021) { + pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); + pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); return true; } @@ -979,6 +980,15 @@ static struct microcode_ops microcode_intel_ops = { .apply_microcode = apply_microcode_intel, }; +static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c) +{ + u64 llc_size = c->x86_cache_size * 1024; + + do_div(llc_size, c->x86_max_cores); + + return (int)llc_size; +} + struct microcode_ops * __init init_intel_microcode(void) { struct cpuinfo_x86 *c = &boot_cpu_data; @@ -989,5 +999,7 @@ struct microcode_ops * __init init_intel_microcode(void) return NULL; } + llc_size_per_core = calc_llc_size_per_core(c); + return µcode_intel_ops; } diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 236324e83a3ae..85eb5fc180c81 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -254,9 +254,9 @@ static void __init ms_hyperv_init_platform(void) #endif } -const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { +const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = { .name = "Microsoft Hyper-V", .detect = ms_hyperv_platform, - .init_platform = ms_hyperv_init_platform, + .type = X86_HYPER_MS_HYPERV, + .init.init_platform = ms_hyperv_init_platform, }; -EXPORT_SYMBOL(x86_hyper_ms_hyperv); diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index 6b7e17bf0b71d..e7ecedafa1c8f 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -5,6 +5,8 @@ #include #include +#include "cpu.h" + /* * Get CPU information for use by the procfs. */ @@ -78,8 +80,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "microcode\t: 0x%x\n", c->microcode); if (cpu_has(c, X86_FEATURE_TSC)) { - unsigned int freq = cpufreq_quick_get(cpu); + unsigned int freq = aperfmperf_get_khz(cpu); + if (!freq) + freq = cpufreq_quick_get(cpu); if (!freq) freq = cpu_khz; seq_printf(m, "cpu MHz\t\t: %u.%03u\n", diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 05459ad3db46e..d0e69769abfd3 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -21,7 +21,6 @@ struct cpuid_bit { static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 }, { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, - { X86_FEATURE_INTEL_PT, CPUID_EBX, 25, 0x00000007, 0 }, { X86_FEATURE_AVX512_4VNNIW, CPUID_EDX, 2, 0x00000007, 0 }, { X86_FEATURE_AVX512_4FMAPS, CPUID_EDX, 3, 0x00000007, 0 }, { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 40ed26852ebd9..8e005329648b6 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -205,10 +205,10 @@ static bool __init vmware_legacy_x2apic_available(void) (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0; } -const __refconst struct hypervisor_x86 x86_hyper_vmware = { +const __initconst struct hypervisor_x86 x86_hyper_vmware = { .name = "VMware", .detect = vmware_platform, - .init_platform = vmware_platform_setup, - .x2apic_available = vmware_legacy_x2apic_available, + .type = X86_HYPER_VMWARE, + .init.init_platform = vmware_platform_setup, + .init.x2apic_available = vmware_legacy_x2apic_available, }; -EXPORT_SYMBOL(x86_hyper_vmware); diff --git a/arch/x86/kernel/doublefault.c b/arch/x86/kernel/doublefault.c index 0e662c55ae902..0b8cedb20d6d9 100644 --- a/arch/x86/kernel/doublefault.c +++ b/arch/x86/kernel/doublefault.c @@ -50,25 +50,23 @@ static void doublefault_fn(void) cpu_relax(); } -struct tss_struct doublefault_tss __cacheline_aligned = { - .x86_tss = { - .sp0 = STACK_START, - .ss0 = __KERNEL_DS, - .ldt = 0, - .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, - - .ip = (unsigned long) doublefault_fn, - /* 0x2 bit is always set */ - .flags = X86_EFLAGS_SF | 0x2, - .sp = STACK_START, - .es = __USER_DS, - .cs = __KERNEL_CS, - .ss = __KERNEL_DS, - .ds = __USER_DS, - .fs = __KERNEL_PERCPU, - - .__cr3 = __pa_nodebug(swapper_pg_dir), - } +struct x86_hw_tss doublefault_tss __cacheline_aligned = { + .sp0 = STACK_START, + .ss0 = __KERNEL_DS, + .ldt = 0, + .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, + + .ip = (unsigned long) doublefault_fn, + /* 0x2 bit is always set */ + .flags = X86_EFLAGS_SF | 0x2, + .sp = STACK_START, + .es = __USER_DS, + .cs = __KERNEL_CS, + .ss = __KERNEL_DS, + .ds = __USER_DS, + .fs = __KERNEL_PERCPU, + + .__cr3 = __pa_nodebug(swapper_pg_dir), }; /* dummy for do_double_fault() call */ diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index f13b4c00a5de4..afbecff161d16 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -43,6 +44,24 @@ bool in_task_stack(unsigned long *stack, struct task_struct *task, return true; } +bool in_entry_stack(unsigned long *stack, struct stack_info *info) +{ + struct entry_stack *ss = cpu_entry_stack(smp_processor_id()); + + void *begin = ss; + void *end = ss + 1; + + if ((void *)stack < begin || (void *)stack >= end) + return false; + + info->type = STACK_TYPE_ENTRY; + info->begin = begin; + info->end = end; + info->next_sp = NULL; + + return true; +} + static void printk_stack_address(unsigned long address, int reliable, char *log_lvl) { @@ -50,6 +69,39 @@ static void printk_stack_address(unsigned long address, int reliable, printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); } +void show_iret_regs(struct pt_regs *regs) +{ + printk(KERN_DEFAULT "RIP: %04x:%pS\n", (int)regs->cs, (void *)regs->ip); + printk(KERN_DEFAULT "RSP: %04x:%016lx EFLAGS: %08lx", (int)regs->ss, + regs->sp, regs->flags); +} + +static void show_regs_if_on_stack(struct stack_info *info, struct pt_regs *regs, + bool partial) +{ + /* + * These on_stack() checks aren't strictly necessary: the unwind code + * has already validated the 'regs' pointer. The checks are done for + * ordering reasons: if the registers are on the next stack, we don't + * want to print them out yet. Otherwise they'll be shown as part of + * the wrong stack. Later, when show_trace_log_lvl() switches to the + * next stack, this function will be called again with the same regs so + * they can be printed in the right context. + */ + if (!partial && on_stack(info, regs, sizeof(*regs))) { + __show_regs(regs, 0); + + } else if (partial && on_stack(info, (void *)regs + IRET_FRAME_OFFSET, + IRET_FRAME_SIZE)) { + /* + * When an interrupt or exception occurs in entry code, the + * full pt_regs might not have been saved yet. In that case + * just print the iret frame. + */ + show_iret_regs(regs); + } +} + void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, char *log_lvl) { @@ -57,11 +109,13 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, struct stack_info stack_info = {0}; unsigned long visit_mask = 0; int graph_idx = 0; + bool partial; printk("%sCall Trace:\n", log_lvl); unwind_start(&state, task, regs, stack); stack = stack ? : get_stack_pointer(task, regs); + regs = unwind_get_entry_regs(&state, &partial); /* * Iterate through the stacks, starting with the current stack pointer. @@ -71,31 +125,35 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, * - task stack * - interrupt stack * - HW exception stacks (double fault, nmi, debug, mce) + * - entry stack * - * x86-32 can have up to three stacks: + * x86-32 can have up to four stacks: * - task stack * - softirq stack * - hardirq stack + * - entry stack */ - for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { + for ( ; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { const char *stack_name; - /* - * If we overflowed the task stack into a guard page, jump back - * to the bottom of the usable stack. - */ - if (task_stack_page(task) - (void *)stack < PAGE_SIZE) - stack = task_stack_page(task); - - if (get_stack_info(stack, task, &stack_info, &visit_mask)) - break; + if (get_stack_info(stack, task, &stack_info, &visit_mask)) { + /* + * We weren't on a valid stack. It's possible that + * we overflowed a valid stack into a guard page. + * See if the next page up is valid so that we can + * generate some kind of backtrace if this happens. + */ + stack = (unsigned long *)PAGE_ALIGN((unsigned long)stack); + if (get_stack_info(stack, task, &stack_info, &visit_mask)) + break; + } stack_name = stack_type_name(stack_info.type); if (stack_name) printk("%s <%s>\n", log_lvl, stack_name); - if (regs && on_stack(&stack_info, regs, sizeof(*regs))) - __show_regs(regs, 0); + if (regs) + show_regs_if_on_stack(&stack_info, regs, partial); /* * Scan the stack, printing any text addresses we find. At the @@ -119,7 +177,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, /* * Don't print regs->ip again if it was already printed - * by __show_regs() below. + * by show_regs_if_on_stack(). */ if (regs && stack == ®s->ip) goto next; @@ -154,9 +212,9 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, unwind_next_frame(&state); /* if the frame has entry regs, print them */ - regs = unwind_get_entry_regs(&state); - if (regs && on_stack(&stack_info, regs, sizeof(*regs))) - __show_regs(regs, 0); + regs = unwind_get_entry_regs(&state, &partial); + if (regs) + show_regs_if_on_stack(&stack_info, regs, partial); } if (stack_name) @@ -252,11 +310,13 @@ int __die(const char *str, struct pt_regs *regs, long err) unsigned long sp; #endif printk(KERN_DEFAULT - "%s: %04lx [#%d]%s%s%s%s\n", str, err & 0xffff, ++die_counter, + "%s: %04lx [#%d]%s%s%s%s%s\n", str, err & 0xffff, ++die_counter, IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "", IS_ENABLED(CONFIG_SMP) ? " SMP" : "", debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", - IS_ENABLED(CONFIG_KASAN) ? " KASAN" : ""); + IS_ENABLED(CONFIG_KASAN) ? " KASAN" : "", + IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION) ? + (boot_cpu_has(X86_FEATURE_PTI) ? " PTI" : " NOPTI") : ""); if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index daefae83a3aa8..04170f63e3a1d 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -26,6 +26,9 @@ const char *stack_type_name(enum stack_type type) if (type == STACK_TYPE_SOFTIRQ) return "SOFTIRQ"; + if (type == STACK_TYPE_ENTRY) + return "ENTRY_TRAMPOLINE"; + return NULL; } @@ -93,6 +96,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, if (task != current) goto unknown; + if (in_entry_stack(stack, info)) + goto recursion_check; + if (in_hardirq_stack(stack, info)) goto recursion_check; diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 88ce2ffdb1103..563e28d14f2ca 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -37,6 +37,15 @@ const char *stack_type_name(enum stack_type type) if (type == STACK_TYPE_IRQ) return "IRQ"; + if (type == STACK_TYPE_ENTRY) { + /* + * On 64-bit, we have a generic entry stack that we + * use for all the kernel entry points, including + * SYSENTER. + */ + return "ENTRY_TRAMPOLINE"; + } + if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST) return exception_stack_names[type - STACK_TYPE_EXCEPTION]; @@ -115,6 +124,9 @@ int get_stack_info(unsigned long *stack, struct task_struct *task, if (in_irq_stack(stack, info)) goto recursion_check; + if (in_entry_stack(stack, info)) + goto recursion_check; + goto unknown; recursion_check: diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 7affb7e3d9a5b..6abd83572b016 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -249,6 +249,10 @@ static void __init fpu__init_system_ctx_switch(void) */ static void __init fpu__init_parse_early_param(void) { + char arg[32]; + char *argptr = arg; + int bit; + if (cmdline_find_option_bool(boot_command_line, "no387")) setup_clear_cpu_cap(X86_FEATURE_FPU); @@ -266,6 +270,13 @@ static void __init fpu__init_parse_early_param(void) if (cmdline_find_option_bool(boot_command_line, "noxsaves")) setup_clear_cpu_cap(X86_FEATURE_XSAVES); + + if (cmdline_find_option(boot_command_line, "clearcpuid", arg, + sizeof(arg)) && + get_option(&argptr, &bit) && + bit >= 0 && + bit < NCAPINTS * 32) + setup_clear_cpu_cap(bit); } /* diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index f1d5476c90220..87a57b7642d36 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -15,6 +15,7 @@ #include #include +#include /* * Although we spell it out in here, the Processor Trace @@ -36,6 +37,19 @@ static const char *xfeature_names[] = "unknown xstate feature" , }; +static short xsave_cpuid_features[] __initdata = { + X86_FEATURE_FPU, + X86_FEATURE_XMM, + X86_FEATURE_AVX, + X86_FEATURE_MPX, + X86_FEATURE_MPX, + X86_FEATURE_AVX512F, + X86_FEATURE_AVX512F, + X86_FEATURE_AVX512F, + X86_FEATURE_INTEL_PT, + X86_FEATURE_PKU, +}; + /* * Mask of xstate features supported by the CPU and the kernel: */ @@ -59,26 +73,6 @@ unsigned int fpu_user_xstate_size; void fpu__xstate_clear_all_cpu_caps(void) { setup_clear_cpu_cap(X86_FEATURE_XSAVE); - setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); - setup_clear_cpu_cap(X86_FEATURE_XSAVEC); - setup_clear_cpu_cap(X86_FEATURE_XSAVES); - setup_clear_cpu_cap(X86_FEATURE_AVX); - setup_clear_cpu_cap(X86_FEATURE_AVX2); - setup_clear_cpu_cap(X86_FEATURE_AVX512F); - setup_clear_cpu_cap(X86_FEATURE_AVX512IFMA); - setup_clear_cpu_cap(X86_FEATURE_AVX512PF); - setup_clear_cpu_cap(X86_FEATURE_AVX512ER); - setup_clear_cpu_cap(X86_FEATURE_AVX512CD); - setup_clear_cpu_cap(X86_FEATURE_AVX512DQ); - setup_clear_cpu_cap(X86_FEATURE_AVX512BW); - setup_clear_cpu_cap(X86_FEATURE_AVX512VL); - setup_clear_cpu_cap(X86_FEATURE_MPX); - setup_clear_cpu_cap(X86_FEATURE_XGETBV1); - setup_clear_cpu_cap(X86_FEATURE_AVX512VBMI); - setup_clear_cpu_cap(X86_FEATURE_PKU); - setup_clear_cpu_cap(X86_FEATURE_AVX512_4VNNIW); - setup_clear_cpu_cap(X86_FEATURE_AVX512_4FMAPS); - setup_clear_cpu_cap(X86_FEATURE_AVX512_VPOPCNTDQ); } /* @@ -726,6 +720,7 @@ void __init fpu__init_system_xstate(void) unsigned int eax, ebx, ecx, edx; static int on_boot_cpu __initdata = 1; int err; + int i; WARN_ON_FPU(!on_boot_cpu); on_boot_cpu = 0; @@ -759,6 +754,14 @@ void __init fpu__init_system_xstate(void) goto out_disable; } + /* + * Clear XSAVE features that are disabled in the normal CPUID. + */ + for (i = 0; i < ARRAY_SIZE(xsave_cpuid_features); i++) { + if (!boot_cpu_has(xsave_cpuid_features[i])) + xfeatures_mask &= ~BIT(i); + } + xfeatures_mask &= fpu__get_supported_xfeatures_mask(); /* Enable xstate instructions to be able to continue with initialization: */ diff --git a/arch/x86/kernel/ftrace_32.S b/arch/x86/kernel/ftrace_32.S index b6c6468e10bc9..4c8440de33559 100644 --- a/arch/x86/kernel/ftrace_32.S +++ b/arch/x86/kernel/ftrace_32.S @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef CC_USING_FENTRY # define function_hook __fentry__ @@ -197,7 +198,8 @@ ftrace_stub: movl 0x4(%ebp), %edx subl $MCOUNT_INSN_SIZE, %eax - call *ftrace_trace_function + movl ftrace_trace_function, %ecx + CALL_NOSPEC %ecx popl %edx popl %ecx @@ -241,5 +243,5 @@ return_to_handler: movl %eax, %ecx popl %edx popl %eax - jmp *%ecx + JMP_NOSPEC %ecx #endif diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S index c832291d948a6..7cb8ba08beb99 100644 --- a/arch/x86/kernel/ftrace_64.S +++ b/arch/x86/kernel/ftrace_64.S @@ -7,7 +7,7 @@ #include #include #include - +#include .code64 .section .entry.text, "ax" @@ -286,8 +286,8 @@ trace: * ip and parent ip are used and the list function is called when * function tracing is enabled. */ - call *ftrace_trace_function - + movq ftrace_trace_function, %r8 + CALL_NOSPEC %r8 restore_mcount_regs jmp fgraph_trace @@ -329,5 +329,5 @@ GLOBAL(return_to_handler) movq 8(%rsp), %rdx movq (%rsp), %rax addq $24, %rsp - jmp *%rdi + JMP_NOSPEC %rdi #endif diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 6a5d757b9cfdc..7ba5d819ebe3b 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -157,8 +157,8 @@ unsigned long __head __startup_64(unsigned long physaddr, p = fixup_pointer(&phys_base, physaddr); *p += load_delta - sme_get_me_mask(); - /* Encrypt the kernel (if SME is active) */ - sme_encrypt_kernel(); + /* Encrypt the kernel and related (if SME is active) */ + sme_encrypt_kernel(bp); /* * Return the SME encryption mask (if SME is active) to be used as a diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index f1d528bb66a6c..c29020907886a 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -212,9 +212,6 @@ ENTRY(startup_32_smp) #endif .Ldefault_entry: -#define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \ - X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \ - X86_CR0_PG) movl $(CR0_STATE & ~X86_CR0_PG),%eax movl %eax,%cr0 @@ -402,7 +399,7 @@ ENTRY(early_idt_handler_array) # 24(%rsp) error code i = 0 .rept NUM_EXCEPTION_VECTORS - .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 + .if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0 pushl $0 # Dummy error code, to make stack frame uniform .endif pushl $i # 20(%esp) Vector number diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 6dde3f3fc1f8e..04a625f0fcda3 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -38,11 +38,12 @@ * */ -#define p4d_index(x) (((x) >> P4D_SHIFT) & (PTRS_PER_P4D-1)) #define pud_index(x) (((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) +#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH) PGD_PAGE_OFFSET = pgd_index(__PAGE_OFFSET_BASE) PGD_START_KERNEL = pgd_index(__START_KERNEL_map) +#endif L3_START_KERNEL = pud_index(__START_KERNEL_map) .text @@ -50,6 +51,7 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map) .code64 .globl startup_64 startup_64: + UNWIND_HINT_EMPTY /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, * and someone has loaded an identity mapped page table @@ -89,6 +91,7 @@ startup_64: addq $(early_top_pgt - __START_KERNEL_map), %rax jmp 1f ENTRY(secondary_startup_64) + UNWIND_HINT_EMPTY /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, * and someone has loaded a mapped page table. @@ -133,6 +136,7 @@ ENTRY(secondary_startup_64) movq $1f, %rax jmp *%rax 1: + UNWIND_HINT_EMPTY /* Check if nx is implemented */ movl $0x80000001, %eax @@ -150,9 +154,6 @@ ENTRY(secondary_startup_64) 1: wrmsr /* Make changes effective */ /* Setup cr0 */ -#define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \ - X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \ - X86_CR0_PG) movl $CR0_STATE, %eax /* Make changes effective */ movq %rax, %cr0 @@ -235,7 +236,7 @@ ENTRY(secondary_startup_64) pushq %rax # target address in negative space lretq .Lafter_lret: -ENDPROC(secondary_startup_64) +END(secondary_startup_64) #include "verify_cpu.S" @@ -247,6 +248,7 @@ ENDPROC(secondary_startup_64) */ ENTRY(start_cpu0) movq initial_stack(%rip), %rsp + UNWIND_HINT_EMPTY jmp .Ljump_to_C_code ENDPROC(start_cpu0) #endif @@ -266,26 +268,24 @@ ENDPROC(start_cpu0) .quad init_thread_union + THREAD_SIZE - SIZEOF_PTREGS __FINITDATA -bad_address: - jmp bad_address - __INIT ENTRY(early_idt_handler_array) - # 104(%rsp) %rflags - # 96(%rsp) %cs - # 88(%rsp) %rip - # 80(%rsp) error code i = 0 .rept NUM_EXCEPTION_VECTORS - .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 - pushq $0 # Dummy error code, to make stack frame uniform + .if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0 + UNWIND_HINT_IRET_REGS + pushq $0 # Dummy error code, to make stack frame uniform + .else + UNWIND_HINT_IRET_REGS offset=8 .endif pushq $i # 72(%rsp) Vector number jmp early_idt_handler_common + UNWIND_HINT_IRET_REGS i = i + 1 .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc .endr -ENDPROC(early_idt_handler_array) + UNWIND_HINT_IRET_REGS offset=16 +END(early_idt_handler_array) early_idt_handler_common: /* @@ -313,6 +313,7 @@ early_idt_handler_common: pushq %r13 /* pt_regs->r13 */ pushq %r14 /* pt_regs->r14 */ pushq %r15 /* pt_regs->r15 */ + UNWIND_HINT_REGS cmpq $14,%rsi /* Page fault? */ jnz 10f @@ -327,8 +328,8 @@ early_idt_handler_common: 20: decl early_recursion_flag(%rip) - jmp restore_regs_and_iret -ENDPROC(early_idt_handler_common) + jmp restore_regs_and_return_to_kernel +END(early_idt_handler_common) __INITDATA @@ -340,6 +341,27 @@ GLOBAL(early_recursion_flag) .balign PAGE_SIZE; \ GLOBAL(name) +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * Each PGD needs to be 8k long and 8k aligned. We do not + * ever go out to userspace with these, so we do not + * strictly *need* the second page, but this allows us to + * have a single set_pgd() implementation that does not + * need to worry about whether it has 4k or 8k to work + * with. + * + * This ensures PGDs are 8k long: + */ +#define PTI_USER_PGD_FILL 512 +/* This ensures they are 8k-aligned: */ +#define NEXT_PGD_PAGE(name) \ + .balign 2 * PAGE_SIZE; \ +GLOBAL(name) +#else +#define NEXT_PGD_PAGE(name) NEXT_PAGE(name) +#define PTI_USER_PGD_FILL 0 +#endif + /* Automate the creation of 1 to 1 mapping pmd entries */ #define PMDS(START, PERM, COUNT) \ i = 0 ; \ @@ -349,30 +371,29 @@ GLOBAL(name) .endr __INITDATA -NEXT_PAGE(early_top_pgt) +NEXT_PGD_PAGE(early_top_pgt) .fill 511,8,0 #ifdef CONFIG_X86_5LEVEL .quad level4_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC #else .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC #endif + .fill PTI_USER_PGD_FILL,8,0 NEXT_PAGE(early_dynamic_pgts) .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0 .data -#ifndef CONFIG_XEN -NEXT_PAGE(init_top_pgt) - .fill 512,8,0 -#else -NEXT_PAGE(init_top_pgt) +#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH) +NEXT_PGD_PAGE(init_top_pgt) .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC .org init_top_pgt + PGD_PAGE_OFFSET*8, 0 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC .org init_top_pgt + PGD_START_KERNEL*8, 0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC + .fill PTI_USER_PGD_FILL,8,0 NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC @@ -382,6 +403,10 @@ NEXT_PAGE(level2_ident_pgt) * Don't set NX because code runs from these pages. */ PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD) +#else +NEXT_PGD_PAGE(init_top_pgt) + .fill 512,8,0 + .fill PTI_USER_PGD_FILL,8,0 #endif #ifdef CONFIG_X86_5LEVEL @@ -435,7 +460,7 @@ ENTRY(phys_base) EXPORT_SYMBOL(phys_base) #include "../../x86/xen/xen-head.S" - + __PAGE_ALIGNED_BSS NEXT_PAGE(empty_zero_page) .skip PAGE_SIZE diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 014cb2fc47fff..236917bac5f23 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -56,7 +56,7 @@ struct idt_data { * Early traps running on the DEFAULT_STACK because the other interrupt * stacks work only after cpu_init(). */ -static const __initdata struct idt_data early_idts[] = { +static const __initconst struct idt_data early_idts[] = { INTG(X86_TRAP_DB, debug), SYSG(X86_TRAP_BP, int3), #ifdef CONFIG_X86_32 @@ -70,7 +70,7 @@ static const __initdata struct idt_data early_idts[] = { * the traps which use them are reinitialized with IST after cpu_init() has * set up TSS. */ -static const __initdata struct idt_data def_idts[] = { +static const __initconst struct idt_data def_idts[] = { INTG(X86_TRAP_DE, divide_error), INTG(X86_TRAP_NMI, nmi), INTG(X86_TRAP_BR, bounds), @@ -108,7 +108,7 @@ static const __initdata struct idt_data def_idts[] = { /* * The APIC and SMP idt entries */ -static const __initdata struct idt_data apic_idts[] = { +static const __initconst struct idt_data apic_idts[] = { #ifdef CONFIG_SMP INTG(RESCHEDULE_VECTOR, reschedule_interrupt), INTG(CALL_FUNCTION_VECTOR, call_function_interrupt), @@ -150,7 +150,7 @@ static const __initdata struct idt_data apic_idts[] = { * Early traps running on the DEFAULT_STACK because the other interrupt * stacks work only after cpu_init(). */ -static const __initdata struct idt_data early_pf_idts[] = { +static const __initconst struct idt_data early_pf_idts[] = { INTG(X86_TRAP_PF, page_fault), }; @@ -158,7 +158,7 @@ static const __initdata struct idt_data early_pf_idts[] = { * Override for the debug_idt. Same as the default, but with interrupt * stack set to DEFAULT_STACK (0). Required for NMI trap handling. */ -static const __initdata struct idt_data dbg_idts[] = { +static const __initconst struct idt_data dbg_idts[] = { INTG(X86_TRAP_DB, debug), INTG(X86_TRAP_BP, int3), }; @@ -180,7 +180,7 @@ gate_desc debug_idt_table[IDT_ENTRIES] __page_aligned_bss; * The exceptions which use Interrupt stacks. They are setup after * cpu_init() when the TSS has been initialized. */ -static const __initdata struct idt_data ist_idts[] = { +static const __initconst struct idt_data ist_idts[] = { ISTG(X86_TRAP_DB, debug, DEBUG_STACK), ISTG(X86_TRAP_NMI, nmi, NMI_STACK), SISTG(X86_TRAP_BP, int3, DEBUG_STACK), diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 3feb648781c47..2f723301eb58f 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -67,7 +67,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) * because the ->io_bitmap_max value must match the bitmap * contents: */ - tss = &per_cpu(cpu_tss, get_cpu()); + tss = &per_cpu(cpu_tss_rw, get_cpu()); if (turn_on) bitmap_clear(t->io_bitmap_ptr, from, num); diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 52089c043160b..aa9d51eea9d0e 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -219,18 +219,6 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; - /* - * NB: Unlike exception entries, IRQ entries do not reliably - * handle context tracking in the low-level entry code. This is - * because syscall entries execute briefly with IRQs on before - * updating context tracking state, so we can take an IRQ from - * kernel mode with CONTEXT_USER. The low-level entry code only - * updates the context if we came from user mode, so we won't - * switch to CONTEXT_KERNEL. We'll fix that once the syscall - * code is cleaned up enough that we can cleanly defer enabling - * IRQs. - */ - entering_irq(); /* entering_irq() tells RCU that we're not quiescent. Check it. */ diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index a83b3346a0e10..c1bdbd3d3232c 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -20,6 +20,7 @@ #include #include +#include #ifdef CONFIG_DEBUG_STACKOVERFLOW @@ -55,11 +56,11 @@ DEFINE_PER_CPU(struct irq_stack *, softirq_stack); static void call_on_stack(void *func, void *stack) { asm volatile("xchgl %%ebx,%%esp \n" - "call *%%edi \n" + CALL_NOSPEC "movl %%ebx,%%esp \n" : "=b" (stack) : "0" (stack), - "D"(func) + [thunk_target] "D"(func) : "memory", "cc", "edx", "ecx", "eax"); } @@ -95,11 +96,11 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) call_on_stack(print_stack_overflow, isp); asm volatile("xchgl %%ebx,%%esp \n" - "call *%%edi \n" + CALL_NOSPEC "movl %%ebx,%%esp \n" : "=a" (arg1), "=b" (isp) : "0" (desc), "1" (isp), - "D" (desc->handle_irq) + [thunk_target] "D" (desc->handle_irq) : "memory", "cc", "ecx"); return 1; } diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index 020efbf5786b3..d86e344f5b3de 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -57,10 +57,10 @@ static inline void stack_overflow_check(struct pt_regs *regs) if (regs->sp >= estack_top && regs->sp <= estack_bottom) return; - WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx)\n", + WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx,ip:%pF)\n", current->comm, curbase, regs->sp, irq_stack_top, irq_stack_bottom, - estack_top, estack_bottom); + estack_top, estack_bottom, (void *)regs->ip); if (sysctl_panic_on_stackoverflow) panic("low stack detected by irq handler - check messages\n"); diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c index 041f7b6dfa0fe..bcfee4f69b0e5 100644 --- a/arch/x86/kernel/kprobes/ftrace.c +++ b/arch/x86/kernel/kprobes/ftrace.c @@ -26,7 +26,7 @@ #include "common.h" static nokprobe_inline -int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, +void __skip_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, unsigned long orig_ip) { /* @@ -41,20 +41,21 @@ int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, __this_cpu_write(current_kprobe, NULL); if (orig_ip) regs->ip = orig_ip; - return 1; } int skip_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - if (kprobe_ftrace(p)) - return __skip_singlestep(p, regs, kcb, 0); - else - return 0; + if (kprobe_ftrace(p)) { + __skip_singlestep(p, regs, kcb, 0); + preempt_enable_no_resched(); + return 1; + } + return 0; } NOKPROBE_SYMBOL(skip_singlestep); -/* Ftrace callback handler for kprobes */ +/* Ftrace callback handler for kprobes -- called under preepmt disabed */ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { @@ -77,13 +78,17 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ regs->ip = ip + sizeof(kprobe_opcode_t); + /* To emulate trap based kprobes, preempt_disable here */ + preempt_disable(); __this_cpu_write(current_kprobe, p); kcb->kprobe_status = KPROBE_HIT_ACTIVE; - if (!p->pre_handler || !p->pre_handler(p, regs)) + if (!p->pre_handler || !p->pre_handler(p, regs)) { __skip_singlestep(p, regs, kcb, orig_ip); + preempt_enable_no_resched(); + } /* * If pre_handler returns !0, it sets regs->ip and - * resets current kprobe. + * resets current kprobe, and keep preempt count +1. */ } end: diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 4f98aad382378..3668f28cf5fc7 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "common.h" @@ -205,7 +206,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src) } /* Check whether insn is indirect jump */ -static int insn_is_indirect_jump(struct insn *insn) +static int __insn_is_indirect_jump(struct insn *insn) { return ((insn->opcode.bytes[0] == 0xff && (X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */ @@ -239,6 +240,26 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len) return (start <= target && target <= start + len); } +static int insn_is_indirect_jump(struct insn *insn) +{ + int ret = __insn_is_indirect_jump(insn); + +#ifdef CONFIG_RETPOLINE + /* + * Jump to x86_indirect_thunk_* is treated as an indirect jump. + * Note that even with CONFIG_RETPOLINE=y, the kernel compiled with + * older gcc may use indirect jump. So we add this check instead of + * replace indirect-jump check. + */ + if (!ret) + ret = insn_jump_into_range(insn, + (unsigned long)__indirect_thunk_start, + (unsigned long)__indirect_thunk_end - + (unsigned long)__indirect_thunk_start); +#endif + return ret; +} + /* Decode whole function to ensure any instructions don't jump into target */ static int can_optimize(unsigned long paddr) { diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 8bb9594d07616..a94de09edbed2 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -544,12 +544,12 @@ static uint32_t __init kvm_detect(void) return kvm_cpuid_base(); } -const struct hypervisor_x86 x86_hyper_kvm __refconst = { +const __initconst struct hypervisor_x86 x86_hyper_kvm = { .name = "KVM", .detect = kvm_detect, - .x2apic_available = kvm_para_available, + .type = X86_HYPER_KVM, + .init.x2apic_available = kvm_para_available, }; -EXPORT_SYMBOL_GPL(x86_hyper_kvm); static __init int activate_jump_labels(void) { diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 4d17bacf40308..26d713ecad34a 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -5,6 +5,11 @@ * Copyright (C) 2002 Andi Kleen * * This handles calls from both 32bit and 64bit mode. + * + * Lock order: + * contex.ldt_usr_sem + * mmap_sem + * context.lock */ #include @@ -13,11 +18,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -41,17 +48,15 @@ static void refresh_ldt_segments(void) #endif } -/* context.lock is held for us, so we don't need any locking. */ +/* context.lock is held by the task which issued the smp function call */ static void flush_ldt(void *__mm) { struct mm_struct *mm = __mm; - mm_context_t *pc; if (this_cpu_read(cpu_tlbstate.loaded_mm) != mm) return; - pc = &mm->context; - set_ldt(pc->ldt->entries, pc->ldt->nr_entries); + load_mm_ldt(mm); refresh_ldt_segments(); } @@ -88,25 +93,143 @@ static struct ldt_struct *alloc_ldt_struct(unsigned int num_entries) return NULL; } + /* The new LDT isn't aliased for PTI yet. */ + new_ldt->slot = -1; + new_ldt->nr_entries = num_entries; return new_ldt; } +/* + * If PTI is enabled, this maps the LDT into the kernelmode and + * usermode tables for the given mm. + * + * There is no corresponding unmap function. Even if the LDT is freed, we + * leave the PTEs around until the slot is reused or the mm is destroyed. + * This is harmless: the LDT is always in ordinary memory, and no one will + * access the freed slot. + * + * If we wanted to unmap freed LDTs, we'd also need to do a flush to make + * it useful, and the flush would slow down modify_ldt(). + */ +static int +map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + bool is_vmalloc, had_top_level_entry; + unsigned long va; + spinlock_t *ptl; + pgd_t *pgd; + int i; + + if (!static_cpu_has(X86_FEATURE_PTI)) + return 0; + + /* + * Any given ldt_struct should have map_ldt_struct() called at most + * once. + */ + WARN_ON(ldt->slot != -1); + + /* + * Did we already have the top level entry allocated? We can't + * use pgd_none() for this because it doens't do anything on + * 4-level page table kernels. + */ + pgd = pgd_offset(mm, LDT_BASE_ADDR); + had_top_level_entry = (pgd->pgd != 0); + + is_vmalloc = is_vmalloc_addr(ldt->entries); + + for (i = 0; i * PAGE_SIZE < ldt->nr_entries * LDT_ENTRY_SIZE; i++) { + unsigned long offset = i << PAGE_SHIFT; + const void *src = (char *)ldt->entries + offset; + unsigned long pfn; + pte_t pte, *ptep; + + va = (unsigned long)ldt_slot_va(slot) + offset; + pfn = is_vmalloc ? vmalloc_to_pfn(src) : + page_to_pfn(virt_to_page(src)); + /* + * Treat the PTI LDT range as a *userspace* range. + * get_locked_pte() will allocate all needed pagetables + * and account for them in this mm. + */ + ptep = get_locked_pte(mm, va, &ptl); + if (!ptep) + return -ENOMEM; + /* + * Map it RO so the easy to find address is not a primary + * target via some kernel interface which misses a + * permission check. + */ + pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL)); + set_pte_at(mm, va, ptep, pte); + pte_unmap_unlock(ptep, ptl); + } + + if (mm->context.ldt) { + /* + * We already had an LDT. The top-level entry should already + * have been allocated and synchronized with the usermode + * tables. + */ + WARN_ON(!had_top_level_entry); + if (static_cpu_has(X86_FEATURE_PTI)) + WARN_ON(!kernel_to_user_pgdp(pgd)->pgd); + } else { + /* + * This is the first time we're mapping an LDT for this process. + * Sync the pgd to the usermode tables. + */ + WARN_ON(had_top_level_entry); + if (static_cpu_has(X86_FEATURE_PTI)) { + WARN_ON(kernel_to_user_pgdp(pgd)->pgd); + set_pgd(kernel_to_user_pgdp(pgd), *pgd); + } + } + + va = (unsigned long)ldt_slot_va(slot); + flush_tlb_mm_range(mm, va, va + LDT_SLOT_STRIDE, 0); + + ldt->slot = slot; +#endif + return 0; +} + +static void free_ldt_pgtables(struct mm_struct *mm) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + struct mmu_gather tlb; + unsigned long start = LDT_BASE_ADDR; + unsigned long end = start + (1UL << PGDIR_SHIFT); + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + tlb_gather_mmu(&tlb, mm, start, end); + free_pgd_range(&tlb, start, end, start, end); + tlb_finish_mmu(&tlb, start, end); +#endif +} + /* After calling this, the LDT is immutable. */ static void finalize_ldt_struct(struct ldt_struct *ldt) { paravirt_alloc_ldt(ldt->entries, ldt->nr_entries); } -/* context.lock is held */ -static void install_ldt(struct mm_struct *current_mm, - struct ldt_struct *ldt) +static void install_ldt(struct mm_struct *mm, struct ldt_struct *ldt) { - /* Synchronizes with lockless_dereference in load_mm_ldt. */ - smp_store_release(¤t_mm->context.ldt, ldt); + mutex_lock(&mm->context.lock); + + /* Synchronizes with READ_ONCE in load_mm_ldt. */ + smp_store_release(&mm->context.ldt, ldt); + + /* Activate the LDT for all CPUs using currents mm. */ + on_each_cpu_mask(mm_cpumask(mm), flush_ldt, mm, true); - /* Activate the LDT for all CPUs using current_mm. */ - on_each_cpu_mask(mm_cpumask(current_mm), flush_ldt, current_mm, true); + mutex_unlock(&mm->context.lock); } static void free_ldt_struct(struct ldt_struct *ldt) @@ -123,27 +246,20 @@ static void free_ldt_struct(struct ldt_struct *ldt) } /* - * we do not have to muck with descriptors here, that is - * done in switch_mm() as needed. + * Called on fork from arch_dup_mmap(). Just copy the current LDT state, + * the new task is not running, so nothing can be installed. */ -int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm) +int ldt_dup_context(struct mm_struct *old_mm, struct mm_struct *mm) { struct ldt_struct *new_ldt; - struct mm_struct *old_mm; int retval = 0; - mutex_init(&mm->context.lock); - old_mm = current->mm; - if (!old_mm) { - mm->context.ldt = NULL; + if (!old_mm) return 0; - } mutex_lock(&old_mm->context.lock); - if (!old_mm->context.ldt) { - mm->context.ldt = NULL; + if (!old_mm->context.ldt) goto out_unlock; - } new_ldt = alloc_ldt_struct(old_mm->context.ldt->nr_entries); if (!new_ldt) { @@ -155,6 +271,12 @@ int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm) new_ldt->nr_entries * LDT_ENTRY_SIZE); finalize_ldt_struct(new_ldt); + retval = map_ldt_struct(mm, new_ldt, 0); + if (retval) { + free_ldt_pgtables(mm); + free_ldt_struct(new_ldt); + goto out_unlock; + } mm->context.ldt = new_ldt; out_unlock: @@ -173,13 +295,18 @@ void destroy_context_ldt(struct mm_struct *mm) mm->context.ldt = NULL; } +void ldt_arch_exit_mmap(struct mm_struct *mm) +{ + free_ldt_pgtables(mm); +} + static int read_ldt(void __user *ptr, unsigned long bytecount) { struct mm_struct *mm = current->mm; unsigned long entries_size; int retval; - mutex_lock(&mm->context.lock); + down_read(&mm->context.ldt_usr_sem); if (!mm->context.ldt) { retval = 0; @@ -208,7 +335,7 @@ static int read_ldt(void __user *ptr, unsigned long bytecount) retval = bytecount; out_unlock: - mutex_unlock(&mm->context.lock); + up_read(&mm->context.ldt_usr_sem); return retval; } @@ -268,7 +395,8 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) ldt.avl = 0; } - mutex_lock(&mm->context.lock); + if (down_write_killable(&mm->context.ldt_usr_sem)) + return -EINTR; old_ldt = mm->context.ldt; old_nr_entries = old_ldt ? old_ldt->nr_entries : 0; @@ -285,18 +413,37 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) new_ldt->entries[ldt_info.entry_number] = ldt; finalize_ldt_struct(new_ldt); + /* + * If we are using PTI, map the new LDT into the userspace pagetables. + * If there is already an LDT, use the other slot so that other CPUs + * will continue to use the old LDT until install_ldt() switches + * them over to the new LDT. + */ + error = map_ldt_struct(mm, new_ldt, old_ldt ? !old_ldt->slot : 0); + if (error) { + /* + * This only can fail for the first LDT setup. If an LDT is + * already installed then the PTE page is already + * populated. Mop up a half populated page table. + */ + if (!WARN_ON_ONCE(old_ldt)) + free_ldt_pgtables(mm); + free_ldt_struct(new_ldt); + goto out_unlock; + } + install_ldt(mm, new_ldt); free_ldt_struct(old_ldt); error = 0; out_unlock: - mutex_unlock(&mm->context.lock); + up_write(&mm->context.ldt_usr_sem); out: return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, - unsigned long bytecount) +SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , + unsigned long , bytecount) { int ret = -ENOSYS; @@ -314,5 +461,14 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr, ret = write_ldt(ptr, bytecount, 0); break; } - return ret; + /* + * The SYSCALL_DEFINE() macros give us an 'unsigned long' + * return type, but tht ABI for sys_modify_ldt() expects + * 'int'. This cast gives us an int-sized value in %rax + * for the return code. The 'unsigned' is necessary so + * the compiler does not try to sign-extend the negative + * return codes into the high half of the register when + * taking the value from int->long. + */ + return (unsigned int)ret; } diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 00bc751c861ce..edfede7686887 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -48,8 +48,6 @@ static void load_segments(void) "\tmovl $"STR(__KERNEL_DS)",%%eax\n" "\tmovl %%eax,%%ds\n" "\tmovl %%eax,%%es\n" - "\tmovl %%eax,%%fs\n" - "\tmovl %%eax,%%gs\n" "\tmovl %%eax,%%ss\n" : : : "eax", "memory"); #undef STR @@ -232,8 +230,8 @@ void machine_kexec(struct kimage *image) * The gdt & idt are now invalid. * If you want to load them you must set up your own idt & gdt. */ - set_gdt(phys_to_virt(0), 0); idt_invalidate(phys_to_virt(0)); + set_gdt(phys_to_virt(0), 0); /* now call it */ image->start = relocate_kernel_ptr((unsigned long)image->head, diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 410c5dadcee31..3a4b12809ab5f 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -431,6 +431,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) } static unsigned long mpf_base; +static bool mpf_found; static unsigned long __init get_mpc_size(unsigned long physptr) { @@ -504,7 +505,7 @@ void __init default_get_smp_config(unsigned int early) if (!smp_found_config) return; - if (!mpf_base) + if (!mpf_found) return; if (acpi_lapic && early) @@ -593,6 +594,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) smp_found_config = 1; #endif mpf_base = base; + mpf_found = true; pr_info("found SMP MP-table at [mem %#010lx-%#010lx] mapped at [%p]\n", base, base + sizeof(*mpf) - 1, mpf); @@ -858,7 +860,7 @@ static int __init update_mp_table(void) if (!enable_update_mptable) return 0; - if (!mpf_base) + if (!mpf_found) return 0; mpf = early_memremap(mpf_base, sizeof(*mpf)); diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c index ac0be8283325e..9edadabf04f66 100644 --- a/arch/x86/kernel/paravirt_patch_64.c +++ b/arch/x86/kernel/paravirt_patch_64.c @@ -10,7 +10,6 @@ DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax"); DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax"); DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax"); DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3"); -DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)"); DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd"); DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq"); @@ -60,7 +59,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf, PATCH_SITE(pv_mmu_ops, read_cr2); PATCH_SITE(pv_mmu_ops, read_cr3); PATCH_SITE(pv_mmu_ops, write_cr3); - PATCH_SITE(pv_mmu_ops, flush_tlb_single); PATCH_SITE(pv_cpu_ops, wbinvd); #if defined(CONFIG_PARAVIRT_SPINLOCKS) case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock): diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c67685337c5ac..8bd1d8292cf76 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -47,9 +47,25 @@ * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { +__visible DEFINE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw) = { .x86_tss = { - .sp0 = TOP_OF_INIT_STACK, + /* + * .sp0 is only used when entering ring 0 from a lower + * privilege level. Since the init task never runs anything + * but ring 0 code, there is no need for a valid value here. + * Poison it. + */ + .sp0 = (1UL << (BITS_PER_LONG-1)) + 1, + +#ifdef CONFIG_X86_64 + /* + * .sp1 is cpu_current_top_of_stack. The init task never + * runs user code, but cpu_current_top_of_stack should still + * be well defined before the first context switch. + */ + .sp1 = TOP_OF_INIT_STACK, +#endif + #ifdef CONFIG_X86_32 .ss0 = __KERNEL_DS, .ss1 = __KERNEL_CS, @@ -65,11 +81,8 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { */ .io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 }, #endif -#ifdef CONFIG_X86_32 - .SYSENTER_stack_canary = STACK_END_MAGIC, -#endif }; -EXPORT_PER_CPU_SYMBOL(cpu_tss); +EXPORT_PER_CPU_SYMBOL(cpu_tss_rw); DEFINE_PER_CPU(bool, __tss_limit_invalid); EXPORT_PER_CPU_SYMBOL_GPL(__tss_limit_invalid); @@ -98,7 +111,7 @@ void exit_thread(struct task_struct *tsk) struct fpu *fpu = &t->fpu; if (bp) { - struct tss_struct *tss = &per_cpu(cpu_tss, get_cpu()); + struct tss_struct *tss = &per_cpu(cpu_tss_rw, get_cpu()); t->io_bitmap_ptr = NULL; clear_thread_flag(TIF_IO_BITMAP); @@ -367,19 +380,24 @@ void stop_this_cpu(void *dummy) disable_local_APIC(); mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); + /* + * Use wbinvd on processors that support SME. This provides support + * for performing a successful kexec when going from SME inactive + * to SME active (or vice-versa). The cache must be cleared so that + * if there are entries with the same physical address, both with and + * without the encryption bit, they don't race each other when flushed + * and potentially end up with the wrong entry being committed to + * memory. + */ + if (boot_cpu_has(X86_FEATURE_SME)) + native_wbinvd(); for (;;) { /* - * Use wbinvd followed by hlt to stop the processor. This - * provides support for kexec on a processor that supports - * SME. With kexec, going from SME inactive to SME active - * requires clearing cache entries so that addresses without - * the encryption bit set don't corrupt the same physical - * address that has the encryption bit set when caches are - * flushed. To achieve this a wbinvd is performed followed by - * a hlt. Even if the processor is not in the kexec/SME - * scenario this only adds a wbinvd to a halting processor. + * Use native_halt() so that memory contents don't change + * (stack usage and variables) after possibly issuing the + * native_wbinvd() above. */ - asm volatile("wbinvd; hlt" : : : "memory"); + native_halt(); } } diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 11966251cd425..5224c60991841 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -234,7 +234,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct fpu *prev_fpu = &prev->fpu; struct fpu *next_fpu = &next->fpu; int cpu = smp_processor_id(); - struct tss_struct *tss = &per_cpu(cpu_tss, cpu); + struct tss_struct *tss = &per_cpu(cpu_tss_rw, cpu); /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -284,9 +284,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* * Reload esp0 and cpu_current_top_of_stack. This changes - * current_thread_info(). + * current_thread_info(). Refresh the SYSENTER configuration in + * case prev or next is vm86. */ - load_sp0(tss, next); + update_sp0(next_p); + refresh_sysenter_cs(next); this_cpu_write(cpu_current_top_of_stack, (unsigned long)task_stack_page(next_p) + THREAD_SIZE); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 302e7b2572d18..c754662320163 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -69,9 +69,8 @@ void __show_regs(struct pt_regs *regs, int all) unsigned int fsindex, gsindex; unsigned int ds, cs, es; - printk(KERN_DEFAULT "RIP: %04lx:%pS\n", regs->cs, (void *)regs->ip); - printk(KERN_DEFAULT "RSP: %04lx:%016lx EFLAGS: %08lx", regs->ss, - regs->sp, regs->flags); + show_iret_regs(regs); + if (regs->orig_ax != -1) pr_cont(" ORIG_RAX: %016lx\n", regs->orig_ax); else @@ -88,6 +87,9 @@ void __show_regs(struct pt_regs *regs, int all) printk(KERN_DEFAULT "R13: %016lx R14: %016lx R15: %016lx\n", regs->r13, regs->r14, regs->r15); + if (!all) + return; + asm("movl %%ds,%0" : "=r" (ds)); asm("movl %%cs,%0" : "=r" (cs)); asm("movl %%es,%0" : "=r" (es)); @@ -98,9 +100,6 @@ void __show_regs(struct pt_regs *regs, int all) rdmsrl(MSR_GS_BASE, gs); rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); - if (!all) - return; - cr0 = read_cr0(); cr2 = read_cr2(); cr3 = __read_cr3(); @@ -274,7 +273,6 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp, struct inactive_task_frame *frame; struct task_struct *me = current; - p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE; childregs = task_pt_regs(p); fork_frame = container_of(childregs, struct fork_frame, regs); frame = &fork_frame->frame; @@ -401,7 +399,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct fpu *prev_fpu = &prev->fpu; struct fpu *next_fpu = &next->fpu; int cpu = smp_processor_id(); - struct tss_struct *tss = &per_cpu(cpu_tss, cpu); + struct tss_struct *tss = &per_cpu(cpu_tss_rw, cpu); WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_ENTRY) && this_cpu_read(irq_count) != -1); @@ -463,9 +461,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * Switch the PDA and FPU contexts. */ this_cpu_write(current_task, next_p); + this_cpu_write(cpu_current_top_of_stack, task_top_of_stack(next_p)); - /* Reload esp0 and ss1. This changes current_thread_info(). */ - load_sp0(tss, next); + /* Reload sp0. */ + update_sp0(next_p); /* * Now maybe reload the debug registers and handle I/O bitmaps diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 0957dd73d1275..e84cb4c75cd0e 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -376,14 +376,6 @@ static void __init reserve_initrd(void) !ramdisk_image || !ramdisk_size) return; /* No initrd provided by bootloader */ - /* - * If SME is active, this memory will be marked encrypted by the - * kernel when it is accessed (including relocation). However, the - * ramdisk image was loaded decrypted by the bootloader, so make - * sure that it is encrypted before accessing it. - */ - sme_early_encrypt(ramdisk_image, ramdisk_end - ramdisk_image); - initrd_start = 0; mapped_size = memblock_mem_size(max_pfn_mapped); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 65a0ccdc30507..2651ca2112c45 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -128,25 +128,16 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0xa, 0xf); spin_unlock_irqrestore(&rtc_lock, flags); - local_flush_tlb(); - pr_debug("1.\n"); *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = start_eip >> 4; - pr_debug("2.\n"); *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = start_eip & 0xf; - pr_debug("3.\n"); } static inline void smpboot_restore_warm_reset_vector(void) { unsigned long flags; - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - /* * Paranoid: Set warm reset code and vector here back * to default values. @@ -239,7 +230,7 @@ static void notrace start_secondary(void *unused) load_cr3(swapper_pg_dir); __flush_tlb_all(); #endif - + load_current_idt(); cpu_init(); x86_cpuinit.early_percpu_clock_init(); preempt_disable(); @@ -962,8 +953,7 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle) #ifdef CONFIG_X86_32 /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); - per_cpu(cpu_current_top_of_stack, cpu) = - (unsigned long)task_stack_page(idle) + THREAD_SIZE; + per_cpu(cpu_current_top_of_stack, cpu) = task_top_of_stack(idle); #else initial_gs = per_cpu_offset(cpu); #endif @@ -991,12 +981,8 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle, initial_code = (unsigned long)start_secondary; initial_stack = idle->thread.sp; - /* - * Enable the espfix hack for this CPU - */ -#ifdef CONFIG_X86_ESPFIX64 + /* Enable the espfix hack for this CPU */ init_espfix_ap(cpu); -#endif /* So we see what's up */ announce_cpu(cpu, apicid); diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 8dabd7bf16730..60244bfaf88f6 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -98,7 +98,7 @@ static int __save_stack_trace_reliable(struct stack_trace *trace, for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state); unwind_next_frame(&state)) { - regs = unwind_get_entry_regs(&state); + regs = unwind_get_entry_regs(&state, NULL); if (regs) { /* * Kernel mode registers on the stack indicate an diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index a4eb27918cebf..a2486f4440734 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -138,6 +138,17 @@ static int map_tboot_page(unsigned long vaddr, unsigned long pfn, return -1; set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot)); pte_unmap(pte); + + /* + * PTI poisons low addresses in the kernel page tables in the + * name of making them unusable for userspace. To execute + * code at such a low address, the poison must be cleared. + * + * Note: 'pgd' actually gets set in p4d_alloc() _or_ + * pud_alloc() depending on 4/5-level paging. + */ + pgd->pgd &= ~_PAGE_NX; + return 0; } diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 9a9c9b076955d..a5b802a122127 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -93,17 +93,10 @@ static void set_tls_desc(struct task_struct *p, int idx, cpu = get_cpu(); while (n-- > 0) { - if (LDT_empty(info) || LDT_zero(info)) { + if (LDT_empty(info) || LDT_zero(info)) memset(desc, 0, sizeof(*desc)); - } else { + else fill_ldt(desc, info); - - /* - * Always set the accessed bit so that the CPU - * doesn't try to write to the (read-only) GDT. - */ - desc->type |= 1; - } ++info; ++desc; } diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5a6b8f809792b..b33e860d32fe8 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -141,8 +142,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) * will catch asm bugs and any attempt to use ist_preempt_enable * from double_fault. */ - BUG_ON((unsigned long)(current_top_of_stack() - - current_stack_pointer) >= THREAD_SIZE); + BUG_ON(!on_thread_stack()); preempt_enable_no_resched(); } @@ -349,23 +349,42 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) /* * If IRET takes a non-IST fault on the espfix64 stack, then we - * end up promoting it to a doublefault. In that case, modify - * the stack to make it look like we just entered the #GP - * handler from user space, similar to bad_iret. + * end up promoting it to a doublefault. In that case, take + * advantage of the fact that we're not using the normal (TSS.sp0) + * stack right now. We can write a fake #GP(0) frame at TSS.sp0 + * and then modify our own IRET frame so that, when we return, + * we land directly at the #GP(0) vector with the stack already + * set up according to its expectations. + * + * The net result is that our #GP handler will think that we + * entered from usermode with the bad user context. * * No need for ist_enter here because we don't use RCU. */ - if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && + if (((long)regs->sp >> P4D_SHIFT) == ESPFIX_PGD_ENTRY && regs->cs == __KERNEL_CS && regs->ip == (unsigned long)native_irq_return_iret) { - struct pt_regs *normal_regs = task_pt_regs(current); + struct pt_regs *gpregs = (struct pt_regs *)this_cpu_read(cpu_tss_rw.x86_tss.sp0) - 1; - /* Fake a #GP(0) from userspace. */ - memmove(&normal_regs->ip, (void *)regs->sp, 5*8); - normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ + /* + * regs->sp points to the failing IRET frame on the + * ESPFIX64 stack. Copy it to the entry stack. This fills + * in gpregs->ss through gpregs->ip. + * + */ + memmove(&gpregs->ip, (void *)regs->sp, 5*8); + gpregs->orig_ax = 0; /* Missing (lost) #GP error code */ + + /* + * Adjust our frame so that we return straight to the #GP + * vector with the expected RSP value. This is safe because + * we won't enable interupts or schedule before we invoke + * general_protection, so nothing will clobber the stack + * frame we just set up. + */ regs->ip = (unsigned long)general_protection; - regs->sp = (unsigned long)&normal_regs->orig_ax; + regs->sp = (unsigned long)&gpregs->orig_ax; return; } @@ -390,7 +409,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) * * Processors update CR2 whenever a page fault is detected. If a * second page fault occurs while an earlier page fault is being - * deliv- ered, the faulting linear address of the second fault will + * delivered, the faulting linear address of the second fault will * overwrite the contents of CR2 (replacing the previous * address). These updates to CR2 occur even if the page fault * results in a double fault or occurs during the delivery of a @@ -601,14 +620,15 @@ NOKPROBE_SYMBOL(do_int3); #ifdef CONFIG_X86_64 /* - * Help handler running on IST stack to switch off the IST stack if the - * interrupted code was in user mode. The actual stack switch is done in - * entry_64.S + * Help handler running on a per-cpu (IST or entry trampoline) stack + * to switch to the normal thread stack if the interrupted code was in + * user mode. The actual stack switch is done in entry_64.S */ asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs) { - struct pt_regs *regs = task_pt_regs(current); - *regs = *eregs; + struct pt_regs *regs = (struct pt_regs *)this_cpu_read(cpu_current_top_of_stack) - 1; + if (regs != eregs) + *regs = *eregs; return regs; } NOKPROBE_SYMBOL(sync_regs); @@ -624,13 +644,13 @@ struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) /* * This is called from entry_64.S early in handling a fault * caused by a bad iret to user mode. To handle the fault - * correctly, we want move our stack frame to task_pt_regs - * and we want to pretend that the exception came from the - * iret target. + * correctly, we want to move our stack frame to where it would + * be had we entered directly on the entry stack (rather than + * just below the IRET frame) and we want to pretend that the + * exception came from the IRET target. */ struct bad_iret_stack *new_stack = - container_of(task_pt_regs(current), - struct bad_iret_stack, regs); + (struct bad_iret_stack *)this_cpu_read(cpu_tss_rw.x86_tss.sp0) - 1; /* Copy the IRET target to the new stack. */ memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8); @@ -795,14 +815,6 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code) debug_stack_usage_dec(); exit: -#if defined(CONFIG_X86_32) - /* - * This is the most likely code path that involves non-trivial use - * of the SYSENTER stack. Check that we haven't overrun it. - */ - WARN(this_cpu_read(cpu_tss.SYSENTER_stack_canary) != STACK_END_MAGIC, - "Overran or corrupted SYSENTER stack\n"); -#endif ist_exit(regs); } NOKPROBE_SYMBOL(do_debug); @@ -929,6 +941,9 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) void __init trap_init(void) { + /* Init cpu_entry_area before IST entries are set up */ + setup_cpu_entry_areas(); + idt_setup_traps(); /* @@ -936,8 +951,9 @@ void __init trap_init(void) * "sidt" instruction will not leak the location of the kernel, and * to defend the IDT against arbitrary memory write vulnerabilities. * It will be reloaded in cpu_init() */ - __set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO); - idt_descr.address = fix_to_virt(FIX_RO_IDT); + cea_set_pte(CPU_ENTRY_AREA_RO_IDT_VADDR, __pa_symbol(idt_table), + PAGE_KERNEL_RO); + idt_descr.address = CPU_ENTRY_AREA_RO_IDT; /* * Should be a barrier for any external CPU state: diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index ad2b925a808e7..47506567435ee 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -602,7 +602,6 @@ unsigned long native_calibrate_tsc(void) case INTEL_FAM6_KABYLAKE_DESKTOP: crystal_khz = 24000; /* 24.0 MHz */ break; - case INTEL_FAM6_SKYLAKE_X: case INTEL_FAM6_ATOM_DENVERTON: crystal_khz = 25000; /* 25.0 MHz */ break; @@ -612,6 +611,8 @@ unsigned long native_calibrate_tsc(void) } } + if (crystal_khz == 0) + return 0; /* * TSC frequency determined by CPUID is a "hardware reported" * frequency and is the most accurate one so far we have. This diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index a3f973b2c97a0..be86a865087a6 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -253,22 +253,15 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state) return NULL; } -static bool stack_access_ok(struct unwind_state *state, unsigned long addr, +static bool stack_access_ok(struct unwind_state *state, unsigned long _addr, size_t len) { struct stack_info *info = &state->stack_info; + void *addr = (void *)_addr; - /* - * If the address isn't on the current stack, switch to the next one. - * - * We may have to traverse multiple stacks to deal with the possibility - * that info->next_sp could point to an empty stack and the address - * could be on a subsequent stack. - */ - while (!on_stack(info, (void *)addr, len)) - if (get_stack_info(info->next_sp, state->task, info, - &state->stack_mask)) - return false; + if (!on_stack(info, addr, len) && + (get_stack_info(addr, state->task, info, &state->stack_mask))) + return false; return true; } @@ -283,42 +276,32 @@ static bool deref_stack_reg(struct unwind_state *state, unsigned long addr, return true; } -#define REGS_SIZE (sizeof(struct pt_regs)) -#define SP_OFFSET (offsetof(struct pt_regs, sp)) -#define IRET_REGS_SIZE (REGS_SIZE - offsetof(struct pt_regs, ip)) -#define IRET_SP_OFFSET (SP_OFFSET - offsetof(struct pt_regs, ip)) - static bool deref_stack_regs(struct unwind_state *state, unsigned long addr, - unsigned long *ip, unsigned long *sp, bool full) + unsigned long *ip, unsigned long *sp) { - size_t regs_size = full ? REGS_SIZE : IRET_REGS_SIZE; - size_t sp_offset = full ? SP_OFFSET : IRET_SP_OFFSET; - struct pt_regs *regs = (struct pt_regs *)(addr + regs_size - REGS_SIZE); - - if (IS_ENABLED(CONFIG_X86_64)) { - if (!stack_access_ok(state, addr, regs_size)) - return false; + struct pt_regs *regs = (struct pt_regs *)addr; - *ip = regs->ip; - *sp = regs->sp; + /* x86-32 support will be more complicated due to the ®s->sp hack */ + BUILD_BUG_ON(IS_ENABLED(CONFIG_X86_32)); - return true; - } - - if (!stack_access_ok(state, addr, sp_offset)) + if (!stack_access_ok(state, addr, sizeof(struct pt_regs))) return false; *ip = regs->ip; + *sp = regs->sp; + return true; +} - if (user_mode(regs)) { - if (!stack_access_ok(state, addr + sp_offset, - REGS_SIZE - SP_OFFSET)) - return false; +static bool deref_stack_iret_regs(struct unwind_state *state, unsigned long addr, + unsigned long *ip, unsigned long *sp) +{ + struct pt_regs *regs = (void *)addr - IRET_FRAME_OFFSET; - *sp = regs->sp; - } else - *sp = (unsigned long)®s->sp; + if (!stack_access_ok(state, addr, IRET_FRAME_SIZE)) + return false; + *ip = regs->ip; + *sp = regs->sp; return true; } @@ -327,7 +310,6 @@ bool unwind_next_frame(struct unwind_state *state) unsigned long ip_p, sp, orig_ip, prev_sp = state->sp; enum stack_type prev_type = state->stack_info.type; struct orc_entry *orc; - struct pt_regs *ptregs; bool indirect = false; if (unwind_done(state)) @@ -435,7 +417,7 @@ bool unwind_next_frame(struct unwind_state *state) break; case ORC_TYPE_REGS: - if (!deref_stack_regs(state, sp, &state->ip, &state->sp, true)) { + if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) { orc_warn("can't dereference registers at %p for ip %pB\n", (void *)sp, (void *)orig_ip); goto done; @@ -447,20 +429,14 @@ bool unwind_next_frame(struct unwind_state *state) break; case ORC_TYPE_REGS_IRET: - if (!deref_stack_regs(state, sp, &state->ip, &state->sp, false)) { + if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) { orc_warn("can't dereference iret registers at %p for ip %pB\n", (void *)sp, (void *)orig_ip); goto done; } - ptregs = container_of((void *)sp, struct pt_regs, ip); - if ((unsigned long)ptregs >= prev_sp && - on_stack(&state->stack_info, ptregs, REGS_SIZE)) { - state->regs = ptregs; - state->full_regs = false; - } else - state->regs = NULL; - + state->regs = (void *)sp - IRET_FRAME_OFFSET; + state->full_regs = false; state->signal = true; break; @@ -553,8 +529,18 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, } if (get_stack_info((unsigned long *)state->sp, state->task, - &state->stack_info, &state->stack_mask)) - return; + &state->stack_info, &state->stack_mask)) { + /* + * We weren't on a valid stack. It's possible that + * we overflowed a valid stack into a guard page. + * See if the next page up is valid so that we can + * generate some kind of backtrace if this happens. + */ + void *next_page = (void *)PAGE_ALIGN((unsigned long)state->sp); + if (get_stack_info(next_page, state->task, &state->stack_info, + &state->stack_mask)) + return; + } /* * The caller can provide the address of the first frame directly diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S index 014ea59aa153e..3d3c2f71f6171 100644 --- a/arch/x86/kernel/verify_cpu.S +++ b/arch/x86/kernel/verify_cpu.S @@ -33,7 +33,7 @@ #include #include -verify_cpu: +ENTRY(verify_cpu) pushf # Save caller passed flags push $0 # Kill any dangerous flags popf @@ -139,3 +139,4 @@ verify_cpu: popf # Restore caller passed flags xorl %eax, %eax ret +ENDPROC(verify_cpu) diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 68244742ecb0b..5edb27f1a2c40 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -55,6 +55,7 @@ #include #include #include +#include /* * Known problems: @@ -94,7 +95,6 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) { - struct tss_struct *tss; struct task_struct *tsk = current; struct vm86plus_struct __user *user; struct vm86 *vm86 = current->thread.vm86; @@ -146,12 +146,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) do_exit(SIGSEGV); } - tss = &per_cpu(cpu_tss, get_cpu()); + preempt_disable(); tsk->thread.sp0 = vm86->saved_sp0; tsk->thread.sysenter_cs = __KERNEL_CS; - load_sp0(tss, &tsk->thread); + update_sp0(tsk); + refresh_sysenter_cs(&tsk->thread); vm86->saved_sp0 = 0; - put_cpu(); + preempt_enable(); memcpy(®s->pt, &vm86->regs32, sizeof(struct pt_regs)); @@ -237,7 +238,6 @@ SYSCALL_DEFINE2(vm86, unsigned long, cmd, unsigned long, arg) static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) { - struct tss_struct *tss; struct task_struct *tsk = current; struct vm86 *vm86 = tsk->thread.vm86; struct kernel_vm86_regs vm86regs; @@ -365,15 +365,17 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) vm86->saved_sp0 = tsk->thread.sp0; lazy_save_gs(vm86->regs32.gs); - tss = &per_cpu(cpu_tss, get_cpu()); /* make room for real-mode segments */ + preempt_disable(); tsk->thread.sp0 += 16; - if (static_cpu_has(X86_FEATURE_SEP)) + if (static_cpu_has(X86_FEATURE_SEP)) { tsk->thread.sysenter_cs = 0; + refresh_sysenter_cs(&tsk->thread); + } - load_sp0(tss, &tsk->thread); - put_cpu(); + update_sp0(tsk); + preempt_enable(); if (vm86->flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(tsk->mm); diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index a4009fb9be872..9b138a06c1a46 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -61,11 +61,17 @@ jiffies_64 = jiffies; . = ALIGN(HPAGE_SIZE); \ __end_rodata_hpage_align = .; +#define ALIGN_ENTRY_TEXT_BEGIN . = ALIGN(PMD_SIZE); +#define ALIGN_ENTRY_TEXT_END . = ALIGN(PMD_SIZE); + #else #define X64_ALIGN_RODATA_BEGIN #define X64_ALIGN_RODATA_END +#define ALIGN_ENTRY_TEXT_BEGIN +#define ALIGN_ENTRY_TEXT_END + #endif PHDRS { @@ -102,11 +108,28 @@ SECTIONS CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT + ALIGN_ENTRY_TEXT_BEGIN ENTRY_TEXT IRQENTRY_TEXT + ALIGN_ENTRY_TEXT_END SOFTIRQENTRY_TEXT *(.fixup) *(.gnu.warning) + +#ifdef CONFIG_X86_64 + . = ALIGN(PAGE_SIZE); + _entry_trampoline = .; + *(.entry_trampoline) + . = ALIGN(PAGE_SIZE); + ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); +#endif + +#ifdef CONFIG_RETPOLINE + __indirect_thunk_start = .; + *(.text.__x86.indirect_thunk) + __indirect_thunk_end = .; +#endif + /* End of text section */ _etext = .; } :text = 0x9090 diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index a088b2c47f739..5b2d10c1973ab 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -28,6 +28,8 @@ void x86_init_noop(void) { } void __init x86_init_uint_noop(unsigned int unused) { } int __init iommu_init_noop(void) { return 0; } void iommu_shutdown_noop(void) { } +bool __init bool_x86_init_noop(void) { return false; } +void x86_op_int_noop(int cpu) { } /* * The platform setup functions are preset with the default functions @@ -81,6 +83,12 @@ struct x86_init_ops x86_init __initdata = { .init_irq = x86_default_pci_init_irq, .fixup_irqs = x86_default_pci_fixup_irqs, }, + + .hyper = { + .init_platform = x86_init_noop, + .x2apic_available = bool_x86_init_noop, + .init_mem_mapping = x86_init_noop, + }, }; struct x86_cpuinit_ops x86_cpuinit = { @@ -101,6 +109,7 @@ struct x86_platform_ops x86_platform __ro_after_init = { .get_nmi_reason = default_get_nmi_reason, .save_sched_clock_state = tsc_save_sched_clock_state, .restore_sched_clock_state = tsc_restore_sched_clock_state, + .hyper.pin_vcpu = x86_op_int_noop, }; EXPORT_SYMBOL_GPL(x86_platform); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index d90cdc77e0773..7bbb5da2b49da 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2404,9 +2404,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n) } static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, - u64 cr0, u64 cr4) + u64 cr0, u64 cr3, u64 cr4) { int bad; + u64 pcid; + + /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */ + pcid = 0; + if (cr4 & X86_CR4_PCIDE) { + pcid = cr3 & 0xfff; + cr3 &= ~0xfff; + } + + bad = ctxt->ops->set_cr(ctxt, 3, cr3); + if (bad) + return X86EMUL_UNHANDLEABLE; /* * First enable PAE, long mode needs it before CR0.PG = 1 is set. @@ -2425,6 +2437,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, bad = ctxt->ops->set_cr(ctxt, 4, cr4); if (bad) return X86EMUL_UNHANDLEABLE; + if (pcid) { + bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid); + if (bad) + return X86EMUL_UNHANDLEABLE; + } + } return X86EMUL_CONTINUE; @@ -2435,11 +2453,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) struct desc_struct desc; struct desc_ptr dt; u16 selector; - u32 val, cr0, cr4; + u32 val, cr0, cr3, cr4; int i; cr0 = GET_SMSTATE(u32, smbase, 0x7ffc); - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8)); + cr3 = GET_SMSTATE(u32, smbase, 0x7ff8); ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED; ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0); @@ -2481,14 +2499,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8)); - return rsm_enter_protected_mode(ctxt, cr0, cr4); + return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); } static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) { struct desc_struct desc; struct desc_ptr dt; - u64 val, cr0, cr4; + u64 val, cr0, cr3, cr4; u32 base3; u16 selector; int i, r; @@ -2505,7 +2523,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1); cr0 = GET_SMSTATE(u64, smbase, 0x7f58); - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50)); + cr3 = GET_SMSTATE(u64, smbase, 0x7f50); cr4 = GET_SMSTATE(u64, smbase, 0x7f48); ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00)); val = GET_SMSTATE(u64, smbase, 0x7ed0); @@ -2533,7 +2551,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) dt.address = GET_SMSTATE(u64, smbase, 0x7e68); ctxt->ops->set_gdt(ctxt, &dt); - r = rsm_enter_protected_mode(ctxt, cr0, cr4); + r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); if (r != X86EMUL_CONTINUE) return r; diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 36c90d631096d..ef03efba1c232 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -266,9 +266,14 @@ static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id) recalculate_apic_map(apic->vcpu->kvm); } +static inline u32 kvm_apic_calc_x2apic_ldr(u32 id) +{ + return ((id >> 4) << 16) | (1 << (id & 0xf)); +} + static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u32 id) { - u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf)); + u32 ldr = kvm_apic_calc_x2apic_ldr(id); WARN_ON_ONCE(id != apic->vcpu->vcpu_id); @@ -2196,6 +2201,7 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, { if (apic_x2apic_mode(vcpu->arch.apic)) { u32 *id = (u32 *)(s->regs + APIC_ID); + u32 *ldr = (u32 *)(s->regs + APIC_LDR); if (vcpu->kvm->arch.x2apic_format) { if (*id != vcpu->vcpu_id) @@ -2206,6 +2212,10 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, else *id <<= 24; } + + /* In x2APIC mode, the LDR is fixed and based on the id */ + if (set) + *ldr = kvm_apic_calc_x2apic_ldr(*id); } return 0; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7a69cf0537111..0fce8d73403c3 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3382,7 +3382,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) spin_lock(&vcpu->kvm->mmu_lock); if(make_mmu_pages_available(vcpu) < 0) { spin_unlock(&vcpu->kvm->mmu_lock); - return 1; + return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, 0, 0, vcpu->arch.mmu.shadow_root_level, 1, ACC_ALL); @@ -3397,7 +3397,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) spin_lock(&vcpu->kvm->mmu_lock); if (make_mmu_pages_available(vcpu) < 0) { spin_unlock(&vcpu->kvm->mmu_lock); - return 1; + return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT), i << 30, PT32_ROOT_LEVEL, 1, ACC_ALL); @@ -3437,7 +3437,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) spin_lock(&vcpu->kvm->mmu_lock); if (make_mmu_pages_available(vcpu) < 0) { spin_unlock(&vcpu->kvm->mmu_lock); - return 1; + return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, root_gfn, 0, vcpu->arch.mmu.shadow_root_level, 0, ACC_ALL); @@ -3474,7 +3474,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) spin_lock(&vcpu->kvm->mmu_lock); if (make_mmu_pages_available(vcpu) < 0) { spin_unlock(&vcpu->kvm->mmu_lock); - return 1; + return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL, 0, ACC_ALL); @@ -5476,13 +5476,13 @@ int kvm_mmu_module_init(void) pte_list_desc_cache = kmem_cache_create("pte_list_desc", sizeof(struct pte_list_desc), - 0, 0, NULL); + 0, SLAB_ACCOUNT, NULL); if (!pte_list_desc_cache) goto nomem; mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", sizeof(struct kvm_mmu_page), - 0, 0, NULL); + 0, SLAB_ACCOUNT, NULL); if (!mmu_page_header_cache) goto nomem; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 0e68f0b3cbf72..6a8284f723283 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "trace.h" @@ -2189,6 +2190,8 @@ static int ud_interception(struct vcpu_svm *svm) int er; er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(&svm->vcpu, UD_VECTOR); return 1; @@ -3657,6 +3660,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) u32 ecx = msr->index; u64 data = msr->data; switch (ecx) { + case MSR_IA32_CR_PAT: + if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data)) + return 1; + vcpu->arch.pat = data; + svm->vmcb->save.g_pat = data; + mark_dirty(svm->vmcb, VMCB_NPT); + break; case MSR_IA32_TSC: kvm_write_tsc(vcpu, msr); break; @@ -4955,6 +4965,25 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%[svm]) \n\t" "mov %%r14, %c[r14](%[svm]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t" +#endif + /* + * Clear host registers marked as clobbered to prevent + * speculative use. + */ + "xor %%" _ASM_BX ", %%" _ASM_BX " \n\t" + "xor %%" _ASM_CX ", %%" _ASM_CX " \n\t" + "xor %%" _ASM_DX ", %%" _ASM_DX " \n\t" + "xor %%" _ASM_SI ", %%" _ASM_SI " \n\t" + "xor %%" _ASM_DI ", %%" _ASM_DI " \n\t" +#ifdef CONFIG_X86_64 + "xor %%r8, %%r8 \n\t" + "xor %%r9, %%r9 \n\t" + "xor %%r10, %%r10 \n\t" + "xor %%r11, %%r11 \n\t" + "xor %%r12, %%r12 \n\t" + "xor %%r13, %%r13 \n\t" + "xor %%r14, %%r14 \n\t" + "xor %%r15, %%r15 \n\t" #endif "pop %%" _ASM_BP : @@ -4985,6 +5014,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif ); + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); + #ifdef CONFIG_X86_64 wrmsrl(MSR_GS_BASE, svm->host.gs_base); #else diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a6f4f095f8f4e..ef16cf0f7cfd0 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "trace.h" #include "pmu.h" @@ -202,6 +203,10 @@ struct loaded_vmcs { bool nmi_known_unmasked; unsigned long vmcs_host_cr3; /* May not match real cr3 */ unsigned long vmcs_host_cr4; /* May not match real cr4 */ + /* Support for vnmi-less CPUs */ + int soft_vnmi_blocked; + ktime_t entry_time; + s64 vnmi_blocked_time; struct list_head loaded_vmcss_on_cpu_link; }; @@ -884,8 +889,16 @@ static inline short vmcs_field_to_offset(unsigned long field) { BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX); - if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) || - vmcs_field_to_offset_table[field] == 0) + if (field >= ARRAY_SIZE(vmcs_field_to_offset_table)) + return -ENOENT; + + /* + * FIXME: Mitigation for CVE-2017-5753. To be replaced with a + * generic mechanism. + */ + asm("lfence"); + + if (vmcs_field_to_offset_table[field] == 0) return -ENOENT; return vmcs_field_to_offset_table[field]; @@ -1286,6 +1299,11 @@ static inline bool cpu_has_vmx_invpcid(void) SECONDARY_EXEC_ENABLE_INVPCID; } +static inline bool cpu_has_virtual_nmis(void) +{ + return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; +} + static inline bool cpu_has_vmx_wbinvd_exit(void) { return vmcs_config.cpu_based_2nd_exec_ctrl & @@ -1343,11 +1361,6 @@ static inline bool nested_cpu_has2(struct vmcs12 *vmcs12, u32 bit) (vmcs12->secondary_vm_exec_control & bit); } -static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12) -{ - return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS; -} - static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12) { return vmcs12->pin_based_vm_exec_control & @@ -2291,7 +2304,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) * processors. See 22.2.4. */ vmcs_writel(HOST_TR_BASE, - (unsigned long)this_cpu_ptr(&cpu_tss)); + (unsigned long)&get_cpu_entry_area(cpu)->tss.x86_tss); vmcs_writel(HOST_GDTR_BASE, (unsigned long)gdt); /* 22.2.4 */ /* @@ -2841,8 +2854,9 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) * Advertise EPTP switching unconditionally * since we emulate it */ - vmx->nested.nested_vmx_vmfunc_controls = - VMX_VMFUNC_EPTP_SWITCHING; + if (enable_ept) + vmx->nested.nested_vmx_vmfunc_controls = + VMX_VMFUNC_EPTP_SWITCHING; } /* @@ -3699,9 +3713,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) &_vmexit_control) < 0) return -EIO; - min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING | - PIN_BASED_VIRTUAL_NMIS; - opt = PIN_BASED_POSTED_INTR | PIN_BASED_VMX_PREEMPTION_TIMER; + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR | + PIN_BASED_VMX_PREEMPTION_TIMER; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, &_pin_based_exec_control) < 0) return -EIO; @@ -5667,7 +5681,8 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) static void enable_nmi_window(struct kvm_vcpu *vcpu) { - if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) { + if (!cpu_has_virtual_nmis() || + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) { enable_irq_window(vcpu); return; } @@ -5707,6 +5722,19 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + if (!cpu_has_virtual_nmis()) { + /* + * Tracking the NMI-blocked state in software is built upon + * finding the next open IRQ window. This, in turn, depends on + * well-behaving guests: They have to keep IRQs disabled at + * least as long as the NMI handler runs. Otherwise we may + * cause NMI nesting, maybe breaking the guest. But as this is + * highly unlikely, we can live with the residual risk. + */ + vmx->loaded_vmcs->soft_vnmi_blocked = 1; + vmx->loaded_vmcs->vnmi_blocked_time = 0; + } + ++vcpu->stat.nmi_injections; vmx->loaded_vmcs->nmi_known_unmasked = false; @@ -5725,6 +5753,8 @@ static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); bool masked; + if (!cpu_has_virtual_nmis()) + return vmx->loaded_vmcs->soft_vnmi_blocked; if (vmx->loaded_vmcs->nmi_known_unmasked) return false; masked = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI; @@ -5736,13 +5766,20 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) { struct vcpu_vmx *vmx = to_vmx(vcpu); - vmx->loaded_vmcs->nmi_known_unmasked = !masked; - if (masked) - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); - else - vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); + if (!cpu_has_virtual_nmis()) { + if (vmx->loaded_vmcs->soft_vnmi_blocked != masked) { + vmx->loaded_vmcs->soft_vnmi_blocked = masked; + vmx->loaded_vmcs->vnmi_blocked_time = 0; + } + } else { + vmx->loaded_vmcs->nmi_known_unmasked = !masked; + if (masked) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + else + vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + } } static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) @@ -5750,6 +5787,10 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) if (to_vmx(vcpu)->nested.nested_run_pending) return 0; + if (!cpu_has_virtual_nmis() && + to_vmx(vcpu)->loaded_vmcs->soft_vnmi_blocked) + return 0; + return !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & (GUEST_INTR_STATE_MOV_SS | GUEST_INTR_STATE_STI | GUEST_INTR_STATE_NMI)); @@ -5883,6 +5924,8 @@ static int handle_exception(struct kvm_vcpu *vcpu) return 1; } er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(vcpu, UD_VECTOR); return 1; @@ -6478,6 +6521,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) * AAK134, BY25. */ if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && + cpu_has_virtual_nmis() && (exit_qualification & INTR_INFO_UNBLOCK_NMI)) vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI); @@ -6716,12 +6760,7 @@ static __init int hardware_setup(void) memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE); memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE); - /* - * Allow direct access to the PC debug port (it is often used for I/O - * delays, but the vmexits simply slow things down). - */ memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE); - clear_bit(0x80, vmx_io_bitmap_a); memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); @@ -6961,7 +7000,7 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx) } /* Create a new VMCS */ - item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL); + item = kzalloc(sizeof(struct vmcs02_list), GFP_KERNEL); if (!item) return NULL; item->vmcs02.vmcs = alloc_vmcs(); @@ -7978,6 +8017,7 @@ static int handle_pml_full(struct kvm_vcpu *vcpu) * "blocked by NMI" bit has to be set before next VM entry. */ if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && + cpu_has_virtual_nmis() && (exit_qualification & INTR_INFO_UNBLOCK_NMI)) vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI); @@ -8822,6 +8862,25 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) return 0; } + if (unlikely(!cpu_has_virtual_nmis() && + vmx->loaded_vmcs->soft_vnmi_blocked)) { + if (vmx_interrupt_allowed(vcpu)) { + vmx->loaded_vmcs->soft_vnmi_blocked = 0; + } else if (vmx->loaded_vmcs->vnmi_blocked_time > 1000000000LL && + vcpu->arch.nmi_pending) { + /* + * This CPU don't support us in finding the end of an + * NMI-blocked window if the guest runs with IRQs + * disabled. So we pull the trigger after 1 s of + * futile waiting, but inform the user about this. + */ + printk(KERN_WARNING "%s: Breaking out of NMI-blocked " + "state on VCPU %d after 1 s timeout\n", + __func__, vcpu->vcpu_id); + vmx->loaded_vmcs->soft_vnmi_blocked = 0; + } + } + if (exit_reason < kvm_vmx_max_exit_handlers && kvm_vmx_exit_handlers[exit_reason]) return kvm_vmx_exit_handlers[exit_reason](vcpu); @@ -9104,33 +9163,38 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK; - if (vmx->loaded_vmcs->nmi_known_unmasked) - return; - /* - * Can't use vmx->exit_intr_info since we're not sure what - * the exit reason is. - */ - exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; - vector = exit_intr_info & INTR_INFO_VECTOR_MASK; - /* - * SDM 3: 27.7.1.2 (September 2008) - * Re-set bit "block by NMI" before VM entry if vmexit caused by - * a guest IRET fault. - * SDM 3: 23.2.2 (September 2008) - * Bit 12 is undefined in any of the following cases: - * If the VM exit sets the valid bit in the IDT-vectoring - * information field. - * If the VM exit is due to a double fault. - */ - if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi && - vector != DF_VECTOR && !idtv_info_valid) - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); - else - vmx->loaded_vmcs->nmi_known_unmasked = - !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) - & GUEST_INTR_STATE_NMI); + if (cpu_has_virtual_nmis()) { + if (vmx->loaded_vmcs->nmi_known_unmasked) + return; + /* + * Can't use vmx->exit_intr_info since we're not sure what + * the exit reason is. + */ + exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; + vector = exit_intr_info & INTR_INFO_VECTOR_MASK; + /* + * SDM 3: 27.7.1.2 (September 2008) + * Re-set bit "block by NMI" before VM entry if vmexit caused by + * a guest IRET fault. + * SDM 3: 23.2.2 (September 2008) + * Bit 12 is undefined in any of the following cases: + * If the VM exit sets the valid bit in the IDT-vectoring + * information field. + * If the VM exit is due to a double fault. + */ + if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi && + vector != DF_VECTOR && !idtv_info_valid) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + else + vmx->loaded_vmcs->nmi_known_unmasked = + !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) + & GUEST_INTR_STATE_NMI); + } else if (unlikely(vmx->loaded_vmcs->soft_vnmi_blocked)) + vmx->loaded_vmcs->vnmi_blocked_time += + ktime_to_ns(ktime_sub(ktime_get(), + vmx->loaded_vmcs->entry_time)); } static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, @@ -9247,6 +9311,11 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long debugctlmsr, cr3, cr4; + /* Record the guest's net vcpu time for enforced NMI injections. */ + if (unlikely(!cpu_has_virtual_nmis() && + vmx->loaded_vmcs->soft_vnmi_blocked)) + vmx->loaded_vmcs->entry_time = ktime_get(); + /* Don't enter VMX if guest state is invalid, let the exit handler start emulation until we arrive back to a valid state */ if (vmx->emulation_required) @@ -9345,6 +9414,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) /* Save guest registers, load host registers, keep flags */ "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" "pop %0 \n\t" + "setbe %c[fail](%0)\n\t" "mov %%" _ASM_AX ", %c[rax](%0) \n\t" "mov %%" _ASM_BX ", %c[rbx](%0) \n\t" __ASM_SIZE(pop) " %c[rcx](%0) \n\t" @@ -9361,12 +9431,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%0) \n\t" "mov %%r14, %c[r14](%0) \n\t" "mov %%r15, %c[r15](%0) \n\t" + "xor %%r8d, %%r8d \n\t" + "xor %%r9d, %%r9d \n\t" + "xor %%r10d, %%r10d \n\t" + "xor %%r11d, %%r11d \n\t" + "xor %%r12d, %%r12d \n\t" + "xor %%r13d, %%r13d \n\t" + "xor %%r14d, %%r14d \n\t" + "xor %%r15d, %%r15d \n\t" #endif "mov %%cr2, %%" _ASM_AX " \n\t" "mov %%" _ASM_AX ", %c[cr2](%0) \n\t" + "xor %%eax, %%eax \n\t" + "xor %%ebx, %%ebx \n\t" + "xor %%esi, %%esi \n\t" + "xor %%edi, %%edi \n\t" "pop %%" _ASM_BP "; pop %%" _ASM_DX " \n\t" - "setbe %c[fail](%0) \n\t" ".pushsection .rodata \n\t" ".global vmx_return \n\t" "vmx_return: " _ASM_PTR " 2b \n\t" @@ -9403,6 +9484,9 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) #endif ); + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); + /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */ if (debugctlmsr) update_debugctlmsr(debugctlmsr); @@ -11325,6 +11409,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip); vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base); vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base); + vmcs_write32(GUEST_IDTR_LIMIT, 0xFFFF); + vmcs_write32(GUEST_GDTR_LIMIT, 0xFFFF); /* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1. */ if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 03869eb7fcd67..575c8953cc9a3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1830,6 +1830,9 @@ static void kvm_setup_pvclock_page(struct kvm_vcpu *v) */ BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0); + if (guest_hv_clock.version & 1) + ++guest_hv_clock.version; /* first time write, random junk */ + vcpu->hv_clock.version = guest_hv_clock.version + 1; kvm_write_guest_cached(v->kvm, &vcpu->pv_time, &vcpu->hv_clock, @@ -4359,7 +4362,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v) addr, n, v)) && kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v)) break; - trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v); + trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v); handled += n; addr += n; len -= n; @@ -4618,7 +4621,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes) { if (vcpu->mmio_read_completed) { trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, - vcpu->mmio_fragments[0].gpa, *(u64 *)val); + vcpu->mmio_fragments[0].gpa, val); vcpu->mmio_read_completed = 0; return 1; } @@ -4640,14 +4643,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa, static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val) { - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val); + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val); return vcpu_mmio_write(vcpu, gpa, bytes, val); } static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, void *val, int bytes) { - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0); + trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL); return X86EMUL_IO_NEEDED; } @@ -5705,6 +5708,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, emulation_type)) return EMULATE_DONE; + if (ctxt->have_exception && inject_emulated_exception(vcpu)) + return EMULATE_DONE; if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; return handle_emulation_failure(vcpu); @@ -6740,6 +6745,20 @@ static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu) kvm_x86_ops->tlb_flush(vcpu); } +void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, + unsigned long start, unsigned long end) +{ + unsigned long apic_address; + + /* + * The physical address of apic access page is stored in the VMCS. + * Update it when it becomes invalid. + */ + apic_address = gfn_to_hva(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT); + if (start <= apic_address && apic_address < end) + kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD); +} + void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu) { struct page *page = NULL; @@ -7340,7 +7359,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) #endif kvm_rip_write(vcpu, regs->rip); - kvm_set_rflags(vcpu, regs->rflags); + kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED); vcpu->arch.exception.pending = false; diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 457f681ef3792..d435c89875c14 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -26,6 +26,7 @@ lib-y += memcpy_$(BITS).o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o +lib-$(CONFIG_RETPOLINE) += retpoline.o obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S index 4d34bb548b41e..46e71a74e6129 100644 --- a/arch/x86/lib/checksum_32.S +++ b/arch/x86/lib/checksum_32.S @@ -29,7 +29,8 @@ #include #include #include - +#include + /* * computes a partial checksum, e.g. for TCP/UDP fragments */ @@ -156,7 +157,7 @@ ENTRY(csum_partial) negl %ebx lea 45f(%ebx,%ebx,2), %ebx testl %esi, %esi - jmp *%ebx + JMP_NOSPEC %ebx # Handle 2-byte-aligned regions 20: addw (%esi), %ax @@ -439,7 +440,7 @@ ENTRY(csum_partial_copy_generic) andl $-32,%edx lea 3f(%ebx,%ebx), %ebx testl %esi, %esi - jmp *%ebx + JMP_NOSPEC %ebx 1: addl $64,%esi addl $64,%edi SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c index 553f8fd23cc47..4846eff7e4c8b 100644 --- a/arch/x86/lib/delay.c +++ b/arch/x86/lib/delay.c @@ -107,10 +107,10 @@ static void delay_mwaitx(unsigned long __loops) delay = min_t(u64, MWAITX_MAX_LOOPS, loops); /* - * Use cpu_tss as a cacheline-aligned, seldomly + * Use cpu_tss_rw as a cacheline-aligned, seldomly * accessed per-cpu variable as the monitor target. */ - __monitorx(raw_cpu_ptr(&cpu_tss), 0, 0); + __monitorx(raw_cpu_ptr(&cpu_tss_rw), 0, 0); /* * AMD, like Intel, supports the EAX hint and EAX=0xf diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S new file mode 100644 index 0000000000000..dfb2ba91b670d --- /dev/null +++ b/arch/x86/lib/retpoline.S @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include +#include +#include +#include + +.macro THUNK reg + .section .text.__x86.indirect_thunk + +ENTRY(__x86_indirect_thunk_\reg) + CFI_STARTPROC + JMP_NOSPEC %\reg + CFI_ENDPROC +ENDPROC(__x86_indirect_thunk_\reg) +.endm + +/* + * Despite being an assembler file we can't just use .irp here + * because __KSYM_DEPS__ only uses the C preprocessor and would + * only see one instance of "__x86_indirect_thunk_\reg" rather + * than one per register with the correct names. So we do it + * the simple and nasty way... + */ +#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym) +#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg) +#define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg) + +GENERATE_THUNK(_ASM_AX) +GENERATE_THUNK(_ASM_BX) +GENERATE_THUNK(_ASM_CX) +GENERATE_THUNK(_ASM_DX) +GENERATE_THUNK(_ASM_SI) +GENERATE_THUNK(_ASM_DI) +GENERATE_THUNK(_ASM_BP) +GENERATE_THUNK(_ASM_SP) +#ifdef CONFIG_64BIT +GENERATE_THUNK(r8) +GENERATE_THUNK(r9) +GENERATE_THUNK(r10) +GENERATE_THUNK(r11) +GENERATE_THUNK(r12) +GENERATE_THUNK(r13) +GENERATE_THUNK(r14) +GENERATE_THUNK(r15) +#endif diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 12e377184ee4a..e0b85930dd773 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -607,7 +607,7 @@ fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -ff: +ff: UD0 EndTable Table: 3-byte opcode 1 (0x0f 0x38) @@ -717,7 +717,7 @@ AVXcode: 2 7e: vpermt2d/q Vx,Hx,Wx (66),(ev) 7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) 80: INVEPT Gy,Mdq (66) -81: INVPID Gy,Mdq (66) +81: INVVPID Gy,Mdq (66) 82: INVPCID Gy,Mdq (66) 83: vpmultishiftqb Vx,Hx,Wx (66),(ev) 88: vexpandps/d Vpd,Wpd (66),(ev) @@ -896,7 +896,7 @@ EndTable GrpTable: Grp3_1 0: TEST Eb,Ib -1: +1: TEST Eb,Ib 2: NOT Eb 3: NEG Eb 4: MUL AL,Eb @@ -970,6 +970,15 @@ GrpTable: Grp9 EndTable GrpTable: Grp10 +# all are UD1 +0: UD1 +1: UD1 +2: UD1 +3: UD1 +4: UD1 +5: UD1 +6: UD1 +7: UD1 EndTable # Grp11A and Grp11B are expressed as Grp11 in Intel SDM diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 7ba7f3d7f4775..52906808e2775 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -10,7 +10,7 @@ CFLAGS_REMOVE_mem_encrypt.o = -pg endif obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ - pat.o pgtable.o physaddr.o setup_nx.o tlb.o + pat.o pgtable.o physaddr.o setup_nx.o tlb.o cpu_entry_area.o # Make sure __phys_addr has no stackprotector nostackp := $(call cc-option, -fno-stack-protector) @@ -43,9 +43,10 @@ obj-$(CONFIG_AMD_NUMA) += amdtopology.o obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o -obj-$(CONFIG_X86_INTEL_MPX) += mpx.o -obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o -obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o +obj-$(CONFIG_X86_INTEL_MPX) += mpx.o +obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o +obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o +obj-$(CONFIG_PAGE_TABLE_ISOLATION) += pti.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_boot.o diff --git a/arch/x86/mm/cpu_entry_area.c b/arch/x86/mm/cpu_entry_area.c new file mode 100644 index 0000000000000..b9283cc276220 --- /dev/null +++ b/arch/x86/mm/cpu_entry_area.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include +#include +#include + +static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage); + +#ifdef CONFIG_X86_64 +static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks + [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); +#endif + +struct cpu_entry_area *get_cpu_entry_area(int cpu) +{ + unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE; + BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0); + + return (struct cpu_entry_area *) va; +} +EXPORT_SYMBOL(get_cpu_entry_area); + +void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags) +{ + unsigned long va = (unsigned long) cea_vaddr; + + set_pte_vaddr(va, pfn_pte(pa >> PAGE_SHIFT, flags)); +} + +static void __init +cea_map_percpu_pages(void *cea_vaddr, void *ptr, int pages, pgprot_t prot) +{ + for ( ; pages; pages--, cea_vaddr+= PAGE_SIZE, ptr += PAGE_SIZE) + cea_set_pte(cea_vaddr, per_cpu_ptr_to_phys(ptr), prot); +} + +static void percpu_setup_debug_store(int cpu) +{ +#ifdef CONFIG_CPU_SUP_INTEL + int npages; + void *cea; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return; + + cea = &get_cpu_entry_area(cpu)->cpu_debug_store; + npages = sizeof(struct debug_store) / PAGE_SIZE; + BUILD_BUG_ON(sizeof(struct debug_store) % PAGE_SIZE != 0); + cea_map_percpu_pages(cea, &per_cpu(cpu_debug_store, cpu), npages, + PAGE_KERNEL); + + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers; + /* + * Force the population of PMDs for not yet allocated per cpu + * memory like debug store buffers. + */ + npages = sizeof(struct debug_store_buffers) / PAGE_SIZE; + for (; npages; npages--, cea += PAGE_SIZE) + cea_set_pte(cea, 0, PAGE_NONE); +#endif +} + +/* Setup the fixmap mappings only once per-processor */ +static void __init setup_cpu_entry_area(int cpu) +{ +#ifdef CONFIG_X86_64 + extern char _entry_trampoline[]; + + /* On 64-bit systems, we use a read-only fixmap GDT and TSS. */ + pgprot_t gdt_prot = PAGE_KERNEL_RO; + pgprot_t tss_prot = PAGE_KERNEL_RO; +#else + /* + * On native 32-bit systems, the GDT cannot be read-only because + * our double fault handler uses a task gate, and entering through + * a task gate needs to change an available TSS to busy. If the + * GDT is read-only, that will triple fault. The TSS cannot be + * read-only because the CPU writes to it on task switches. + * + * On Xen PV, the GDT must be read-only because the hypervisor + * requires it. + */ + pgprot_t gdt_prot = boot_cpu_has(X86_FEATURE_XENPV) ? + PAGE_KERNEL_RO : PAGE_KERNEL; + pgprot_t tss_prot = PAGE_KERNEL; +#endif + + cea_set_pte(&get_cpu_entry_area(cpu)->gdt, get_cpu_gdt_paddr(cpu), + gdt_prot); + + cea_map_percpu_pages(&get_cpu_entry_area(cpu)->entry_stack_page, + per_cpu_ptr(&entry_stack_storage, cpu), 1, + PAGE_KERNEL); + + /* + * The Intel SDM says (Volume 3, 7.2.1): + * + * Avoid placing a page boundary in the part of the TSS that the + * processor reads during a task switch (the first 104 bytes). The + * processor may not correctly perform address translations if a + * boundary occurs in this area. During a task switch, the processor + * reads and writes into the first 104 bytes of each TSS (using + * contiguous physical addresses beginning with the physical address + * of the first byte of the TSS). So, after TSS access begins, if + * part of the 104 bytes is not physically contiguous, the processor + * will access incorrect information without generating a page-fault + * exception. + * + * There are also a lot of errata involving the TSS spanning a page + * boundary. Assert that we're not doing that. + */ + BUILD_BUG_ON((offsetof(struct tss_struct, x86_tss) ^ + offsetofend(struct tss_struct, x86_tss)) & PAGE_MASK); + BUILD_BUG_ON(sizeof(struct tss_struct) % PAGE_SIZE != 0); + cea_map_percpu_pages(&get_cpu_entry_area(cpu)->tss, + &per_cpu(cpu_tss_rw, cpu), + sizeof(struct tss_struct) / PAGE_SIZE, tss_prot); + +#ifdef CONFIG_X86_32 + per_cpu(cpu_entry_area, cpu) = get_cpu_entry_area(cpu); +#endif + +#ifdef CONFIG_X86_64 + BUILD_BUG_ON(sizeof(exception_stacks) % PAGE_SIZE != 0); + BUILD_BUG_ON(sizeof(exception_stacks) != + sizeof(((struct cpu_entry_area *)0)->exception_stacks)); + cea_map_percpu_pages(&get_cpu_entry_area(cpu)->exception_stacks, + &per_cpu(exception_stacks, cpu), + sizeof(exception_stacks) / PAGE_SIZE, PAGE_KERNEL); + + cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline, + __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); +#endif + percpu_setup_debug_store(cpu); +} + +static __init void setup_cpu_entry_area_ptes(void) +{ +#ifdef CONFIG_X86_32 + unsigned long start, end; + + BUILD_BUG_ON(CPU_ENTRY_AREA_PAGES * PAGE_SIZE < CPU_ENTRY_AREA_MAP_SIZE); + BUG_ON(CPU_ENTRY_AREA_BASE & ~PMD_MASK); + + start = CPU_ENTRY_AREA_BASE; + end = start + CPU_ENTRY_AREA_MAP_SIZE; + + /* Careful here: start + PMD_SIZE might wrap around */ + for (; start < end && start >= CPU_ENTRY_AREA_BASE; start += PMD_SIZE) + populate_extra_pte(start); +#endif +} + +void __init setup_cpu_entry_areas(void) +{ + unsigned int cpu; + + setup_cpu_entry_area_ptes(); + + for_each_possible_cpu(cpu) + setup_cpu_entry_area(cpu); +} diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c index bfcffdf6c5775..421f2664ffa06 100644 --- a/arch/x86/mm/debug_pagetables.c +++ b/arch/x86/mm/debug_pagetables.c @@ -5,7 +5,7 @@ static int ptdump_show(struct seq_file *m, void *v) { - ptdump_walk_pgd_level(m, NULL); + ptdump_walk_pgd_level_debugfs(m, NULL, false); return 0; } @@ -22,21 +22,89 @@ static const struct file_operations ptdump_fops = { .release = single_release, }; -static struct dentry *pe; +static int ptdump_show_curknl(struct seq_file *m, void *v) +{ + if (current->mm->pgd) { + down_read(¤t->mm->mmap_sem); + ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, false); + up_read(¤t->mm->mmap_sem); + } + return 0; +} + +static int ptdump_open_curknl(struct inode *inode, struct file *filp) +{ + return single_open(filp, ptdump_show_curknl, NULL); +} + +static const struct file_operations ptdump_curknl_fops = { + .owner = THIS_MODULE, + .open = ptdump_open_curknl, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#ifdef CONFIG_PAGE_TABLE_ISOLATION +static struct dentry *pe_curusr; + +static int ptdump_show_curusr(struct seq_file *m, void *v) +{ + if (current->mm->pgd) { + down_read(¤t->mm->mmap_sem); + ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, true); + up_read(¤t->mm->mmap_sem); + } + return 0; +} + +static int ptdump_open_curusr(struct inode *inode, struct file *filp) +{ + return single_open(filp, ptdump_show_curusr, NULL); +} + +static const struct file_operations ptdump_curusr_fops = { + .owner = THIS_MODULE, + .open = ptdump_open_curusr, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +static struct dentry *dir, *pe_knl, *pe_curknl; static int __init pt_dump_debug_init(void) { - pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, NULL, - &ptdump_fops); - if (!pe) + dir = debugfs_create_dir("page_tables", NULL); + if (!dir) return -ENOMEM; + pe_knl = debugfs_create_file("kernel", 0400, dir, NULL, + &ptdump_fops); + if (!pe_knl) + goto err; + + pe_curknl = debugfs_create_file("current_kernel", 0400, + dir, NULL, &ptdump_curknl_fops); + if (!pe_curknl) + goto err; + +#ifdef CONFIG_PAGE_TABLE_ISOLATION + pe_curusr = debugfs_create_file("current_user", 0400, + dir, NULL, &ptdump_curusr_fops); + if (!pe_curusr) + goto err; +#endif return 0; +err: + debugfs_remove_recursive(dir); + return -ENOMEM; } static void __exit pt_dump_debug_exit(void) { - debugfs_remove_recursive(pe); + debugfs_remove_recursive(dir); } module_init(pt_dump_debug_init); diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 5e3ac6fe6c9e3..2a4849e92831b 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -44,68 +44,97 @@ struct addr_marker { unsigned long max_lines; }; -/* indices for address_markers; keep sync'd w/ address_markers below */ +/* Address space markers hints */ + +#ifdef CONFIG_X86_64 + enum address_markers_idx { USER_SPACE_NR = 0, -#ifdef CONFIG_X86_64 KERNEL_SPACE_NR, LOW_KERNEL_NR, +#if defined(CONFIG_MODIFY_LDT_SYSCALL) && defined(CONFIG_X86_5LEVEL) + LDT_NR, +#endif VMALLOC_START_NR, VMEMMAP_START_NR, #ifdef CONFIG_KASAN KASAN_SHADOW_START_NR, KASAN_SHADOW_END_NR, #endif -# ifdef CONFIG_X86_ESPFIX64 + CPU_ENTRY_AREA_NR, +#if defined(CONFIG_MODIFY_LDT_SYSCALL) && !defined(CONFIG_X86_5LEVEL) + LDT_NR, +#endif +#ifdef CONFIG_X86_ESPFIX64 ESPFIX_START_NR, -# endif +#endif +#ifdef CONFIG_EFI + EFI_END_NR, +#endif HIGH_KERNEL_NR, MODULES_VADDR_NR, MODULES_END_NR, -#else + FIXADDR_START_NR, + END_OF_SPACE_NR, +}; + +static struct addr_marker address_markers[] = { + [USER_SPACE_NR] = { 0, "User Space" }, + [KERNEL_SPACE_NR] = { (1UL << 63), "Kernel Space" }, + [LOW_KERNEL_NR] = { 0UL, "Low Kernel Mapping" }, + [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" }, + [VMEMMAP_START_NR] = { 0UL, "Vmemmap" }, +#ifdef CONFIG_KASAN + [KASAN_SHADOW_START_NR] = { KASAN_SHADOW_START, "KASAN shadow" }, + [KASAN_SHADOW_END_NR] = { KASAN_SHADOW_END, "KASAN shadow end" }, +#endif +#ifdef CONFIG_MODIFY_LDT_SYSCALL + [LDT_NR] = { LDT_BASE_ADDR, "LDT remap" }, +#endif + [CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" }, +#ifdef CONFIG_X86_ESPFIX64 + [ESPFIX_START_NR] = { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, +#endif +#ifdef CONFIG_EFI + [EFI_END_NR] = { EFI_VA_END, "EFI Runtime Services" }, +#endif + [HIGH_KERNEL_NR] = { __START_KERNEL_map, "High Kernel Mapping" }, + [MODULES_VADDR_NR] = { MODULES_VADDR, "Modules" }, + [MODULES_END_NR] = { MODULES_END, "End Modules" }, + [FIXADDR_START_NR] = { FIXADDR_START, "Fixmap Area" }, + [END_OF_SPACE_NR] = { -1, NULL } +}; + +#else /* CONFIG_X86_64 */ + +enum address_markers_idx { + USER_SPACE_NR = 0, KERNEL_SPACE_NR, VMALLOC_START_NR, VMALLOC_END_NR, -# ifdef CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM PKMAP_BASE_NR, -# endif - FIXADDR_START_NR, #endif + CPU_ENTRY_AREA_NR, + FIXADDR_START_NR, + END_OF_SPACE_NR, }; -/* Address space markers hints */ static struct addr_marker address_markers[] = { - { 0, "User Space" }, -#ifdef CONFIG_X86_64 - { 0x8000000000000000UL, "Kernel Space" }, - { 0/* PAGE_OFFSET */, "Low Kernel Mapping" }, - { 0/* VMALLOC_START */, "vmalloc() Area" }, - { 0/* VMEMMAP_START */, "Vmemmap" }, -#ifdef CONFIG_KASAN - { KASAN_SHADOW_START, "KASAN shadow" }, - { KASAN_SHADOW_END, "KASAN shadow end" }, + [USER_SPACE_NR] = { 0, "User Space" }, + [KERNEL_SPACE_NR] = { PAGE_OFFSET, "Kernel Mapping" }, + [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" }, + [VMALLOC_END_NR] = { 0UL, "vmalloc() End" }, +#ifdef CONFIG_HIGHMEM + [PKMAP_BASE_NR] = { 0UL, "Persistent kmap() Area" }, #endif -# ifdef CONFIG_X86_ESPFIX64 - { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, -# endif -# ifdef CONFIG_EFI - { EFI_VA_END, "EFI Runtime Services" }, -# endif - { __START_KERNEL_map, "High Kernel Mapping" }, - { MODULES_VADDR, "Modules" }, - { MODULES_END, "End Modules" }, -#else - { PAGE_OFFSET, "Kernel Mapping" }, - { 0/* VMALLOC_START */, "vmalloc() Area" }, - { 0/*VMALLOC_END*/, "vmalloc() End" }, -# ifdef CONFIG_HIGHMEM - { 0/*PKMAP_BASE*/, "Persistent kmap() Area" }, -# endif - { 0/*FIXADDR_START*/, "Fixmap Area" }, -#endif - { -1, NULL } /* End of list */ + [CPU_ENTRY_AREA_NR] = { 0UL, "CPU entry area" }, + [FIXADDR_START_NR] = { 0UL, "Fixmap area" }, + [END_OF_SPACE_NR] = { -1, NULL } }; +#endif /* !CONFIG_X86_64 */ + /* Multipliers for offsets within the PTEs */ #define PTE_LEVEL_MULT (PAGE_SIZE) #define PMD_LEVEL_MULT (PTRS_PER_PTE * PTE_LEVEL_MULT) @@ -140,7 +169,7 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg) static const char * const level_name[] = { "cr3", "pgd", "p4d", "pud", "pmd", "pte" }; - if (!pgprot_val(prot)) { + if (!(pr & _PAGE_PRESENT)) { /* Not present */ pt_dump_cont_printf(m, dmsg, " "); } else { @@ -447,7 +476,7 @@ static inline bool is_hypervisor_range(int idx) } static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd, - bool checkwx) + bool checkwx, bool dmesg) { #ifdef CONFIG_X86_64 pgd_t *start = (pgd_t *) &init_top_pgt; @@ -460,7 +489,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd, if (pgd) { start = pgd; - st.to_dmesg = true; + st.to_dmesg = dmesg; } st.check_wx = checkwx; @@ -498,13 +527,37 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd, void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) { - ptdump_walk_pgd_level_core(m, pgd, false); + ptdump_walk_pgd_level_core(m, pgd, false, true); +} + +void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + if (user && static_cpu_has(X86_FEATURE_PTI)) + pgd = kernel_to_user_pgdp(pgd); +#endif + ptdump_walk_pgd_level_core(m, pgd, false, false); +} +EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs); + +static void ptdump_walk_user_pgd_level_checkwx(void) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + pgd_t *pgd = (pgd_t *) &init_top_pgt; + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + pr_info("x86/mm: Checking user space page tables\n"); + pgd = kernel_to_user_pgdp(pgd); + ptdump_walk_pgd_level_core(NULL, pgd, true, false); +#endif } -EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level); void ptdump_walk_pgd_level_checkwx(void) { - ptdump_walk_pgd_level_core(NULL, NULL, true); + ptdump_walk_pgd_level_core(NULL, NULL, true, false); + ptdump_walk_user_pgd_level_checkwx(); } static int __init pt_dump_init(void) @@ -525,8 +578,8 @@ static int __init pt_dump_init(void) address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE; # endif address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; + address_markers[CPU_ENTRY_AREA_NR].start_address = CPU_ENTRY_AREA_BASE; #endif - return 0; } __initcall(pt_dump_init); diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index c3521e2be3961..30bc4812ceb8a 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -67,17 +67,22 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup, * wrapped around) will be set. Additionally, seeing the refcount * reach 0 will set ZF (Zero Flag: result was zero). In each of * these cases we want a report, since it's a boundary condition. - * + * The SF case is not reported since it indicates post-boundary + * manipulations below zero or above INT_MAX. And if none of the + * flags are set, something has gone very wrong, so report it. */ if (regs->flags & (X86_EFLAGS_OF | X86_EFLAGS_ZF)) { bool zero = regs->flags & X86_EFLAGS_ZF; refcount_error_report(regs, zero ? "hit zero" : "overflow"); + } else if ((regs->flags & X86_EFLAGS_SF) == 0) { + /* Report if none of OF, ZF, nor SF are set. */ + refcount_error_report(regs, "unexpected saturation"); } return true; } -EXPORT_SYMBOL_GPL(ex_handler_refcount); +EXPORT_SYMBOL(ex_handler_refcount); /* * Handler for when we fail to restore a task's FPU state. We should never get diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index b0ff378650a9c..b264b590eeec0 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -29,26 +29,6 @@ #define CREATE_TRACE_POINTS #include -/* - * Page fault error code bits: - * - * bit 0 == 0: no page found 1: protection fault - * bit 1 == 0: read access 1: write access - * bit 2 == 0: kernel-mode access 1: user-mode access - * bit 3 == 1: use of reserved bit detected - * bit 4 == 1: fault was an instruction fetch - * bit 5 == 1: protection keys block access - */ -enum x86_pf_error_code { - - PF_PROT = 1 << 0, - PF_WRITE = 1 << 1, - PF_USER = 1 << 2, - PF_RSVD = 1 << 3, - PF_INSTR = 1 << 4, - PF_PK = 1 << 5, -}; - /* * Returns 0 if mmiotrace is disabled, or if the fault is not * handled by mmiotrace: @@ -150,7 +130,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) * If it was a exec (instruction fetch) fault on NX page, then * do not ignore the fault: */ - if (error_code & PF_INSTR) + if (error_code & X86_PF_INSTR) return 0; instr = (void *)convert_ip_to_linear(current, regs); @@ -180,7 +160,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) * siginfo so userspace can discover which protection key was set * on the PTE. * - * If we get here, we know that the hardware signaled a PF_PK + * If we get here, we know that the hardware signaled a X86_PF_PK * fault and that there was a VMA once we got in the fault * handler. It does *not* guarantee that the VMA we find here * was the one that we faulted on. @@ -193,19 +173,20 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really * faulted on a pte with its pkey=4. */ -static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey) +static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info, + u32 *pkey) { /* This is effectively an #ifdef */ if (!boot_cpu_has(X86_FEATURE_OSPKE)) return; /* Fault not from Protection Keys: nothing to do */ - if (si_code != SEGV_PKUERR) + if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV)) return; /* * force_sig_info_fault() is called from a number of * contexts, some of which have a VMA and some of which - * do not. The PF_PK handing happens after we have a + * do not. The X86_PF_PK handing happens after we have a * valid VMA, so we should never reach this without a * valid VMA. */ @@ -239,7 +220,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, lsb = PAGE_SHIFT; info.si_addr_lsb = lsb; - fill_sig_info_pkey(si_code, &info, pkey); + fill_sig_info_pkey(si_signo, si_code, &info, pkey); force_sig_info(si_signo, &info, tsk); } @@ -698,7 +679,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code, if (!oops_may_print()) return; - if (error_code & PF_INSTR) { + if (error_code & X86_PF_INSTR) { unsigned int level; pgd_t *pgd; pte_t *pte; @@ -780,7 +761,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, */ if (current->thread.sig_on_uaccess_err && signal) { tsk->thread.trap_nr = X86_TRAP_PF; - tsk->thread.error_code = error_code | PF_USER; + tsk->thread.error_code = error_code | X86_PF_USER; tsk->thread.cr2 = address; /* XXX: hwpoison faults will set the wrong code. */ @@ -898,7 +879,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, struct task_struct *tsk = current; /* User mode accesses just cause a SIGSEGV */ - if (error_code & PF_USER) { + if (error_code & X86_PF_USER) { /* * It's possible to have interrupts off here: */ @@ -919,7 +900,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, * Instruction fetch faults in the vsyscall page might need * emulation. */ - if (unlikely((error_code & PF_INSTR) && + if (unlikely((error_code & X86_PF_INSTR) && ((address & ~0xfff) == VSYSCALL_ADDR))) { if (emulate_vsyscall(regs, address)) return; @@ -932,7 +913,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, * are always protection faults. */ if (address >= TASK_SIZE_MAX) - error_code |= PF_PROT; + error_code |= X86_PF_PROT; if (likely(show_unhandled_signals)) show_signal_msg(regs, error_code, address, tsk); @@ -993,11 +974,11 @@ static inline bool bad_area_access_from_pkeys(unsigned long error_code, if (!boot_cpu_has(X86_FEATURE_OSPKE)) return false; - if (error_code & PF_PK) + if (error_code & X86_PF_PK) return true; /* this checks permission keys on the VMA: */ - if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE), - (error_code & PF_INSTR), foreign)) + if (!arch_vma_access_permitted(vma, (error_code & X86_PF_WRITE), + (error_code & X86_PF_INSTR), foreign)) return true; return false; } @@ -1025,7 +1006,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, int code = BUS_ADRERR; /* Kernel mode? Handle exceptions or die: */ - if (!(error_code & PF_USER)) { + if (!(error_code & X86_PF_USER)) { no_context(regs, error_code, address, SIGBUS, BUS_ADRERR); return; } @@ -1053,14 +1034,14 @@ static noinline void mm_fault_error(struct pt_regs *regs, unsigned long error_code, unsigned long address, u32 *pkey, unsigned int fault) { - if (fatal_signal_pending(current) && !(error_code & PF_USER)) { + if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) { no_context(regs, error_code, address, 0, 0); return; } if (fault & VM_FAULT_OOM) { /* Kernel mode? Handle exceptions or die: */ - if (!(error_code & PF_USER)) { + if (!(error_code & X86_PF_USER)) { no_context(regs, error_code, address, SIGSEGV, SEGV_MAPERR); return; @@ -1085,16 +1066,16 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, static int spurious_fault_check(unsigned long error_code, pte_t *pte) { - if ((error_code & PF_WRITE) && !pte_write(*pte)) + if ((error_code & X86_PF_WRITE) && !pte_write(*pte)) return 0; - if ((error_code & PF_INSTR) && !pte_exec(*pte)) + if ((error_code & X86_PF_INSTR) && !pte_exec(*pte)) return 0; /* * Note: We do not do lazy flushing on protection key - * changes, so no spurious fault will ever set PF_PK. + * changes, so no spurious fault will ever set X86_PF_PK. */ - if ((error_code & PF_PK)) + if ((error_code & X86_PF_PK)) return 1; return 1; @@ -1140,8 +1121,8 @@ spurious_fault(unsigned long error_code, unsigned long address) * change, so user accesses are not expected to cause spurious * faults. */ - if (error_code != (PF_WRITE | PF_PROT) - && error_code != (PF_INSTR | PF_PROT)) + if (error_code != (X86_PF_WRITE | X86_PF_PROT) && + error_code != (X86_PF_INSTR | X86_PF_PROT)) return 0; pgd = init_mm.pgd + pgd_index(address); @@ -1201,19 +1182,19 @@ access_error(unsigned long error_code, struct vm_area_struct *vma) * always an unconditional error and can never result in * a follow-up action to resolve the fault, like a COW. */ - if (error_code & PF_PK) + if (error_code & X86_PF_PK) return 1; /* * Make sure to check the VMA so that we do not perform - * faults just to hit a PF_PK as soon as we fill in a + * faults just to hit a X86_PF_PK as soon as we fill in a * page. */ - if (!arch_vma_access_permitted(vma, (error_code & PF_WRITE), - (error_code & PF_INSTR), foreign)) + if (!arch_vma_access_permitted(vma, (error_code & X86_PF_WRITE), + (error_code & X86_PF_INSTR), foreign)) return 1; - if (error_code & PF_WRITE) { + if (error_code & X86_PF_WRITE) { /* write, present and write, not present: */ if (unlikely(!(vma->vm_flags & VM_WRITE))) return 1; @@ -1221,7 +1202,7 @@ access_error(unsigned long error_code, struct vm_area_struct *vma) } /* read, present: */ - if (unlikely(error_code & PF_PROT)) + if (unlikely(error_code & X86_PF_PROT)) return 1; /* read, not present: */ @@ -1244,7 +1225,7 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs) if (!static_cpu_has(X86_FEATURE_SMAP)) return false; - if (error_code & PF_USER) + if (error_code & X86_PF_USER) return false; if (!user_mode(regs) && (regs->flags & X86_EFLAGS_AC)) @@ -1297,7 +1278,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * protection error (error_code & 9) == 0. */ if (unlikely(fault_in_kernel_space(address))) { - if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) { + if (!(error_code & (X86_PF_RSVD | X86_PF_USER | X86_PF_PROT))) { if (vmalloc_fault(address) >= 0) return; @@ -1325,7 +1306,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, if (unlikely(kprobes_fault(regs))) return; - if (unlikely(error_code & PF_RSVD)) + if (unlikely(error_code & X86_PF_RSVD)) pgtable_bad(regs, error_code, address); if (unlikely(smap_violation(error_code, regs))) { @@ -1351,7 +1332,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, */ if (user_mode(regs)) { local_irq_enable(); - error_code |= PF_USER; + error_code |= X86_PF_USER; flags |= FAULT_FLAG_USER; } else { if (regs->flags & X86_EFLAGS_IF) @@ -1360,9 +1341,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); - if (error_code & PF_WRITE) + if (error_code & X86_PF_WRITE) flags |= FAULT_FLAG_WRITE; - if (error_code & PF_INSTR) + if (error_code & X86_PF_INSTR) flags |= FAULT_FLAG_INSTRUCTION; /* @@ -1382,7 +1363,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * space check, thus avoiding the deadlock: */ if (unlikely(!down_read_trylock(&mm->mmap_sem))) { - if ((error_code & PF_USER) == 0 && + if (!(error_code & X86_PF_USER) && !search_exception_tables(regs->ip)) { bad_area_nosemaphore(regs, error_code, address, NULL); return; @@ -1409,7 +1390,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, bad_area(regs, error_code, address); return; } - if (error_code & PF_USER) { + if (error_code & X86_PF_USER) { /* * Accessing the stack below %sp is always a bug. * The large cushion allows instructions like enter diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index af5c1ed21d43a..6b462a472a7bf 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -20,6 +20,7 @@ #include #include #include +#include /* * We need to define the tracepoints somewhere, and tlb.c @@ -161,6 +162,12 @@ struct map_range { static int page_size_mask; +static void enable_global_pages(void) +{ + if (!static_cpu_has(X86_FEATURE_PTI)) + __supported_pte_mask |= _PAGE_GLOBAL; +} + static void __init probe_page_size_mask(void) { /* @@ -179,11 +186,11 @@ static void __init probe_page_size_mask(void) cr4_set_bits_and_update_boot(X86_CR4_PSE); /* Enable PGE if available */ + __supported_pte_mask &= ~_PAGE_GLOBAL; if (boot_cpu_has(X86_FEATURE_PGE)) { cr4_set_bits_and_update_boot(X86_CR4_PGE); - __supported_pte_mask |= _PAGE_GLOBAL; - } else - __supported_pte_mask &= ~_PAGE_GLOBAL; + enable_global_pages(); + } /* Enable 1 GB linear kernel mappings if available: */ if (direct_gbpages && boot_cpu_has(X86_FEATURE_GBPAGES)) { @@ -196,34 +203,44 @@ static void __init probe_page_size_mask(void) static void setup_pcid(void) { -#ifdef CONFIG_X86_64 - if (boot_cpu_has(X86_FEATURE_PCID)) { - if (boot_cpu_has(X86_FEATURE_PGE)) { - /* - * This can't be cr4_set_bits_and_update_boot() -- - * the trampoline code can't handle CR4.PCIDE and - * it wouldn't do any good anyway. Despite the name, - * cr4_set_bits_and_update_boot() doesn't actually - * cause the bits in question to remain set all the - * way through the secondary boot asm. - * - * Instead, we brute-force it and set CR4.PCIDE - * manually in start_secondary(). - */ - cr4_set_bits(X86_CR4_PCIDE); - } else { - /* - * flush_tlb_all(), as currently implemented, won't - * work if PCID is on but PGE is not. Since that - * combination doesn't exist on real hardware, there's - * no reason to try to fully support it, but it's - * polite to avoid corrupting data if we're on - * an improperly configured VM. - */ - setup_clear_cpu_cap(X86_FEATURE_PCID); - } + if (!IS_ENABLED(CONFIG_X86_64)) + return; + + if (!boot_cpu_has(X86_FEATURE_PCID)) + return; + + if (boot_cpu_has(X86_FEATURE_PGE)) { + /* + * This can't be cr4_set_bits_and_update_boot() -- the + * trampoline code can't handle CR4.PCIDE and it wouldn't + * do any good anyway. Despite the name, + * cr4_set_bits_and_update_boot() doesn't actually cause + * the bits in question to remain set all the way through + * the secondary boot asm. + * + * Instead, we brute-force it and set CR4.PCIDE manually in + * start_secondary(). + */ + cr4_set_bits(X86_CR4_PCIDE); + + /* + * INVPCID's single-context modes (2/3) only work if we set + * X86_CR4_PCIDE, *and* we INVPCID support. It's unusable + * on systems that have X86_CR4_PCIDE clear, or that have + * no INVPCID support at all. + */ + if (boot_cpu_has(X86_FEATURE_INVPCID)) + setup_force_cpu_cap(X86_FEATURE_INVPCID_SINGLE); + } else { + /* + * flush_tlb_all(), as currently implemented, won't work if + * PCID is on but PGE is not. Since that combination + * doesn't exist on real hardware, there's no reason to try + * to fully support it, but it's polite to avoid corrupting + * data if we're on an improperly configured VM. + */ + setup_clear_cpu_cap(X86_FEATURE_PCID); } -#endif } #ifdef CONFIG_X86_32 @@ -624,6 +641,7 @@ void __init init_mem_mapping(void) { unsigned long end; + pti_check_boottime_disable(); probe_page_size_mask(); setup_pcid(); @@ -671,7 +689,7 @@ void __init init_mem_mapping(void) load_cr3(swapper_pg_dir); __flush_tlb_all(); - hypervisor_init_mem_mapping(); + x86_init.hyper.init_mem_mapping(); early_memtest(0, max_pfn_mapped << PAGE_SHIFT); } @@ -847,12 +865,12 @@ void __init zone_sizes_init(void) free_area_init_nodes(max_zone_pfns); } -DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { +__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { .loaded_mm = &init_mm, .next_asid = 1, .cr4 = ~0UL, /* fail hard if we screw up cr4 shadow initialization */ }; -EXPORT_SYMBOL_GPL(cpu_tlbstate); +EXPORT_PER_CPU_SYMBOL(cpu_tlbstate); void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache) { diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 8a64a6f2848d9..135c9a7898c7d 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include "mm_internal.h" @@ -766,6 +767,7 @@ void __init mem_init(void) mem_init_print_info(NULL); printk(KERN_INFO "virtual kernel memory layout:\n" " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" + " cpu_entry : 0x%08lx - 0x%08lx (%4ld kB)\n" #ifdef CONFIG_HIGHMEM " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" #endif @@ -777,6 +779,10 @@ void __init mem_init(void) FIXADDR_START, FIXADDR_TOP, (FIXADDR_TOP - FIXADDR_START) >> 10, + CPU_ENTRY_AREA_BASE, + CPU_ENTRY_AREA_BASE + CPU_ENTRY_AREA_MAP_SIZE, + CPU_ENTRY_AREA_MAP_SIZE >> 10, + #ifdef CONFIG_HIGHMEM PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, (LAST_PKMAP*PAGE_SIZE) >> 10, diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 048fbe8fc2740..adcea90a2046e 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1426,16 +1426,16 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HAVE_BOOTMEM_INFO_NODE) void register_page_bootmem_memmap(unsigned long section_nr, - struct page *start_page, unsigned long size) + struct page *start_page, unsigned long nr_pages) { unsigned long addr = (unsigned long)start_page; - unsigned long end = (unsigned long)(start_page + size); + unsigned long end = (unsigned long)(start_page + nr_pages); unsigned long next; pgd_t *pgd; p4d_t *p4d; pud_t *pud; pmd_t *pmd; - unsigned int nr_pages; + unsigned int nr_pmd_pages; struct page *page; for (; addr < end; addr = next) { @@ -1482,9 +1482,9 @@ void register_page_bootmem_memmap(unsigned long section_nr, if (pmd_none(*pmd)) continue; - nr_pages = 1 << (get_order(PMD_SIZE)); + nr_pmd_pages = 1 << get_order(PMD_SIZE); page = pmd_page(*pmd); - while (nr_pages--) + while (nr_pmd_pages--) get_page_bootmem(section_nr, page++, SECTION_INFO); } diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c index 8f5be3eb40ddb..af6f2f9c6a265 100644 --- a/arch/x86/mm/kasan_init_64.c +++ b/arch/x86/mm/kasan_init_64.c @@ -4,19 +4,155 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include extern struct range pfn_mapped[E820_MAX_ENTRIES]; -static int __init map_range(struct range *range) +static p4d_t tmp_p4d_table[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE); + +static __init void *early_alloc(size_t size, int nid, bool panic) +{ + if (panic) + return memblock_virt_alloc_try_nid(size, size, + __pa(MAX_DMA_ADDRESS), BOOTMEM_ALLOC_ACCESSIBLE, nid); + else + return memblock_virt_alloc_try_nid_nopanic(size, size, + __pa(MAX_DMA_ADDRESS), BOOTMEM_ALLOC_ACCESSIBLE, nid); +} + +static void __init kasan_populate_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, int nid) +{ + pte_t *pte; + + if (pmd_none(*pmd)) { + void *p; + + if (boot_cpu_has(X86_FEATURE_PSE) && + ((end - addr) == PMD_SIZE) && + IS_ALIGNED(addr, PMD_SIZE)) { + p = early_alloc(PMD_SIZE, nid, false); + if (p && pmd_set_huge(pmd, __pa(p), PAGE_KERNEL)) + return; + else if (p) + memblock_free(__pa(p), PMD_SIZE); + } + + p = early_alloc(PAGE_SIZE, nid, true); + pmd_populate_kernel(&init_mm, pmd, p); + } + + pte = pte_offset_kernel(pmd, addr); + do { + pte_t entry; + void *p; + + if (!pte_none(*pte)) + continue; + + p = early_alloc(PAGE_SIZE, nid, true); + entry = pfn_pte(PFN_DOWN(__pa(p)), PAGE_KERNEL); + set_pte_at(&init_mm, addr, pte, entry); + } while (pte++, addr += PAGE_SIZE, addr != end); +} + +static void __init kasan_populate_pud(pud_t *pud, unsigned long addr, + unsigned long end, int nid) +{ + pmd_t *pmd; + unsigned long next; + + if (pud_none(*pud)) { + void *p; + + if (boot_cpu_has(X86_FEATURE_GBPAGES) && + ((end - addr) == PUD_SIZE) && + IS_ALIGNED(addr, PUD_SIZE)) { + p = early_alloc(PUD_SIZE, nid, false); + if (p && pud_set_huge(pud, __pa(p), PAGE_KERNEL)) + return; + else if (p) + memblock_free(__pa(p), PUD_SIZE); + } + + p = early_alloc(PAGE_SIZE, nid, true); + pud_populate(&init_mm, pud, p); + } + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (!pmd_large(*pmd)) + kasan_populate_pmd(pmd, addr, next, nid); + } while (pmd++, addr = next, addr != end); +} + +static void __init kasan_populate_p4d(p4d_t *p4d, unsigned long addr, + unsigned long end, int nid) +{ + pud_t *pud; + unsigned long next; + + if (p4d_none(*p4d)) { + void *p = early_alloc(PAGE_SIZE, nid, true); + + p4d_populate(&init_mm, p4d, p); + } + + pud = pud_offset(p4d, addr); + do { + next = pud_addr_end(addr, end); + if (!pud_large(*pud)) + kasan_populate_pud(pud, addr, next, nid); + } while (pud++, addr = next, addr != end); +} + +static void __init kasan_populate_pgd(pgd_t *pgd, unsigned long addr, + unsigned long end, int nid) +{ + void *p; + p4d_t *p4d; + unsigned long next; + + if (pgd_none(*pgd)) { + p = early_alloc(PAGE_SIZE, nid, true); + pgd_populate(&init_mm, pgd, p); + } + + p4d = p4d_offset(pgd, addr); + do { + next = p4d_addr_end(addr, end); + kasan_populate_p4d(p4d, addr, next, nid); + } while (p4d++, addr = next, addr != end); +} + +static void __init kasan_populate_shadow(unsigned long addr, unsigned long end, + int nid) +{ + pgd_t *pgd; + unsigned long next; + + addr = addr & PAGE_MASK; + end = round_up(end, PAGE_SIZE); + pgd = pgd_offset_k(addr); + do { + next = pgd_addr_end(addr, end); + kasan_populate_pgd(pgd, addr, next, nid); + } while (pgd++, addr = next, addr != end); +} + +static void __init map_range(struct range *range) { unsigned long start; unsigned long end; @@ -24,15 +160,17 @@ static int __init map_range(struct range *range) start = (unsigned long)kasan_mem_to_shadow(pfn_to_kaddr(range->start)); end = (unsigned long)kasan_mem_to_shadow(pfn_to_kaddr(range->end)); - return vmemmap_populate(start, end, NUMA_NO_NODE); + kasan_populate_shadow(start, end, early_pfn_to_nid(range->start)); } static void __init clear_pgds(unsigned long start, unsigned long end) { pgd_t *pgd; + /* See comment in kasan_init() */ + unsigned long pgd_end = end & PGDIR_MASK; - for (; start < end; start += PGDIR_SIZE) { + for (; start < pgd_end; start += PGDIR_SIZE) { pgd = pgd_offset_k(start); /* * With folded p4d, pgd_clear() is nop, use p4d_clear() @@ -43,29 +181,61 @@ static void __init clear_pgds(unsigned long start, else pgd_clear(pgd); } + + pgd = pgd_offset_k(start); + for (; start < end; start += P4D_SIZE) + p4d_clear(p4d_offset(pgd, start)); +} + +static inline p4d_t *early_p4d_offset(pgd_t *pgd, unsigned long addr) +{ + unsigned long p4d; + + if (!IS_ENABLED(CONFIG_X86_5LEVEL)) + return (p4d_t *)pgd; + + p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK; + p4d += __START_KERNEL_map - phys_base; + return (p4d_t *)p4d + p4d_index(addr); +} + +static void __init kasan_early_p4d_populate(pgd_t *pgd, + unsigned long addr, + unsigned long end) +{ + pgd_t pgd_entry; + p4d_t *p4d, p4d_entry; + unsigned long next; + + if (pgd_none(*pgd)) { + pgd_entry = __pgd(_KERNPG_TABLE | __pa_nodebug(kasan_zero_p4d)); + set_pgd(pgd, pgd_entry); + } + + p4d = early_p4d_offset(pgd, addr); + do { + next = p4d_addr_end(addr, end); + + if (!p4d_none(*p4d)) + continue; + + p4d_entry = __p4d(_KERNPG_TABLE | __pa_nodebug(kasan_zero_pud)); + set_p4d(p4d, p4d_entry); + } while (p4d++, addr = next, addr != end && p4d_none(*p4d)); } static void __init kasan_map_early_shadow(pgd_t *pgd) { - int i; - unsigned long start = KASAN_SHADOW_START; + /* See comment in kasan_init() */ + unsigned long addr = KASAN_SHADOW_START & PGDIR_MASK; unsigned long end = KASAN_SHADOW_END; + unsigned long next; - for (i = pgd_index(start); start < end; i++) { - switch (CONFIG_PGTABLE_LEVELS) { - case 4: - pgd[i] = __pgd(__pa_nodebug(kasan_zero_pud) | - _KERNPG_TABLE); - break; - case 5: - pgd[i] = __pgd(__pa_nodebug(kasan_zero_p4d) | - _KERNPG_TABLE); - break; - default: - BUILD_BUG(); - } - start += PGDIR_SIZE; - } + pgd += pgd_index(addr); + do { + next = pgd_addr_end(addr, end); + kasan_early_p4d_populate(pgd, addr, next); + } while (pgd++, addr = next, addr != end); } #ifdef CONFIG_KASAN_INLINE @@ -102,7 +272,7 @@ void __init kasan_early_init(void) for (i = 0; i < PTRS_PER_PUD; i++) kasan_zero_pud[i] = __pud(pud_val); - for (i = 0; CONFIG_PGTABLE_LEVELS >= 5 && i < PTRS_PER_P4D; i++) + for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++) kasan_zero_p4d[i] = __p4d(p4d_val); kasan_map_early_shadow(early_top_pgt); @@ -112,37 +282,78 @@ void __init kasan_early_init(void) void __init kasan_init(void) { int i; + void *shadow_cpu_entry_begin, *shadow_cpu_entry_end; #ifdef CONFIG_KASAN_INLINE register_die_notifier(&kasan_die_notifier); #endif memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt)); + + /* + * We use the same shadow offset for 4- and 5-level paging to + * facilitate boot-time switching between paging modes. + * As result in 5-level paging mode KASAN_SHADOW_START and + * KASAN_SHADOW_END are not aligned to PGD boundary. + * + * KASAN_SHADOW_START doesn't share PGD with anything else. + * We claim whole PGD entry to make things easier. + * + * KASAN_SHADOW_END lands in the last PGD entry and it collides with + * bunch of things like kernel code, modules, EFI mapping, etc. + * We need to take extra steps to not overwrite them. + */ + if (IS_ENABLED(CONFIG_X86_5LEVEL)) { + void *ptr; + + ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END)); + memcpy(tmp_p4d_table, (void *)ptr, sizeof(tmp_p4d_table)); + set_pgd(&early_top_pgt[pgd_index(KASAN_SHADOW_END)], + __pgd(__pa(tmp_p4d_table) | _KERNPG_TABLE)); + } + load_cr3(early_top_pgt); __flush_tlb_all(); - clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); + clear_pgds(KASAN_SHADOW_START & PGDIR_MASK, KASAN_SHADOW_END); - kasan_populate_zero_shadow((void *)KASAN_SHADOW_START, + kasan_populate_zero_shadow((void *)(KASAN_SHADOW_START & PGDIR_MASK), kasan_mem_to_shadow((void *)PAGE_OFFSET)); for (i = 0; i < E820_MAX_ENTRIES; i++) { if (pfn_mapped[i].end == 0) break; - if (map_range(&pfn_mapped[i])) - panic("kasan: unable to allocate shadow!"); + map_range(&pfn_mapped[i]); } + + shadow_cpu_entry_begin = (void *)CPU_ENTRY_AREA_BASE; + shadow_cpu_entry_begin = kasan_mem_to_shadow(shadow_cpu_entry_begin); + shadow_cpu_entry_begin = (void *)round_down((unsigned long)shadow_cpu_entry_begin, + PAGE_SIZE); + + shadow_cpu_entry_end = (void *)(CPU_ENTRY_AREA_BASE + + CPU_ENTRY_AREA_MAP_SIZE); + shadow_cpu_entry_end = kasan_mem_to_shadow(shadow_cpu_entry_end); + shadow_cpu_entry_end = (void *)round_up((unsigned long)shadow_cpu_entry_end, + PAGE_SIZE); + kasan_populate_zero_shadow( kasan_mem_to_shadow((void *)PAGE_OFFSET + MAXMEM), - kasan_mem_to_shadow((void *)__START_KERNEL_map)); + shadow_cpu_entry_begin); + + kasan_populate_shadow((unsigned long)shadow_cpu_entry_begin, + (unsigned long)shadow_cpu_entry_end, 0); + + kasan_populate_zero_shadow(shadow_cpu_entry_end, + kasan_mem_to_shadow((void *)__START_KERNEL_map)); - vmemmap_populate((unsigned long)kasan_mem_to_shadow(_stext), - (unsigned long)kasan_mem_to_shadow(_end), - NUMA_NO_NODE); + kasan_populate_shadow((unsigned long)kasan_mem_to_shadow(_stext), + (unsigned long)kasan_mem_to_shadow(_end), + early_pfn_to_nid(__pa(_stext))); kasan_populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_END), - (void *)KASAN_SHADOW_END); + (void *)KASAN_SHADOW_END); load_cr3(init_top_pgt); __flush_tlb_all(); diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 879ef930e2c2b..aedebd2ebf1ea 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -34,25 +34,14 @@ #define TB_SHIFT 40 /* - * Virtual address start and end range for randomization. The end changes base - * on configuration to have the highest amount of space for randomization. - * It increases the possible random position for each randomized region. + * Virtual address start and end range for randomization. * - * You need to add an if/def entry if you introduce a new memory region - * compatible with KASLR. Your entry must be in logical order with memory - * layout. For example, ESPFIX is before EFI because its virtual address is - * before. You also need to add a BUILD_BUG_ON() in kernel_randomize_memory() to - * ensure that this order is correct and won't be changed. + * The end address could depend on more configuration options to make the + * highest amount of space for randomization available, but that's too hard + * to keep straight and caused issues already. */ static const unsigned long vaddr_start = __PAGE_OFFSET_BASE; - -#if defined(CONFIG_X86_ESPFIX64) -static const unsigned long vaddr_end = ESPFIX_BASE_ADDR; -#elif defined(CONFIG_EFI) -static const unsigned long vaddr_end = EFI_VA_END; -#else -static const unsigned long vaddr_end = __START_KERNEL_map; -#endif +static const unsigned long vaddr_end = CPU_ENTRY_AREA_BASE; /* Default values */ unsigned long page_offset_base = __PAGE_OFFSET_BASE; @@ -101,15 +90,12 @@ void __init kernel_randomize_memory(void) unsigned long remain_entropy; /* - * All these BUILD_BUG_ON checks ensures the memory layout is - * consistent with the vaddr_start/vaddr_end variables. + * These BUILD_BUG_ON checks ensure the memory layout is consistent + * with the vaddr_start/vaddr_end variables. These checks are very + * limited.... */ BUILD_BUG_ON(vaddr_start >= vaddr_end); - BUILD_BUG_ON(IS_ENABLED(CONFIG_X86_ESPFIX64) && - vaddr_end >= EFI_VA_END); - BUILD_BUG_ON((IS_ENABLED(CONFIG_X86_ESPFIX64) || - IS_ENABLED(CONFIG_EFI)) && - vaddr_end >= __START_KERNEL_map); + BUILD_BUG_ON(vaddr_end != CPU_ENTRY_AREA_BASE); BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); if (!kaslr_memory_enabled()) diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 0286327e65fa2..48c03c74c7f4b 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -213,37 +213,62 @@ void swiotlb_set_mem_attributes(void *vaddr, unsigned long size) set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT); } -static void __init sme_clear_pgd(pgd_t *pgd_base, unsigned long start, - unsigned long end) +struct sme_populate_pgd_data { + void *pgtable_area; + pgd_t *pgd; + + pmdval_t pmd_flags; + pteval_t pte_flags; + unsigned long paddr; + + unsigned long vaddr; + unsigned long vaddr_end; +}; + +static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd) { unsigned long pgd_start, pgd_end, pgd_size; pgd_t *pgd_p; - pgd_start = start & PGDIR_MASK; - pgd_end = end & PGDIR_MASK; + pgd_start = ppd->vaddr & PGDIR_MASK; + pgd_end = ppd->vaddr_end & PGDIR_MASK; - pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1); - pgd_size *= sizeof(pgd_t); + pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t); - pgd_p = pgd_base + pgd_index(start); + pgd_p = ppd->pgd + pgd_index(ppd->vaddr); memset(pgd_p, 0, pgd_size); } -#define PGD_FLAGS _KERNPG_TABLE_NOENC -#define P4D_FLAGS _KERNPG_TABLE_NOENC -#define PUD_FLAGS _KERNPG_TABLE_NOENC -#define PMD_FLAGS (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL) +#define PGD_FLAGS _KERNPG_TABLE_NOENC +#define P4D_FLAGS _KERNPG_TABLE_NOENC +#define PUD_FLAGS _KERNPG_TABLE_NOENC +#define PMD_FLAGS _KERNPG_TABLE_NOENC + +#define PMD_FLAGS_LARGE (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL) + +#define PMD_FLAGS_DEC PMD_FLAGS_LARGE +#define PMD_FLAGS_DEC_WP ((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \ + (_PAGE_PAT | _PAGE_PWT)) + +#define PMD_FLAGS_ENC (PMD_FLAGS_LARGE | _PAGE_ENC) + +#define PTE_FLAGS (__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL) + +#define PTE_FLAGS_DEC PTE_FLAGS +#define PTE_FLAGS_DEC_WP ((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \ + (_PAGE_PAT | _PAGE_PWT)) + +#define PTE_FLAGS_ENC (PTE_FLAGS | _PAGE_ENC) -static void __init *sme_populate_pgd(pgd_t *pgd_base, void *pgtable_area, - unsigned long vaddr, pmdval_t pmd_val) +static pmd_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd) { pgd_t *pgd_p; p4d_t *p4d_p; pud_t *pud_p; pmd_t *pmd_p; - pgd_p = pgd_base + pgd_index(vaddr); + pgd_p = ppd->pgd + pgd_index(ppd->vaddr); if (native_pgd_val(*pgd_p)) { if (IS_ENABLED(CONFIG_X86_5LEVEL)) p4d_p = (p4d_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK); @@ -253,15 +278,15 @@ static void __init *sme_populate_pgd(pgd_t *pgd_base, void *pgtable_area, pgd_t pgd; if (IS_ENABLED(CONFIG_X86_5LEVEL)) { - p4d_p = pgtable_area; + p4d_p = ppd->pgtable_area; memset(p4d_p, 0, sizeof(*p4d_p) * PTRS_PER_P4D); - pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D; + ppd->pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D; pgd = native_make_pgd((pgdval_t)p4d_p + PGD_FLAGS); } else { - pud_p = pgtable_area; + pud_p = ppd->pgtable_area; memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD); - pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD; + ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD; pgd = native_make_pgd((pgdval_t)pud_p + PGD_FLAGS); } @@ -269,58 +294,160 @@ static void __init *sme_populate_pgd(pgd_t *pgd_base, void *pgtable_area, } if (IS_ENABLED(CONFIG_X86_5LEVEL)) { - p4d_p += p4d_index(vaddr); + p4d_p += p4d_index(ppd->vaddr); if (native_p4d_val(*p4d_p)) { pud_p = (pud_t *)(native_p4d_val(*p4d_p) & ~PTE_FLAGS_MASK); } else { p4d_t p4d; - pud_p = pgtable_area; + pud_p = ppd->pgtable_area; memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD); - pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD; + ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD; p4d = native_make_p4d((pudval_t)pud_p + P4D_FLAGS); native_set_p4d(p4d_p, p4d); } } - pud_p += pud_index(vaddr); + pud_p += pud_index(ppd->vaddr); if (native_pud_val(*pud_p)) { if (native_pud_val(*pud_p) & _PAGE_PSE) - goto out; + return NULL; pmd_p = (pmd_t *)(native_pud_val(*pud_p) & ~PTE_FLAGS_MASK); } else { pud_t pud; - pmd_p = pgtable_area; + pmd_p = ppd->pgtable_area; memset(pmd_p, 0, sizeof(*pmd_p) * PTRS_PER_PMD); - pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD; + ppd->pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD; pud = native_make_pud((pmdval_t)pmd_p + PUD_FLAGS); native_set_pud(pud_p, pud); } - pmd_p += pmd_index(vaddr); + return pmd_p; +} + +static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd) +{ + pmd_t *pmd_p; + + pmd_p = sme_prepare_pgd(ppd); + if (!pmd_p) + return; + + pmd_p += pmd_index(ppd->vaddr); if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE)) - native_set_pmd(pmd_p, native_make_pmd(pmd_val)); + native_set_pmd(pmd_p, native_make_pmd(ppd->paddr | ppd->pmd_flags)); +} + +static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd) +{ + pmd_t *pmd_p; + pte_t *pte_p; + + pmd_p = sme_prepare_pgd(ppd); + if (!pmd_p) + return; + + pmd_p += pmd_index(ppd->vaddr); + if (native_pmd_val(*pmd_p)) { + if (native_pmd_val(*pmd_p) & _PAGE_PSE) + return; + + pte_p = (pte_t *)(native_pmd_val(*pmd_p) & ~PTE_FLAGS_MASK); + } else { + pmd_t pmd; + + pte_p = ppd->pgtable_area; + memset(pte_p, 0, sizeof(*pte_p) * PTRS_PER_PTE); + ppd->pgtable_area += sizeof(*pte_p) * PTRS_PER_PTE; + + pmd = native_make_pmd((pteval_t)pte_p + PMD_FLAGS); + native_set_pmd(pmd_p, pmd); + } -out: - return pgtable_area; + pte_p += pte_index(ppd->vaddr); + if (!native_pte_val(*pte_p)) + native_set_pte(pte_p, native_make_pte(ppd->paddr | ppd->pte_flags)); +} + +static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd) +{ + while (ppd->vaddr < ppd->vaddr_end) { + sme_populate_pgd_large(ppd); + + ppd->vaddr += PMD_PAGE_SIZE; + ppd->paddr += PMD_PAGE_SIZE; + } +} + +static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd) +{ + while (ppd->vaddr < ppd->vaddr_end) { + sme_populate_pgd(ppd); + + ppd->vaddr += PAGE_SIZE; + ppd->paddr += PAGE_SIZE; + } +} + +static void __init __sme_map_range(struct sme_populate_pgd_data *ppd, + pmdval_t pmd_flags, pteval_t pte_flags) +{ + unsigned long vaddr_end; + + ppd->pmd_flags = pmd_flags; + ppd->pte_flags = pte_flags; + + /* Save original end value since we modify the struct value */ + vaddr_end = ppd->vaddr_end; + + /* If start is not 2MB aligned, create PTE entries */ + ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE); + __sme_map_range_pte(ppd); + + /* Create PMD entries */ + ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK; + __sme_map_range_pmd(ppd); + + /* If end is not 2MB aligned, create PTE entries */ + ppd->vaddr_end = vaddr_end; + __sme_map_range_pte(ppd); +} + +static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd) +{ + __sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC); +} + +static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd) +{ + __sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC); +} + +static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd) +{ + __sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP); } static unsigned long __init sme_pgtable_calc(unsigned long len) { - unsigned long p4d_size, pud_size, pmd_size; + unsigned long p4d_size, pud_size, pmd_size, pte_size; unsigned long total; /* * Perform a relatively simplistic calculation of the pagetable - * entries that are needed. That mappings will be covered by 2MB - * PMD entries so we can conservatively calculate the required + * entries that are needed. Those mappings will be covered mostly + * by 2MB PMD entries so we can conservatively calculate the required * number of P4D, PUD and PMD structures needed to perform the - * mappings. Incrementing the count for each covers the case where - * the addresses cross entries. + * mappings. For mappings that are not 2MB aligned, PTE mappings + * would be needed for the start and end portion of the address range + * that fall outside of the 2MB alignment. This results in, at most, + * two extra pages to hold PTE entries for each range that is mapped. + * Incrementing the count for each covers the case where the addresses + * cross entries. */ if (IS_ENABLED(CONFIG_X86_5LEVEL)) { p4d_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1; @@ -334,8 +461,9 @@ static unsigned long __init sme_pgtable_calc(unsigned long len) } pmd_size = (ALIGN(len, PUD_SIZE) / PUD_SIZE) + 1; pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD; + pte_size = 2 * sizeof(pte_t) * PTRS_PER_PTE; - total = p4d_size + pud_size + pmd_size; + total = p4d_size + pud_size + pmd_size + pte_size; /* * Now calculate the added pagetable structures needed to populate @@ -359,29 +487,29 @@ static unsigned long __init sme_pgtable_calc(unsigned long len) return total; } -void __init sme_encrypt_kernel(void) +void __init __nostackprotector sme_encrypt_kernel(struct boot_params *bp) { unsigned long workarea_start, workarea_end, workarea_len; unsigned long execute_start, execute_end, execute_len; unsigned long kernel_start, kernel_end, kernel_len; + unsigned long initrd_start, initrd_end, initrd_len; + struct sme_populate_pgd_data ppd; unsigned long pgtable_area_len; - unsigned long paddr, pmd_flags; unsigned long decrypted_base; - void *pgtable_area; - pgd_t *pgd; if (!sme_active()) return; /* - * Prepare for encrypting the kernel by building new pagetables with - * the necessary attributes needed to encrypt the kernel in place. + * Prepare for encrypting the kernel and initrd by building new + * pagetables with the necessary attributes needed to encrypt the + * kernel in place. * * One range of virtual addresses will map the memory occupied - * by the kernel as encrypted. + * by the kernel and initrd as encrypted. * * Another range of virtual addresses will map the memory occupied - * by the kernel as decrypted and write-protected. + * by the kernel and initrd as decrypted and write-protected. * * The use of write-protect attribute will prevent any of the * memory from being cached. @@ -392,6 +520,20 @@ void __init sme_encrypt_kernel(void) kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE); kernel_len = kernel_end - kernel_start; + initrd_start = 0; + initrd_end = 0; + initrd_len = 0; +#ifdef CONFIG_BLK_DEV_INITRD + initrd_len = (unsigned long)bp->hdr.ramdisk_size | + ((unsigned long)bp->ext_ramdisk_size << 32); + if (initrd_len) { + initrd_start = (unsigned long)bp->hdr.ramdisk_image | + ((unsigned long)bp->ext_ramdisk_image << 32); + initrd_end = PAGE_ALIGN(initrd_start + initrd_len); + initrd_len = initrd_end - initrd_start; + } +#endif + /* Set the encryption workarea to be immediately after the kernel */ workarea_start = kernel_end; @@ -414,16 +556,21 @@ void __init sme_encrypt_kernel(void) */ pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD; pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2; + if (initrd_len) + pgtable_area_len += sme_pgtable_calc(initrd_len) * 2; /* PUDs and PMDs needed in the current pagetables for the workarea */ pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len); /* * The total workarea includes the executable encryption area and - * the pagetable area. + * the pagetable area. The start of the workarea is already 2MB + * aligned, align the end of the workarea on a 2MB boundary so that + * we don't try to create/allocate PTE entries from the workarea + * before it is mapped. */ workarea_len = execute_len + pgtable_area_len; - workarea_end = workarea_start + workarea_len; + workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE); /* * Set the address to the start of where newly created pagetable @@ -432,45 +579,30 @@ void __init sme_encrypt_kernel(void) * pagetables and when the new encrypted and decrypted kernel * mappings are populated. */ - pgtable_area = (void *)execute_end; + ppd.pgtable_area = (void *)execute_end; /* * Make sure the current pagetable structure has entries for * addressing the workarea. */ - pgd = (pgd_t *)native_read_cr3_pa(); - paddr = workarea_start; - while (paddr < workarea_end) { - pgtable_area = sme_populate_pgd(pgd, pgtable_area, - paddr, - paddr + PMD_FLAGS); - - paddr += PMD_PAGE_SIZE; - } + ppd.pgd = (pgd_t *)native_read_cr3_pa(); + ppd.paddr = workarea_start; + ppd.vaddr = workarea_start; + ppd.vaddr_end = workarea_end; + sme_map_range_decrypted(&ppd); /* Flush the TLB - no globals so cr3 is enough */ native_write_cr3(__native_read_cr3()); /* * A new pagetable structure is being built to allow for the kernel - * to be encrypted. It starts with an empty PGD that will then be - * populated with new PUDs and PMDs as the encrypted and decrypted - * kernel mappings are created. + * and initrd to be encrypted. It starts with an empty PGD that will + * then be populated with new PUDs and PMDs as the encrypted and + * decrypted kernel mappings are created. */ - pgd = pgtable_area; - memset(pgd, 0, sizeof(*pgd) * PTRS_PER_PGD); - pgtable_area += sizeof(*pgd) * PTRS_PER_PGD; - - /* Add encrypted kernel (identity) mappings */ - pmd_flags = PMD_FLAGS | _PAGE_ENC; - paddr = kernel_start; - while (paddr < kernel_end) { - pgtable_area = sme_populate_pgd(pgd, pgtable_area, - paddr, - paddr + pmd_flags); - - paddr += PMD_PAGE_SIZE; - } + ppd.pgd = ppd.pgtable_area; + memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD); + ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD; /* * A different PGD index/entry must be used to get different @@ -479,47 +611,79 @@ void __init sme_encrypt_kernel(void) * the base of the mapping. */ decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1); + if (initrd_len) { + unsigned long check_base; + + check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1); + decrypted_base = max(decrypted_base, check_base); + } decrypted_base <<= PGDIR_SHIFT; + /* Add encrypted kernel (identity) mappings */ + ppd.paddr = kernel_start; + ppd.vaddr = kernel_start; + ppd.vaddr_end = kernel_end; + sme_map_range_encrypted(&ppd); + /* Add decrypted, write-protected kernel (non-identity) mappings */ - pmd_flags = (PMD_FLAGS & ~_PAGE_CACHE_MASK) | (_PAGE_PAT | _PAGE_PWT); - paddr = kernel_start; - while (paddr < kernel_end) { - pgtable_area = sme_populate_pgd(pgd, pgtable_area, - paddr + decrypted_base, - paddr + pmd_flags); - - paddr += PMD_PAGE_SIZE; + ppd.paddr = kernel_start; + ppd.vaddr = kernel_start + decrypted_base; + ppd.vaddr_end = kernel_end + decrypted_base; + sme_map_range_decrypted_wp(&ppd); + + if (initrd_len) { + /* Add encrypted initrd (identity) mappings */ + ppd.paddr = initrd_start; + ppd.vaddr = initrd_start; + ppd.vaddr_end = initrd_end; + sme_map_range_encrypted(&ppd); + /* + * Add decrypted, write-protected initrd (non-identity) mappings + */ + ppd.paddr = initrd_start; + ppd.vaddr = initrd_start + decrypted_base; + ppd.vaddr_end = initrd_end + decrypted_base; + sme_map_range_decrypted_wp(&ppd); } /* Add decrypted workarea mappings to both kernel mappings */ - paddr = workarea_start; - while (paddr < workarea_end) { - pgtable_area = sme_populate_pgd(pgd, pgtable_area, - paddr, - paddr + PMD_FLAGS); + ppd.paddr = workarea_start; + ppd.vaddr = workarea_start; + ppd.vaddr_end = workarea_end; + sme_map_range_decrypted(&ppd); - pgtable_area = sme_populate_pgd(pgd, pgtable_area, - paddr + decrypted_base, - paddr + PMD_FLAGS); - - paddr += PMD_PAGE_SIZE; - } + ppd.paddr = workarea_start; + ppd.vaddr = workarea_start + decrypted_base; + ppd.vaddr_end = workarea_end + decrypted_base; + sme_map_range_decrypted(&ppd); /* Perform the encryption */ sme_encrypt_execute(kernel_start, kernel_start + decrypted_base, - kernel_len, workarea_start, (unsigned long)pgd); + kernel_len, workarea_start, (unsigned long)ppd.pgd); + + if (initrd_len) + sme_encrypt_execute(initrd_start, initrd_start + decrypted_base, + initrd_len, workarea_start, + (unsigned long)ppd.pgd); /* * At this point we are running encrypted. Remove the mappings for * the decrypted areas - all that is needed for this is to remove * the PGD entry/entries. */ - sme_clear_pgd(pgd, kernel_start + decrypted_base, - kernel_end + decrypted_base); + ppd.vaddr = kernel_start + decrypted_base; + ppd.vaddr_end = kernel_end + decrypted_base; + sme_clear_pgd(&ppd); + + if (initrd_len) { + ppd.vaddr = initrd_start + decrypted_base; + ppd.vaddr_end = initrd_end + decrypted_base; + sme_clear_pgd(&ppd); + } - sme_clear_pgd(pgd, workarea_start + decrypted_base, - workarea_end + decrypted_base); + ppd.vaddr = workarea_start + decrypted_base; + ppd.vaddr_end = workarea_end + decrypted_base; + sme_clear_pgd(&ppd); /* Flush the TLB - no globals so cr3 is enough */ native_write_cr3(__native_read_cr3()); diff --git a/arch/x86/mm/mem_encrypt_boot.S b/arch/x86/mm/mem_encrypt_boot.S index 730e6d541df1d..01f682cf77a8b 100644 --- a/arch/x86/mm/mem_encrypt_boot.S +++ b/arch/x86/mm/mem_encrypt_boot.S @@ -22,9 +22,9 @@ ENTRY(sme_encrypt_execute) /* * Entry parameters: - * RDI - virtual address for the encrypted kernel mapping - * RSI - virtual address for the decrypted kernel mapping - * RDX - length of kernel + * RDI - virtual address for the encrypted mapping + * RSI - virtual address for the decrypted mapping + * RDX - length to encrypt * RCX - virtual address of the encryption workarea, including: * - stack page (PAGE_SIZE) * - encryption routine page (PAGE_SIZE) @@ -41,9 +41,9 @@ ENTRY(sme_encrypt_execute) addq $PAGE_SIZE, %rax /* Workarea encryption routine */ push %r12 - movq %rdi, %r10 /* Encrypted kernel */ - movq %rsi, %r11 /* Decrypted kernel */ - movq %rdx, %r12 /* Kernel length */ + movq %rdi, %r10 /* Encrypted area */ + movq %rsi, %r11 /* Decrypted area */ + movq %rdx, %r12 /* Area length */ /* Copy encryption routine into the workarea */ movq %rax, %rdi /* Workarea encryption routine */ @@ -52,10 +52,10 @@ ENTRY(sme_encrypt_execute) rep movsb /* Setup registers for call */ - movq %r10, %rdi /* Encrypted kernel */ - movq %r11, %rsi /* Decrypted kernel */ + movq %r10, %rdi /* Encrypted area */ + movq %r11, %rsi /* Decrypted area */ movq %r8, %rdx /* Pagetables used for encryption */ - movq %r12, %rcx /* Kernel length */ + movq %r12, %rcx /* Area length */ movq %rax, %r8 /* Workarea encryption routine */ addq $PAGE_SIZE, %r8 /* Workarea intermediate copy buffer */ @@ -71,7 +71,7 @@ ENDPROC(sme_encrypt_execute) ENTRY(__enc_copy) /* - * Routine used to encrypt kernel. + * Routine used to encrypt memory in place. * This routine must be run outside of the kernel proper since * the kernel will be encrypted during the process. So this * routine is defined here and then copied to an area outside @@ -79,19 +79,19 @@ ENTRY(__enc_copy) * during execution. * * On entry the registers must be: - * RDI - virtual address for the encrypted kernel mapping - * RSI - virtual address for the decrypted kernel mapping + * RDI - virtual address for the encrypted mapping + * RSI - virtual address for the decrypted mapping * RDX - address of the pagetables to use for encryption - * RCX - length of kernel + * RCX - length of area * R8 - intermediate copy buffer * * RAX - points to this routine * - * The kernel will be encrypted by copying from the non-encrypted - * kernel space to an intermediate buffer and then copying from the - * intermediate buffer back to the encrypted kernel space. The physical - * addresses of the two kernel space mappings are the same which - * results in the kernel being encrypted "in place". + * The area will be encrypted by copying from the non-encrypted + * memory space to an intermediate buffer and then copying from the + * intermediate buffer back to the encrypted memory space. The physical + * addresses of the two mappings are the same which results in the area + * being encrypted "in place". */ /* Enable the new page tables */ mov %rdx, %cr3 @@ -103,47 +103,55 @@ ENTRY(__enc_copy) orq $X86_CR4_PGE, %rdx mov %rdx, %cr4 + push %r15 + push %r12 + + movq %rcx, %r9 /* Save area length */ + movq %rdi, %r10 /* Save encrypted area address */ + movq %rsi, %r11 /* Save decrypted area address */ + /* Set the PAT register PA5 entry to write-protect */ - push %rcx movl $MSR_IA32_CR_PAT, %ecx rdmsr - push %rdx /* Save original PAT value */ + mov %rdx, %r15 /* Save original PAT value */ andl $0xffff00ff, %edx /* Clear PA5 */ orl $0x00000500, %edx /* Set PA5 to WP */ wrmsr - pop %rdx /* RDX contains original PAT value */ - pop %rcx - - movq %rcx, %r9 /* Save kernel length */ - movq %rdi, %r10 /* Save encrypted kernel address */ - movq %rsi, %r11 /* Save decrypted kernel address */ wbinvd /* Invalidate any cache entries */ - /* Copy/encrypt 2MB at a time */ + /* Copy/encrypt up to 2MB at a time */ + movq $PMD_PAGE_SIZE, %r12 1: - movq %r11, %rsi /* Source - decrypted kernel */ + cmpq %r12, %r9 + jnb 2f + movq %r9, %r12 + +2: + movq %r11, %rsi /* Source - decrypted area */ movq %r8, %rdi /* Dest - intermediate copy buffer */ - movq $PMD_PAGE_SIZE, %rcx /* 2MB length */ + movq %r12, %rcx rep movsb movq %r8, %rsi /* Source - intermediate copy buffer */ - movq %r10, %rdi /* Dest - encrypted kernel */ - movq $PMD_PAGE_SIZE, %rcx /* 2MB length */ + movq %r10, %rdi /* Dest - encrypted area */ + movq %r12, %rcx rep movsb - addq $PMD_PAGE_SIZE, %r11 - addq $PMD_PAGE_SIZE, %r10 - subq $PMD_PAGE_SIZE, %r9 /* Kernel length decrement */ + addq %r12, %r11 + addq %r12, %r10 + subq %r12, %r9 /* Kernel length decrement */ jnz 1b /* Kernel length not zero? */ /* Restore PAT register */ - push %rdx /* Save original PAT value */ movl $MSR_IA32_CR_PAT, %ecx rdmsr - pop %rdx /* Restore original PAT value */ + mov %r15, %rdx /* Restore original PAT value */ wrmsr + pop %r12 + pop %r15 + ret .L__enc_copy_end: ENDPROC(__enc_copy) diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 17ebc5a978ccd..9b7bcbd33cc24 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -355,14 +355,15 @@ static inline void _pgd_free(pgd_t *pgd) kmem_cache_free(pgd_cache, pgd); } #else + static inline pgd_t *_pgd_alloc(void) { - return (pgd_t *)__get_free_page(PGALLOC_GFP); + return (pgd_t *)__get_free_pages(PGALLOC_GFP, PGD_ALLOCATION_ORDER); } static inline void _pgd_free(pgd_t *pgd) { - free_page((unsigned long)pgd); + free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER); } #endif /* CONFIG_X86_PAE */ diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index 6b9bf023a7005..c3c5274410a90 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c new file mode 100644 index 0000000000000..ce38f165489b5 --- /dev/null +++ b/arch/x86/mm/pti.c @@ -0,0 +1,368 @@ +/* + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * 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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This code is based in part on work published here: + * + * https://github.com/IAIK/KAISER + * + * The original work was written by and and signed off by for the Linux + * kernel by: + * + * Signed-off-by: Richard Fellner + * Signed-off-by: Moritz Lipp + * Signed-off-by: Daniel Gruss + * Signed-off-by: Michael Schwarz + * + * Major changes to the original code by: Dave Hansen + * Mostly rewritten by Thomas Gleixner and + * Andy Lutomirsky + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt + +/* Backporting helper */ +#ifndef __GFP_NOTRACK +#define __GFP_NOTRACK 0 +#endif + +static void __init pti_print_if_insecure(const char *reason) +{ + if (boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + pr_info("%s\n", reason); +} + +static void __init pti_print_if_secure(const char *reason) +{ + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + pr_info("%s\n", reason); +} + +void __init pti_check_boottime_disable(void) +{ + char arg[5]; + int ret; + + if (hypervisor_is_type(X86_HYPER_XEN_PV)) { + pti_print_if_insecure("disabled on XEN PV."); + return; + } + + ret = cmdline_find_option(boot_command_line, "pti", arg, sizeof(arg)); + if (ret > 0) { + if (ret == 3 && !strncmp(arg, "off", 3)) { + pti_print_if_insecure("disabled on command line."); + return; + } + if (ret == 2 && !strncmp(arg, "on", 2)) { + pti_print_if_secure("force enabled on command line."); + goto enable; + } + if (ret == 4 && !strncmp(arg, "auto", 4)) + goto autosel; + } + + if (cmdline_find_option_bool(boot_command_line, "nopti")) { + pti_print_if_insecure("disabled on command line."); + return; + } + +autosel: + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + return; +enable: + setup_force_cpu_cap(X86_FEATURE_PTI); +} + +pgd_t __pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd) +{ + /* + * Changes to the high (kernel) portion of the kernelmode page + * tables are not automatically propagated to the usermode tables. + * + * Users should keep in mind that, unlike the kernelmode tables, + * there is no vmalloc_fault equivalent for the usermode tables. + * Top-level entries added to init_mm's usermode pgd after boot + * will not be automatically propagated to other mms. + */ + if (!pgdp_maps_userspace(pgdp)) + return pgd; + + /* + * The user page tables get the full PGD, accessible from + * userspace: + */ + kernel_to_user_pgdp(pgdp)->pgd = pgd.pgd; + + /* + * If this is normal user memory, make it NX in the kernel + * pagetables so that, if we somehow screw up and return to + * usermode with the kernel CR3 loaded, we'll get a page fault + * instead of allowing user code to execute with the wrong CR3. + * + * As exceptions, we don't set NX if: + * - _PAGE_USER is not set. This could be an executable + * EFI runtime mapping or something similar, and the kernel + * may execute from it + * - we don't have NX support + * - we're clearing the PGD (i.e. the new pgd is not present). + */ + if ((pgd.pgd & (_PAGE_USER|_PAGE_PRESENT)) == (_PAGE_USER|_PAGE_PRESENT) && + (__supported_pte_mask & _PAGE_NX)) + pgd.pgd |= _PAGE_NX; + + /* return the copy of the PGD we want the kernel to use: */ + return pgd; +} + +/* + * Walk the user copy of the page tables (optionally) trying to allocate + * page table pages on the way down. + * + * Returns a pointer to a P4D on success, or NULL on failure. + */ +static __init p4d_t *pti_user_pagetable_walk_p4d(unsigned long address) +{ + pgd_t *pgd = kernel_to_user_pgdp(pgd_offset_k(address)); + gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); + + if (address < PAGE_OFFSET) { + WARN_ONCE(1, "attempt to walk user address\n"); + return NULL; + } + + if (pgd_none(*pgd)) { + unsigned long new_p4d_page = __get_free_page(gfp); + if (!new_p4d_page) + return NULL; + + set_pgd(pgd, __pgd(_KERNPG_TABLE | __pa(new_p4d_page))); + } + BUILD_BUG_ON(pgd_large(*pgd) != 0); + + return p4d_offset(pgd, address); +} + +/* + * Walk the user copy of the page tables (optionally) trying to allocate + * page table pages on the way down. + * + * Returns a pointer to a PMD on success, or NULL on failure. + */ +static __init pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) +{ + gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); + p4d_t *p4d = pti_user_pagetable_walk_p4d(address); + pud_t *pud; + + BUILD_BUG_ON(p4d_large(*p4d) != 0); + if (p4d_none(*p4d)) { + unsigned long new_pud_page = __get_free_page(gfp); + if (!new_pud_page) + return NULL; + + set_p4d(p4d, __p4d(_KERNPG_TABLE | __pa(new_pud_page))); + } + + pud = pud_offset(p4d, address); + /* The user page tables do not use large mappings: */ + if (pud_large(*pud)) { + WARN_ON(1); + return NULL; + } + if (pud_none(*pud)) { + unsigned long new_pmd_page = __get_free_page(gfp); + if (!new_pmd_page) + return NULL; + + set_pud(pud, __pud(_KERNPG_TABLE | __pa(new_pmd_page))); + } + + return pmd_offset(pud, address); +} + +#ifdef CONFIG_X86_VSYSCALL_EMULATION +/* + * Walk the shadow copy of the page tables (optionally) trying to allocate + * page table pages on the way down. Does not support large pages. + * + * Note: this is only used when mapping *new* kernel data into the + * user/shadow page tables. It is never used for userspace data. + * + * Returns a pointer to a PTE on success, or NULL on failure. + */ +static __init pte_t *pti_user_pagetable_walk_pte(unsigned long address) +{ + gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); + pmd_t *pmd = pti_user_pagetable_walk_pmd(address); + pte_t *pte; + + /* We can't do anything sensible if we hit a large mapping. */ + if (pmd_large(*pmd)) { + WARN_ON(1); + return NULL; + } + + if (pmd_none(*pmd)) { + unsigned long new_pte_page = __get_free_page(gfp); + if (!new_pte_page) + return NULL; + + set_pmd(pmd, __pmd(_KERNPG_TABLE | __pa(new_pte_page))); + } + + pte = pte_offset_kernel(pmd, address); + if (pte_flags(*pte) & _PAGE_USER) { + WARN_ONCE(1, "attempt to walk to user pte\n"); + return NULL; + } + return pte; +} + +static void __init pti_setup_vsyscall(void) +{ + pte_t *pte, *target_pte; + unsigned int level; + + pte = lookup_address(VSYSCALL_ADDR, &level); + if (!pte || WARN_ON(level != PG_LEVEL_4K) || pte_none(*pte)) + return; + + target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR); + if (WARN_ON(!target_pte)) + return; + + *target_pte = *pte; + set_vsyscall_pgtable_user_bits(kernel_to_user_pgdp(swapper_pg_dir)); +} +#else +static void __init pti_setup_vsyscall(void) { } +#endif + +static void __init +pti_clone_pmds(unsigned long start, unsigned long end, pmdval_t clear) +{ + unsigned long addr; + + /* + * Clone the populated PMDs which cover start to end. These PMD areas + * can have holes. + */ + for (addr = start; addr < end; addr += PMD_SIZE) { + pmd_t *pmd, *target_pmd; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + + pgd = pgd_offset_k(addr); + if (WARN_ON(pgd_none(*pgd))) + return; + p4d = p4d_offset(pgd, addr); + if (WARN_ON(p4d_none(*p4d))) + return; + pud = pud_offset(p4d, addr); + if (pud_none(*pud)) + continue; + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + continue; + + target_pmd = pti_user_pagetable_walk_pmd(addr); + if (WARN_ON(!target_pmd)) + return; + + /* + * Copy the PMD. That is, the kernelmode and usermode + * tables will share the last-level page tables of this + * address range + */ + *target_pmd = pmd_clear_flags(*pmd, clear); + } +} + +/* + * Clone a single p4d (i.e. a top-level entry on 4-level systems and a + * next-level entry on 5-level systems. + */ +static void __init pti_clone_p4d(unsigned long addr) +{ + p4d_t *kernel_p4d, *user_p4d; + pgd_t *kernel_pgd; + + user_p4d = pti_user_pagetable_walk_p4d(addr); + kernel_pgd = pgd_offset_k(addr); + kernel_p4d = p4d_offset(kernel_pgd, addr); + *user_p4d = *kernel_p4d; +} + +/* + * Clone the CPU_ENTRY_AREA into the user space visible page table. + */ +static void __init pti_clone_user_shared(void) +{ + pti_clone_p4d(CPU_ENTRY_AREA_BASE); +} + +/* + * Clone the ESPFIX P4D into the user space visinble page table + */ +static void __init pti_setup_espfix64(void) +{ +#ifdef CONFIG_X86_ESPFIX64 + pti_clone_p4d(ESPFIX_BASE_ADDR); +#endif +} + +/* + * Clone the populated PMDs of the entry and irqentry text and force it RO. + */ +static void __init pti_clone_entry_text(void) +{ + pti_clone_pmds((unsigned long) __entry_text_start, + (unsigned long) __irqentry_text_end, + _PAGE_RW | _PAGE_GLOBAL); +} + +/* + * Initialize kernel page table isolation + */ +void __init pti_init(void) +{ + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + pr_info("enabled\n"); + + pti_clone_user_shared(); + pti_clone_entry_text(); + pti_setup_espfix64(); + pti_setup_vsyscall(); +} diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 3118392cdf756..5bfe61a5e8e3c 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -28,6 +28,38 @@ * Implement flush IPI by CALL_FUNCTION_VECTOR, Alex Shi */ +/* + * We get here when we do something requiring a TLB invalidation + * but could not go invalidate all of the contexts. We do the + * necessary invalidation by clearing out the 'ctx_id' which + * forces a TLB flush when the context is loaded. + */ +void clear_asid_other(void) +{ + u16 asid; + + /* + * This is only expected to be set if we have disabled + * kernel _PAGE_GLOBAL pages. + */ + if (!static_cpu_has(X86_FEATURE_PTI)) { + WARN_ON_ONCE(1); + return; + } + + for (asid = 0; asid < TLB_NR_DYN_ASIDS; asid++) { + /* Do not need to flush the current asid */ + if (asid == this_cpu_read(cpu_tlbstate.loaded_mm_asid)) + continue; + /* + * Make sure the next time we go to switch to + * this asid, we do a flush: + */ + this_cpu_write(cpu_tlbstate.ctxs[asid].ctx_id, 0); + } + this_cpu_write(cpu_tlbstate.invalidate_other, false); +} + atomic64_t last_mm_ctx_id = ATOMIC64_INIT(1); @@ -42,6 +74,9 @@ static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen, return; } + if (this_cpu_read(cpu_tlbstate.invalidate_other)) + clear_asid_other(); + for (asid = 0; asid < TLB_NR_DYN_ASIDS; asid++) { if (this_cpu_read(cpu_tlbstate.ctxs[asid].ctx_id) != next->context.ctx_id) @@ -65,6 +100,25 @@ static void choose_new_asid(struct mm_struct *next, u64 next_tlb_gen, *need_flush = true; } +static void load_new_mm_cr3(pgd_t *pgdir, u16 new_asid, bool need_flush) +{ + unsigned long new_mm_cr3; + + if (need_flush) { + invalidate_user_asid(new_asid); + new_mm_cr3 = build_cr3(pgdir, new_asid); + } else { + new_mm_cr3 = build_cr3_noflush(pgdir, new_asid); + } + + /* + * Caution: many callers of this function expect + * that load_cr3() is serializing and orders TLB + * fills with respect to the mm_cpumask writes. + */ + write_cr3(new_mm_cr3); +} + void leave_mm(int cpu) { struct mm_struct *loaded_mm = this_cpu_read(cpu_tlbstate.loaded_mm); @@ -97,6 +151,34 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, local_irq_restore(flags); } +static void sync_current_stack_to_mm(struct mm_struct *mm) +{ + unsigned long sp = current_stack_pointer; + pgd_t *pgd = pgd_offset(mm, sp); + + if (CONFIG_PGTABLE_LEVELS > 4) { + if (unlikely(pgd_none(*pgd))) { + pgd_t *pgd_ref = pgd_offset_k(sp); + + set_pgd(pgd, *pgd_ref); + } + } else { + /* + * "pgd" is faked. The top level entries are "p4d"s, so sync + * the p4d. This compiles to approximately the same code as + * the 5-level case. + */ + p4d_t *p4d = p4d_offset(pgd, sp); + + if (unlikely(p4d_none(*p4d))) { + pgd_t *pgd_ref = pgd_offset_k(sp); + p4d_t *p4d_ref = p4d_offset(pgd_ref, sp); + + set_p4d(p4d, *p4d_ref); + } + } +} + void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { @@ -128,7 +210,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * isn't free. */ #ifdef CONFIG_DEBUG_VM - if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev, prev_asid))) { + if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev->pgd, prev_asid))) { /* * If we were to BUG here, we'd be very likely to kill * the system so hard that we don't see the call trace. @@ -172,11 +254,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * mapped in the new pgd, we'll double-fault. Forcibly * map it. */ - unsigned int index = pgd_index(current_stack_pointer); - pgd_t *pgd = next->pgd + index; - - if (unlikely(pgd_none(*pgd))) - set_pgd(pgd, init_mm.pgd[index]); + sync_current_stack_to_mm(next); } /* Stop remote flushes for the previous mm */ @@ -195,7 +273,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, if (need_flush) { this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id); this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen); - write_cr3(build_cr3(next, new_asid)); + load_new_mm_cr3(next->pgd, new_asid, true); /* * NB: This gets called via leave_mm() in the idle path @@ -208,7 +286,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); } else { /* The new ASID is already up to date. */ - write_cr3(build_cr3_noflush(next, new_asid)); + load_new_mm_cr3(next->pgd, new_asid, false); /* See above wrt _rcuidle. */ trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, 0); @@ -288,7 +366,7 @@ void initialize_tlbstate_and_flush(void) !(cr4_read_shadow() & X86_CR4_PCIDE)); /* Force ASID 0 and force a TLB flush. */ - write_cr3(build_cr3(mm, 0)); + write_cr3(build_cr3(mm->pgd, 0)); /* Reinitialize tlbstate. */ this_cpu_write(cpu_tlbstate.loaded_mm_asid, 0); @@ -551,7 +629,7 @@ static void do_kernel_range_flush(void *info) /* flush range by one by one 'invlpg' */ for (addr = f->start; addr < f->end; addr += PAGE_SIZE) - __flush_tlb_single(addr); + __flush_tlb_one(addr); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index bb461cfd01abc..526536c81ddc4 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c @@ -97,7 +97,7 @@ static int __init broadcom_postcore_init(void) * We should get host bridge information from ACPI unless the BIOS * doesn't support it. */ - if (acpi_os_get_root_pointer()) + if (!acpi_disabled && acpi_os_get_root_pointer()) return 0; #endif diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 20fb31579b694..61975b6bcb1a0 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -134,7 +134,9 @@ pgd_t * __init efi_call_phys_prolog(void) pud[j] = *pud_offset(p4d_k, vaddr); } } + pgd_offset_k(pgd * PGDIR_SIZE)->pgd &= ~_PAGE_NX; } + out: __flush_tlb_all(); @@ -195,6 +197,9 @@ static pgd_t *efi_pgd; * because we want to avoid inserting EFI region mappings (EFI_VA_END * to EFI_VA_START) into the standard kernel page tables. Everything * else can be shared, see efi_sync_low_kernel_mappings(). + * + * We don't want the pgd on the pgd_list and cannot use pgd_alloc() for the + * allocation. */ int __init efi_alloc_page_tables(void) { @@ -207,7 +212,7 @@ int __init efi_alloc_page_tables(void) return 0; gfp_mask = GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO; - efi_pgd = (pgd_t *)__get_free_page(gfp_mask); + efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER); if (!efi_pgd) return -ENOMEM; diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 8a99a2e96537a..5b513ccffde40 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -592,7 +592,18 @@ static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff, /* * Update the first page pointer to skip over the CSH header. */ - cap_info->pages[0] += csh->headersize; + cap_info->phys[0] += csh->headersize; + + /* + * cap_info->capsule should point at a virtual mapping of the entire + * capsule, starting at the capsule header. Our image has the Quark + * security header prepended, so we cannot rely on the default vmap() + * mapping created by the generic capsule code. + * Given that the Quark firmware does not appear to care about the + * virtual mapping, let's just point cap_info->capsule at our copy + * of the capsule header. + */ + cap_info->capsule = &cap_info->header; return 1; } diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index f44c0bc95aa2f..8538a6723171a 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -299,7 +299,7 @@ static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp, local_flush_tlb(); stat->d_alltlb++; } else { - __flush_tlb_one(msg->address); + __flush_tlb_single(msg->address); stat->d_onetlb++; } stat->d_requestee++; diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 84fcfde53f8f3..04d5157fe7f8f 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -160,17 +160,19 @@ static void do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct *t = &per_cpu(cpu_tss, cpu); #ifdef CONFIG_X86_64 struct desc_struct *desc = get_cpu_gdt_rw(cpu); tss_desc tss; #endif - set_tss_desc(cpu, t); /* - * This just modifies memory; should not be - * necessary. But... This is necessary, because - * 386 hardware has concept of busy TSS or some - * similar stupidity. - */ + + /* + * We need to reload TR, which requires that we change the + * GDT entry to indicate "available" first. + * + * XXX: This could probably all be replaced by a call to + * force_reload_TR(). + */ + set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss); #ifdef CONFIG_X86_64 memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc)); diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 836a1eb5df436..3ee234b6234dd 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -369,7 +370,9 @@ void free_ldt(struct mm_context *mm) mm->arch.ldt.entry_count = 0; } -int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , + unsigned long , bytecount) { - return do_modify_ldt_skas(func, ptr, bytecount); + /* See non-um modify_ldt() for why we do this cast */ + return (unsigned int)do_modify_ldt_skas(func, ptr, bytecount); } diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index de503c225ae1f..754d5391d9fa7 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -226,12 +226,12 @@ static uint32_t __init xen_platform_hvm(void) return xen_cpuid_base(); } -const struct hypervisor_x86 x86_hyper_xen_hvm = { +const __initconst struct hypervisor_x86 x86_hyper_xen_hvm = { .name = "Xen HVM", .detect = xen_platform_hvm, - .init_platform = xen_hvm_guest_init, - .pin_vcpu = xen_pin_vcpu, - .x2apic_available = xen_x2apic_para_available, - .init_mem_mapping = xen_hvm_init_mem_mapping, + .type = X86_HYPER_XEN_HVM, + .init.init_platform = xen_hvm_guest_init, + .init.x2apic_available = xen_x2apic_para_available, + .init.init_mem_mapping = xen_hvm_init_mem_mapping, + .runtime.pin_vcpu = xen_pin_vcpu, }; -EXPORT_SYMBOL(x86_hyper_xen_hvm); diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index d4396e27b1fb7..ae3a071e1d0f4 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -601,7 +601,7 @@ static struct trap_array_entry trap_array[] = { #ifdef CONFIG_X86_MCE { machine_check, xen_machine_check, true }, #endif - { nmi, xen_nmi, true }, + { nmi, xen_xennmi, true }, { overflow, xen_overflow, false }, #ifdef CONFIG_IA32_EMULATION { entry_INT80_compat, xen_entry_INT80_compat, false }, @@ -811,15 +811,14 @@ static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, } } -static void xen_load_sp0(struct tss_struct *tss, - struct thread_struct *thread) +static void xen_load_sp0(unsigned long sp0) { struct multicall_space mcs; mcs = xen_mc_entry(0); - MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); + MULTI_stack_switch(mcs.mc, __KERNEL_DS, sp0); xen_mc_issue(PARAVIRT_LAZY_CPU); - tss->x86_tss.sp0 = thread->sp0; + this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0); } void xen_set_iopl_mask(unsigned mask) @@ -1460,9 +1459,9 @@ static uint32_t __init xen_platform_pv(void) return 0; } -const struct hypervisor_x86 x86_hyper_xen_pv = { +const __initconst struct hypervisor_x86 x86_hyper_xen_pv = { .name = "Xen PV", .detect = xen_platform_pv, - .pin_vcpu = xen_pin_vcpu, + .type = X86_HYPER_XEN_PV, + .runtime.pin_vcpu = xen_pin_vcpu, }; -EXPORT_SYMBOL(x86_hyper_xen_pv); diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c index 71495f1a86d72..a0e2b8c6e5c73 100644 --- a/arch/x86/xen/mmu_pv.c +++ b/arch/x86/xen/mmu_pv.c @@ -449,7 +449,7 @@ __visible pmd_t xen_make_pmd(pmdval_t pmd) } PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd); -#if CONFIG_PGTABLE_LEVELS == 4 +#ifdef CONFIG_X86_64 __visible pudval_t xen_pud_val(pud_t pud) { return pte_mfn_to_pfn(pud.pud); @@ -538,7 +538,7 @@ static void xen_set_p4d(p4d_t *ptr, p4d_t val) xen_mc_issue(PARAVIRT_LAZY_MMU); } -#endif /* CONFIG_PGTABLE_LEVELS == 4 */ +#endif /* CONFIG_X86_64 */ static int xen_pmd_walk(struct mm_struct *mm, pmd_t *pmd, int (*func)(struct mm_struct *mm, struct page *, enum pt_level), @@ -580,21 +580,17 @@ static int xen_p4d_walk(struct mm_struct *mm, p4d_t *p4d, int (*func)(struct mm_struct *mm, struct page *, enum pt_level), bool last, unsigned long limit) { - int i, nr, flush = 0; + int flush = 0; + pud_t *pud; - nr = last ? p4d_index(limit) + 1 : PTRS_PER_P4D; - for (i = 0; i < nr; i++) { - pud_t *pud; - if (p4d_none(p4d[i])) - continue; + if (p4d_none(*p4d)) + return flush; - pud = pud_offset(&p4d[i], 0); - if (PTRS_PER_PUD > 1) - flush |= (*func)(mm, virt_to_page(pud), PT_PUD); - flush |= xen_pud_walk(mm, pud, func, - last && i == nr - 1, limit); - } + pud = pud_offset(p4d, 0); + if (PTRS_PER_PUD > 1) + flush |= (*func)(mm, virt_to_page(pud), PT_PUD); + flush |= xen_pud_walk(mm, pud, func, last, limit); return flush; } @@ -644,8 +640,6 @@ static int __xen_pgd_walk(struct mm_struct *mm, pgd_t *pgd, continue; p4d = p4d_offset(&pgd[i], 0); - if (PTRS_PER_P4D > 1) - flush |= (*func)(mm, virt_to_page(p4d), PT_P4D); flush |= xen_p4d_walk(mm, p4d, func, i == nr - 1, limit); } @@ -1176,22 +1170,14 @@ static void __init xen_cleanmfnmap(unsigned long vaddr) { pgd_t *pgd; p4d_t *p4d; - unsigned int i; bool unpin; unpin = (vaddr == 2 * PGDIR_SIZE); vaddr &= PMD_MASK; pgd = pgd_offset_k(vaddr); p4d = p4d_offset(pgd, 0); - for (i = 0; i < PTRS_PER_P4D; i++) { - if (p4d_none(p4d[i])) - continue; - xen_cleanmfnmap_p4d(p4d + i, unpin); - } - if (IS_ENABLED(CONFIG_X86_5LEVEL)) { - set_pgd(pgd, __pgd(0)); - xen_cleanmfnmap_free_pgtbl(p4d, unpin); - } + if (!p4d_none(*p4d)) + xen_cleanmfnmap_p4d(p4d, unpin); } static void __init xen_pagetable_p2m_free(void) @@ -1692,7 +1678,7 @@ static void xen_release_pmd(unsigned long pfn) xen_release_ptpage(pfn, PT_PMD); } -#if CONFIG_PGTABLE_LEVELS >= 4 +#ifdef CONFIG_X86_64 static void xen_alloc_pud(struct mm_struct *mm, unsigned long pfn) { xen_alloc_ptpage(mm, pfn, PT_PUD); @@ -2029,13 +2015,12 @@ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr) */ void __init xen_relocate_p2m(void) { - phys_addr_t size, new_area, pt_phys, pmd_phys, pud_phys, p4d_phys; + phys_addr_t size, new_area, pt_phys, pmd_phys, pud_phys; unsigned long p2m_pfn, p2m_pfn_end, n_frames, pfn, pfn_end; - int n_pte, n_pt, n_pmd, n_pud, n_p4d, idx_pte, idx_pt, idx_pmd, idx_pud, idx_p4d; + int n_pte, n_pt, n_pmd, n_pud, idx_pte, idx_pt, idx_pmd, idx_pud; pte_t *pt; pmd_t *pmd; pud_t *pud; - p4d_t *p4d = NULL; pgd_t *pgd; unsigned long *new_p2m; int save_pud; @@ -2045,11 +2030,7 @@ void __init xen_relocate_p2m(void) n_pt = roundup(size, PMD_SIZE) >> PMD_SHIFT; n_pmd = roundup(size, PUD_SIZE) >> PUD_SHIFT; n_pud = roundup(size, P4D_SIZE) >> P4D_SHIFT; - if (PTRS_PER_P4D > 1) - n_p4d = roundup(size, PGDIR_SIZE) >> PGDIR_SHIFT; - else - n_p4d = 0; - n_frames = n_pte + n_pt + n_pmd + n_pud + n_p4d; + n_frames = n_pte + n_pt + n_pmd + n_pud; new_area = xen_find_free_area(PFN_PHYS(n_frames)); if (!new_area) { @@ -2065,76 +2046,56 @@ void __init xen_relocate_p2m(void) * To avoid any possible virtual address collision, just use * 2 * PUD_SIZE for the new area. */ - p4d_phys = new_area; - pud_phys = p4d_phys + PFN_PHYS(n_p4d); + pud_phys = new_area; pmd_phys = pud_phys + PFN_PHYS(n_pud); pt_phys = pmd_phys + PFN_PHYS(n_pmd); p2m_pfn = PFN_DOWN(pt_phys) + n_pt; pgd = __va(read_cr3_pa()); new_p2m = (unsigned long *)(2 * PGDIR_SIZE); - idx_p4d = 0; save_pud = n_pud; - do { - if (n_p4d > 0) { - p4d = early_memremap(p4d_phys, PAGE_SIZE); - clear_page(p4d); - n_pud = min(save_pud, PTRS_PER_P4D); - } - for (idx_pud = 0; idx_pud < n_pud; idx_pud++) { - pud = early_memremap(pud_phys, PAGE_SIZE); - clear_page(pud); - for (idx_pmd = 0; idx_pmd < min(n_pmd, PTRS_PER_PUD); - idx_pmd++) { - pmd = early_memremap(pmd_phys, PAGE_SIZE); - clear_page(pmd); - for (idx_pt = 0; idx_pt < min(n_pt, PTRS_PER_PMD); - idx_pt++) { - pt = early_memremap(pt_phys, PAGE_SIZE); - clear_page(pt); - for (idx_pte = 0; - idx_pte < min(n_pte, PTRS_PER_PTE); - idx_pte++) { - set_pte(pt + idx_pte, - pfn_pte(p2m_pfn, PAGE_KERNEL)); - p2m_pfn++; - } - n_pte -= PTRS_PER_PTE; - early_memunmap(pt, PAGE_SIZE); - make_lowmem_page_readonly(__va(pt_phys)); - pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, - PFN_DOWN(pt_phys)); - set_pmd(pmd + idx_pt, - __pmd(_PAGE_TABLE | pt_phys)); - pt_phys += PAGE_SIZE; + for (idx_pud = 0; idx_pud < n_pud; idx_pud++) { + pud = early_memremap(pud_phys, PAGE_SIZE); + clear_page(pud); + for (idx_pmd = 0; idx_pmd < min(n_pmd, PTRS_PER_PUD); + idx_pmd++) { + pmd = early_memremap(pmd_phys, PAGE_SIZE); + clear_page(pmd); + for (idx_pt = 0; idx_pt < min(n_pt, PTRS_PER_PMD); + idx_pt++) { + pt = early_memremap(pt_phys, PAGE_SIZE); + clear_page(pt); + for (idx_pte = 0; + idx_pte < min(n_pte, PTRS_PER_PTE); + idx_pte++) { + set_pte(pt + idx_pte, + pfn_pte(p2m_pfn, PAGE_KERNEL)); + p2m_pfn++; } - n_pt -= PTRS_PER_PMD; - early_memunmap(pmd, PAGE_SIZE); - make_lowmem_page_readonly(__va(pmd_phys)); - pin_pagetable_pfn(MMUEXT_PIN_L2_TABLE, - PFN_DOWN(pmd_phys)); - set_pud(pud + idx_pmd, __pud(_PAGE_TABLE | pmd_phys)); - pmd_phys += PAGE_SIZE; + n_pte -= PTRS_PER_PTE; + early_memunmap(pt, PAGE_SIZE); + make_lowmem_page_readonly(__va(pt_phys)); + pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, + PFN_DOWN(pt_phys)); + set_pmd(pmd + idx_pt, + __pmd(_PAGE_TABLE | pt_phys)); + pt_phys += PAGE_SIZE; } - n_pmd -= PTRS_PER_PUD; - early_memunmap(pud, PAGE_SIZE); - make_lowmem_page_readonly(__va(pud_phys)); - pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(pud_phys)); - if (n_p4d > 0) - set_p4d(p4d + idx_pud, __p4d(_PAGE_TABLE | pud_phys)); - else - set_pgd(pgd + 2 + idx_pud, __pgd(_PAGE_TABLE | pud_phys)); - pud_phys += PAGE_SIZE; - } - if (n_p4d > 0) { - save_pud -= PTRS_PER_P4D; - early_memunmap(p4d, PAGE_SIZE); - make_lowmem_page_readonly(__va(p4d_phys)); - pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, PFN_DOWN(p4d_phys)); - set_pgd(pgd + 2 + idx_p4d, __pgd(_PAGE_TABLE | p4d_phys)); - p4d_phys += PAGE_SIZE; + n_pt -= PTRS_PER_PMD; + early_memunmap(pmd, PAGE_SIZE); + make_lowmem_page_readonly(__va(pmd_phys)); + pin_pagetable_pfn(MMUEXT_PIN_L2_TABLE, + PFN_DOWN(pmd_phys)); + set_pud(pud + idx_pmd, __pud(_PAGE_TABLE | pmd_phys)); + pmd_phys += PAGE_SIZE; } - } while (++idx_p4d < n_p4d); + n_pmd -= PTRS_PER_PUD; + early_memunmap(pud, PAGE_SIZE); + make_lowmem_page_readonly(__va(pud_phys)); + pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(pud_phys)); + set_pgd(pgd + 2 + idx_pud, __pgd(_PAGE_TABLE | pud_phys)); + pud_phys += PAGE_SIZE; + } /* Now copy the old p2m info to the new area. */ memcpy(new_p2m, xen_p2m_addr, size); @@ -2300,7 +2261,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) switch (idx) { case FIX_BTMAP_END ... FIX_BTMAP_BEGIN: - case FIX_RO_IDT: #ifdef CONFIG_X86_32 case FIX_WP_TEST: # ifdef CONFIG_HIGHMEM @@ -2311,7 +2271,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) #endif case FIX_TEXT_POKE0: case FIX_TEXT_POKE1: - case FIX_GDT_REMAP_BEGIN ... FIX_GDT_REMAP_END: /* All local page mappings */ pte = pfn_pte(phys, prot); break; @@ -2361,7 +2320,7 @@ static void __init xen_post_allocator_init(void) pv_mmu_ops.set_pte = xen_set_pte; pv_mmu_ops.set_pmd = xen_set_pmd; pv_mmu_ops.set_pud = xen_set_pud; -#if CONFIG_PGTABLE_LEVELS >= 4 +#ifdef CONFIG_X86_64 pv_mmu_ops.set_p4d = xen_set_p4d; #endif @@ -2371,7 +2330,7 @@ static void __init xen_post_allocator_init(void) pv_mmu_ops.alloc_pmd = xen_alloc_pmd; pv_mmu_ops.release_pte = xen_release_pte; pv_mmu_ops.release_pmd = xen_release_pmd; -#if CONFIG_PGTABLE_LEVELS >= 4 +#ifdef CONFIG_X86_64 pv_mmu_ops.alloc_pud = xen_alloc_pud; pv_mmu_ops.release_pud = xen_release_pud; #endif @@ -2435,14 +2394,14 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { .make_pmd = PV_CALLEE_SAVE(xen_make_pmd), .pmd_val = PV_CALLEE_SAVE(xen_pmd_val), -#if CONFIG_PGTABLE_LEVELS >= 4 +#ifdef CONFIG_X86_64 .pud_val = PV_CALLEE_SAVE(xen_pud_val), .make_pud = PV_CALLEE_SAVE(xen_make_pud), .set_p4d = xen_set_p4d_hyper, .alloc_pud = xen_alloc_pmd_init, .release_pud = xen_release_pmd_init, -#endif /* CONFIG_PGTABLE_LEVELS == 4 */ +#endif /* CONFIG_X86_64 */ .activate_mm = xen_activate_mm, .dup_mmap = xen_dup_mmap, diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index 05f91ce9b55ee..c0c756c76afeb 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -14,6 +14,7 @@ * single-threaded. */ #include +#include #include #include #include @@ -294,12 +295,19 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) #endif memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); + /* + * Bring up the CPU in cpu_bringup_and_idle() with the stack + * pointing just below where pt_regs would be if it were a normal + * kernel entry. + */ ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle; ctxt->flags = VGCF_IN_KERNEL; ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */ ctxt->user_regs.ds = __USER_DS; ctxt->user_regs.es = __USER_DS; ctxt->user_regs.ss = __KERNEL_DS; + ctxt->user_regs.cs = __KERNEL_CS; + ctxt->user_regs.esp = (unsigned long)task_pt_regs(idle); xen_copy_trap_info(ctxt->trap_ctxt); @@ -314,8 +322,13 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) ctxt->gdt_frames[0] = gdt_mfn; ctxt->gdt_ents = GDT_ENTRIES; + /* + * Set SS:SP that Xen will use when entering guest kernel mode + * from guest user mode. Subsequent calls to load_sp0() can + * change this value. + */ ctxt->kernel_ss = __KERNEL_DS; - ctxt->kernel_sp = idle->thread.sp0; + ctxt->kernel_sp = task_top_of_stack(idle); #ifdef CONFIG_X86_32 ctxt->event_callback_cs = __KERNEL_CS; @@ -327,10 +340,8 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) (unsigned long)xen_hypervisor_callback; ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback; - ctxt->user_regs.cs = __KERNEL_CS; per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir); - ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs); ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(swapper_pg_dir)); if (HYPERVISOR_vcpu_op(VCPUOP_initialise, xen_vcpu_nr(cpu), ctxt)) BUG(); diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S index c98a48c861fd3..8a10c9a9e2b50 100644 --- a/arch/x86/xen/xen-asm_64.S +++ b/arch/x86/xen/xen-asm_64.S @@ -30,7 +30,7 @@ xen_pv_trap debug xen_pv_trap xendebug xen_pv_trap int3 xen_pv_trap xenint3 -xen_pv_trap nmi +xen_pv_trap xennmi xen_pv_trap overflow xen_pv_trap bounds xen_pv_trap invalid_op diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index b5b8d7f435574..497cc55a0c16c 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #ifdef CONFIG_XEN_PV __INIT ENTRY(startup_xen) + UNWIND_HINT_EMPTY cld /* Clear .bss */ @@ -34,21 +36,24 @@ ENTRY(startup_xen) mov $init_thread_union+THREAD_SIZE, %_ASM_SP jmp xen_start_kernel - +END(startup_xen) __FINIT #endif .pushsection .text .balign PAGE_SIZE ENTRY(hypercall_page) - .skip PAGE_SIZE + .rept (PAGE_SIZE / 32) + UNWIND_HINT_EMPTY + .skip 32 + .endr #define HYPERCALL(n) \ .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \ .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32 #include #undef HYPERCALL - +END(hypercall_page) .popsection ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") diff --git a/block/badblocks.c b/block/badblocks.c index 43c71166e1e2a..91f7bcf979d37 100644 --- a/block/badblocks.c +++ b/block/badblocks.c @@ -178,7 +178,7 @@ int badblocks_set(struct badblocks *bb, sector_t s, int sectors, if (bb->shift < 0) /* badblocks are disabled */ - return 0; + return 1; if (bb->shift) { /* round the start down, and the end up */ diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index a4783da90ba88..0f860cf0d56d1 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -108,6 +108,7 @@ #include "blk-mq-tag.h" #include "blk-mq-sched.h" #include "bfq-iosched.h" +#include "blk-wbt.h" #define BFQ_BFQQ_FNS(name) \ void bfq_mark_bfqq_##name(struct bfq_queue *bfqq) \ @@ -4775,7 +4776,7 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_type *e) bfq_init_root_group(bfqd->root_group, bfqd); bfq_init_entity(&bfqd->oom_bfqq.entity, bfqd->root_group); - + wbt_disable_default(q); return 0; out_free: diff --git a/block/bio.c b/block/bio.c index 101c2a9b54815..7f978eac9a7ae 100644 --- a/block/bio.c +++ b/block/bio.c @@ -597,7 +597,10 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) * so we don't set nor calculate new physical/hw segment counts here */ bio->bi_disk = bio_src->bi_disk; + bio->bi_partno = bio_src->bi_partno; bio_set_flag(bio, BIO_CLONED); + if (bio_flagged(bio_src, BIO_THROTTLED)) + bio_set_flag(bio, BIO_THROTTLED); bio->bi_opf = bio_src->bi_opf; bio->bi_write_hint = bio_src->bi_write_hint; bio->bi_iter = bio_src->bi_iter; diff --git a/block/blk-core.c b/block/blk-core.c index 048be4aa60244..7b30bf10b1d4f 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -333,11 +333,13 @@ EXPORT_SYMBOL(blk_stop_queue); void blk_sync_queue(struct request_queue *q) { del_timer_sync(&q->timeout); + cancel_work_sync(&q->timeout_work); if (q->mq_ops) { struct blk_mq_hw_ctx *hctx; int i; + cancel_delayed_work_sync(&q->requeue_work); queue_for_each_hw_ctx(q, hctx, i) cancel_delayed_work_sync(&hctx->run_work); } else { @@ -604,8 +606,8 @@ void blk_set_queue_dying(struct request_queue *q) spin_lock_irq(q->queue_lock); blk_queue_for_each_rl(rl, q) { if (rl->rq_pool) { - wake_up(&rl->wait[BLK_RW_SYNC]); - wake_up(&rl->wait[BLK_RW_ASYNC]); + wake_up_all(&rl->wait[BLK_RW_SYNC]); + wake_up_all(&rl->wait[BLK_RW_ASYNC]); } } spin_unlock_irq(q->queue_lock); @@ -844,6 +846,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) setup_timer(&q->backing_dev_info->laptop_mode_wb_timer, laptop_mode_timer_fn, (unsigned long) q); setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); + INIT_WORK(&q->timeout_work, NULL); INIT_LIST_HEAD(&q->queue_head); INIT_LIST_HEAD(&q->timeout_list); INIT_LIST_HEAD(&q->icq_list); diff --git a/block/blk-map.c b/block/blk-map.c index d5251edcc0ddd..368daa02714e3 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -12,22 +12,29 @@ #include "blk.h" /* - * Append a bio to a passthrough request. Only works can be merged into - * the request based on the driver constraints. + * Append a bio to a passthrough request. Only works if the bio can be merged + * into the request based on the driver constraints. */ -int blk_rq_append_bio(struct request *rq, struct bio *bio) +int blk_rq_append_bio(struct request *rq, struct bio **bio) { - blk_queue_bounce(rq->q, &bio); + struct bio *orig_bio = *bio; + + blk_queue_bounce(rq->q, bio); if (!rq->bio) { - blk_rq_bio_prep(rq->q, rq, bio); + blk_rq_bio_prep(rq->q, rq, *bio); } else { - if (!ll_back_merge_fn(rq->q, rq, bio)) + if (!ll_back_merge_fn(rq->q, rq, *bio)) { + if (orig_bio != *bio) { + bio_put(*bio); + *bio = orig_bio; + } return -EINVAL; + } - rq->biotail->bi_next = bio; - rq->biotail = bio; - rq->__data_len += bio->bi_iter.bi_size; + rq->biotail->bi_next = *bio; + rq->biotail = *bio; + rq->__data_len += (*bio)->bi_iter.bi_size; } return 0; @@ -80,14 +87,12 @@ static int __blk_rq_map_user_iov(struct request *rq, * We link the bounce buffer in and could have to traverse it * later so we have to get a ref to prevent it from being freed */ - ret = blk_rq_append_bio(rq, bio); - bio_get(bio); + ret = blk_rq_append_bio(rq, &bio); if (ret) { - bio_endio(bio); __blk_rq_unmap_user(orig_bio); - bio_put(bio); return ret; } + bio_get(bio); return 0; } @@ -220,7 +225,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, int reading = rq_data_dir(rq) == READ; unsigned long addr = (unsigned long) kbuf; int do_copy = 0; - struct bio *bio; + struct bio *bio, *orig_bio; int ret; if (len > (queue_max_hw_sectors(q) << 9)) @@ -243,10 +248,11 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (do_copy) rq->rq_flags |= RQF_COPY_USER; - ret = blk_rq_append_bio(rq, bio); + orig_bio = bio; + ret = blk_rq_append_bio(rq, &bio); if (unlikely(ret)) { /* request is too big */ - bio_put(bio); + bio_put(orig_bio); return ret; } diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index 4ab69435708c2..eca011fdfa0ed 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -94,7 +94,7 @@ void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx) struct request_queue *q = hctx->queue; struct elevator_queue *e = q->elevator; const bool has_sched_dispatch = e && e->type->ops.mq.dispatch_request; - bool did_work = false; + bool do_sched_dispatch = true; LIST_HEAD(rq_list); /* RCU or SRCU read lock is needed before checking quiesced flag */ @@ -125,18 +125,18 @@ void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx) */ if (!list_empty(&rq_list)) { blk_mq_sched_mark_restart_hctx(hctx); - did_work = blk_mq_dispatch_rq_list(q, &rq_list); + do_sched_dispatch = blk_mq_dispatch_rq_list(q, &rq_list); } else if (!has_sched_dispatch) { blk_mq_flush_busy_ctxs(hctx, &rq_list); blk_mq_dispatch_rq_list(q, &rq_list); } /* - * We want to dispatch from the scheduler if we had no work left - * on the dispatch list, OR if we did have work but weren't able - * to make progress. + * We want to dispatch from the scheduler if there was nothing + * on the dispatch list or we were able to dispatch from the + * dispatch list. */ - if (!did_work && has_sched_dispatch) { + if (do_sched_dispatch && has_sched_dispatch) { do { struct request *rq; diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 8631763866c6d..a8cd7b3d96471 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -2223,13 +2223,7 @@ bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg, out_unlock: spin_unlock_irq(q->queue_lock); out: - /* - * As multiple blk-throtls may stack in the same issue path, we - * don't want bios to leave with the flag set. Clear the flag if - * being issued. - */ - if (!throttled) - bio_clear_flag(bio, BIO_THROTTLED); + bio_set_flag(bio, BIO_THROTTLED); #ifdef CONFIG_BLK_DEV_THROTTLING_LOW if (throttled || !td->track_bio_latency) diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 17ec83bb09002..6427be7ac3637 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -134,8 +134,6 @@ void blk_timeout_work(struct work_struct *work) struct request *rq, *tmp; int next_set = 0; - if (blk_queue_enter(q, true)) - return; spin_lock_irqsave(q->queue_lock, flags); list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) @@ -145,7 +143,6 @@ void blk_timeout_work(struct work_struct *work) mod_timer(&q->timeout, round_jiffies_up(next)); spin_unlock_irqrestore(q->queue_lock, flags); - blk_queue_exit(q); } /** diff --git a/block/blk-wbt.c b/block/blk-wbt.c index 6a9a0f03a67bd..e59d59c11ebbb 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -654,7 +654,7 @@ void wbt_set_write_cache(struct rq_wb *rwb, bool write_cache_on) } /* - * Disable wbt, if enabled by default. Only called from CFQ. + * Disable wbt, if enabled by default. */ void wbt_disable_default(struct request_queue *q) { diff --git a/block/bounce.c b/block/bounce.c index fceb1a96480bf..1d05c422c932a 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -200,6 +200,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, unsigned i = 0; bool bounce = false; int sectors = 0; + bool passthrough = bio_is_passthrough(*bio_orig); bio_for_each_segment(from, *bio_orig, iter) { if (i++ < BIO_MAX_PAGES) @@ -210,13 +211,14 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, if (!bounce) return; - if (sectors < bio_sectors(*bio_orig)) { + if (!passthrough && sectors < bio_sectors(*bio_orig)) { bio = bio_split(*bio_orig, sectors, GFP_NOIO, bounce_bio_split); bio_chain(bio, *bio_orig); generic_make_request(*bio_orig); *bio_orig = bio; } - bio = bio_clone_bioset(*bio_orig, GFP_NOIO, bounce_bio_set); + bio = bio_clone_bioset(*bio_orig, GFP_NOIO, passthrough ? NULL : + bounce_bio_set); bio_for_each_segment_all(to, bio, i) { struct page *page = to->bv_page; diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000000..788968681cfff --- /dev/null +++ b/build.sh @@ -0,0 +1,170 @@ +#!/bin/bash +if [[ $UID -eq 0 ]]; +then + echo "do not run as root!" + exit 1; +fi + +crosscompile=0 +if [[ -z $(cat /proc/cpuinfo | grep -i 'model name.*ArmV7') ]]; +then + echo do crosscompile; + if [[ -z "$(which arm-linux-gnueabihf-gcc)" ]];then echo "please install gcc-arm-linux-gnueabihf";exit 1;fi + + export ARCH=arm;export CROSS_COMPILE=arm-linux-gnueabihf- + crosscompile=1 +fi; +if [[ -z "$(which mkimage)" ]];then echo "please install u-boot-tools";exit 1;fi + +function prepare_SD +{ + SD=../SD + cd $(dirname $0) + mkdir -p ../SD + echo "cleanup..." + rm -r $SD/BPI-BOOT/ 2>/dev/null + rm -r $SD/BPI-ROOT/ 2>/dev/null + mkdir -p $SD/BPI-BOOT/bananapi/bpi-r2/linux/ + mkdir -p $SD/BPI-ROOT/lib/modules + mkdir -p $SD/BPI-ROOT/etc/firmware + mkdir -p $SD/BPI-ROOT/usr/bin + mkdir -p $SD/BPI-ROOT/system/etc/firmware + echo "copy..." + export INSTALL_MOD_PATH=$SD/BPI-ROOT/; + echo "INSTALL_MOD_PATH: $INSTALL_MOD_PATH" + cp ./uImage $SD/BPI-BOOT/bananapi/bpi-r2/linux/uImage + make modules_install + #cp -r ../mod/lib/modules $SD/BPI-ROOT/lib/ + + cp utils/wmt/config/* $SD/BPI-ROOT/system/etc/firmware/ + cp utils/wmt/src/{wmt_loader,wmt_loopback,stp_uart_launcher} $SD/BPI-ROOT/usr/bin/ + cp -r utils/wmt/firmware/* $SD/BPI-ROOT/etc/firmware/ + + if [[ -n "$(grep 'CONFIG_MT76=' .config)" ]];then + echo "MT76 set, including the firmware-files..."; + mkdir $SD/BPI-ROOT/lib/firmware/ + cp drivers/net/wireless/mediatek/mt76/firmware/* $SD/BPI-ROOT/lib/firmware/ + fi +} + +if [[ -d drivers ]]; +then + action=$1 + LANG=C + #git pull + #git reset --hard v4.14 + CFLAGS=-j$(grep ^processor /proc/cpuinfo | wc -l) + #export INSTALL_MOD_PATH=$(dirname $(pwd))/mod/; +# if [[ ! -z ${#INSTALL_MOD_PATH} ]]; then +# rm -r $INSTALL_MOD_PATH/lib/modules 2>/dev/null +# #echo $INSTALL_MOD_PATH +# fi + + if [[ "$action" == "reset" ]]; + then + git reset --hard v4.14 + action=importconfig + fi + + if [[ "$action" == "update" ]]; + then + git pull + fi + + if [[ "$action" == "defconfig" ]]; + then + nano arch/arm/configs/mt7623n_evb_fwu_defconfig + fi + + if [[ "$action" == "importconfig" ]]; + then +# cp ../mt7623n_evb_bpi_defconfig arch/arm/configs/ +# make mt7623n_evb_bpi_defconfig +# cp ../mt7623n_evb_ryderlee_defconfig arch/arm/configs/ +# make mt7623n_evb_ryderlee_defconfig +# cp ../mt7623n_evb_fwu_defconfig arch/arm/configs/ + make mt7623n_evb_fwu_defconfig + fi + + if [[ "$action" == "config" ]]; + then + make menuconfig + fi + + if [[ -z "$action" ]]; + then + kernver=$(make kernelversion) + gitbranch=$(git rev-parse --abbrev-ref HEAD) + # set -x + exec 3> >(tee build.log) + export LOCALVERSION="-${gitbranch}" +# make --debug && make modules_install + make ${CFLAGS} 2>&3 #&& make modules_install 2>&3 + ret=$? +# set +x + exec 3>&- + if [[ $ret == 0 ]]; + then + cat arch/arm/boot/zImage arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dtb > arch/arm/boot/zImage-dtb + mkimage -A arm -O linux -T kernel -C none -a 80008000 -e 80008000 -n "Linux Kernel $kernver-$gitbranch" -d arch/arm/boot/zImage-dtb ./uImage + echo "===========================================" + echo "1) pack" + if [[ $crosscompile -eq 0 ]];then + echo "2) install to System" + else + echo "2) install to SD-Card" + fi; + read -n1 -p "choice [12]:" choice + echo + if [[ "$choice" == "1" ]]; then + prepare_SD + echo "pack..." + olddir=$(pwd) + cd ../SD + fname=bpi-r2_${kernver}_${gitbranch}.tar.gz + tar -cz --owner=root --group=root -f $fname BPI-BOOT BPI-ROOT + md5sum $fname > $fname.md5 + ls -lh $(pwd)"/"$fname + cd $olddir + elif [[ "$choice" == "2" ]];then + if [[ $crosscompile -eq 0 ]]; + then + kernelfile=/boot/bananapi/bpi-r2/linux/uImage + if [[ -e $kernelfile ]];then + echo "backup of kernel: $kernelfile.bak" + cp $kernelfile $kernelfile.bak + cp ./uImage $kernelfile + sudo make modules_install + else + echo "actual Kernel not found...is /boot mounted?" + fi + else + read -p "Press [enter] to copy data to SD-Card..." + if [[ -d /media/$USER/BPI-BOOT ]]; + then + kernelfile=/media/$USER/BPI-BOOT/bananapi/bpi-r2/linux/uImage + if [[ -e $kernelfile ]];then + echo "backup of kernel: $kernelfile.bak" + cp $kernelfile $kernelfile.bak + fi + echo "copy new kernel" + cp ./uImage /media/$USER/BPI-BOOT/bananapi/bpi-r2/linux/uImage + echo "copy modules (root needed because of ext-fs permission)" + export INSTALL_MOD_PATH=/media/$USER/BPI-ROOT/; + echo "INSTALL_MOD_PATH: $INSTALL_MOD_PATH" + sudo make ARCH=$ARCH INSTALL_MOD_PATH=$INSTALL_MOD_PATH modules_install + #sudo cp -r ../mod/lib/modules /media/$USER/BPI-ROOT/lib/ + if [[ -n "$(grep 'CONFIG_MT76=' .config)" ]];then + echo "MT76 set,don't forget the firmware-files..."; + fi + sync + else + echo "SD-Card not found!" + fi + fi + else + echo "wrong option: $choice" + fi + fi + fi +fi diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 337cf382718ee..6ec360213107f 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -699,14 +699,15 @@ void af_alg_free_areq_sgls(struct af_alg_async_req *areq) } tsgl = areq->tsgl; - for_each_sg(tsgl, sg, areq->tsgl_entries, i) { - if (!sg_page(sg)) - continue; - put_page(sg_page(sg)); - } + if (tsgl) { + for_each_sg(tsgl, sg, areq->tsgl_entries, i) { + if (!sg_page(sg)) + continue; + put_page(sg_page(sg)); + } - if (areq->tsgl && areq->tsgl_entries) sock_kfree_s(sk, tsgl, areq->tsgl_entries * sizeof(*tsgl)); + } } EXPORT_SYMBOL_GPL(af_alg_free_areq_sgls); @@ -1047,6 +1048,18 @@ ssize_t af_alg_sendpage(struct socket *sock, struct page *page, } EXPORT_SYMBOL_GPL(af_alg_sendpage); +/** + * af_alg_free_resources - release resources required for crypto request + */ +void af_alg_free_resources(struct af_alg_async_req *areq) +{ + struct sock *sk = areq->sk; + + af_alg_free_areq_sgls(areq); + sock_kfree_s(sk, areq, areq->areqlen); +} +EXPORT_SYMBOL_GPL(af_alg_free_resources); + /** * af_alg_async_cb - AIO callback handler * @@ -1063,18 +1076,13 @@ void af_alg_async_cb(struct crypto_async_request *_req, int err) struct kiocb *iocb = areq->iocb; unsigned int resultlen; - lock_sock(sk); - /* Buffer size written by crypto operation. */ resultlen = areq->outlen; - af_alg_free_areq_sgls(areq); - sock_kfree_s(sk, areq, areq->areqlen); - __sock_put(sk); + af_alg_free_resources(areq); + sock_put(sk); iocb->ki_complete(iocb, err ? err : resultlen, 0); - - release_sock(sk); } EXPORT_SYMBOL_GPL(af_alg_async_cb); @@ -1157,12 +1165,6 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, if (!af_alg_readable(sk)) break; - if (!ctx->used) { - err = af_alg_wait_for_data(sk, flags); - if (err) - return err; - } - seglen = min_t(size_t, (maxsize - len), msg_data_left(msg)); diff --git a/crypto/algapi.c b/crypto/algapi.c index aa699ff6c8765..50eb828db767e 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -167,6 +167,18 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, spawn->alg = NULL; spawns = &inst->alg.cra_users; + + /* + * We may encounter an unregistered instance here, since + * an instance's spawns are set up prior to the instance + * being registered. An unregistered instance will have + * NULL ->cra_users.next, since ->cra_users isn't + * properly initialized until registration. But an + * unregistered instance cannot have any users, so treat + * it the same as ->cra_users being empty. + */ + if (spawns->next == NULL) + break; } } while ((spawns = crypto_more_spawns(alg, &stack, &top, &secondary_spawns))); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 516b38c3a1695..782cb8fec3236 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -101,16 +101,22 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct aead_tfm *aeadc = pask->private; struct crypto_aead *tfm = aeadc->aead; struct crypto_skcipher *null_tfm = aeadc->null_tfm; - unsigned int as = crypto_aead_authsize(tfm); + unsigned int i, as = crypto_aead_authsize(tfm); struct af_alg_async_req *areq; - struct af_alg_tsgl *tsgl; - struct scatterlist *src; + struct af_alg_tsgl *tsgl, *tmp; + struct scatterlist *rsgl_src, *tsgl_src = NULL; int err = 0; size_t used = 0; /* [in] TX bufs to be en/decrypted */ size_t outlen = 0; /* [out] RX bufs produced by kernel */ size_t usedpages = 0; /* [in] RX bufs to be used from user */ size_t processed = 0; /* [in] TX bufs to be consumed */ + if (!ctx->used) { + err = af_alg_wait_for_data(sk, flags); + if (err) + return err; + } + /* * Data length provided by caller via sendmsg/sendpage that has not * yet been processed. @@ -178,7 +184,22 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, } processed = used + ctx->aead_assoclen; - tsgl = list_first_entry(&ctx->tsgl_list, struct af_alg_tsgl, list); + list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { + for (i = 0; i < tsgl->cur; i++) { + struct scatterlist *process_sg = tsgl->sg + i; + + if (!(process_sg->length) || !sg_page(process_sg)) + continue; + tsgl_src = process_sg; + break; + } + if (tsgl_src) + break; + } + if (processed && !tsgl_src) { + err = -EFAULT; + goto free; + } /* * Copy of AAD from source to destination @@ -194,7 +215,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, */ /* Use the RX SGL as source (and destination) for crypto op. */ - src = areq->first_rsgl.sgl.sg; + rsgl_src = areq->first_rsgl.sgl.sg; if (ctx->enc) { /* @@ -207,7 +228,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, * v v * RX SGL: AAD || PT || Tag */ - err = crypto_aead_copy_sgl(null_tfm, tsgl->sg, + err = crypto_aead_copy_sgl(null_tfm, tsgl_src, areq->first_rsgl.sgl.sg, processed); if (err) goto free; @@ -225,7 +246,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, */ /* Copy AAD || CT to RX SGL buffer for in-place operation. */ - err = crypto_aead_copy_sgl(null_tfm, tsgl->sg, + err = crypto_aead_copy_sgl(null_tfm, tsgl_src, areq->first_rsgl.sgl.sg, outlen); if (err) goto free; @@ -257,23 +278,34 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, areq->tsgl); } else /* no RX SGL present (e.g. authentication only) */ - src = areq->tsgl; + rsgl_src = areq->tsgl; } /* Initialize the crypto operation */ - aead_request_set_crypt(&areq->cra_u.aead_req, src, + aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, areq->first_rsgl.sgl.sg, used, ctx->iv); aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); aead_request_set_tfm(&areq->cra_u.aead_req, tfm); if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ + sock_hold(sk); areq->iocb = msg->msg_iocb; + + /* Remember output size that will be generated. */ + areq->outlen = outlen; + aead_request_set_callback(&areq->cra_u.aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_async_cb, areq); err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) : crypto_aead_decrypt(&areq->cra_u.aead_req); + + /* AIO operation in progress */ + if (err == -EINPROGRESS || err == -EBUSY) + return -EIOCBQUEUED; + + sock_put(sk); } else { /* Synchronous operation */ aead_request_set_callback(&areq->cra_u.aead_req, @@ -285,19 +317,9 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, &ctx->completion); } - /* AIO operation in progress */ - if (err == -EINPROGRESS) { - sock_hold(sk); - - /* Remember output size that will be generated. */ - areq->outlen = outlen; - - return -EIOCBQUEUED; - } free: - af_alg_free_areq_sgls(areq); - sock_kfree_s(sk, areq, areq->areqlen); + af_alg_free_resources(areq); return err ? err : outlen; } @@ -487,6 +509,7 @@ static void aead_release(void *private) struct aead_tfm *tfm = private; crypto_free_aead(tfm->aead); + crypto_put_default_null_skcipher2(); kfree(tfm); } @@ -519,7 +542,6 @@ static void aead_sock_destruct(struct sock *sk) unsigned int ivlen = crypto_aead_ivsize(tfm); af_alg_pull_tsgl(sk, ctx->used, NULL, 0); - crypto_put_default_null_skcipher2(); sock_kzfree_s(sk, ctx->iv, ivlen); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 8ae4170aaeb4f..7a3e663d54d5c 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -72,6 +72,12 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, int err = 0; size_t len = 0; + if (!ctx->used) { + err = af_alg_wait_for_data(sk, flags); + if (err) + return err; + } + /* Allocate cipher request for current operation. */ areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + crypto_skcipher_reqsize(tfm)); @@ -117,13 +123,24 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ + sock_hold(sk); areq->iocb = msg->msg_iocb; + + /* Remember output size that will be generated. */ + areq->outlen = len; + skcipher_request_set_callback(&areq->cra_u.skcipher_req, CRYPTO_TFM_REQ_MAY_SLEEP, af_alg_async_cb, areq); err = ctx->enc ? crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); + + /* AIO operation in progress */ + if (err == -EINPROGRESS || err == -EBUSY) + return -EIOCBQUEUED; + + sock_put(sk); } else { /* Synchronous operation */ skcipher_request_set_callback(&areq->cra_u.skcipher_req, @@ -137,19 +154,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, &ctx->completion); } - /* AIO operation in progress */ - if (err == -EINPROGRESS) { - sock_hold(sk); - - /* Remember output size that will be generated. */ - areq->outlen = len; - - return -EIOCBQUEUED; - } free: - af_alg_free_areq_sgls(areq); - sock_kfree_s(sk, areq, areq->areqlen); + af_alg_free_resources(areq); return err ? err : len; } diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 2d93d9eccb4d0..986033e64a838 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -150,7 +150,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, pr_devel("Sig %u: Found cert serial match X.509[%u]\n", sinfo->index, certix); - if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) { + if (strcmp(x509->pub->pkey_algo, sinfo->sig->pkey_algo) != 0) { pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", sinfo->index); continue; diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index dd03fead1ca35..ce2df8c9c5839 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -409,6 +409,8 @@ int x509_extract_key_data(void *context, size_t hdrlen, ctx->cert->pub->pkey_algo = "rsa"; /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; ctx->key = value + 1; ctx->key_size = vlen - 1; return 0; diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index eea71dc9686c2..1bd0cf71a22d3 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -135,7 +135,7 @@ int x509_check_for_self_signed(struct x509_certificate *cert) } ret = -EKEYREJECTED; - if (cert->pub->pkey_algo != cert->sig->pkey_algo) + if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0) goto out; ret = public_key_verify_signature(cert->pub, cert->sig); diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c index db1bc3147bc47..600afa99941fe 100644 --- a/crypto/chacha20poly1305.c +++ b/crypto/chacha20poly1305.c @@ -610,6 +610,11 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, algt->mask)); if (IS_ERR(poly)) return PTR_ERR(poly); + poly_hash = __crypto_hash_alg_common(poly); + + err = -EINVAL; + if (poly_hash->digestsize != POLY1305_DIGEST_SIZE) + goto out_put_poly; err = -ENOMEM; inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); @@ -618,7 +623,6 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, ctx = aead_instance_ctx(inst); ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize; - poly_hash = __crypto_hash_alg_common(poly); err = crypto_init_ahash_spawn(&ctx->poly, poly_hash, aead_crypto_instance(inst)); if (err) diff --git a/crypto/dh.c b/crypto/dh.c index b1032a5c1bfa1..aadaf36fb56f9 100644 --- a/crypto/dh.c +++ b/crypto/dh.c @@ -21,19 +21,12 @@ struct dh_ctx { MPI xa; }; -static inline void dh_clear_params(struct dh_ctx *ctx) +static void dh_clear_ctx(struct dh_ctx *ctx) { mpi_free(ctx->p); mpi_free(ctx->g); - ctx->p = NULL; - ctx->g = NULL; -} - -static void dh_free_ctx(struct dh_ctx *ctx) -{ - dh_clear_params(ctx); mpi_free(ctx->xa); - ctx->xa = NULL; + memset(ctx, 0, sizeof(*ctx)); } /* @@ -71,10 +64,8 @@ static int dh_set_params(struct dh_ctx *ctx, struct dh *params) return -EINVAL; ctx->g = mpi_read_raw_data(params->g, params->g_size); - if (!ctx->g) { - mpi_free(ctx->p); + if (!ctx->g) return -EINVAL; - } return 0; } @@ -86,21 +77,23 @@ static int dh_set_secret(struct crypto_kpp *tfm, const void *buf, struct dh params; /* Free the old MPI key if any */ - dh_free_ctx(ctx); + dh_clear_ctx(ctx); if (crypto_dh_decode_key(buf, len, ¶ms) < 0) - return -EINVAL; + goto err_clear_ctx; if (dh_set_params(ctx, ¶ms) < 0) - return -EINVAL; + goto err_clear_ctx; ctx->xa = mpi_read_raw_data(params.key, params.key_size); - if (!ctx->xa) { - dh_clear_params(ctx); - return -EINVAL; - } + if (!ctx->xa) + goto err_clear_ctx; return 0; + +err_clear_ctx: + dh_clear_ctx(ctx); + return -EINVAL; } static int dh_compute_value(struct kpp_request *req) @@ -158,7 +151,7 @@ static void dh_exit_tfm(struct crypto_kpp *tfm) { struct dh_ctx *ctx = dh_get_ctx(tfm); - dh_free_ctx(ctx); + dh_clear_ctx(ctx); } static struct kpp_alg dh = { diff --git a/crypto/dh_helper.c b/crypto/dh_helper.c index 8ba8a3f826200..7f00c771fe8d7 100644 --- a/crypto/dh_helper.c +++ b/crypto/dh_helper.c @@ -83,6 +83,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params) if (secret.len != crypto_dh_key_len(params)) return -EINVAL; + /* + * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since + * some drivers assume otherwise. + */ + if (params->key_size > params->p_size || + params->g_size > params->p_size) + return -EINVAL; + /* Don't allocate memory. Set pointers to data within * the given buffer */ @@ -90,6 +98,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params) params->p = (void *)(ptr + params->key_size); params->g = (void *)(ptr + params->key_size + params->p_size); + /* + * Don't permit 'p' to be 0. It's not a prime number, and it's subject + * to corner cases such as 'mod 0' being undefined or + * crypto_kpp_maxsize() returning 0. + */ + if (memchr_inv(params->p, 0, params->p_size) == NULL) + return -EINVAL; + return 0; } EXPORT_SYMBOL_GPL(crypto_dh_decode_key); diff --git a/crypto/hmac.c b/crypto/hmac.c index 92871dc2a63ec..e74730224f0a5 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -195,11 +195,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) salg = shash_attr_alg(tb[1], 0, 0); if (IS_ERR(salg)) return PTR_ERR(salg); + alg = &salg->base; + /* The underlying hash algorithm must be unkeyed */ err = -EINVAL; + if (crypto_shash_alg_has_setkey(salg)) + goto out_put_alg; + ds = salg->digestsize; ss = salg->statesize; - alg = &salg->base; if (ds > alg->cra_blocksize || ss < alg->cra_blocksize) goto out_put_alg; diff --git a/crypto/lrw.c b/crypto/lrw.c index a8bfae4451bfc..eb681e9fe5743 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -610,8 +610,10 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb) ecb_name[len - 1] = 0; if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, - "lrw(%s)", ecb_name) >= CRYPTO_MAX_ALG_NAME) - return -ENAMETOOLONG; + "lrw(%s)", ecb_name) >= CRYPTO_MAX_ALG_NAME) { + err = -ENAMETOOLONG; + goto err_drop_spawn; + } } inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c index 4e64726588524..eca04d3729b37 100644 --- a/crypto/mcryptd.c +++ b/crypto/mcryptd.c @@ -81,6 +81,7 @@ static int mcryptd_init_queue(struct mcryptd_queue *queue, pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue); crypto_init_queue(&cpu_queue->queue, max_cpu_qlen); INIT_WORK(&cpu_queue->work, mcryptd_queue_worker); + spin_lock_init(&cpu_queue->q_lock); } return 0; } @@ -104,15 +105,16 @@ static int mcryptd_enqueue_request(struct mcryptd_queue *queue, int cpu, err; struct mcryptd_cpu_queue *cpu_queue; - cpu = get_cpu(); - cpu_queue = this_cpu_ptr(queue->cpu_queue); - rctx->tag.cpu = cpu; + cpu_queue = raw_cpu_ptr(queue->cpu_queue); + spin_lock(&cpu_queue->q_lock); + cpu = smp_processor_id(); + rctx->tag.cpu = smp_processor_id(); err = crypto_enqueue_request(&cpu_queue->queue, request); pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n", cpu, cpu_queue, request); + spin_unlock(&cpu_queue->q_lock); queue_work_on(cpu, kcrypto_wq, &cpu_queue->work); - put_cpu(); return err; } @@ -161,16 +163,11 @@ static void mcryptd_queue_worker(struct work_struct *work) cpu_queue = container_of(work, struct mcryptd_cpu_queue, work); i = 0; while (i < MCRYPTD_BATCH || single_task_running()) { - /* - * preempt_disable/enable is used to prevent - * being preempted by mcryptd_enqueue_request() - */ - local_bh_disable(); - preempt_disable(); + + spin_lock_bh(&cpu_queue->q_lock); backlog = crypto_get_backlog(&cpu_queue->queue); req = crypto_dequeue_request(&cpu_queue->queue); - preempt_enable(); - local_bh_enable(); + spin_unlock_bh(&cpu_queue->q_lock); if (!req) { mcryptd_opportunistic_flush(); @@ -185,7 +182,7 @@ static void mcryptd_queue_worker(struct work_struct *work) ++i; } if (cpu_queue->queue.qlen) - queue_work(kcrypto_wq, &cpu_queue->work); + queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work); } void mcryptd_flusher(struct work_struct *__work) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index ee9cfb99fe256..f8ec3d4ba4a80 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -254,6 +254,14 @@ static void pcrypt_aead_exit_tfm(struct crypto_aead *tfm) crypto_free_aead(ctx->child); } +static void pcrypt_free(struct aead_instance *inst) +{ + struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst); + + crypto_drop_aead(&ctx->spawn); + kfree(inst); +} + static int pcrypt_init_instance(struct crypto_instance *inst, struct crypto_alg *alg) { @@ -319,6 +327,8 @@ static int pcrypt_create_aead(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.encrypt = pcrypt_aead_encrypt; inst->alg.decrypt = pcrypt_aead_decrypt; + inst->free = pcrypt_free; + err = aead_register_instance(tmpl, inst); if (err) goto out_drop_aead; @@ -349,14 +359,6 @@ static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb) return -EINVAL; } -static void pcrypt_free(struct crypto_instance *inst) -{ - struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst); - - crypto_drop_aead(&ctx->spawn); - kfree(inst); -} - static int pcrypt_cpumask_change_notify(struct notifier_block *self, unsigned long val, void *data) { @@ -469,7 +471,6 @@ static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) static struct crypto_template pcrypt_tmpl = { .name = "pcrypt", .create = pcrypt_create, - .free = pcrypt_free, .module = THIS_MODULE, }; diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c index 0b66dc8246068..cad395d70d78e 100644 --- a/crypto/rsa_helper.c +++ b/crypto/rsa_helper.c @@ -30,7 +30,7 @@ int rsa_get_n(void *context, size_t hdrlen, unsigned char tag, return -EINVAL; if (fips_enabled) { - while (!*ptr && n_sz) { + while (n_sz && !*ptr) { ptr++; n_sz--; } diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index f550b5d946307..d7da0eea5622a 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, - walk.src.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, walk.src.virt.addr, diff --git a/crypto/shash.c b/crypto/shash.c index 325a14da58278..e849d3ee2e272 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -25,11 +25,12 @@ static const struct crypto_type crypto_shash_type; -static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) +int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) { return -ENOSYS; } +EXPORT_SYMBOL_GPL(shash_no_setkey); static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) diff --git a/crypto/skcipher.c b/crypto/skcipher.c index d5692e35fab1f..11af5fd6a4435 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -449,6 +449,8 @@ static int skcipher_walk_skcipher(struct skcipher_walk *walk, walk->total = req->cryptlen; walk->nbytes = 0; + walk->iv = req->iv; + walk->oiv = req->iv; if (unlikely(!walk->total)) return 0; @@ -456,9 +458,6 @@ static int skcipher_walk_skcipher(struct skcipher_walk *walk, scatterwalk_start(&walk->in, req->src); scatterwalk_start(&walk->out, req->dst); - walk->iv = req->iv; - walk->oiv = req->iv; - walk->flags &= ~SKCIPHER_WALK_SLEEP; walk->flags |= req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? SKCIPHER_WALK_SLEEP : 0; @@ -510,6 +509,8 @@ static int skcipher_walk_aead_common(struct skcipher_walk *walk, int err; walk->nbytes = 0; + walk->iv = req->iv; + walk->oiv = req->iv; if (unlikely(!walk->total)) return 0; @@ -522,8 +523,8 @@ static int skcipher_walk_aead_common(struct skcipher_walk *walk, scatterwalk_copychunks(NULL, &walk->in, req->assoclen, 2); scatterwalk_copychunks(NULL, &walk->out, req->assoclen, 2); - walk->iv = req->iv; - walk->oiv = req->iv; + scatterwalk_done(&walk->in, 0, walk->total); + scatterwalk_done(&walk->out, 0, walk->total); if (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) walk->flags |= SKCIPHER_WALK_SLEEP; diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 0022a18d36eeb..f5f58a6eee5dd 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -340,7 +340,7 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs, } sg_init_aead(sg, xbuf, - *b_size + (enc ? authsize : 0)); + *b_size + (enc ? 0 : authsize)); sg_init_aead(sgout, xoutbuf, *b_size + (enc ? authsize : 0)); @@ -348,7 +348,9 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs, sg_set_buf(&sg[0], assoc, aad_size); sg_set_buf(&sgout[0], assoc, aad_size); - aead_request_set_crypt(req, sg, sgout, *b_size, iv); + aead_request_set_crypt(req, sg, sgout, + *b_size + (enc ? 0 : authsize), + iv); aead_request_set_ad(req, aad_size); if (secs) diff --git a/cryptodev/README b/cryptodev/README new file mode 100644 index 0000000000000..56cf00df6eb67 --- /dev/null +++ b/cryptodev/README @@ -0,0 +1,27 @@ +CryptoDev + +http://forum.banana-pi.org/t/is-it-possible-to-have-the-crypto-extensions-working/4034/2 + + +1. How to build the cryptodev driver + + 1) Downloadd it from here : http://cryptodev-linux.org/download.html + 2) decompress it on host PC in which there is BPI R2 BSP + 3) Run below command to compile it + cd cryptodev-linux-1.9 + make KERNEL_DIR=/work/BPI-R2-bsp_bk/linux-mt/ CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm + 4) Copy the cryptodev.ko to board and load it + insmod cryptodev.ko + +After this step, we will a device /dev/crypto + +2. How to validate if it works + + 1) Decompresss cryptodev-linux-1.9.tar.gz to R2 board + 2) Build the test tool + cd cryptodev-linux-1.9/tests + make (if it fails, please install libssl-dev first) + 3) Run command ./speed to test the performance + + +or simply run build.sh in this folder...you got cryptodev.ko and cryptodev_test.tar.gz (test-applications) in this folder diff --git a/cryptodev/build.sh b/cryptodev/build.sh new file mode 100755 index 0000000000000..f4f839d1760b6 --- /dev/null +++ b/cryptodev/build.sh @@ -0,0 +1,19 @@ +#!/bin/bash +( +cd $(dirname $0) +kerneldir=$(dirname $(pwd)) +cd cryptodev-linux-1.9 +make KERNEL_DIR=$kerneldir CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm +if [[ $? == 0 ]];then + echo "build successful" + #cp cryptodev.ko $kerneldir/../SD/BPI-ROOT/lib/modules/ + cp cryptodev.ko ../ +fi +echo "build test-tool" +cd tests +make KERNEL_DIR=$kerneldir CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm +if [[ $? == 0 ]];then + echo "build successful" + tar -czf ../../cryptodev_test.tar.gz {async_cipher,async_hmac,async_speed,cipher,cipher-aead,cipher-aead-srtp,cipher_comp,cipher-gcm,fullspeed,hash_comp,hashcrypt_speed,hmac,hmac_comp,sha_speed,speed} +fi +) diff --git a/cryptodev/cryptodev-linux-1.9/.gitignore b/cryptodev/cryptodev-linux-1.9/.gitignore new file mode 100644 index 0000000000000..685e8ebfeb47b --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/.gitignore @@ -0,0 +1,29 @@ +.*.cmd +.tmp_versions/ +*~ +Module.markers +Module.symvers +*.ko +*.o +*.mod.c +modules.order +tests/async_cipher +tests/async_hmac +tests/async_speed +tests/cipher +tests/cipher_comp +tests/hmac +tests/hmac_comp +tests/speed +tests/sha_speed +tests/hash_comp +tests/hashcrypt_speed +releases +scripts +version.h +tests/cipher-aead +tests/fullspeed +examples/aes +lib/benchmark +tests/cipher-aead-srtp +tests/cipher-gcm diff --git a/cryptodev/cryptodev-linux-1.9/AUTHORS b/cryptodev/cryptodev-linux-1.9/AUTHORS new file mode 100644 index 0000000000000..6f9408ec9b7b0 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/AUTHORS @@ -0,0 +1,19 @@ +Michal Ludvig: + Initial implementation for linux 2.6.8 + +Nikos Mavrogiannopoulos: + Port to 2.6.27 and later, better compatibility + with OpenBSD (and FreeBSD) cryptodev and maintanance. + +Michael Weiser: + Porting to blkcipher async API. Several hardware drivers + only implemented this API. + +Phil Sutter: + Implemented a zero copy version of the internal engine. + +Dmitry Kasatkin: + Multi-update support for hash calculation. + + +Maintained by Nikos Mavrogiannopoulos (nmav [at] gnutls [dot] org) diff --git a/cryptodev/cryptodev-linux-1.9/COPYING b/cryptodev/cryptodev-linux-1.9/COPYING new file mode 100644 index 0000000000000..d159169d10508 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/cryptodev/cryptodev-linux-1.9/INSTALL b/cryptodev/cryptodev-linux-1.9/INSTALL new file mode 100644 index 0000000000000..2754c5933287e --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/INSTALL @@ -0,0 +1,32 @@ +=== Installation instructions === + +Simply run: +$ make +# make install + +The first command compiles the code and generates the kernel module +and the latter installs the header files and the kernel module. + +After that you should set your system to load the kernel module on system +load. In most systems this can be done as: +# echo "cryptodev" >>/etc/modules + +or in systemd-enabled systems: +# echo "cryptodev" > /etc/modules-load.d/cryptodev.conf + +=== Testing installation === + +* cryptodev-linux: +Check whether cryptodev-linux is operating as expected using the following +command. +$ make check + +* OpenSSL: +run the following commands prior and after installation and compare. +$ openssl speed -evp aes-128-cbc +$ openssl speed -evp sha1 + +* GnuTLS 3.x: +run the following command prior and after installation and compare. +$ gnutls-cli --benchmark-ciphers + diff --git a/cryptodev/cryptodev-linux-1.9/Makefile b/cryptodev/cryptodev-linux-1.9/Makefile new file mode 100644 index 0000000000000..5a080e063e6f5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/Makefile @@ -0,0 +1,67 @@ +# +# Since version 1.6 the asynchronous mode has been +# disabled by default. To re-enable it uncomment the +# corresponding CFLAG. +# +CRYPTODEV_CFLAGS ?= #-DENABLE_ASYNC +KBUILD_CFLAGS += -I$(src) $(CRYPTODEV_CFLAGS) +KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build +VERSION = 1.9 + +prefix ?= /usr/local +includedir = $(prefix)/include + +cryptodev-objs = ioctl.o main.o cryptlib.o authenc.o zc.o util.o + +obj-m += cryptodev.o + +KERNEL_MAKE_OPTS := -C $(KERNEL_DIR) M=$(CURDIR) +ifneq ($(ARCH),) +KERNEL_MAKE_OPTS += ARCH=$(ARCH) +endif +ifneq ($(CROSS_COMPILE),) +KERNEL_MAKE_OPTS += CROSS_COMPILE=$(CROSS_COMPILE) +endif + +build: version.h + $(MAKE) $(KERNEL_MAKE_OPTS) modules + +version.h: Makefile + @echo "#define VERSION \"$(VERSION)\"" > version.h + +install: modules_install + +modules_install: + $(MAKE) $(KERNEL_MAKE_OPTS) modules_install + install -m 644 -D crypto/cryptodev.h $(DESTDIR)/$(includedir)/crypto/cryptodev.h + +clean: + $(MAKE) $(KERNEL_MAKE_OPTS) clean + rm -f $(hostprogs) *~ + CFLAGS=$(CRYPTODEV_CFLAGS) KERNEL_DIR=$(KERNEL_DIR) $(MAKE) -C tests clean + +check: + CFLAGS=$(CRYPTODEV_CFLAGS) KERNEL_DIR=$(KERNEL_DIR) $(MAKE) -C tests check + +CPOPTS = +ifneq ($(SHOW_TYPES),) +CPOPTS += --show-types +endif +ifneq ($(IGNORE_TYPES),) +CPOPTS += --ignore $(IGNORE_TYPES) +endif + +checkpatch: + $(KERNEL_DIR)/scripts/checkpatch.pl $(CPOPTS) --file *.c *.h + +VERSIONTAG = refs/tags/cryptodev-linux-$(VERSION) +FILEBASE = cryptodev-linux-$(VERSION) +OUTPUT = $(FILEBASE).tar.gz + +dist: clean + @echo Packing + @rm -f *.tar.gz + @git archive --format=tar.gz --prefix=$(FILEBASE)/ --output=$(OUTPUT) $(VERSIONTAG) + @echo Signing $(OUTPUT) + @gpg --output $(OUTPUT).sig -sb $(OUTPUT) + @gpg --verify $(OUTPUT).sig $(OUTPUT) diff --git a/cryptodev/cryptodev-linux-1.9/NEWS b/cryptodev/cryptodev-linux-1.9/NEWS new file mode 100644 index 0000000000000..49e65e8e0ac1d --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/NEWS @@ -0,0 +1,244 @@ +Version 1.9 (released 2017-04-22) + +* fix benchmarks linking + +* fix Makefile to allow parallel make with -j option + +* use Linux kernel conventions for Makefile variables + +* for consistency, use $(...) instead of ${...} in makefiles + +* fix clean-up on error path for crypto_create_session + +* remove code duplication in cryptodev_hash_init + +* add separate target for building tests + +* fix destination for staged installs + +* add install target for tests + +* fix comment typo + +* avoid calls to kmalloc on hotpaths + +* avoid redundant checks in cryptodev_hash_deinit + +* Fix test compile time warnings + +* Support skcipher in addition to ablkcipher API + +* Adjust to recent user page API changes + +* Adjust to another change in the user page API + +* fix issues with install target + +* setting KERNEL_DIR is not necessary to build tests + +* fix ignored SIGALRM signals on some platforms + +* fix incorrect return code in case of error from openssl_cioccrypt + +* remove not used local variables + +* fix warnings of "implicit declaration of function" in async_speed + +* rename header file to clarify purpose + +* use buf_align macro to reduce code duplication + +* avoid implicit conversion between signed and unsigned char + +* do more strict code checking to avoid maintenance issues + +* adjust to API changes in kernel >=4.10 + +* zc: Use the power of #elif + +* Fix ablkcipher algorithms usage in v4.8+ kernels + +Version 1.8 (released 2015-11-28) + +* Fixed compilation against linux-3.19. + +* Tests: cixed arg passing to CC in implicit rule. + +* Fix tag printing in cipher-gcm test by Fridolin Pokorny. + +* Fix compilation against linux 4.3 by Gustavo Zacarias. + +Version 1.7 (released 2015-02-07) + +* Added support for composite AEAD keys by Cristian Stoica. + +* Added support for sysctl to modify verbosity by Nikolaos Tsakalakis. + +* Several bugfixes by Cristian Stoica. + +* When a driver requires aligned data but unaligned are provided, then + zero copy is disabled to prevent driver failing to encrypt. + +* Compatibility to kernel version 3.13 and above by Cosmin Paraschiv. + +* Various checkpatch.pl fixes. + +* Introduced ddebug, dinfo, dwarning and derr macros wrapping dprintk. + +* Improved support for cross-compiling. + +* Hmac_comp test has become more picky when checking results. + +* Fixed allocated resource cleanup in error case, patch by Cristian Stoica. + +* Buffer size allocation fixup for AEAD modes by Nikos Mavrogiannopoulos. + +* Support for composite AEAD keys added by Cristian Stoica. + +* Fixed tag and dsl_len calculation for AEAD ciphers, patch by Cristian Stoica. + +* Documentation updates by Nikos Mavrogiannopoulos. + + +Version 1.6 (released 2013-03-20) + +* Added modules_install target in Makefile + +* Added SHA224. Patch by Yashpal Dutta. + +* Asynchronous operations will not be scheduled if zero copy is disabled. + +* Asynchronous operations are disabled by default, unless -DENABLE_ASYNC + is enabled on Makefile. + + +Version 1.5 (released 2012-08-04) + +* Fixes in AEAD support. Patches by Jaren Johnston. + +* Simplifications in memory locking. Patch by Phil Sutter. + +* Allow empty plaintext and authenticated data in AEAD ciphers. + Patch by Jaren Johnston. + + +Version 1.4 (released 2012-03-15) + +* Correctly report hw accelerated ciphers. + + +Version 1.3 (released 2012-02-29) + +* Return EBADMSG instead of ECANCELED on tag verification failure in + authenc modes. + +* COP_FLAG_RESET can be combined with COP_FLAG_UPDATE for efficiency. + +* Added more test cases. + +* Automatically set public permissions for the device + + +Version 1.2 (released 2012-02-24) + +* In kernels that do not distinguish between hw accelerated ciphers or + not set the SIOP_FLAG_KERNEL_DRIVER_ONLY flag based on driver name. + +* camelia was renamed to camellia. + +* Added COP_FLAG_RESET to allow resetting the state in multi-update. + +* Corrected issue in ARM processors with mv_cesa. + + +Version 1.1 (released 2012-02-20) + +* Fixed alignment issue in speed.c + +* Defined HASH_MAX_LEN in cryptodev.h + +* CIOCGSESSINFO ioctl() sets the SIOP_FLAG_KERNEL_DRIVER_ONLY flag if the + driver is only available through kernel driver (and is not just software + cipher). + +* Added new encryption ioctl, CIOCAUTHCRYPT, which combines authentication + and encryption. Operates in AEAD, TLS and SRTP modes (the API might change + in later versions). + + +Version 1.0 (released 2011-04-12) + +* Several fixes in the included examples. Based on patches by Vladimir + Zapolskiy. + + +Version 0.9 (released 2011-02-11) + +* Added additional test tools: + - sha_speed does performance testing of SHA1 and SHA256 + - hashcrypt_speed additionally encrypts with AES128 and AES256 + +* Allow updating the IV in userspace via the COP_FLAG_WRITE_IV flag. + +* Export the alignmask in an OCF compatible way. + +* Fix for kernel crash on passing incorrect session ID. + +* Added CIOCGSESSINFO to export additional information for each session. + + +Version 0.8 (released 2010-11-06) + +* Made cryptodev aware of alignment constraints. + +* Added support for CRYPTO_AES_ECB. + +* Added asynchronous operation support using + CIOCASYNCCRYPT, CIOCASYNCFETCH ioctls and poll(). + + +Version 0.7 (released 2010-10-08) + +* Added COP_FLAG_FINAL to make multi-update more efficient. + +* Added CRIOGET_NOT_NEEDED definition to allow users of the API to + distinguish from the bare OpenBSD API that requires the CRIOGET. + + +Version 0.6 (released 2010-09-16) + +* multi-update support for hash calculation using the new flag + COP_FLAG_UPDATE. + +* Relicensed under GPLv2. + +* Added AES-CTR. + +* Corrected fallback to non-zero copy when referenced pages were + not writable. + + +Version 0.5 (released 2010-07-06) + +* Corrected issue with zero copy on multiple pages. + +* Fallback to normal operation if user pages cannot be mapped. + + +Version 0.4 (released 2010-07-03) + +* Internal engine supports operations with zero copy from user space. + + +Version 0.3 (released 2010-06-19) + +* Corrected bug when initializing unsupported algorithms. + + +Version 0.2 (released 2010-06-18) + +* Added compat_ioctl() to allow working on systems where userspace is 32bits + and kernel is operating in 64bit mode (Phil Sutter) + +* Added several sanity checks to input. + diff --git a/cryptodev/cryptodev-linux-1.9/README b/cryptodev/cryptodev-linux-1.9/README new file mode 100644 index 0000000000000..eb192046eaed1 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/README @@ -0,0 +1,40 @@ +This is a /dev/crypto device driver, equivalent to those in OpenBSD or +FreeBSD. The main idea is to access of existing ciphers in kernel space +from userspace, thus enabling the re-use of a hardware implementation of a +cipher. + +For questions and suggestions please use the mailing lists at: +http://cryptodev-linux.org/lists.html + + +=== How to combine with cryptographic libraries === + +* GnuTLS: + +GnuTLS needs to be compiled with --enable-cryptodev in order to take +advantage of /dev/crypto. GnuTLS 3.0.14 or later is recommended. + +* OpenSSL: + +Note that OpenSSL's cryptodev implementation is outdated, and there +are issues with it. For that we recommend to use the patches +below, that we have provided to the openssl project. + +http://rt.openssl.org/Ticket/Display.html?id=2770&user=guest&pass=guest + +After applying the patches you can add cryptodev support by using the +-DHAVE_CRYPTODEV and -DUSE_CRYPTODEV_DIGESTS flags during compilation. +Note that the latter flag (digests) may induce a performance penalty +in some systems. + + +=== Modifying and viewing verbosity at runtime === + +For debugging often the verbosity of the driver needs to be adjusted. +The sysctl tool can be used for that. + +# sysctl ioctl.cryptodev_verbosity +ioctl.cryptodev_verbosity = 0 + +# sysctl ioctl.cryptodev_verbosity=3 +ioctl.cryptodev_verbosity = 3 diff --git a/cryptodev/cryptodev-linux-1.9/authenc.c b/cryptodev/cryptodev-linux-1.9/authenc.c new file mode 100644 index 0000000000000..1bd7377de4fbd --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/authenc.c @@ -0,0 +1,758 @@ +/* + * Driver for /dev/crypto device (aka CryptoDev) + * + * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * This file handles the AEAD part of /dev/crypto. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cryptodev_int.h" +#include "zc.h" +#include "util.h" +#include "cryptlib.h" +#include "version.h" + + +/* make caop->dst available in scatterlist. + * (caop->src is assumed to be equal to caop->dst) + */ +static int get_userbuf_tls(struct csession *ses, struct kernel_crypt_auth_op *kcaop, + struct scatterlist **dst_sg) +{ + int pagecount = 0; + struct crypt_auth_op *caop = &kcaop->caop; + int rc; + + if (caop->dst == NULL) + return -EINVAL; + + if (ses->alignmask) { + if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask)) + dwarning(2, "careful - source address %p is not %d byte aligned", + caop->dst, ses->alignmask + 1); + } + + if (kcaop->dst_len == 0) { + dwarning(1, "Destination length cannot be zero"); + return -EINVAL; + } + + pagecount = PAGECOUNT(caop->dst, kcaop->dst_len); + + ses->used_pages = pagecount; + ses->readonly_pages = 0; + + rc = adjust_sg_array(ses, pagecount); + if (rc) + return rc; + + rc = __get_userbuf(caop->dst, kcaop->dst_len, 1, pagecount, + ses->pages, ses->sg, kcaop->task, kcaop->mm); + if (unlikely(rc)) { + derr(1, "failed to get user pages for data input"); + return -EINVAL; + } + + (*dst_sg) = ses->sg; + + return 0; +} + + +#define MAX_SRTP_AUTH_DATA_DIFF 256 + +/* Makes caop->auth_src available as scatterlist. + * It also provides a pointer to caop->dst, which however, + * is assumed to be within the caop->auth_src buffer. If not + * (if their difference exceeds MAX_SRTP_AUTH_DATA_DIFF) it + * returns error. + */ +static int get_userbuf_srtp(struct csession *ses, struct kernel_crypt_auth_op *kcaop, + struct scatterlist **auth_sg, struct scatterlist **dst_sg) +{ + int pagecount, diff; + int auth_pagecount = 0; + struct crypt_auth_op *caop = &kcaop->caop; + int rc; + + if (caop->dst == NULL && caop->auth_src == NULL) { + derr(1, "dst and auth_src cannot be both null"); + return -EINVAL; + } + + if (ses->alignmask) { + if (!IS_ALIGNED((unsigned long)caop->dst, ses->alignmask)) + dwarning(2, "careful - source address %p is not %d byte aligned", + caop->dst, ses->alignmask + 1); + if (!IS_ALIGNED((unsigned long)caop->auth_src, ses->alignmask)) + dwarning(2, "careful - source address %p is not %d byte aligned", + caop->auth_src, ses->alignmask + 1); + } + + if (unlikely(kcaop->dst_len == 0 || caop->auth_len == 0)) { + dwarning(1, "Destination length cannot be zero"); + return -EINVAL; + } + + /* Note that in SRTP auth data overlap with data to be encrypted (dst) + */ + + auth_pagecount = PAGECOUNT(caop->auth_src, caop->auth_len); + diff = (int)(caop->src - caop->auth_src); + if (diff > MAX_SRTP_AUTH_DATA_DIFF || diff < 0) { + dwarning(1, "auth_src must overlap with src (diff: %d).", diff); + return -EINVAL; + } + + pagecount = auth_pagecount; + + rc = adjust_sg_array(ses, pagecount*2); /* double pages to have pages for dst(=auth_src) */ + if (rc) { + derr(1, "cannot adjust sg array"); + return rc; + } + + rc = __get_userbuf(caop->auth_src, caop->auth_len, 1, auth_pagecount, + ses->pages, ses->sg, kcaop->task, kcaop->mm); + if (unlikely(rc)) { + derr(1, "failed to get user pages for data input"); + return -EINVAL; + } + + ses->used_pages = pagecount; + ses->readonly_pages = 0; + + (*auth_sg) = ses->sg; + + (*dst_sg) = ses->sg + auth_pagecount; + sg_init_table(*dst_sg, auth_pagecount); + sg_copy(ses->sg, (*dst_sg), caop->auth_len); + (*dst_sg) = sg_advance(*dst_sg, diff); + if (*dst_sg == NULL) { + release_user_pages(ses); + derr(1, "failed to get enough pages for auth data"); + return -EINVAL; + } + + return 0; +} + +/* + * Return tag (digest) length for authenticated encryption + * If the cipher and digest are separate, hdata.init is set - just return + * digest length. Otherwise return digest length for aead ciphers + */ +static int cryptodev_get_tag_len(struct csession *ses_ptr) +{ + if (ses_ptr->hdata.init) + return ses_ptr->hdata.digestsize; + else + return cryptodev_cipher_get_tag_size(&ses_ptr->cdata); +} + +/* + * Calculate destination buffer length for authenticated encryption. The + * expectation is that user-space code allocates exactly the same space for + * destination buffer before calling cryptodev. The result is cipher-dependent. + */ +static int cryptodev_get_dst_len(struct crypt_auth_op *caop, struct csession *ses_ptr) +{ + int dst_len = caop->len; + if (caop->op == COP_DECRYPT) + return dst_len; + + dst_len += caop->tag_len; + + /* for TLS always add some padding so the total length is rounded to + * cipher block size */ + if (caop->flags & COP_FLAG_AEAD_TLS_TYPE) { + int bs = ses_ptr->cdata.blocksize; + dst_len += bs - (dst_len % bs); + } + + return dst_len; +} + +static int fill_kcaop_from_caop(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr) +{ + struct crypt_auth_op *caop = &kcaop->caop; + struct csession *ses_ptr; + int ret; + + /* this also enters ses_ptr->sem */ + ses_ptr = crypto_get_session_by_sid(fcr, caop->ses); + if (unlikely(!ses_ptr)) { + derr(1, "invalid session ID=0x%08X", caop->ses); + return -EINVAL; + } + + if (caop->flags & COP_FLAG_AEAD_TLS_TYPE || caop->flags & COP_FLAG_AEAD_SRTP_TYPE) { + if (caop->src != caop->dst) { + derr(1, "Non-inplace encryption and decryption is not efficient and not implemented"); + ret = -EINVAL; + goto out_unlock; + } + } + + if (caop->tag_len == 0) + caop->tag_len = cryptodev_get_tag_len(ses_ptr); + + kcaop->ivlen = caop->iv ? ses_ptr->cdata.ivsize : 0; + kcaop->dst_len = cryptodev_get_dst_len(caop, ses_ptr); + kcaop->task = current; + kcaop->mm = current->mm; + + if (caop->iv) { + ret = copy_from_user(kcaop->iv, caop->iv, kcaop->ivlen); + if (unlikely(ret)) { + derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p", + kcaop->ivlen, ret, caop->iv); + ret = -EFAULT; + goto out_unlock; + } + } + + ret = 0; + +out_unlock: + crypto_put_session(ses_ptr); + return ret; + +} + +static int fill_caop_from_kcaop(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr) +{ + int ret; + + kcaop->caop.len = kcaop->dst_len; + + if (kcaop->ivlen && kcaop->caop.flags & COP_FLAG_WRITE_IV) { + ret = copy_to_user(kcaop->caop.iv, + kcaop->iv, kcaop->ivlen); + if (unlikely(ret)) { + derr(1, "Error in copying to userspace"); + return -EFAULT; + } + } + return 0; +} + + +int kcaop_from_user(struct kernel_crypt_auth_op *kcaop, + struct fcrypt *fcr, void __user *arg) +{ + if (unlikely(copy_from_user(&kcaop->caop, arg, sizeof(kcaop->caop)))) { + derr(1, "Error in copying from userspace"); + return -EFAULT; + } + + return fill_kcaop_from_caop(kcaop, fcr); +} + +int kcaop_to_user(struct kernel_crypt_auth_op *kcaop, + struct fcrypt *fcr, void __user *arg) +{ + int ret; + + ret = fill_caop_from_kcaop(kcaop, fcr); + if (unlikely(ret)) { + derr(1, "fill_caop_from_kcaop"); + return ret; + } + + if (unlikely(copy_to_user(arg, &kcaop->caop, sizeof(kcaop->caop)))) { + derr(1, "Error in copying to userspace"); + return -EFAULT; + } + return 0; +} + +static void copy_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len) +{ + scatterwalk_map_and_copy(hash, dst_sg, len, hash_len, 1); +} + +static void read_tls_hash(struct scatterlist *dst_sg, int len, void *hash, int hash_len) +{ + scatterwalk_map_and_copy(hash, dst_sg, len - hash_len, hash_len, 0); +} + +static int pad_record(struct scatterlist *dst_sg, int len, int block_size) +{ + uint8_t pad[block_size]; + int pad_size = block_size - (len % block_size); + + memset(pad, pad_size - 1, pad_size); + + scatterwalk_map_and_copy(pad, dst_sg, len, pad_size, 1); + + return pad_size; +} + +static int verify_tls_record_pad(struct scatterlist *dst_sg, int len, int block_size) +{ + uint8_t pad[256]; /* the maximum allowed */ + uint8_t pad_size; + int i; + + scatterwalk_map_and_copy(&pad_size, dst_sg, len - 1, 1, 0); + + if (pad_size + 1 > len) { + derr(1, "Pad size: %d", pad_size); + return -EBADMSG; + } + + scatterwalk_map_and_copy(pad, dst_sg, len - pad_size - 1, pad_size + 1, 0); + + for (i = 0; i < pad_size; i++) + if (pad[i] != pad_size) { + derr(1, "Pad size: %u, pad: %d", pad_size, pad[i]); + return -EBADMSG; + } + + return pad_size + 1; +} + +/* Authenticate and encrypt the TLS way (also perform padding). + * During decryption it verifies the pad and tag and returns -EBADMSG on error. + */ +static int +tls_auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, + struct scatterlist *auth_sg, uint32_t auth_len, + struct scatterlist *dst_sg, uint32_t len) +{ + int ret, fail = 0; + struct crypt_auth_op *caop = &kcaop->caop; + uint8_t vhash[AALG_MAX_RESULT_LEN]; + uint8_t hash_output[AALG_MAX_RESULT_LEN]; + + /* TLS authenticates the plaintext except for the padding. + */ + if (caop->op == COP_ENCRYPT) { + if (ses_ptr->hdata.init != 0) { + if (auth_len > 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + auth_sg, auth_len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + } + + if (len > 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + dst_sg, len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + } + + ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_final: %d", ret); + return ret; + } + + copy_tls_hash(dst_sg, len, hash_output, caop->tag_len); + len += caop->tag_len; + } + + if (ses_ptr->cdata.init != 0) { + if (ses_ptr->cdata.blocksize > 1) { + ret = pad_record(dst_sg, len, ses_ptr->cdata.blocksize); + len += ret; + } + + ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, + dst_sg, dst_sg, len); + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_encrypt: %d", ret); + return ret; + } + } + } else { + if (ses_ptr->cdata.init != 0) { + ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, + dst_sg, dst_sg, len); + + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_decrypt: %d", ret); + return ret; + } + + if (ses_ptr->cdata.blocksize > 1) { + ret = verify_tls_record_pad(dst_sg, len, ses_ptr->cdata.blocksize); + if (unlikely(ret < 0)) { + derr(2, "verify_record_pad: %d", ret); + fail = 1; + } else { + len -= ret; + } + } + } + + if (ses_ptr->hdata.init != 0) { + if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) { + derr(1, "Illegal tag len size"); + return -EINVAL; + } + + read_tls_hash(dst_sg, len, vhash, caop->tag_len); + len -= caop->tag_len; + + if (auth_len > 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + auth_sg, auth_len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + } + + if (len > 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + dst_sg, len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + } + + ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_final: %d", ret); + return ret; + } + + if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) { + derr(2, "MAC verification failed (tag_len: %d)", caop->tag_len); + return -EBADMSG; + } + } + } + kcaop->dst_len = len; + return 0; +} + +/* Authenticate and encrypt the SRTP way. During decryption + * it verifies the tag and returns -EBADMSG on error. + */ +static int +srtp_auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, + struct scatterlist *auth_sg, uint32_t auth_len, + struct scatterlist *dst_sg, uint32_t len) +{ + int ret, fail = 0; + struct crypt_auth_op *caop = &kcaop->caop; + uint8_t vhash[AALG_MAX_RESULT_LEN]; + uint8_t hash_output[AALG_MAX_RESULT_LEN]; + + /* SRTP authenticates the encrypted data. + */ + if (caop->op == COP_ENCRYPT) { + if (ses_ptr->cdata.init != 0) { + ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, + dst_sg, dst_sg, len); + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_encrypt: %d", ret); + return ret; + } + } + + if (ses_ptr->hdata.init != 0) { + if (auth_len > 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + auth_sg, auth_len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + } + + ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_final: %d", ret); + return ret; + } + + if (unlikely(copy_to_user(caop->tag, hash_output, caop->tag_len))) + return -EFAULT; + } + + } else { + if (ses_ptr->hdata.init != 0) { + if (unlikely(caop->tag_len > sizeof(vhash) || caop->tag_len > len)) { + derr(1, "Illegal tag len size"); + return -EINVAL; + } + + if (unlikely(copy_from_user(vhash, caop->tag, caop->tag_len))) + return -EFAULT; + + ret = cryptodev_hash_update(&ses_ptr->hdata, + auth_sg, auth_len); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_update: %d", ret); + return ret; + } + + ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output); + if (unlikely(ret)) { + derr(0, "cryptodev_hash_final: %d", ret); + return ret; + } + + if (memcmp(vhash, hash_output, caop->tag_len) != 0 || fail != 0) { + derr(2, "MAC verification failed"); + return -EBADMSG; + } + } + + if (ses_ptr->cdata.init != 0) { + ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, + dst_sg, dst_sg, len); + + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_decrypt: %d", ret); + return ret; + } + } + + } + kcaop->dst_len = len; + return 0; +} + +/* Typical AEAD (i.e. GCM) encryption/decryption. + * During decryption the tag is verified. + */ +static int +auth_n_crypt(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop, + struct scatterlist *auth_sg, uint32_t auth_len, + struct scatterlist *src_sg, + struct scatterlist *dst_sg, uint32_t len) +{ + int ret; + struct crypt_auth_op *caop = &kcaop->caop; + int max_tag_len; + + max_tag_len = cryptodev_cipher_get_tag_size(&ses_ptr->cdata); + if (unlikely(caop->tag_len > max_tag_len)) { + derr(0, "Illegal tag length: %d", caop->tag_len); + return -EINVAL; + } + + if (caop->tag_len) + cryptodev_cipher_set_tag_size(&ses_ptr->cdata, caop->tag_len); + else + caop->tag_len = max_tag_len; + + cryptodev_cipher_auth(&ses_ptr->cdata, auth_sg, auth_len); + + if (caop->op == COP_ENCRYPT) { + ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, + src_sg, dst_sg, len); + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_encrypt: %d", ret); + return ret; + } + kcaop->dst_len = len + caop->tag_len; + caop->tag = caop->dst + len; + } else { + ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, + src_sg, dst_sg, len); + + if (unlikely(ret)) { + derr(0, "cryptodev_cipher_decrypt: %d", ret); + return ret; + } + kcaop->dst_len = len - caop->tag_len; + caop->tag = caop->dst + len - caop->tag_len; + } + + return 0; +} + +/* This is the main crypto function - zero-copy edition */ +static int +__crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop) +{ + struct scatterlist *dst_sg, *auth_sg, *src_sg; + struct crypt_auth_op *caop = &kcaop->caop; + int ret = 0; + + if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) { + if (unlikely(ses_ptr->cdata.init != 0 && + (ses_ptr->cdata.stream == 0 || + ses_ptr->cdata.aead != 0))) { + derr(0, "Only stream modes are allowed in SRTP mode (but not AEAD)"); + return -EINVAL; + } + + ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg); + if (unlikely(ret)) { + derr(1, "get_userbuf_srtp(): Error getting user pages."); + return ret; + } + + ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, + dst_sg, caop->len); + + release_user_pages(ses_ptr); + } else { /* TLS and normal cases. Here auth data are usually small + * so we just copy them to a free page, instead of trying + * to map them. + */ + unsigned char *auth_buf = NULL; + struct scatterlist tmp; + + if (unlikely(caop->auth_len > PAGE_SIZE)) { + derr(1, "auth data len is excessive."); + return -EINVAL; + } + + auth_buf = (char *)__get_free_page(GFP_KERNEL); + if (unlikely(!auth_buf)) { + derr(1, "unable to get a free page."); + return -ENOMEM; + } + + if (caop->auth_src && caop->auth_len > 0) { + if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) { + derr(1, "unable to copy auth data from userspace."); + ret = -EFAULT; + goto free_auth_buf; + } + + sg_init_one(&tmp, auth_buf, caop->auth_len); + auth_sg = &tmp; + } else { + auth_sg = NULL; + } + + if (caop->flags & COP_FLAG_AEAD_TLS_TYPE && ses_ptr->cdata.aead == 0) { + ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg); + if (unlikely(ret)) { + derr(1, "get_userbuf_tls(): Error getting user pages."); + goto free_auth_buf; + } + + ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, + dst_sg, caop->len); + } else { + if (unlikely(ses_ptr->cdata.init == 0 || + (ses_ptr->cdata.stream == 0 && + ses_ptr->cdata.aead == 0))) { + derr(0, "Only stream and AEAD ciphers are allowed for authenc"); + ret = -EINVAL; + goto free_auth_buf; + } + + ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, kcaop->dst_len, + kcaop->task, kcaop->mm, &src_sg, &dst_sg); + if (unlikely(ret)) { + derr(1, "get_userbuf(): Error getting user pages."); + goto free_auth_buf; + } + + ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len, + src_sg, dst_sg, caop->len); + } + + release_user_pages(ses_ptr); + +free_auth_buf: + free_page((unsigned long)auth_buf); + } + + return ret; +} + + +int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop) +{ + struct csession *ses_ptr; + struct crypt_auth_op *caop = &kcaop->caop; + int ret; + + if (unlikely(caop->op != COP_ENCRYPT && caop->op != COP_DECRYPT)) { + ddebug(1, "invalid operation op=%u", caop->op); + return -EINVAL; + } + + /* this also enters ses_ptr->sem */ + ses_ptr = crypto_get_session_by_sid(fcr, caop->ses); + if (unlikely(!ses_ptr)) { + derr(1, "invalid session ID=0x%08X", caop->ses); + return -EINVAL; + } + + if (unlikely(ses_ptr->cdata.init == 0)) { + derr(1, "cipher context not initialized"); + ret = -EINVAL; + goto out_unlock; + } + + /* If we have a hash/mac handle reset its state */ + if (ses_ptr->hdata.init != 0) { + ret = cryptodev_hash_reset(&ses_ptr->hdata); + if (unlikely(ret)) { + derr(1, "error in cryptodev_hash_reset()"); + goto out_unlock; + } + } + + cryptodev_cipher_set_iv(&ses_ptr->cdata, kcaop->iv, + min(ses_ptr->cdata.ivsize, kcaop->ivlen)); + + ret = __crypto_auth_run_zc(ses_ptr, kcaop); + if (unlikely(ret)) { + derr(1, "error in __crypto_auth_run_zc()"); + goto out_unlock; + } + + ret = 0; + + cryptodev_cipher_get_iv(&ses_ptr->cdata, kcaop->iv, + min(ses_ptr->cdata.ivsize, kcaop->ivlen)); + +out_unlock: + crypto_put_session(ses_ptr); + return ret; +} diff --git a/cryptodev/cryptodev-linux-1.9/cipherapi.h b/cryptodev/cryptodev-linux-1.9/cipherapi.h new file mode 100644 index 0000000000000..b6ed6c2793507 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/cipherapi.h @@ -0,0 +1,56 @@ +#ifndef CIPHERAPI_H +# define CIPHERAPI_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) +# include + +typedef struct crypto_ablkcipher cryptodev_crypto_blkcipher_t; +typedef struct ablkcipher_request cryptodev_blkcipher_request_t; + +# define cryptodev_crypto_alloc_blkcipher crypto_alloc_ablkcipher +# define cryptodev_crypto_blkcipher_blocksize crypto_ablkcipher_blocksize +# define cryptodev_crypto_blkcipher_ivsize crypto_ablkcipher_ivsize +# define cryptodev_crypto_blkcipher_alignmask crypto_ablkcipher_alignmask +# define cryptodev_crypto_blkcipher_setkey crypto_ablkcipher_setkey + +static inline void cryptodev_crypto_free_blkcipher(cryptodev_crypto_blkcipher_t *c) { + if (c) + crypto_free_ablkcipher(c); +} + +# define cryptodev_blkcipher_request_alloc ablkcipher_request_alloc +# define cryptodev_blkcipher_request_set_callback ablkcipher_request_set_callback + +static inline void cryptodev_blkcipher_request_free(cryptodev_blkcipher_request_t *r) { + if (r) + ablkcipher_request_free(r); +} + +# define cryptodev_blkcipher_request_set_crypt ablkcipher_request_set_crypt +# define cryptodev_crypto_blkcipher_encrypt crypto_ablkcipher_encrypt +# define cryptodev_crypto_blkcipher_decrypt crypto_ablkcipher_decrypt +# define cryptodev_crypto_blkcipher_tfm crypto_ablkcipher_tfm +#else +#include + +typedef struct crypto_skcipher cryptodev_crypto_blkcipher_t; +typedef struct skcipher_request cryptodev_blkcipher_request_t; + +# define cryptodev_crypto_alloc_blkcipher crypto_alloc_skcipher +# define cryptodev_crypto_blkcipher_blocksize crypto_skcipher_blocksize +# define cryptodev_crypto_blkcipher_ivsize crypto_skcipher_ivsize +# define cryptodev_crypto_blkcipher_alignmask crypto_skcipher_alignmask +# define cryptodev_crypto_blkcipher_setkey crypto_skcipher_setkey +# define cryptodev_crypto_free_blkcipher crypto_free_skcipher +# define cryptodev_blkcipher_request_alloc skcipher_request_alloc +# define cryptodev_blkcipher_request_set_callback skcipher_request_set_callback +# define cryptodev_blkcipher_request_free skcipher_request_free +# define cryptodev_blkcipher_request_set_crypt skcipher_request_set_crypt +# define cryptodev_crypto_blkcipher_encrypt crypto_skcipher_encrypt +# define cryptodev_crypto_blkcipher_decrypt crypto_skcipher_decrypt +# define cryptodev_crypto_blkcipher_tfm crypto_skcipher_tfm +#endif + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/cryptlib.c b/cryptodev/cryptodev-linux-1.9/cryptlib.c new file mode 100644 index 0000000000000..2c6028ee2b230 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/cryptlib.c @@ -0,0 +1,437 @@ +/* + * Driver for /dev/crypto device (aka CryptoDev) + * + * Copyright (c) 2010,2011 Nikos Mavrogiannopoulos + * Portions Copyright (c) 2010 Michael Weiser + * Portions Copyright (c) 2010 Phil Sutter + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cryptodev_int.h" +#include "cipherapi.h" + +extern const struct crypto_type crypto_givcipher_type; + +static void cryptodev_complete(struct crypto_async_request *req, int err) +{ + struct cryptodev_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, + int aead) +{ + /* + * For blockciphers (AES-CBC) or non-composite aead ciphers (like AES-GCM), + * the key length is simply the cipher keylen obtained from userspace. If + * the cipher is composite aead, the keylen is the sum of cipher keylen, + * hmac keylen and a key header length. This key format is the one used in + * Linux kernel for composite aead ciphers (crypto/authenc.c) + */ + unsigned int klen = sop->keylen; + + if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) + return -EINVAL; + + if (aead && sop->mackeylen) { + if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) + return -EINVAL; + klen += sop->mackeylen; + klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param)); + } + + *keylen = klen; + return 0; +} + +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead) +{ + /* + * Get cipher key from user-space. For blockciphers just copy it from + * user-space. For composite aead ciphers combine it with the hmac key in + * the format used by Linux kernel in crypto/authenc.c: + * + * [[AUTHENC_KEY_HEADER + CIPHER_KEYLEN] [AUTHENTICATION KEY] [CIPHER KEY]] + */ + struct crypto_authenc_key_param *param; + struct rtattr *rta; + int ret = 0; + + if (aead && sop->mackeylen) { + /* + * Composite aead ciphers. The first four bytes are the header type and + * header length for aead keys + */ + rta = (void *)key; + rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; + rta->rta_len = RTA_LENGTH(sizeof(*param)); + + /* + * The next four bytes hold the length of the encryption key + */ + param = RTA_DATA(rta); + param->enckeylen = cpu_to_be32(sop->keylen); + + /* Advance key pointer eight bytes and copy the hmac key */ + key += RTA_SPACE(sizeof(*param)); + if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) { + ret = -EFAULT; + goto error; + } + /* Advance key pointer past the hmac key */ + key += sop->mackeylen; + } + /* now copy the blockcipher key */ + if (unlikely(copy_from_user(key, sop->key, sop->keylen))) + ret = -EFAULT; + +error: + return ret; +} + +/* Was correct key length supplied? */ +static int check_key_size(size_t keylen, const char *alg_name, + unsigned int min_keysize, unsigned int max_keysize) +{ + if (max_keysize > 0 && unlikely((keylen < min_keysize) || + (keylen > max_keysize))) { + ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.", + keylen, alg_name, min_keysize, max_keysize); + return -EINVAL; + } + + return 0; +} + +int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, + uint8_t *keyp, size_t keylen, int stream, int aead) +{ + int ret; + + if (aead == 0) { + unsigned int min_keysize, max_keysize; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) + struct crypto_tfm *tfm; +#else + struct ablkcipher_alg *alg; +#endif + + out->async.s = cryptodev_crypto_alloc_blkcipher(alg_name, 0, 0); + if (unlikely(IS_ERR(out->async.s))) { + ddebug(1, "Failed to load cipher %s", alg_name); + return -EINVAL; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) + tfm = crypto_skcipher_tfm(out->async.s); + if ((tfm->__crt_alg->cra_type == &crypto_ablkcipher_type) || + (tfm->__crt_alg->cra_type == &crypto_givcipher_type)) { + struct ablkcipher_alg *alg; + + alg = &tfm->__crt_alg->cra_ablkcipher; + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; + } else { + struct skcipher_alg *alg; + + alg = crypto_skcipher_alg(out->async.s); + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; + } +#else + alg = crypto_ablkcipher_alg(out->async.s); + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; +#endif + ret = check_key_size(keylen, alg_name, min_keysize, + max_keysize); + if (ret) + goto error; + + out->blocksize = cryptodev_crypto_blkcipher_blocksize(out->async.s); + out->ivsize = cryptodev_crypto_blkcipher_ivsize(out->async.s); + out->alignmask = cryptodev_crypto_blkcipher_alignmask(out->async.s); + + ret = cryptodev_crypto_blkcipher_setkey(out->async.s, keyp, keylen); + } else { + out->async.as = crypto_alloc_aead(alg_name, 0, 0); + if (unlikely(IS_ERR(out->async.as))) { + ddebug(1, "Failed to load cipher %s", alg_name); + return -EINVAL; + } + + out->blocksize = crypto_aead_blocksize(out->async.as); + out->ivsize = crypto_aead_ivsize(out->async.as); + out->alignmask = crypto_aead_alignmask(out->async.as); + + ret = crypto_aead_setkey(out->async.as, keyp, keylen); + } + + if (unlikely(ret)) { + ddebug(1, "Setting key failed for %s-%zu.", alg_name, keylen*8); + ret = -EINVAL; + goto error; + } + + out->stream = stream; + out->aead = aead; + + init_completion(&out->async.result.completion); + + if (aead == 0) { + out->async.request = cryptodev_blkcipher_request_alloc(out->async.s, GFP_KERNEL); + if (unlikely(!out->async.request)) { + derr(1, "error allocating async crypto request"); + ret = -ENOMEM; + goto error; + } + + cryptodev_blkcipher_request_set_callback(out->async.request, + CRYPTO_TFM_REQ_MAY_BACKLOG, + cryptodev_complete, &out->async.result); + } else { + out->async.arequest = aead_request_alloc(out->async.as, GFP_KERNEL); + if (unlikely(!out->async.arequest)) { + derr(1, "error allocating async crypto request"); + ret = -ENOMEM; + goto error; + } + + aead_request_set_callback(out->async.arequest, + CRYPTO_TFM_REQ_MAY_BACKLOG, + cryptodev_complete, &out->async.result); + } + + out->init = 1; + return 0; +error: + if (aead == 0) { + cryptodev_blkcipher_request_free(out->async.request); + cryptodev_crypto_free_blkcipher(out->async.s); + } else { + if (out->async.arequest) + aead_request_free(out->async.arequest); + if (out->async.as) + crypto_free_aead(out->async.as); + } + + return ret; +} + +void cryptodev_cipher_deinit(struct cipher_data *cdata) +{ + if (cdata->init) { + if (cdata->aead == 0) { + cryptodev_blkcipher_request_free(cdata->async.request); + cryptodev_crypto_free_blkcipher(cdata->async.s); + } else { + if (cdata->async.arequest) + aead_request_free(cdata->async.arequest); + if (cdata->async.as) + crypto_free_aead(cdata->async.as); + } + + cdata->init = 0; + } +} + +static inline int waitfor(struct cryptodev_result *cr, ssize_t ret) +{ + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + wait_for_completion(&cr->completion); + /* At this point we known for sure the request has finished, + * because wait_for_completion above was not interruptible. + * This is important because otherwise hardware or driver + * might try to access memory which will be freed or reused for + * another request. */ + + if (unlikely(cr->err)) { + derr(0, "error from async request: %d", cr->err); + return cr->err; + } + + break; + default: + return ret; + } + + return 0; +} + +ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, + const struct scatterlist *src, struct scatterlist *dst, + size_t len) +{ + int ret; + + reinit_completion(&cdata->async.result.completion); + + if (cdata->aead == 0) { + cryptodev_blkcipher_request_set_crypt(cdata->async.request, + (struct scatterlist *)src, dst, + len, cdata->async.iv); + ret = cryptodev_crypto_blkcipher_encrypt(cdata->async.request); + } else { + aead_request_set_crypt(cdata->async.arequest, + (struct scatterlist *)src, dst, + len, cdata->async.iv); + ret = crypto_aead_encrypt(cdata->async.arequest); + } + + return waitfor(&cdata->async.result, ret); +} + +ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, + const struct scatterlist *src, struct scatterlist *dst, + size_t len) +{ + int ret; + + reinit_completion(&cdata->async.result.completion); + if (cdata->aead == 0) { + cryptodev_blkcipher_request_set_crypt(cdata->async.request, + (struct scatterlist *)src, dst, + len, cdata->async.iv); + ret = cryptodev_crypto_blkcipher_decrypt(cdata->async.request); + } else { + aead_request_set_crypt(cdata->async.arequest, + (struct scatterlist *)src, dst, + len, cdata->async.iv); + ret = crypto_aead_decrypt(cdata->async.arequest); + } + + return waitfor(&cdata->async.result, ret); +} + +/* Hash functions */ + +int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, + int hmac_mode, void *mackey, size_t mackeylen) +{ + int ret; + + hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0); + if (unlikely(IS_ERR(hdata->async.s))) { + ddebug(1, "Failed to load transform for %s", alg_name); + return -EINVAL; + } + + /* Copy the key from user and set to TFM. */ + if (hmac_mode != 0) { + ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen); + if (unlikely(ret)) { + ddebug(1, "Setting hmac key failed for %s-%zu.", + alg_name, mackeylen*8); + ret = -EINVAL; + goto error; + } + } + + hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); + hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); + + init_completion(&hdata->async.result.completion); + + hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL); + if (unlikely(!hdata->async.request)) { + derr(0, "error allocating async crypto request"); + ret = -ENOMEM; + goto error; + } + + ahash_request_set_callback(hdata->async.request, + CRYPTO_TFM_REQ_MAY_BACKLOG, + cryptodev_complete, &hdata->async.result); + hdata->init = 1; + return 0; + +error: + crypto_free_ahash(hdata->async.s); + return ret; +} + +void cryptodev_hash_deinit(struct hash_data *hdata) +{ + if (hdata->init) { + ahash_request_free(hdata->async.request); + crypto_free_ahash(hdata->async.s); + hdata->init = 0; + } +} + +int cryptodev_hash_reset(struct hash_data *hdata) +{ + int ret; + + ret = crypto_ahash_init(hdata->async.request); + if (unlikely(ret)) { + derr(0, "error in crypto_hash_init()"); + return ret; + } + + return 0; + +} + +ssize_t cryptodev_hash_update(struct hash_data *hdata, + struct scatterlist *sg, size_t len) +{ + int ret; + + reinit_completion(&hdata->async.result.completion); + ahash_request_set_crypt(hdata->async.request, sg, NULL, len); + + ret = crypto_ahash_update(hdata->async.request); + + return waitfor(&hdata->async.result, ret); +} + +int cryptodev_hash_final(struct hash_data *hdata, void *output) +{ + int ret; + + reinit_completion(&hdata->async.result.completion); + ahash_request_set_crypt(hdata->async.request, NULL, output, 0); + + ret = crypto_ahash_final(hdata->async.request); + + return waitfor(&hdata->async.result, ret); +} + diff --git a/cryptodev/cryptodev-linux-1.9/cryptlib.h b/cryptodev/cryptodev-linux-1.9/cryptlib.h new file mode 100644 index 0000000000000..8e8aa71af3133 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/cryptlib.h @@ -0,0 +1,106 @@ +#ifndef CRYPTLIB_H +# define CRYPTLIB_H + +#include + +struct cryptodev_result { + struct completion completion; + int err; +}; + +#include "cipherapi.h" + +struct cipher_data { + int init; /* 0 uninitialized */ + int blocksize; + int aead; + int stream; + int ivsize; + int alignmask; + struct { + /* block ciphers */ + cryptodev_crypto_blkcipher_t *s; + cryptodev_blkcipher_request_t *request; + + /* AEAD ciphers */ + struct crypto_aead *as; + struct aead_request *arequest; + + struct cryptodev_result result; + uint8_t iv[EALG_MAX_BLOCK_LEN]; + } async; +}; + +int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, + uint8_t *key, size_t keylen, int stream, int aead); +void cryptodev_cipher_deinit(struct cipher_data *cdata); +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead); +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, + int aead); +ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, + const struct scatterlist *sg1, + struct scatterlist *sg2, size_t len); +ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, + const struct scatterlist *sg1, + struct scatterlist *sg2, size_t len); + +/* AEAD */ +static inline void cryptodev_cipher_auth(struct cipher_data *cdata, + struct scatterlist *sg1, size_t len) +{ + /* for some reason we _have_ to call that even for zero length sgs */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)) + aead_request_set_assoc(cdata->async.arequest, len ? sg1 : NULL, len); +#else + aead_request_set_ad(cdata->async.arequest, len); +#endif +} + +static inline void cryptodev_cipher_set_tag_size(struct cipher_data *cdata, int size) +{ + if (likely(cdata->aead != 0)) + crypto_aead_setauthsize(cdata->async.as, size); +} + +static inline int cryptodev_cipher_get_tag_size(struct cipher_data *cdata) +{ + if (likely(cdata->init && cdata->aead != 0)) + return crypto_aead_authsize(cdata->async.as); + else + return 0; +} + +static inline void cryptodev_cipher_set_iv(struct cipher_data *cdata, + void *iv, size_t iv_size) +{ + memcpy(cdata->async.iv, iv, min(iv_size, sizeof(cdata->async.iv))); +} + +static inline void cryptodev_cipher_get_iv(struct cipher_data *cdata, + void *iv, size_t iv_size) +{ + memcpy(iv, cdata->async.iv, min(iv_size, sizeof(cdata->async.iv))); +} + +/* Hash */ +struct hash_data { + int init; /* 0 uninitialized */ + int digestsize; + int alignmask; + struct { + struct crypto_ahash *s; + struct cryptodev_result result; + struct ahash_request *request; + } async; +}; + +int cryptodev_hash_final(struct hash_data *hdata, void *output); +ssize_t cryptodev_hash_update(struct hash_data *hdata, + struct scatterlist *sg, size_t len); +int cryptodev_hash_reset(struct hash_data *hdata); +void cryptodev_hash_deinit(struct hash_data *hdata); +int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, + int hmac_mode, void *mackey, size_t mackeylen); + + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/crypto/cryptodev.h b/cryptodev/cryptodev-linux-1.9/crypto/cryptodev.h new file mode 100644 index 0000000000000..7fb9c7dcdae5e --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/crypto/cryptodev.h @@ -0,0 +1,292 @@ +/* This is a source compatible implementation with the original API of + * cryptodev by Angelos D. Keromytis, found at openbsd cryptodev.h. + * Placed under public domain */ + +#ifndef L_CRYPTODEV_H +#define L_CRYPTODEV_H + +#include +#ifndef __KERNEL__ +#define __user +#endif + +/* API extensions for linux */ +#define CRYPTO_HMAC_MAX_KEY_LEN 512 +#define CRYPTO_CIPHER_MAX_KEY_LEN 64 + +/* All the supported algorithms + */ +enum cryptodev_crypto_op_t { + CRYPTO_DES_CBC = 1, + CRYPTO_3DES_CBC = 2, + CRYPTO_BLF_CBC = 3, + CRYPTO_CAST_CBC = 4, + CRYPTO_SKIPJACK_CBC = 5, + CRYPTO_MD5_HMAC = 6, + CRYPTO_SHA1_HMAC = 7, + CRYPTO_RIPEMD160_HMAC = 8, + CRYPTO_MD5_KPDK = 9, + CRYPTO_SHA1_KPDK = 10, + CRYPTO_RIJNDAEL128_CBC = 11, + CRYPTO_AES_CBC = CRYPTO_RIJNDAEL128_CBC, + CRYPTO_ARC4 = 12, + CRYPTO_MD5 = 13, + CRYPTO_SHA1 = 14, + CRYPTO_DEFLATE_COMP = 15, + CRYPTO_NULL = 16, + CRYPTO_LZS_COMP = 17, + CRYPTO_SHA2_256_HMAC = 18, + CRYPTO_SHA2_384_HMAC = 19, + CRYPTO_SHA2_512_HMAC = 20, + CRYPTO_AES_CTR = 21, + CRYPTO_AES_XTS = 22, + CRYPTO_AES_ECB = 23, + CRYPTO_AES_GCM = 50, + + CRYPTO_CAMELLIA_CBC = 101, + CRYPTO_RIPEMD160, + CRYPTO_SHA2_224, + CRYPTO_SHA2_256, + CRYPTO_SHA2_384, + CRYPTO_SHA2_512, + CRYPTO_SHA2_224_HMAC, + CRYPTO_ALGORITHM_ALL, /* Keep updated - see below */ +}; + +#define CRYPTO_ALGORITHM_MAX (CRYPTO_ALGORITHM_ALL - 1) + +/* Values for ciphers */ +#define DES_BLOCK_LEN 8 +#define DES3_BLOCK_LEN 8 +#define RIJNDAEL128_BLOCK_LEN 16 +#define AES_BLOCK_LEN RIJNDAEL128_BLOCK_LEN +#define CAMELLIA_BLOCK_LEN 16 +#define BLOWFISH_BLOCK_LEN 8 +#define SKIPJACK_BLOCK_LEN 8 +#define CAST128_BLOCK_LEN 8 + +/* the maximum of the above */ +#define EALG_MAX_BLOCK_LEN 16 + +/* Values for hashes/MAC */ +#define AALG_MAX_RESULT_LEN 64 + +/* maximum length of verbose alg names (depends on CRYPTO_MAX_ALG_NAME) */ +#define CRYPTODEV_MAX_ALG_NAME 64 + +#define HASH_MAX_LEN 64 + +/* input of CIOCGSESSION */ +struct session_op { + /* Specify either cipher or mac + */ + __u32 cipher; /* cryptodev_crypto_op_t */ + __u32 mac; /* cryptodev_crypto_op_t */ + + __u32 keylen; + __u8 __user *key; + __u32 mackeylen; + __u8 __user *mackey; + + __u32 ses; /* session identifier */ +}; + +struct session_info_op { + __u32 ses; /* session identifier */ + + /* verbose names for the requested ciphers */ + struct alg_info { + char cra_name[CRYPTODEV_MAX_ALG_NAME]; + char cra_driver_name[CRYPTODEV_MAX_ALG_NAME]; + } cipher_info, hash_info; + + __u16 alignmask; /* alignment constraints */ + __u32 flags; /* SIOP_FLAGS_* */ +}; + +/* If this flag is set then this algorithm uses + * a driver only available in kernel (software drivers, + * or drivers based on instruction sets do not set this flag). + * + * If multiple algorithms are involved (as in AEAD case), then + * if one of them is kernel-driver-only this flag will be set. + */ +#define SIOP_FLAG_KERNEL_DRIVER_ONLY 1 + +#define COP_ENCRYPT 0 +#define COP_DECRYPT 1 + +/* input of CIOCCRYPT */ +struct crypt_op { + __u32 ses; /* session identifier */ + __u16 op; /* COP_ENCRYPT or COP_DECRYPT */ + __u16 flags; /* see COP_FLAG_* */ + __u32 len; /* length of source data */ + __u8 __user *src; /* source data */ + __u8 __user *dst; /* pointer to output data */ + /* pointer to output data for hash/MAC operations */ + __u8 __user *mac; + /* initialization vector for encryption operations */ + __u8 __user *iv; +}; + +/* input of CIOCAUTHCRYPT */ +struct crypt_auth_op { + __u32 ses; /* session identifier */ + __u16 op; /* COP_ENCRYPT or COP_DECRYPT */ + __u16 flags; /* see COP_FLAG_AEAD_* */ + __u32 len; /* length of source data */ + __u32 auth_len; /* length of auth data */ + __u8 __user *auth_src; /* authenticated-only data */ + + /* The current implementation is more efficient if data are + * encrypted in-place (src==dst). */ + __u8 __user *src; /* data to be encrypted and authenticated */ + __u8 __user *dst; /* pointer to output data. Must have + * space for tag. For TLS this should be at least + * len + tag_size + block_size for padding */ + + __u8 __user *tag; /* where the tag will be copied to. TLS mode + * doesn't use that as tag is copied to dst. + * SRTP mode copies tag there. */ + __u32 tag_len; /* the length of the tag. Use zero for digest size or max tag. */ + + /* initialization vector for encryption operations */ + __u8 __user *iv; + __u32 iv_len; +}; + +/* In plain AEAD mode the following are required: + * flags : 0 + * iv : the initialization vector (12 bytes) + * auth_len: the length of the data to be authenticated + * auth_src: the data to be authenticated + * len : length of data to be encrypted + * src : the data to be encrypted + * dst : space to hold encrypted data. It must have + * at least a size of len + tag_size. + * tag_size: the size of the desired authentication tag or zero to use + * the maximum tag output. + * + * Note tag isn't being used because the Linux AEAD interface + * copies the tag just after data. + */ + +/* In TLS mode (used for CBC ciphers that required padding) + * the following are required: + * flags : COP_FLAG_AEAD_TLS_TYPE + * iv : the initialization vector + * auth_len: the length of the data to be authenticated only + * len : length of data to be encrypted + * auth_src: the data to be authenticated + * src : the data to be encrypted + * dst : space to hold encrypted data (preferably in-place). It must have + * at least a size of len + tag_size + blocksize. + * tag_size: the size of the desired authentication tag or zero to use + * the default mac output. + * + * Note that the padding used is the minimum padding. + */ + +/* In SRTP mode the following are required: + * flags : COP_FLAG_AEAD_SRTP_TYPE + * iv : the initialization vector + * auth_len: the length of the data to be authenticated. This must + * include the SRTP header + SRTP payload (data to be encrypted) + rest + * + * len : length of data to be encrypted + * auth_src: pointer the data to be authenticated. Should point at the same buffer as src. + * src : pointer to the data to be encrypted. + * dst : This is mandatory to be the same as src (in-place only). + * tag_size: the size of the desired authentication tag or zero to use + * the default mac output. + * tag : Pointer to an address where the authentication tag will be copied. + */ + + +/* struct crypt_op flags */ + +#define COP_FLAG_NONE (0 << 0) /* totally no flag */ +#define COP_FLAG_UPDATE (1 << 0) /* multi-update hash mode */ +#define COP_FLAG_FINAL (1 << 1) /* multi-update final hash mode */ +#define COP_FLAG_WRITE_IV (1 << 2) /* update the IV during operation */ +#define COP_FLAG_NO_ZC (1 << 3) /* do not zero-copy */ +#define COP_FLAG_AEAD_TLS_TYPE (1 << 4) /* authenticate and encrypt using the + * TLS protocol rules */ +#define COP_FLAG_AEAD_SRTP_TYPE (1 << 5) /* authenticate and encrypt using the + * SRTP protocol rules */ +#define COP_FLAG_RESET (1 << 6) /* multi-update reset the state. + * should be used in combination + * with COP_FLAG_UPDATE */ + + +/* Stuff for bignum arithmetic and public key + * cryptography - not supported yet by linux + * cryptodev. + */ + +#define CRYPTO_ALG_FLAG_SUPPORTED 1 +#define CRYPTO_ALG_FLAG_RNG_ENABLE 2 +#define CRYPTO_ALG_FLAG_DSA_SHA 4 + +struct crparam { + __u8 *crp_p; + __u32 crp_nbits; +}; + +#define CRK_MAXPARAM 8 + +/* input of CIOCKEY */ +struct crypt_kop { + __u32 crk_op; /* cryptodev_crk_op_t */ + __u32 crk_status; + __u16 crk_iparams; + __u16 crk_oparams; + __u32 crk_pad1; + struct crparam crk_param[CRK_MAXPARAM]; +}; + +enum cryptodev_crk_op_t { + CRK_MOD_EXP = 0, + CRK_MOD_EXP_CRT = 1, + CRK_DSA_SIGN = 2, + CRK_DSA_VERIFY = 3, + CRK_DH_COMPUTE_KEY = 4, + CRK_ALGORITHM_ALL +}; + +#define CRK_ALGORITHM_MAX (CRK_ALGORITHM_ALL-1) + +/* features to be queried with CIOCASYMFEAT ioctl + */ +#define CRF_MOD_EXP (1 << CRK_MOD_EXP) +#define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT) +#define CRF_DSA_SIGN (1 << CRK_DSA_SIGN) +#define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY) +#define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY) + + +/* ioctl's. Compatible with old linux cryptodev.h + */ +#define CRIOGET _IOWR('c', 101, __u32) +#define CIOCGSESSION _IOWR('c', 102, struct session_op) +#define CIOCFSESSION _IOW('c', 103, __u32) +#define CIOCCRYPT _IOWR('c', 104, struct crypt_op) +#define CIOCKEY _IOWR('c', 105, struct crypt_kop) +#define CIOCASYMFEAT _IOR('c', 106, __u32) +#define CIOCGSESSINFO _IOWR('c', 107, struct session_info_op) + +/* to indicate that CRIOGET is not required in linux + */ +#define CRIOGET_NOT_NEEDED 1 + +/* additional ioctls for AEAD */ +#define CIOCAUTHCRYPT _IOWR('c', 109, struct crypt_auth_op) + +/* additional ioctls for asynchronous operation. + * These are conditionally enabled since version 1.6. + */ +#define CIOCASYNCCRYPT _IOW('c', 110, struct crypt_op) +#define CIOCASYNCFETCH _IOR('c', 111, struct crypt_op) + +#endif /* L_CRYPTODEV_H */ diff --git a/cryptodev/cryptodev-linux-1.9/cryptodev_int.h b/cryptodev/cryptodev-linux-1.9/cryptodev_int.h new file mode 100644 index 0000000000000..d7660fac53442 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/cryptodev_int.h @@ -0,0 +1,145 @@ +/* cipher stuff */ +#ifndef CRYPTODEV_INT_H +# define CRYPTODEV_INT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)) +# define reinit_completion(x) INIT_COMPLETION(*(x)) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PFX "cryptodev: " +#define dprintk(level, severity, format, a...) \ + do { \ + if (level <= cryptodev_verbosity) \ + printk(severity PFX "%s[%u] (%s:%u): " format "\n", \ + current->comm, current->pid, \ + __func__, __LINE__, \ + ##a); \ + } while (0) +#define derr(level, format, a...) dprintk(level, KERN_ERR, format, ##a) +#define dwarning(level, format, a...) dprintk(level, KERN_WARNING, format, ##a) +#define dinfo(level, format, a...) dprintk(level, KERN_INFO, format, ##a) +#define ddebug(level, format, a...) dprintk(level, KERN_DEBUG, format, ##a) + + +extern int cryptodev_verbosity; + +struct fcrypt { + struct list_head list; + struct mutex sem; +}; + +/* compatibility stuff */ +#ifdef CONFIG_COMPAT +#include + +/* input of CIOCGSESSION */ +struct compat_session_op { + /* Specify either cipher or mac + */ + uint32_t cipher; /* cryptodev_crypto_op_t */ + uint32_t mac; /* cryptodev_crypto_op_t */ + + uint32_t keylen; + compat_uptr_t key; /* pointer to key data */ + uint32_t mackeylen; + compat_uptr_t mackey; /* pointer to mac key data */ + + uint32_t ses; /* session identifier */ +}; + +/* input of CIOCCRYPT */ +struct compat_crypt_op { + uint32_t ses; /* session identifier */ + uint16_t op; /* COP_ENCRYPT or COP_DECRYPT */ + uint16_t flags; /* see COP_FLAG_* */ + uint32_t len; /* length of source data */ + compat_uptr_t src; /* source data */ + compat_uptr_t dst; /* pointer to output data */ + compat_uptr_t mac;/* pointer to output data for hash/MAC operations */ + compat_uptr_t iv;/* initialization vector for encryption operations */ +}; + +/* compat ioctls, defined for the above structs */ +#define COMPAT_CIOCGSESSION _IOWR('c', 102, struct compat_session_op) +#define COMPAT_CIOCCRYPT _IOWR('c', 104, struct compat_crypt_op) +#define COMPAT_CIOCASYNCCRYPT _IOW('c', 107, struct compat_crypt_op) +#define COMPAT_CIOCASYNCFETCH _IOR('c', 108, struct compat_crypt_op) + +#endif /* CONFIG_COMPAT */ + +/* kernel-internal extension to struct crypt_op */ +struct kernel_crypt_op { + struct crypt_op cop; + + int ivlen; + __u8 iv[EALG_MAX_BLOCK_LEN]; + + int digestsize; + uint8_t hash_output[AALG_MAX_RESULT_LEN]; + + struct task_struct *task; + struct mm_struct *mm; +}; + +struct kernel_crypt_auth_op { + struct crypt_auth_op caop; + + int dst_len; /* based on src_len + pad + tag */ + int ivlen; + __u8 iv[EALG_MAX_BLOCK_LEN]; + + struct task_struct *task; + struct mm_struct *mm; +}; + +/* auth */ + +int kcaop_from_user(struct kernel_crypt_auth_op *kcop, + struct fcrypt *fcr, void __user *arg); +int kcaop_to_user(struct kernel_crypt_auth_op *kcaop, + struct fcrypt *fcr, void __user *arg); +int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop); +int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop); + +#include + +/* other internal structs */ +struct csession { + struct list_head entry; + struct mutex sem; + struct cipher_data cdata; + struct hash_data hdata; + uint32_t sid; + uint32_t alignmask; + + unsigned int array_size; + unsigned int used_pages; /* the number of pages that are used */ + /* the number of pages marked as NOT-writable; they preceed writeables */ + unsigned int readonly_pages; + struct page **pages; + struct scatterlist *sg; +}; + +struct csession *crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid); + +static inline void crypto_put_session(struct csession *ses_ptr) +{ + mutex_unlock(&ses_ptr->sem); +} +int adjust_sg_array(struct csession *ses, int pagecount); + +#endif /* CRYPTODEV_INT_H */ diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.c b/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.c new file mode 100644 index 0000000000000..6791f4eb13b0e --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.c @@ -0,0 +1,139 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "aes-gcm.h" + +int aes_gcm_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + ctx->sess.cipher = CRYPTO_AES_GCM; + ctx->sess.keylen = key_size; + ctx->sess.key = (void*)key; + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } + printf("Got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { + printf("Note: This is not an accelerated cipher\n"); + } + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void aes_gcm_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +aes_gcm_encrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + const void* plaintext, void* ciphertext, size_t size) +{ + struct crypt_auth_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); + if (plaintext != p) { + fprintf(stderr, "plaintext is not aligned\n"); + return -1; + } + + p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); + if (ciphertext != p) { + fprintf(stderr, "ciphertext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.iv = (void*)iv; + cryp.op = COP_ENCRYPT; + cryp.auth_len = auth_size; + cryp.auth_src = (void*)auth; + cryp.len = size; + cryp.src = (void*)plaintext; + cryp.dst = ciphertext; + if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return -1; + } + + return 0; +} + +int +aes_gcm_decrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + const void* ciphertext, void* plaintext, size_t size) +{ + struct crypt_auth_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); + if (plaintext != p) { + fprintf(stderr, "plaintext is not aligned\n"); + return -1; + } + + p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); + if (ciphertext != p) { + fprintf(stderr, "ciphertext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.iv = (void*)iv; + cryp.op = COP_DECRYPT; + cryp.auth_len = auth_size; + cryp.auth_src = (void*)auth; + cryp.len = size; + cryp.src = (void*)ciphertext; + cryp.dst = plaintext; + if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return -1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.h b/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.h new file mode 100644 index 0000000000000..1ddc5fe464fcb --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes-gcm.h @@ -0,0 +1,28 @@ +#ifndef AES_H +# define AES_H + +#include + +struct cryptodev_ctx { + int cfd; + struct session_op sess; + uint16_t alignmask; +}; + +#define AES_BLOCK_SIZE 16 + +int aes_gcm_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size); +void aes_gcm_ctx_deinit(); + +/* Note that encryption assumes that ciphertext has enough size + * for the tag to be appended. In decryption the tag is assumed + * to be the last bytes of ciphertext. + */ +int aes_gcm_encrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + const void* plaintext, void* ciphertext, size_t size); +int aes_gcm_decrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + const void* ciphertext, void* plaintext, size_t size); + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.c b/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.c new file mode 100644 index 0000000000000..e93e3c4461b23 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.c @@ -0,0 +1,139 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "aes-sha1.h" + +/* This is the TLS version of AES-CBC with HMAC-SHA1. + */ + +int aes_sha1_ctx_init(struct cryptodev_ctx* ctx, int cfd, + const uint8_t *key, unsigned int key_size, + const uint8_t *mac_key, unsigned int mac_key_size) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + ctx->sess.cipher = CRYPTO_AES_CBC; + ctx->sess.keylen = key_size; + ctx->sess.key = (void*)key; + + ctx->sess.mac = CRYPTO_SHA1_HMAC; + ctx->sess.mackeylen = mac_key_size; + ctx->sess.mackey = (void*)mac_key; + + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } + printf("Got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { + printf("Note: This is not an accelerated cipher\n"); + } + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void aes_sha1_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +aes_sha1_encrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + void* plaintext, size_t size) +{ + struct crypt_auth_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); + if (plaintext != p) { + fprintf(stderr, "plaintext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.iv = (void*)iv; + cryp.op = COP_ENCRYPT; + cryp.auth_len = auth_size; + cryp.auth_src = (void*)auth; + cryp.len = size; + cryp.src = (void*)plaintext; + cryp.dst = plaintext; + cryp.flags = COP_FLAG_AEAD_TLS_TYPE; + if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return -1; + } + + return 0; +} + +int +aes_sha1_decrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + void* ciphertext, size_t size) +{ + struct crypt_auth_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); + if (ciphertext != p) { + fprintf(stderr, "ciphertext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.iv = (void*)iv; + cryp.op = COP_DECRYPT; + cryp.auth_len = auth_size; + cryp.auth_src = (void*)auth; + cryp.len = size; + cryp.src = (void*)ciphertext; + cryp.dst = ciphertext; + cryp.flags = COP_FLAG_AEAD_TLS_TYPE; + if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return -1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.h b/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.h new file mode 100644 index 0000000000000..a07334cf3a4ae --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes-sha1.h @@ -0,0 +1,31 @@ +#ifndef AES_H +# define AES_H + +#include + +struct cryptodev_ctx { + int cfd; + struct session_op sess; + uint16_t alignmask; +}; + +#define AES_BLOCK_SIZE 16 + +int aes_sha1_ctx_init(struct cryptodev_ctx* ctx, int cfd, + const uint8_t *key, unsigned int key_size, + const uint8_t *mac_key, unsigned int mac_key_size); +void aes_sha1_ctx_deinit(); + +/* Note that encryption assumes that ciphertext has enough size + * for the tag and padding to be appended. + * + * Only in-place encryption and decryption are supported. + */ +int aes_sha1_encrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + void* plaintext, size_t size); +int aes_sha1_decrypt(struct cryptodev_ctx* ctx, const void* iv, + const void* auth, size_t auth_size, + void* ciphertext, size_t size); + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes.c b/cryptodev/cryptodev-linux-1.9/examples/aes.c new file mode 100644 index 0000000000000..02f7613b6c194 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes.c @@ -0,0 +1,242 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "aes.h" + +#define KEY_SIZE 16 + + +int aes_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + ctx->sess.cipher = CRYPTO_AES_CBC; + ctx->sess.keylen = key_size; + ctx->sess.key = (void*)key; + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + memset(&siop, 0, sizeof(siop)); + + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } + printf("Got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { + printf("Note: This is not an accelerated cipher\n"); + } + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask); */ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void aes_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +aes_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size) +{ + struct crypt_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); + if (plaintext != p) { + fprintf(stderr, "plaintext is not aligned\n"); + return -1; + } + + p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); + if (ciphertext != p) { + fprintf(stderr, "ciphertext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.len = size; + cryp.src = (void*)plaintext; + cryp.dst = ciphertext; + cryp.iv = (void*)iv; + cryp.op = COP_ENCRYPT; + if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 0; +} + +int +aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size) +{ + struct crypt_op cryp; + void* p; + + /* check plaintext and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask); + if (plaintext != p) { + fprintf(stderr, "plaintext is not aligned\n"); + return -1; + } + + p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask); + if (ciphertext != p) { + fprintf(stderr, "ciphertext is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.len = size; + cryp.src = (void*)ciphertext; + cryp.dst = plaintext; + cryp.iv = (void*)iv; + cryp.op = COP_DECRYPT; + if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 0; +} + +static int test_aes(int cfd) +{ + char plaintext1_raw[AES_BLOCK_SIZE + 63], *plaintext1; + char ciphertext1[AES_BLOCK_SIZE] = { 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 }; + char iv1[AES_BLOCK_SIZE]; + uint8_t key1[KEY_SIZE] = { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + char plaintext2_data[AES_BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 }; + char plaintext2_raw[AES_BLOCK_SIZE + 63], *plaintext2; + char ciphertext2[AES_BLOCK_SIZE] = { 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 }; + char iv2[AES_BLOCK_SIZE]; + uint8_t key2[KEY_SIZE]; + struct cryptodev_ctx ctx; + + aes_ctx_init(&ctx, cfd, key1, sizeof(key1)); + + if (ctx.alignmask) + plaintext1 = (char *)(((unsigned long)plaintext1_raw + ctx.alignmask) & ~ctx.alignmask); + else + plaintext1 = plaintext1_raw; + + memset(plaintext1, 0x0, AES_BLOCK_SIZE); + memset(iv1, 0x0, sizeof(iv1)); + + aes_encrypt(&ctx, iv1, plaintext1, plaintext1, AES_BLOCK_SIZE); + + /* Verify the result */ + if (memcmp(plaintext1, ciphertext1, AES_BLOCK_SIZE) != 0) { + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + return -1; + } + + aes_ctx_deinit(&ctx); + + /* Test 2 */ + + memset(key2, 0x0, sizeof(key2)); + memset(iv2, 0x0, sizeof(iv2)); + + aes_ctx_init(&ctx, cfd, key2, sizeof(key2)); + + if (ctx.alignmask) { + plaintext2 = (char *)(((unsigned long)plaintext2_raw + ctx.alignmask) & ~ctx.alignmask); + } else { + plaintext2 = plaintext2_raw; + } + memcpy(plaintext2, plaintext2_data, AES_BLOCK_SIZE); + + /* Encrypt data.in to data.encrypted */ + aes_encrypt(&ctx, iv2, plaintext2, plaintext2, AES_BLOCK_SIZE); + + /* Verify the result */ + if (memcmp(plaintext2, ciphertext2, AES_BLOCK_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < AES_BLOCK_SIZE; i++) { + printf("%02x ", plaintext2[i]); + } + printf("ciphertext:"); + for (i = 0; i < AES_BLOCK_SIZE; i++) { + printf("%02x ", ciphertext2[i]); + } + printf("\n"); + return 1; + } + + aes_ctx_deinit(&ctx); + + printf("AES Test passed\n"); + + return 0; +} + +int +main() +{ + int cfd = -1; + + /* Open the crypto device */ + cfd = open("/dev/crypto", O_RDWR, 0); + if (cfd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + if (test_aes(cfd)) + return 1; + + /* Close the original descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/examples/aes.h b/cryptodev/cryptodev-linux-1.9/examples/aes.h new file mode 100644 index 0000000000000..ade90c92b58c5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/aes.h @@ -0,0 +1,19 @@ +#ifndef AES_H +# define AES_H + +#include + +struct cryptodev_ctx { + int cfd; + struct session_op sess; + uint16_t alignmask; +}; + +#define AES_BLOCK_SIZE 16 + +int aes_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size); +void aes_ctx_deinit(); +int aes_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size); +int aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size); + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/examples/sha.c b/cryptodev/cryptodev-linux-1.9/examples/sha.c new file mode 100644 index 0000000000000..4f45a6b01a500 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/sha.c @@ -0,0 +1,137 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "sha.h" + +int sha_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + if (key == NULL) + ctx->sess.mac = CRYPTO_SHA1; + else { + ctx->sess.mac = CRYPTO_SHA1_HMAC; + ctx->sess.mackeylen = key_size; + ctx->sess.mackey = (void*)key; + } + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } + printf("Got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)) { + printf("Note: This is not an accelerated cipher\n"); + } + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void sha_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +sha_hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest) +{ + struct crypt_op cryp; + void* p; + + /* check text and ciphertext alignment */ + if (ctx->alignmask) { + p = (void*)(((unsigned long)text + ctx->alignmask) & ~ctx->alignmask); + if (text != p) { + fprintf(stderr, "text is not aligned\n"); + return -1; + } + } + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.len = size; + cryp.src = (void*)text; + cryp.mac = digest; + if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 0; +} + +int +main() +{ + int cfd = -1, i; + struct cryptodev_ctx ctx; + uint8_t digest[20]; + char text[] = "The quick brown fox jumps over the lazy dog"; + uint8_t expected[] = "\x2f\xd4\xe1\xc6\x7a\x2d\x28\xfc\xed\x84\x9e\xe1\xbb\x76\xe7\x39\x1b\x93\xeb\x12"; + + /* Open the crypto device */ + cfd = open("/dev/crypto", O_RDWR, 0); + if (cfd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + sha_ctx_init(&ctx, cfd, NULL, 0); + + sha_hash(&ctx, text, strlen(text), digest); + + sha_ctx_deinit(&ctx); + + printf("digest: "); + for (i = 0; i < 20; i++) { + printf("%02x:", digest[i]); + } + printf("\n"); + + if (memcmp(digest, expected, 20) != 0) { + fprintf(stderr, "SHA1 hashing failed\n"); + return 1; + } + + /* Close the original descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/examples/sha.h b/cryptodev/cryptodev-linux-1.9/examples/sha.h new file mode 100644 index 0000000000000..ed0b8cee42521 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/examples/sha.h @@ -0,0 +1,16 @@ +#ifndef SHA_H +# define SHA_H + +#include + +struct cryptodev_ctx { + int cfd; + struct session_op sess; + uint16_t alignmask; +}; + +int sha_ctx_init(struct cryptodev_ctx* ctx, int cfd, const uint8_t *key, unsigned int key_size); +void sha_ctx_deinit(); +int sha_hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest); + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/ioctl.c b/cryptodev/cryptodev-linux-1.9/ioctl.c new file mode 100644 index 0000000000000..0385203b3e513 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/ioctl.c @@ -0,0 +1,1176 @@ +/* + * Driver for /dev/crypto device (aka CryptoDev) + * + * Copyright (c) 2004 Michal Ludvig , SuSE Labs + * Copyright (c) 2009,2010,2011 Nikos Mavrogiannopoulos + * Copyright (c) 2010 Phil Sutter + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Device /dev/crypto provides an interface for + * accessing kernel CryptoAPI algorithms (ciphers, + * hashes) from userspace programs. + * + * /dev/crypto interface was originally introduced in + * OpenBSD and this module attempts to keep the API. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cryptodev_int.h" +#include "zc.h" +#include "version.h" +#include "cipherapi.h" + +MODULE_AUTHOR("Nikos Mavrogiannopoulos "); +MODULE_DESCRIPTION("CryptoDev driver"); +MODULE_LICENSE("GPL"); + +/* ====== Compile-time config ====== */ + +/* Default (pre-allocated) and maximum size of the job queue. + * These are free, pending and done items all together. */ +#define DEF_COP_RINGSIZE 16 +#define MAX_COP_RINGSIZE 64 + +/* ====== Module parameters ====== */ + +int cryptodev_verbosity; +module_param(cryptodev_verbosity, int, 0644); +MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug"); + +/* ====== CryptoAPI ====== */ +struct todo_list_item { + struct list_head __hook; + struct kernel_crypt_op kcop; + int result; +}; + +struct locked_list { + struct list_head list; + struct mutex lock; +}; + +struct crypt_priv { + struct fcrypt fcrypt; + struct locked_list free, todo, done; + int itemcount; + struct work_struct cryptask; + wait_queue_head_t user_waiter; +}; + +#define FILL_SG(sg, ptr, len) \ + do { \ + (sg)->page = virt_to_page(ptr); \ + (sg)->offset = offset_in_page(ptr); \ + (sg)->length = len; \ + (sg)->dma_address = 0; \ + } while (0) + +/* cryptodev's own workqueue, keeps crypto tasks from disturbing the force */ +static struct workqueue_struct *cryptodev_wq; + +/* Prepare session for future use. */ +static int +crypto_create_session(struct fcrypt *fcr, struct session_op *sop) +{ + struct csession *ses_new = NULL, *ses_ptr; + int ret = 0; + const char *alg_name = NULL; + const char *hash_name = NULL; + int hmac_mode = 1, stream = 0, aead = 0; + /* + * With composite aead ciphers, only ckey is used and it can cover all the + * structure space; otherwise both keys may be used simultaneously but they + * are confined to their spaces + */ + struct { + uint8_t ckey[CRYPTO_CIPHER_MAX_KEY_LEN]; + uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN]; + /* padding space for aead keys */ + uint8_t pad[RTA_SPACE(sizeof(struct crypto_authenc_key_param))]; + } keys; + + /* Does the request make sense? */ + if (unlikely(!sop->cipher && !sop->mac)) { + ddebug(1, "Both 'cipher' and 'mac' unset."); + return -EINVAL; + } + + switch (sop->cipher) { + case 0: + break; + case CRYPTO_DES_CBC: + alg_name = "cbc(des)"; + break; + case CRYPTO_3DES_CBC: + alg_name = "cbc(des3_ede)"; + break; + case CRYPTO_BLF_CBC: + alg_name = "cbc(blowfish)"; + break; + case CRYPTO_AES_CBC: + alg_name = "cbc(aes)"; + break; + case CRYPTO_AES_ECB: + alg_name = "ecb(aes)"; + break; + case CRYPTO_CAMELLIA_CBC: + alg_name = "cbc(camellia)"; + break; + case CRYPTO_AES_CTR: + alg_name = "ctr(aes)"; + stream = 1; + break; + case CRYPTO_AES_GCM: + alg_name = "gcm(aes)"; + stream = 1; + aead = 1; + break; + case CRYPTO_NULL: + alg_name = "ecb(cipher_null)"; + stream = 1; + break; + default: + ddebug(1, "bad cipher: %d", sop->cipher); + return -EINVAL; + } + + switch (sop->mac) { + case 0: + break; + case CRYPTO_MD5_HMAC: + hash_name = "hmac(md5)"; + break; + case CRYPTO_RIPEMD160_HMAC: + hash_name = "hmac(rmd160)"; + break; + case CRYPTO_SHA1_HMAC: + hash_name = "hmac(sha1)"; + break; + case CRYPTO_SHA2_224_HMAC: + hash_name = "hmac(sha224)"; + break; + + case CRYPTO_SHA2_256_HMAC: + hash_name = "hmac(sha256)"; + break; + case CRYPTO_SHA2_384_HMAC: + hash_name = "hmac(sha384)"; + break; + case CRYPTO_SHA2_512_HMAC: + hash_name = "hmac(sha512)"; + break; + + /* non-hmac cases */ + case CRYPTO_MD5: + hash_name = "md5"; + hmac_mode = 0; + break; + case CRYPTO_RIPEMD160: + hash_name = "rmd160"; + hmac_mode = 0; + break; + case CRYPTO_SHA1: + hash_name = "sha1"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_224: + hash_name = "sha224"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_256: + hash_name = "sha256"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_384: + hash_name = "sha384"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_512: + hash_name = "sha512"; + hmac_mode = 0; + break; + default: + ddebug(1, "bad mac: %d", sop->mac); + return -EINVAL; + } + + /* Create a session and put it to the list. Zeroing the structure helps + * also with a single exit point in case of errors */ + ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL); + if (!ses_new) + return -ENOMEM; + + /* Set-up crypto transform. */ + if (alg_name) { + unsigned int keylen; + ret = cryptodev_get_cipher_keylen(&keylen, sop, aead); + if (unlikely(ret < 0)) { + ddebug(1, "Setting key failed for %s-%zu.", + alg_name, (size_t)sop->keylen*8); + goto session_error; + } + + ret = cryptodev_get_cipher_key(keys.ckey, sop, aead); + if (unlikely(ret < 0)) + goto session_error; + + ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keys.ckey, + keylen, stream, aead); + if (ret < 0) { + ddebug(1, "Failed to load cipher for %s", alg_name); + ret = -EINVAL; + goto session_error; + } + } + + if (hash_name && aead == 0) { + if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) { + ddebug(1, "Setting key failed for %s-%zu.", + hash_name, (size_t)sop->mackeylen*8); + ret = -EINVAL; + goto session_error; + } + + if (sop->mackey && unlikely(copy_from_user(keys.mkey, sop->mackey, + sop->mackeylen))) { + ret = -EFAULT; + goto session_error; + } + + ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, + keys.mkey, sop->mackeylen); + if (ret != 0) { + ddebug(1, "Failed to load hash for %s", hash_name); + ret = -EINVAL; + goto session_error; + } + + ret = cryptodev_hash_reset(&ses_new->hdata); + if (ret != 0) { + goto session_error; + } + } + + ses_new->alignmask = max(ses_new->cdata.alignmask, + ses_new->hdata.alignmask); + ddebug(2, "got alignmask %d", ses_new->alignmask); + + ses_new->array_size = DEFAULT_PREALLOC_PAGES; + ddebug(2, "preallocating for %d user pages", ses_new->array_size); + ses_new->pages = kzalloc(ses_new->array_size * + sizeof(struct page *), GFP_KERNEL); + ses_new->sg = kzalloc(ses_new->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + if (ses_new->sg == NULL || ses_new->pages == NULL) { + ddebug(0, "Memory error"); + ret = -ENOMEM; + goto session_error; + } + + /* put the new session to the list */ + get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); + mutex_init(&ses_new->sem); + + mutex_lock(&fcr->sem); +restart: + list_for_each_entry(ses_ptr, &fcr->list, entry) { + /* Check for duplicate SID */ + if (unlikely(ses_new->sid == ses_ptr->sid)) { + get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); + /* Unless we have a broken RNG this + shouldn't loop forever... ;-) */ + goto restart; + } + } + + list_add(&ses_new->entry, &fcr->list); + mutex_unlock(&fcr->sem); + + /* Fill in some values for the user. */ + sop->ses = ses_new->sid; + return 0; + + /* We count on ses_new to be initialized with zeroes + * Since hdata and cdata are embedded within ses_new, it follows that + * hdata->init and cdata->init are either zero or one as they have been + * initialized or not */ +session_error: + cryptodev_hash_deinit(&ses_new->hdata); + cryptodev_cipher_deinit(&ses_new->cdata); + kfree(ses_new->sg); + kfree(ses_new->pages); + kfree(ses_new); + return ret; +} + +/* Everything that needs to be done when removing a session. */ +static inline void +crypto_destroy_session(struct csession *ses_ptr) +{ + if (!mutex_trylock(&ses_ptr->sem)) { + ddebug(2, "Waiting for semaphore of sid=0x%08X", ses_ptr->sid); + mutex_lock(&ses_ptr->sem); + } + ddebug(2, "Removed session 0x%08X", ses_ptr->sid); + cryptodev_cipher_deinit(&ses_ptr->cdata); + cryptodev_hash_deinit(&ses_ptr->hdata); + ddebug(2, "freeing space for %d user pages", ses_ptr->array_size); + kfree(ses_ptr->pages); + kfree(ses_ptr->sg); + mutex_unlock(&ses_ptr->sem); + mutex_destroy(&ses_ptr->sem); + kfree(ses_ptr); +} + +/* Look up a session by ID and remove. */ +static int +crypto_finish_session(struct fcrypt *fcr, uint32_t sid) +{ + struct csession *tmp, *ses_ptr; + struct list_head *head; + int ret = 0; + + mutex_lock(&fcr->sem); + head = &fcr->list; + list_for_each_entry_safe(ses_ptr, tmp, head, entry) { + if (ses_ptr->sid == sid) { + list_del(&ses_ptr->entry); + crypto_destroy_session(ses_ptr); + break; + } + } + + if (unlikely(!ses_ptr)) { + derr(1, "Session with sid=0x%08X not found!", sid); + ret = -ENOENT; + } + mutex_unlock(&fcr->sem); + + return ret; +} + +/* Remove all sessions when closing the file */ +static int +crypto_finish_all_sessions(struct fcrypt *fcr) +{ + struct csession *tmp, *ses_ptr; + struct list_head *head; + + mutex_lock(&fcr->sem); + + head = &fcr->list; + list_for_each_entry_safe(ses_ptr, tmp, head, entry) { + list_del(&ses_ptr->entry); + crypto_destroy_session(ses_ptr); + } + mutex_unlock(&fcr->sem); + + return 0; +} + +/* Look up session by session ID. The returned session is locked. */ +struct csession * +crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid) +{ + struct csession *ses_ptr, *retval = NULL; + + if (unlikely(fcr == NULL)) + return NULL; + + mutex_lock(&fcr->sem); + list_for_each_entry(ses_ptr, &fcr->list, entry) { + if (ses_ptr->sid == sid) { + mutex_lock(&ses_ptr->sem); + retval = ses_ptr; + break; + } + } + mutex_unlock(&fcr->sem); + + return retval; +} + +static void cryptask_routine(struct work_struct *work) +{ + struct crypt_priv *pcr = container_of(work, struct crypt_priv, cryptask); + struct todo_list_item *item; + LIST_HEAD(tmp); + + /* fetch all pending jobs into the temporary list */ + mutex_lock(&pcr->todo.lock); + list_cut_position(&tmp, &pcr->todo.list, pcr->todo.list.prev); + mutex_unlock(&pcr->todo.lock); + + /* handle each job locklessly */ + list_for_each_entry(item, &tmp, __hook) { + item->result = crypto_run(&pcr->fcrypt, &item->kcop); + if (unlikely(item->result)) + derr(0, "crypto_run() failed: %d", item->result); + } + + /* push all handled jobs to the done list at once */ + mutex_lock(&pcr->done.lock); + list_splice_tail(&tmp, &pcr->done.list); + mutex_unlock(&pcr->done.lock); + + /* wake for POLLIN */ + wake_up_interruptible(&pcr->user_waiter); +} + +/* ====== /dev/crypto ====== */ + +static int +cryptodev_open(struct inode *inode, struct file *filp) +{ + struct todo_list_item *tmp, *tmp_next; + struct crypt_priv *pcr; + int i; + + pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); + if (!pcr) + return -ENOMEM; + filp->private_data = pcr; + + mutex_init(&pcr->fcrypt.sem); + mutex_init(&pcr->free.lock); + mutex_init(&pcr->todo.lock); + mutex_init(&pcr->done.lock); + + INIT_LIST_HEAD(&pcr->fcrypt.list); + INIT_LIST_HEAD(&pcr->free.list); + INIT_LIST_HEAD(&pcr->todo.list); + INIT_LIST_HEAD(&pcr->done.list); + + INIT_WORK(&pcr->cryptask, cryptask_routine); + + init_waitqueue_head(&pcr->user_waiter); + + for (i = 0; i < DEF_COP_RINGSIZE; i++) { + tmp = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL); + if (!tmp) + goto err_ringalloc; + pcr->itemcount++; + ddebug(2, "allocated new item at %p", tmp); + list_add(&tmp->__hook, &pcr->free.list); + } + + ddebug(2, "Cryptodev handle initialised, %d elements in queue", + DEF_COP_RINGSIZE); + return 0; + +/* In case of errors, free any memory allocated so far */ +err_ringalloc: + list_for_each_entry_safe(tmp, tmp_next, &pcr->free.list, __hook) { + list_del(&tmp->__hook); + kfree(tmp); + } + mutex_destroy(&pcr->done.lock); + mutex_destroy(&pcr->todo.lock); + mutex_destroy(&pcr->free.lock); + mutex_destroy(&pcr->fcrypt.sem); + kfree(pcr); + filp->private_data = NULL; + return -ENOMEM; +} + +static int +cryptodev_release(struct inode *inode, struct file *filp) +{ + struct crypt_priv *pcr = filp->private_data; + struct todo_list_item *item, *item_safe; + int items_freed = 0; + + if (!pcr) + return 0; + + cancel_work_sync(&pcr->cryptask); + + list_splice_tail(&pcr->todo.list, &pcr->free.list); + list_splice_tail(&pcr->done.list, &pcr->free.list); + + list_for_each_entry_safe(item, item_safe, &pcr->free.list, __hook) { + ddebug(2, "freeing item at %p", item); + list_del(&item->__hook); + kfree(item); + items_freed++; + } + + if (items_freed != pcr->itemcount) { + derr(0, "freed %d items, but %d should exist!", + items_freed, pcr->itemcount); + } + + crypto_finish_all_sessions(&pcr->fcrypt); + + mutex_destroy(&pcr->done.lock); + mutex_destroy(&pcr->todo.lock); + mutex_destroy(&pcr->free.lock); + mutex_destroy(&pcr->fcrypt.sem); + + kfree(pcr); + filp->private_data = NULL; + + ddebug(2, "Cryptodev handle deinitialised, %d elements freed", + items_freed); + return 0; +} + +static int +clonefd(struct file *filp) +{ + int ret; + ret = get_unused_fd_flags(0); + if (ret >= 0) { + get_file(filp); + fd_install(ret, filp); + } + + return ret; +} + +#ifdef ENABLE_ASYNC +/* enqueue a job for asynchronous completion + * + * returns: + * -EBUSY when there are no free queue slots left + * (and the number of slots has reached it MAX_COP_RINGSIZE) + * -EFAULT when there was a memory allocation error + * 0 on success */ +static int crypto_async_run(struct crypt_priv *pcr, struct kernel_crypt_op *kcop) +{ + struct todo_list_item *item = NULL; + + if (unlikely(kcop->cop.flags & COP_FLAG_NO_ZC)) + return -EINVAL; + + mutex_lock(&pcr->free.lock); + if (likely(!list_empty(&pcr->free.list))) { + item = list_first_entry(&pcr->free.list, + struct todo_list_item, __hook); + list_del(&item->__hook); + } else if (pcr->itemcount < MAX_COP_RINGSIZE) { + pcr->itemcount++; + } else { + mutex_unlock(&pcr->free.lock); + return -EBUSY; + } + mutex_unlock(&pcr->free.lock); + + if (unlikely(!item)) { + item = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL); + if (unlikely(!item)) + return -EFAULT; + dinfo(1, "increased item count to %d", pcr->itemcount); + } + + memcpy(&item->kcop, kcop, sizeof(struct kernel_crypt_op)); + + mutex_lock(&pcr->todo.lock); + list_add_tail(&item->__hook, &pcr->todo.list); + mutex_unlock(&pcr->todo.lock); + + queue_work(cryptodev_wq, &pcr->cryptask); + return 0; +} + +/* get the first completed job from the "done" queue + * + * returns: + * -EBUSY if no completed jobs are ready (yet) + * the return value of crypto_run() otherwise */ +static int crypto_async_fetch(struct crypt_priv *pcr, + struct kernel_crypt_op *kcop) +{ + struct todo_list_item *item; + int retval; + + mutex_lock(&pcr->done.lock); + if (list_empty(&pcr->done.list)) { + mutex_unlock(&pcr->done.lock); + return -EBUSY; + } + item = list_first_entry(&pcr->done.list, struct todo_list_item, __hook); + list_del(&item->__hook); + mutex_unlock(&pcr->done.lock); + + memcpy(kcop, &item->kcop, sizeof(struct kernel_crypt_op)); + retval = item->result; + + mutex_lock(&pcr->free.lock); + list_add_tail(&item->__hook, &pcr->free.list); + mutex_unlock(&pcr->free.lock); + + /* wake for POLLOUT */ + wake_up_interruptible(&pcr->user_waiter); + + return retval; +} +#endif + +/* this function has to be called from process context */ +static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr) +{ + struct crypt_op *cop = &kcop->cop; + struct csession *ses_ptr; + int rc; + + /* this also enters ses_ptr->sem */ + ses_ptr = crypto_get_session_by_sid(fcr, cop->ses); + if (unlikely(!ses_ptr)) { + derr(1, "invalid session ID=0x%08X", cop->ses); + return -EINVAL; + } + kcop->ivlen = cop->iv ? ses_ptr->cdata.ivsize : 0; + kcop->digestsize = 0; /* will be updated during operation */ + + crypto_put_session(ses_ptr); + + kcop->task = current; + kcop->mm = current->mm; + + if (cop->iv) { + rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen); + if (unlikely(rc)) { + derr(1, "error copying IV (%d bytes), copy_from_user returned %d for address %p", + kcop->ivlen, rc, cop->iv); + return -EFAULT; + } + } + + return 0; +} + +/* this function has to be called from process context */ +static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr) +{ + int ret; + + if (kcop->digestsize) { + ret = copy_to_user(kcop->cop.mac, + kcop->hash_output, kcop->digestsize); + if (unlikely(ret)) + return -EFAULT; + } + if (kcop->ivlen && kcop->cop.flags & COP_FLAG_WRITE_IV) { + ret = copy_to_user(kcop->cop.iv, + kcop->iv, kcop->ivlen); + if (unlikely(ret)) + return -EFAULT; + } + return 0; +} + +static int kcop_from_user(struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop)))) + return -EFAULT; + + return fill_kcop_from_cop(kcop, fcr); +} + +static int kcop_to_user(struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + int ret; + + ret = fill_cop_from_kcop(kcop, fcr); + if (unlikely(ret)) { + derr(1, "Error in fill_cop_from_kcop"); + return ret; + } + + if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop)))) { + derr(1, "Cannot copy to userspace"); + return -EFAULT; + } + return 0; +} + +static inline void tfm_info_to_alg_info(struct alg_info *dst, struct crypto_tfm *tfm) +{ + snprintf(dst->cra_name, CRYPTODEV_MAX_ALG_NAME, + "%s", crypto_tfm_alg_name(tfm)); + snprintf(dst->cra_driver_name, CRYPTODEV_MAX_ALG_NAME, + "%s", crypto_tfm_alg_driver_name(tfm)); +} + +#ifndef CRYPTO_ALG_KERN_DRIVER_ONLY +static unsigned int is_known_accelerated(struct crypto_tfm *tfm) +{ + const char *name = crypto_tfm_alg_driver_name(tfm); + + if (name == NULL) + return 1; /* assume accelerated */ + + /* look for known crypto engine names */ + if (strstr(name, "-talitos") || + !strncmp(name, "mv-", 3) || + !strncmp(name, "atmel-", 6) || + strstr(name, "geode") || + strstr(name, "hifn") || + strstr(name, "-ixp4xx") || + strstr(name, "-omap") || + strstr(name, "-picoxcell") || + strstr(name, "-s5p") || + strstr(name, "-ppc4xx") || + strstr(name, "-caam") || + strstr(name, "-n2")) + return 1; + + return 0; +} +#endif + +static int get_session_info(struct fcrypt *fcr, struct session_info_op *siop) +{ + struct csession *ses_ptr; + struct crypto_tfm *tfm; + + /* this also enters ses_ptr->sem */ + ses_ptr = crypto_get_session_by_sid(fcr, siop->ses); + if (unlikely(!ses_ptr)) { + derr(1, "invalid session ID=0x%08X", siop->ses); + return -EINVAL; + } + + siop->flags = 0; + + if (ses_ptr->cdata.init) { + if (ses_ptr->cdata.aead == 0) + tfm = cryptodev_crypto_blkcipher_tfm(ses_ptr->cdata.async.s); + else + tfm = crypto_aead_tfm(ses_ptr->cdata.async.as); + tfm_info_to_alg_info(&siop->cipher_info, tfm); +#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY + if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#else + if (is_known_accelerated(tfm)) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#endif + } + if (ses_ptr->hdata.init) { + tfm = crypto_ahash_tfm(ses_ptr->hdata.async.s); + tfm_info_to_alg_info(&siop->hash_info, tfm); +#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY + if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#else + if (is_known_accelerated(tfm)) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#endif + } + + siop->alignmask = ses_ptr->alignmask; + + crypto_put_session(ses_ptr); + return 0; +} + +static long +cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_) +{ + void __user *arg = (void __user *)arg_; + int __user *p = arg; + struct session_op sop; + struct kernel_crypt_op kcop; + struct kernel_crypt_auth_op kcaop; + struct crypt_priv *pcr = filp->private_data; + struct fcrypt *fcr; + struct session_info_op siop; + uint32_t ses; + int ret, fd; + + if (unlikely(!pcr)) + BUG(); + + fcr = &pcr->fcrypt; + + switch (cmd) { + case CIOCASYMFEAT: + return put_user(0, p); + case CRIOGET: + fd = clonefd(filp); + ret = put_user(fd, p); + if (unlikely(ret)) { + sys_close(fd); + return ret; + } + return ret; + case CIOCGSESSION: + if (unlikely(copy_from_user(&sop, arg, sizeof(sop)))) + return -EFAULT; + + ret = crypto_create_session(fcr, &sop); + if (unlikely(ret)) + return ret; + ret = copy_to_user(arg, &sop, sizeof(sop)); + if (unlikely(ret)) { + crypto_finish_session(fcr, sop.ses); + return -EFAULT; + } + return ret; + case CIOCFSESSION: + ret = get_user(ses, (uint32_t __user *)arg); + if (unlikely(ret)) + return ret; + ret = crypto_finish_session(fcr, ses); + return ret; + case CIOCGSESSINFO: + if (unlikely(copy_from_user(&siop, arg, sizeof(siop)))) + return -EFAULT; + + ret = get_session_info(fcr, &siop); + if (unlikely(ret)) + return ret; + return copy_to_user(arg, &siop, sizeof(siop)); + case CIOCCRYPT: + if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) { + dwarning(1, "Error copying from user"); + return ret; + } + + ret = crypto_run(fcr, &kcop); + if (unlikely(ret)) { + dwarning(1, "Error in crypto_run"); + return ret; + } + + return kcop_to_user(&kcop, fcr, arg); + case CIOCAUTHCRYPT: + if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) { + dwarning(1, "Error copying from user"); + return ret; + } + + ret = crypto_auth_run(fcr, &kcaop); + if (unlikely(ret)) { + dwarning(1, "Error in crypto_auth_run"); + return ret; + } + return kcaop_to_user(&kcaop, fcr, arg); +#ifdef ENABLE_ASYNC + case CIOCASYNCCRYPT: + if (unlikely(ret = kcop_from_user(&kcop, fcr, arg))) + return ret; + + return crypto_async_run(pcr, &kcop); + case CIOCASYNCFETCH: + ret = crypto_async_fetch(pcr, &kcop); + if (unlikely(ret)) + return ret; + + return kcop_to_user(&kcop, fcr, arg); +#endif + default: + return -EINVAL; + } +} + +/* compatibility code for 32bit userlands */ +#ifdef CONFIG_COMPAT + +static inline void +compat_to_session_op(struct compat_session_op *compat, struct session_op *sop) +{ + sop->cipher = compat->cipher; + sop->mac = compat->mac; + sop->keylen = compat->keylen; + + sop->key = compat_ptr(compat->key); + sop->mackeylen = compat->mackeylen; + sop->mackey = compat_ptr(compat->mackey); + sop->ses = compat->ses; +} + +static inline void +session_op_to_compat(struct session_op *sop, struct compat_session_op *compat) +{ + compat->cipher = sop->cipher; + compat->mac = sop->mac; + compat->keylen = sop->keylen; + + compat->key = ptr_to_compat(sop->key); + compat->mackeylen = sop->mackeylen; + compat->mackey = ptr_to_compat(sop->mackey); + compat->ses = sop->ses; +} + +static inline void +compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop) +{ + cop->ses = compat->ses; + cop->op = compat->op; + cop->flags = compat->flags; + cop->len = compat->len; + + cop->src = compat_ptr(compat->src); + cop->dst = compat_ptr(compat->dst); + cop->mac = compat_ptr(compat->mac); + cop->iv = compat_ptr(compat->iv); +} + +static inline void +crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat) +{ + compat->ses = cop->ses; + compat->op = cop->op; + compat->flags = cop->flags; + compat->len = cop->len; + + compat->src = ptr_to_compat(cop->src); + compat->dst = ptr_to_compat(cop->dst); + compat->mac = ptr_to_compat(cop->mac); + compat->iv = ptr_to_compat(cop->iv); +} + +static int compat_kcop_from_user(struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + struct compat_crypt_op compat_cop; + + if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop)))) + return -EFAULT; + compat_to_crypt_op(&compat_cop, &kcop->cop); + + return fill_kcop_from_cop(kcop, fcr); +} + +static int compat_kcop_to_user(struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + int ret; + struct compat_crypt_op compat_cop; + + ret = fill_cop_from_kcop(kcop, fcr); + if (unlikely(ret)) { + dwarning(1, "Error in fill_cop_from_kcop"); + return ret; + } + crypt_op_to_compat(&kcop->cop, &compat_cop); + + if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop)))) { + dwarning(1, "Error copying to user"); + return -EFAULT; + } + return 0; +} + +static long +cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_) +{ + void __user *arg = (void __user *)arg_; + struct crypt_priv *pcr = file->private_data; + struct fcrypt *fcr; + struct session_op sop; + struct compat_session_op compat_sop; + struct kernel_crypt_op kcop; + int ret; + + if (unlikely(!pcr)) + BUG(); + + fcr = &pcr->fcrypt; + + switch (cmd) { + case CIOCASYMFEAT: + case CRIOGET: + case CIOCFSESSION: + case CIOCGSESSINFO: + return cryptodev_ioctl(file, cmd, arg_); + + case COMPAT_CIOCGSESSION: + if (unlikely(copy_from_user(&compat_sop, arg, + sizeof(compat_sop)))) + return -EFAULT; + compat_to_session_op(&compat_sop, &sop); + + ret = crypto_create_session(fcr, &sop); + if (unlikely(ret)) + return ret; + + session_op_to_compat(&sop, &compat_sop); + ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop)); + if (unlikely(ret)) { + crypto_finish_session(fcr, sop.ses); + return -EFAULT; + } + return ret; + + case COMPAT_CIOCCRYPT: + ret = compat_kcop_from_user(&kcop, fcr, arg); + if (unlikely(ret)) + return ret; + + ret = crypto_run(fcr, &kcop); + if (unlikely(ret)) + return ret; + + return compat_kcop_to_user(&kcop, fcr, arg); +#ifdef ENABLE_ASYNC + case COMPAT_CIOCASYNCCRYPT: + if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg))) + return ret; + + return crypto_async_run(pcr, &kcop); + case COMPAT_CIOCASYNCFETCH: + ret = crypto_async_fetch(pcr, &kcop); + if (unlikely(ret)) + return ret; + + return compat_kcop_to_user(&kcop, fcr, arg); +#endif + default: + return -EINVAL; + } +} + +#endif /* CONFIG_COMPAT */ + +static unsigned int cryptodev_poll(struct file *file, poll_table *wait) +{ + struct crypt_priv *pcr = file->private_data; + int ret = 0; + + poll_wait(file, &pcr->user_waiter, wait); + + if (!list_empty_careful(&pcr->done.list)) + ret |= POLLIN | POLLRDNORM; + if (!list_empty_careful(&pcr->free.list) || pcr->itemcount < MAX_COP_RINGSIZE) + ret |= POLLOUT | POLLWRNORM; + + return ret; +} + +static const struct file_operations cryptodev_fops = { + .owner = THIS_MODULE, + .open = cryptodev_open, + .release = cryptodev_release, + .unlocked_ioctl = cryptodev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = cryptodev_compat_ioctl, +#endif /* CONFIG_COMPAT */ + .poll = cryptodev_poll, +}; + +static struct miscdevice cryptodev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "crypto", + .fops = &cryptodev_fops, + .mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, +}; + +static int __init +cryptodev_register(void) +{ + int rc; + + rc = misc_register(&cryptodev); + if (unlikely(rc)) { + pr_err(PFX "registration of /dev/crypto failed\n"); + return rc; + } + + return 0; +} + +static void __exit +cryptodev_deregister(void) +{ + misc_deregister(&cryptodev); +} + +/* ====== Module init/exit ====== */ +static struct ctl_table verbosity_ctl_dir[] = { + { + .procname = "cryptodev_verbosity", + .data = &cryptodev_verbosity, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + {0, }, +}; + +static struct ctl_table verbosity_ctl_root[] = { + { + .procname = "ioctl", + .mode = 0555, + .child = verbosity_ctl_dir, + }, + {0, }, +}; +static struct ctl_table_header *verbosity_sysctl_header; +static int __init init_cryptodev(void) +{ + int rc; + + cryptodev_wq = create_workqueue("cryptodev_queue"); + if (unlikely(!cryptodev_wq)) { + pr_err(PFX "failed to allocate the cryptodev workqueue\n"); + return -EFAULT; + } + + rc = cryptodev_register(); + if (unlikely(rc)) { + destroy_workqueue(cryptodev_wq); + return rc; + } + + verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root); + + pr_info(PFX "driver %s loaded.\n", VERSION); + + return 0; +} + +static void __exit exit_cryptodev(void) +{ + flush_workqueue(cryptodev_wq); + destroy_workqueue(cryptodev_wq); + + if (verbosity_sysctl_header) + unregister_sysctl_table(verbosity_sysctl_header); + + cryptodev_deregister(); + pr_info(PFX "driver unloaded.\n"); +} + +module_init(init_cryptodev); +module_exit(exit_cryptodev); + diff --git a/cryptodev/cryptodev-linux-1.9/lib/Makefile b/cryptodev/cryptodev-linux-1.9/lib/Makefile new file mode 100644 index 0000000000000..3bedc341d41da --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/Makefile @@ -0,0 +1,15 @@ +CFLAGS=-g -O2 -Wall + +all: benchmark + +benchmark: main.c libthreshold.a + gcc $(CFLAGS) -DDEBUG -o $@ $^ -lssl -lcrypto libthreshold.a + +.o: + gcc $(CCFLAGS) -c $< -o $@ + +libthreshold.a: benchmark.o hash.o threshold.o combo.o + ar rcs $@ $^ + +clean: + rm -f *.o *~ benchmark libthreshold.a diff --git a/cryptodev/cryptodev-linux-1.9/lib/benchmark.c b/cryptodev/cryptodev-linux-1.9/lib/benchmark.c new file mode 100644 index 0000000000000..a04efbc44c8b4 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/benchmark.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "benchmark.h" + +int benchmark_must_finish = 0; + +static void +alarm_handler (int signo) +{ + benchmark_must_finish = 1; +} + +int start_benchmark(struct benchmark_st * st) +{ + int ret; + struct itimerval timer; + + memset(st, 0, sizeof(*st)); + + st->old_handler = signal (SIGPROF, alarm_handler); + + ret = gettimeofday (&st->start, NULL); + if (ret < 0) { + perror("gettimeofday"); + return -1; + } + + benchmark_must_finish = 0; + + memset(&timer, 0, sizeof(timer)); + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 100*1000; + + ret = setitimer(ITIMER_PROF, &timer, NULL); + if (ret < 0) { + perror("setitimer"); + return -1; + } + + return 0; +} + +/* Returns -1 on error or 0 on success. + * elapsed: the elapsed time in milliseconds + */ +int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed) +{ + unsigned long msecs; + struct timeval stop; + int ret; + + signal(SIGPROF, st->old_handler); + + ret = gettimeofday (&stop, NULL); + if (ret < 0) + return -1; + + msecs = (stop.tv_sec * 1000 + stop.tv_usec / 1000 - + (st->start.tv_sec * 1000 + st->start.tv_usec / (1000))); + + if (elapsed) *elapsed = msecs; + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/lib/benchmark.h b/cryptodev/cryptodev-linux-1.9/lib/benchmark.h new file mode 100644 index 0000000000000..173552ec497f1 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/benchmark.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +typedef void (*sighandler_t)(int); + +struct benchmark_st +{ + struct timeval start; + sighandler_t old_handler; +}; + +extern int benchmark_must_finish; + +int start_benchmark(struct benchmark_st * st); +int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed); + diff --git a/cryptodev/cryptodev-linux-1.9/lib/combo.c b/cryptodev/cryptodev-linux-1.9/lib/combo.c new file mode 100644 index 0000000000000..b26da0a584eb5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/combo.c @@ -0,0 +1,171 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "benchmark.h" +#include "hash.h" + +int aead_ctx_init(struct cryptodev_ctx* ctx, int cipher, int hash, void* key, int key_size, int cfd) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + ctx->sess.mac = hash; + ctx->sess.cipher = cipher; + ctx->sess.key = key; + ctx->sess.keylen = key_size; + + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + memset(&siop, 0, sizeof(siop)); + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } +#ifdef DEBUG + printf("Got %s-%s with drivers %s and %s\n", + siop.cipher_info.cra_name, siop.hash_info.cra_name, + siop.cipher_info.cra_driver_name, siop.hash_info.cra_driver_name); +#endif + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void aead_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +aead_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size, void* digest) +{ + struct crypt_auth_op cryp; + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.len = size; + cryp.iv = (void*)iv; + cryp.iv_len = 16; + cryp.src = (void*)plaintext; + cryp.dst = (void*)ciphertext; + cryp.flags = COP_FLAG_AEAD_TLS_TYPE; + + if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return -1; + } + + return 0; +} + +static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024}; + + +int aead_test(int cipher, int mac, void* ukey, int ukey_size, + void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res)) +{ + int cfd = -1, i, ret; + struct cryptodev_ctx ctx; + uint8_t digest[AALG_MAX_RESULT_LEN]; + char text[16*1024]; + char ctext[16*1024]; + char iv[16]; + unsigned long elapsed, counted; + double t1, t2; + struct benchmark_st bst; + + /* Open the crypto device */ + cfd = open("/dev/crypto", O_RDWR, 0); + if (cfd < 0) { + perror("open(/dev/crypto)"); + return -1; + } + + aead_ctx_init(&ctx, cipher, mac, ukey, ukey_size, cfd); + + for (i=0;i t2) { + ret = sizes[i]; + goto finish; + } + } + + ret = -1; +finish: + aead_ctx_deinit(&ctx); + + /* Close the original descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + return ret; +} diff --git a/cryptodev/cryptodev-linux-1.9/lib/hash.c b/cryptodev/cryptodev-linux-1.9/lib/hash.c new file mode 100644 index 0000000000000..386fd7e84e593 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/hash.c @@ -0,0 +1,161 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "hash.h" +#include "benchmark.h" + +int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd) +{ +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(ctx, 0, sizeof(*ctx)); + ctx->cfd = cfd; + + ctx->sess.mac = hash; + + if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) { + perror("ioctl(CIOCGSESSION)"); + return -1; + } + +#ifdef CIOCGSESSINFO + memset(&siop, 0, sizeof(siop)); + siop.ses = ctx->sess.ses; + if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return -1; + } +#ifdef DEBUG + printf("Got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); +#endif + /*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/ + ctx->alignmask = siop.alignmask; +#endif + return 0; +} + +void hash_ctx_deinit(struct cryptodev_ctx* ctx) +{ + if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } +} + +int +hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest) +{ + struct crypt_op cryp; + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = ctx->sess.ses; + cryp.len = size; + cryp.src = (void*)text; + cryp.mac = digest; + if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 0; +} + +static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024}; + +/* Worst case running time: around 1.2 secs + */ +int hash_test(int algo, void (*user_hash)(void* text, int size, void* res)) +{ + int cfd = -1, i, ret; + struct cryptodev_ctx ctx; + uint8_t digest[AALG_MAX_RESULT_LEN]; + char text[16*1024]; + unsigned long elapsed, counted; + double t1, t2; + struct benchmark_st bst; + + /* Open the crypto device */ + cfd = open("/dev/crypto", O_RDWR, 0); + if (cfd < 0) { + perror("open(/dev/crypto)"); + return -1; + } + + hash_ctx_init(&ctx, algo, cfd); + + for (i=0;i t2) { + ret = sizes[i]; + goto finish; + } +#ifdef DEBUG + printf("%d: kernel: %.4f bytes/msec, user: %.4f bytes/msec\n", sizes[i], t1, t2); +#endif + } + + ret = -1; +finish: + hash_ctx_deinit(&ctx); + + /* Close the original descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + return ret; +} + diff --git a/cryptodev/cryptodev-linux-1.9/lib/hash.h b/cryptodev/cryptodev-linux-1.9/lib/hash.h new file mode 100644 index 0000000000000..7c32ceaaa8955 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/hash.h @@ -0,0 +1,20 @@ +#ifndef HASH_H +# define HASH_H + +#include + +struct cryptodev_ctx { + int cfd; + struct session_op sess; + uint16_t alignmask; +}; + +int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd); +void hash_ctx_deinit(struct cryptodev_ctx* ctx); +int hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest); +int hash_test(int algo, void (*user_hash)(void* text, int size, void* res)); + +int aead_test(int cipher, int mac, void* ukey, int ukey_size, + void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res)); + +#endif diff --git a/cryptodev/cryptodev-linux-1.9/lib/main.c b/cryptodev/cryptodev-linux-1.9/lib/main.c new file mode 100644 index 0000000000000..443779af119da --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/main.c @@ -0,0 +1,28 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include "threshold.h" + +int main() +{ +int ret; + + ret = get_sha1_threshold(); + if (ret > 0) + printf("SHA1 in kernel outperforms user-space after %d input bytes\n", ret); + + ret = get_aes_sha1_threshold(); + if (ret > 0) + printf("AES-SHA1 in kernel outperforms user-space after %d input bytes\n", ret); + + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/lib/threshold.c b/cryptodev/cryptodev-linux-1.9/lib/threshold.c new file mode 100644 index 0000000000000..b002d58e2df55 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/threshold.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hash.h" +#include "threshold.h" + +void sha_hash(void* text, int size, void* digest) +{ +SHA_CTX ctx; + + SHA_Init(&ctx); + + SHA_Update(&ctx, text, size); + + SHA_Final(digest, &ctx); +} + +void aes_sha_combo(void* ctx, void* plaintext, void* ciphertext, int size, void* tag) +{ +uint8_t iv[16]; +AES_KEY* key = ctx; +HMAC_CTX hctx; +unsigned int rlen = 20; + + HMAC_CTX_init(&hctx); + HMAC_Init_ex(&hctx, iv, 16, EVP_sha1(), NULL); + + HMAC_Update(&hctx, plaintext, size); + + HMAC_Final(&hctx, tag, &rlen); + HMAC_CTX_cleanup(&hctx); + + AES_cbc_encrypt(plaintext, ciphertext, size, key, iv, 1); +} + +int get_sha1_threshold() +{ + return hash_test(CRYPTO_SHA1, sha_hash); +} + +int get_aes_sha1_threshold() +{ +AES_KEY key; +uint8_t ukey[16]; + + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + memset(ukey, 0xaf, sizeof(ukey)); + AES_set_encrypt_key(ukey, 16*8, &key); + + return aead_test(CRYPTO_AES_CBC, CRYPTO_SHA1, ukey, 16, &key, aes_sha_combo); +} + diff --git a/cryptodev/cryptodev-linux-1.9/lib/threshold.h b/cryptodev/cryptodev-linux-1.9/lib/threshold.h new file mode 100644 index 0000000000000..6c11019b2ee62 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/lib/threshold.h @@ -0,0 +1,10 @@ +/* Return the number of bytes after which the + * kernel operation is more efficient to use. + * If return value is -1, then kernel operation + * cannot, or shouldn't be used, because it is always + * slower. + * + * Running time ~= 1.2 seconds per call. + */ +int get_sha1_threshold(); +int get_aes_sha1_threshold(); diff --git a/cryptodev/cryptodev-linux-1.9/main.c b/cryptodev/cryptodev-linux-1.9/main.c new file mode 100644 index 0000000000000..57e5c38a42f9a --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/main.c @@ -0,0 +1,267 @@ +/* + * Driver for /dev/crypto device (aka CryptoDev) + * + * Copyright (c) 2004 Michal Ludvig , SuSE Labs + * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Device /dev/crypto provides an interface for + * accessing kernel CryptoAPI algorithms (ciphers, + * hashes) from userspace programs. + * + * /dev/crypto interface was originally introduced in + * OpenBSD and this module attempts to keep the API. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cryptodev_int.h" +#include "zc.h" +#include "cryptlib.h" +#include "version.h" + +/* This file contains the traditional operations of encryption + * and hashing of /dev/crypto. + */ + +static int +hash_n_crypt(struct csession *ses_ptr, struct crypt_op *cop, + struct scatterlist *src_sg, struct scatterlist *dst_sg, + uint32_t len) +{ + int ret; + + /* Always hash before encryption and after decryption. Maybe + * we should introduce a flag to switch... TBD later on. + */ + if (cop->op == COP_ENCRYPT) { + if (ses_ptr->hdata.init != 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + src_sg, len); + if (unlikely(ret)) + goto out_err; + } + if (ses_ptr->cdata.init != 0) { + ret = cryptodev_cipher_encrypt(&ses_ptr->cdata, + src_sg, dst_sg, len); + + if (unlikely(ret)) + goto out_err; + } + } else { + if (ses_ptr->cdata.init != 0) { + ret = cryptodev_cipher_decrypt(&ses_ptr->cdata, + src_sg, dst_sg, len); + + if (unlikely(ret)) + goto out_err; + } + + if (ses_ptr->hdata.init != 0) { + ret = cryptodev_hash_update(&ses_ptr->hdata, + dst_sg, len); + if (unlikely(ret)) + goto out_err; + } + } + return 0; +out_err: + derr(0, "CryptoAPI failure: %d", ret); + return ret; +} + +/* This is the main crypto function - feed it with plaintext + and get a ciphertext (or vice versa :-) */ +static int +__crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop) +{ + char *data; + char __user *src, *dst; + struct scatterlist sg; + size_t nbytes, bufsize; + int ret = 0; + + nbytes = cop->len; + data = (char *)__get_free_page(GFP_KERNEL); + + if (unlikely(!data)) { + derr(1, "Error getting free page."); + return -ENOMEM; + } + + bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; + + src = cop->src; + dst = cop->dst; + + while (nbytes > 0) { + size_t current_len = nbytes > bufsize ? bufsize : nbytes; + + if (unlikely(copy_from_user(data, src, current_len))) { + derr(1, "Error copying %zu bytes from user address %p.", current_len, src); + ret = -EFAULT; + break; + } + + sg_init_one(&sg, data, current_len); + + ret = hash_n_crypt(ses_ptr, cop, &sg, &sg, current_len); + + if (unlikely(ret)) { + derr(1, "hash_n_crypt failed."); + break; + } + + if (ses_ptr->cdata.init != 0) { + if (unlikely(copy_to_user(dst, data, current_len))) { + derr(1, "could not copy to user."); + ret = -EFAULT; + break; + } + } + + dst += current_len; + nbytes -= current_len; + src += current_len; + } + + free_page((unsigned long)data); + return ret; +} + + + +/* This is the main crypto function - zero-copy edition */ +static int +__crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop) +{ + struct scatterlist *src_sg, *dst_sg; + struct crypt_op *cop = &kcop->cop; + int ret = 0; + + ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len, + kcop->task, kcop->mm, &src_sg, &dst_sg); + if (unlikely(ret)) { + derr(1, "Error getting user pages. Falling back to non zero copy."); + return __crypto_run_std(ses_ptr, cop); + } + + ret = hash_n_crypt(ses_ptr, cop, src_sg, dst_sg, cop->len); + + release_user_pages(ses_ptr); + return ret; +} + +int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop) +{ + struct csession *ses_ptr; + struct crypt_op *cop = &kcop->cop; + int ret; + + if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { + ddebug(1, "invalid operation op=%u", cop->op); + return -EINVAL; + } + + /* this also enters ses_ptr->sem */ + ses_ptr = crypto_get_session_by_sid(fcr, cop->ses); + if (unlikely(!ses_ptr)) { + derr(1, "invalid session ID=0x%08X", cop->ses); + return -EINVAL; + } + + if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET)) { + ret = cryptodev_hash_reset(&ses_ptr->hdata); + if (unlikely(ret)) { + derr(1, "error in cryptodev_hash_reset()"); + goto out_unlock; + } + } + + if (ses_ptr->cdata.init != 0) { + int blocksize = ses_ptr->cdata.blocksize; + + if (unlikely(cop->len % blocksize)) { + derr(1, "data size (%u) isn't a multiple of block size (%u)", + cop->len, blocksize); + ret = -EINVAL; + goto out_unlock; + } + + cryptodev_cipher_set_iv(&ses_ptr->cdata, kcop->iv, + min(ses_ptr->cdata.ivsize, kcop->ivlen)); + } + + if (likely(cop->len)) { + if (cop->flags & COP_FLAG_NO_ZC) { + if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->src, ses_ptr->alignmask))) { + dwarning(2, "source address %p is not %d byte aligned - disabling zero copy", + cop->src, ses_ptr->alignmask + 1); + cop->flags &= ~COP_FLAG_NO_ZC; + } + + if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->dst, ses_ptr->alignmask))) { + dwarning(2, "destination address %p is not %d byte aligned - disabling zero copy", + cop->dst, ses_ptr->alignmask + 1); + cop->flags &= ~COP_FLAG_NO_ZC; + } + } + + if (cop->flags & COP_FLAG_NO_ZC) + ret = __crypto_run_std(ses_ptr, &kcop->cop); + else + ret = __crypto_run_zc(ses_ptr, kcop); + if (unlikely(ret)) + goto out_unlock; + } + + if (ses_ptr->cdata.init != 0) { + cryptodev_cipher_get_iv(&ses_ptr->cdata, kcop->iv, + min(ses_ptr->cdata.ivsize, kcop->ivlen)); + } + + if (ses_ptr->hdata.init != 0 && + ((cop->flags & COP_FLAG_FINAL) || + (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) { + + ret = cryptodev_hash_final(&ses_ptr->hdata, kcop->hash_output); + if (unlikely(ret)) { + derr(0, "CryptoAPI failure: %d", ret); + goto out_unlock; + } + kcop->digestsize = ses_ptr->hdata.digestsize; + } + +out_unlock: + crypto_put_session(ses_ptr); + return ret; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/Makefile b/cryptodev/cryptodev-linux-1.9/tests/Makefile new file mode 100644 index 0000000000000..2502f32b13919 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/Makefile @@ -0,0 +1,47 @@ +CFLAGS += -I.. $(CRYPTODEV_CFLAGS) -Wall -Werror + +comp_progs := cipher_comp hash_comp hmac_comp + +hostprogs := cipher cipher-aead hmac speed async_cipher async_hmac \ + async_speed sha_speed hashcrypt_speed fullspeed cipher-gcm \ + cipher-aead-srtp $(comp_progs) + +example-cipher-objs := cipher.o +example-cipher-aead-objs := cipher-aead.o +example-hmac-objs := hmac.o +example-speed-objs := speed.c +example-fullspeed-objs := fullspeed.c +example-sha-speed-objs := sha_speed.c +example-async-cipher-objs := async_cipher.o +example-async-hmac-objs := async_hmac.o +example-async-speed-objs := async_speed.o +example-hashcrypt-speed-objs := hashcrypt_speed.c + +prefix ?= /usr/local +execprefix ?= $(prefix) +bindir = $(execprefix)/bin + +all: $(hostprogs) + +check: $(hostprogs) + ./cipher + ./hmac + ./async_cipher + ./async_hmac + ./cipher-aead-srtp + ./cipher-gcm + ./cipher-aead + +install: + install -d $(DESTDIR)/$(bindir) + for prog in $(hostprogs); do \ + install -m 755 $$prog $(DESTDIR)/$(bindir); \ + done + +clean: + rm -f *.o *~ $(hostprogs) + +${comp_progs}: LDLIBS += -lssl -lcrypto +${comp_progs}: %: %.o openssl_wrapper.o + +.PHONY: all clean check install diff --git a/cryptodev/cryptodev-linux-1.9/tests/async_cipher.c b/cryptodev/cryptodev-linux-1.9/tests/async_cipher.c new file mode 100644 index 0000000000000..7a184e5acec2f --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/async_cipher.c @@ -0,0 +1,339 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asynchelper.h" +#include "testhelper.h" + +#ifdef ENABLE_ASYNC + +static int debug = 0; + +#define DATA_SIZE 8*1024 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + +static int +test_crypto(int cfd) +{ + uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext; + uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext; + uint8_t iv[BLOCK_SIZE]; + uint8_t key[KEY_SIZE]; + + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + struct crypt_op cryp; + + if (debug) printf("running %s\n", __func__); + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + if (debug) printf("%s: got the session\n", __func__); + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + plaintext = buf_align(plaintext_raw, siop.alignmask); + ciphertext = buf_align(ciphertext_raw, siop.alignmask); +#else + plaintext = plaintext_raw; + ciphertext = ciphertext_raw; +#endif + memset(plaintext, 0x15, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = DATA_SIZE; + cryp.src = plaintext; + cryp.dst = ciphertext; + cryp.iv = iv; + cryp.op = COP_ENCRYPT; + + DO_OR_DIE(do_async_crypt(cfd, &cryp), 0); + DO_OR_DIE(do_async_fetch(cfd, &cryp), 0); + + if (debug) printf("%s: data encrypted\n", __func__); + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + if (debug) printf("%s: session finished\n", __func__); + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + if (debug) printf("%s: got new session\n", __func__); + + /* Decrypt data.encrypted to data.decrypted */ + cryp.ses = sess.ses; + cryp.len = DATA_SIZE; + cryp.src = ciphertext; + cryp.dst = ciphertext; + cryp.iv = iv; + cryp.op = COP_DECRYPT; + + DO_OR_DIE(do_async_crypt(cfd, &cryp), 0); + DO_OR_DIE(do_async_fetch(cfd, &cryp), 0); + + if (debug) printf("%s: data encrypted\n", __func__); + + /* Verify the result */ + if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) { + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + return 1; + } else if (debug) + printf("Test passed\n"); + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +static int test_aes(int cfd) +{ + uint8_t plaintext1_raw[BLOCK_SIZE + 63], *plaintext1; + uint8_t ciphertext1[BLOCK_SIZE] = { 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 }; + uint8_t iv1[BLOCK_SIZE]; + uint8_t key1[KEY_SIZE] = { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t plaintext2_data[BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 }; + uint8_t plaintext2_raw[BLOCK_SIZE + 63], *plaintext2; + uint8_t ciphertext2[BLOCK_SIZE] = { 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 }; + uint8_t iv2[BLOCK_SIZE]; + uint8_t key2[KEY_SIZE]; + + struct session_op sess1, sess2; +#ifdef CIOCGSESSINFO + struct session_info_op siop1, siop2; +#endif + struct crypt_op cryp1, cryp2; + + memset(&sess1, 0, sizeof(sess1)); + memset(&sess2, 0, sizeof(sess2)); + memset(&cryp1, 0, sizeof(cryp1)); + memset(&cryp2, 0, sizeof(cryp2)); + + /* Get crypto session for AES128 */ + sess1.cipher = CRYPTO_AES_CBC; + sess1.keylen = KEY_SIZE; + sess1.key = key1; + if (ioctl(cfd, CIOCGSESSION, &sess1)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop1.ses = sess1.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop1)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + plaintext1 = buf_align(plaintext1_raw, siop1.alignmask); +#else + plaintext1 = plaintext1_raw; +#endif + memset(plaintext1, 0x0, BLOCK_SIZE); + + memset(iv1, 0x0, sizeof(iv1)); + memset(key2, 0x0, sizeof(key2)); + + /* Get second crypto session for AES128 */ + sess2.cipher = CRYPTO_AES_CBC; + sess2.keylen = KEY_SIZE; + sess2.key = key2; + if (ioctl(cfd, CIOCGSESSION, &sess2)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop2.ses = sess2.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop2)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + plaintext2 = buf_align(plaintext2_raw, siop2.alignmask); +#else + plaintext2 = plaintext2_raw; +#endif + memcpy(plaintext2, plaintext2_data, BLOCK_SIZE); + + /* Encrypt data.in to data.encrypted */ + cryp1.ses = sess1.ses; + cryp1.len = BLOCK_SIZE; + cryp1.src = plaintext1; + cryp1.dst = plaintext1; + cryp1.iv = iv1; + cryp1.op = COP_ENCRYPT; + + DO_OR_DIE(do_async_crypt(cfd, &cryp1), 0); + if (debug) printf("cryp1 written out\n"); + + memset(iv2, 0x0, sizeof(iv2)); + + /* Encrypt data.in to data.encrypted */ + cryp2.ses = sess2.ses; + cryp2.len = BLOCK_SIZE; + cryp2.src = plaintext2; + cryp2.dst = plaintext2; + cryp2.iv = iv2; + cryp2.op = COP_ENCRYPT; + + DO_OR_DIE(do_async_crypt(cfd, &cryp2), 0); + if (debug) printf("cryp2 written out\n"); + + DO_OR_DIE(do_async_fetch(cfd, &cryp1), 0); + DO_OR_DIE(do_async_fetch(cfd, &cryp2), 0); + if (debug) printf("cryp1 + cryp2 successfully read\n"); + + /* Verify the result */ + if (memcmp(plaintext1, ciphertext1, BLOCK_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext1[i]); + } + printf("ciphertext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext1[i]); + } + printf("\n"); + return 1; + } else { + if (debug) printf("result 1 passed\n"); + } + + /* Test 2 */ + + /* Verify the result */ + if (memcmp(plaintext2, ciphertext2, BLOCK_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext2[i]); + } + printf("ciphertext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext2[i]); + } + printf("\n"); + return 1; + } else { + if (debug) printf("result 2 passed\n"); + } + + if (debug) printf("AES Test passed\n"); + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess1.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + if (ioctl(cfd, CIOCFSESSION, &sess2.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +int +main(int argc, char** argv) +{ + int fd = -1, cfd = -1; + + if (argc > 1) debug = 1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + if (test_aes(cfd)) + return 1; + + if (test_crypto(cfd)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} +#else +int +main(int argc, char** argv) +{ + return (0); +} +#endif diff --git a/cryptodev/cryptodev-linux-1.9/tests/async_hmac.c b/cryptodev/cryptodev-linux-1.9/tests/async_hmac.c new file mode 100644 index 0000000000000..014b8ed7e32d5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/async_hmac.c @@ -0,0 +1,301 @@ +/* + * Demo on how to use /dev/crypto device for HMAC. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "asynchelper.h" + +#ifdef ENABLE_ASYNC + +static int debug = 0; + +#define DATA_SIZE 4096 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 +#define SHA1_HASH_LEN 20 + +static int +test_crypto(int cfd) +{ + struct { + uint8_t in[DATA_SIZE], + encrypted[DATA_SIZE], + decrypted[DATA_SIZE], + iv[BLOCK_SIZE], + key[KEY_SIZE]; + } data; + struct session_op sess; + struct crypt_op cryp; + uint8_t mac[AALG_MAX_RESULT_LEN]; + uint8_t oldmac[AALG_MAX_RESULT_LEN]; + uint8_t md5_hmac_out[] = "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; + uint8_t sha1_out[] = "\x8f\x82\x03\x94\xf9\x53\x35\x18\x20\x45\xda\x24\xf3\x4d\xe5\x2b\xf8\xbc\x34\x32"; + int i; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + /* Use the garbage that is on the stack :-) */ + /* memset(&data, 0, sizeof(data)); */ + + /* SHA1 plain test */ + memset(mac, 0, sizeof(mac)); + + sess.cipher = 0; + sess.mac = CRYPTO_SHA1; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + cryp.ses = sess.ses; + cryp.len = sizeof("what do ya want for nothing?")-1; + cryp.src = (uint8_t *)"what do ya want for nothing?"; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + + DO_OR_DIE(do_async_crypt(cfd, &cryp), 0); + DO_OR_DIE(do_async_fetch(cfd, &cryp), 0); + + if (memcmp(mac, sha1_out, 20)!=0) { + printf("mac: "); + for (i=0;i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_ASYNC + +static double udifftimeval(struct timeval start, struct timeval end) +{ + return (double)(end.tv_usec - start.tv_usec) + + (double)(end.tv_sec - start.tv_sec) * 1000 * 1000; +} + +static volatile int must_finish; +static struct pollfd pfd; + +static void alarm_handler(int signo) +{ + must_finish = 1; + pfd.events = POLLIN; +} + +static char *units[] = { "", "Ki", "Mi", "Gi", "Ti", 0}; + +static void value2human(double bytes, double time, double* data, double* speed,char* metric) +{ + int unit = 0; + + *data = bytes; + while (*data > 1024 && units[unit + 1]) { + *data /= 1024; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", units[unit]); +} + + +int encrypt_data(struct session_op *sess, int fdc, int chunksize, int alignmask) +{ + struct crypt_op cop; + char *buffer[64], iv[32]; + static int val = 23; + struct timeval start, end; + double total = 0; + double secs, ddata, dspeed; + char metric[16]; + int rc, wqueue = 0, bufidx = 0; + + memset(iv, 0x23, 32); + + printf("\tEncrypting in chunks of %d bytes: ", chunksize); + fflush(stdout); + + for (rc = 0; rc < 64; rc++) { + if (alignmask) { + if (posix_memalign((void **)(buffer + rc), alignmask + 1, chunksize)) { + printf("posix_memalign() failed!\n"); + return 1; + } + } else { + if (!(buffer[rc] = malloc(chunksize))) { + perror("malloc()"); + return 1; + } + } + memset(buffer[rc], val++, chunksize); + } + pfd.fd = fdc; + pfd.events = POLLOUT | POLLIN; + + must_finish = 0; + alarm(5); + + gettimeofday(&start, NULL); + do { + if ((rc = poll(&pfd, 1, 100)) < 0) { + if (errno & (ERESTART | EINTR)) + continue; + fprintf(stderr, "errno = %d ", errno); + perror("poll()"); + return 1; + } + + if (pfd.revents & POLLOUT) { + memset(&cop, 0, sizeof(cop)); + cop.ses = sess->ses; + cop.len = chunksize; + cop.iv = (unsigned char *)iv; + cop.op = COP_ENCRYPT; + cop.src = cop.dst = (unsigned char *)buffer[bufidx]; + bufidx = (bufidx + 1) % 64; + + if (ioctl(fdc, CIOCASYNCCRYPT, &cop)) { + perror("ioctl(CIOCASYNCCRYPT)"); + return 1; + } + wqueue++; + } + if (pfd.revents & POLLIN) { + if (ioctl(fdc, CIOCASYNCFETCH, &cop)) { + perror("ioctl(CIOCASYNCFETCH)"); + return 1; + } + wqueue--; + total += cop.len; + } + } while(!must_finish || wqueue); + gettimeofday(&end, NULL); + + secs = udifftimeval(start, end)/ 1000000.0; + + value2human(total, secs, &ddata, &dspeed, metric); + printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + + for (rc = 0; rc < 64; rc++) + free(buffer[rc]); + return 0; +} + +int main(void) +{ + int fd, i, fdc = -1, alignmask = 0; + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + char keybuf[32]; + + signal(SIGALRM, alarm_handler); + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + perror("open()"); + return 1; + } + if (ioctl(fd, CRIOGET, &fdc)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + fprintf(stderr, "Testing NULL cipher: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_NULL; + sess.keylen = 0; + sess.key = (unsigned char *)keybuf; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + alignmask = siop.alignmask; +#endif + + for (i = 256; i <= (64 * 4096); i *= 2) { + if (encrypt_data(&sess, fdc, i, alignmask)) + break; + } + + fprintf(stderr, "\nTesting AES-128-CBC cipher: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = 16; + memset(keybuf, 0x42, 16); + sess.key = (unsigned char *)keybuf; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + alignmask = siop.alignmask; +#endif + + for (i = 256; i <= (64 * 1024); i *= 2) { + if (encrypt_data(&sess, fdc, i, alignmask)) + break; + } + + close(fdc); + close(fd); + return 0; +} + +#else +int +main(int argc, char** argv) +{ + return (0); +} +#endif diff --git a/cryptodev/cryptodev-linux-1.9/tests/asynchelper.h b/cryptodev/cryptodev-linux-1.9/tests/asynchelper.h new file mode 100644 index 0000000000000..b5ab16c8fd721 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/asynchelper.h @@ -0,0 +1,54 @@ +#ifndef __ASYNCHELPER_H +#define __ASYNCHELPER_H + +/* poll until POLLOUT, then call CIOCASYNCCRYPT */ +inline int do_async_crypt(int cfd, struct crypt_op *cryp) +{ + struct pollfd pfd; + + pfd.fd = cfd; + pfd.events = POLLOUT; + + if (poll(&pfd, 1, -1) < 1) { + perror("poll()"); + return 1; + } + + if (ioctl(cfd, CIOCASYNCCRYPT, cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + return 0; +} + +/* poll until POLLIN, then call CIOCASYNCFETCH */ +inline int do_async_fetch(int cfd, struct crypt_op *cryp) +{ + struct pollfd pfd; + + pfd.fd = cfd; + pfd.events = POLLIN; + + if (poll(&pfd, 1, -1) < 1) { + perror("poll()"); + return 1; + } + + if (ioctl(cfd, CIOCASYNCFETCH, cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + return 0; +} + +/* Check return value of stmt for identity with goodval. If they + * don't match, call return with the value of stmt. */ +#define DO_OR_DIE(stmt, goodval) { \ + int __rc_val; \ + if ((__rc_val = stmt) != goodval) { \ + perror("DO_OR_DIE(" #stmt "," #goodval ")"); \ + return __rc_val; \ + } \ +} + +#endif /* __ASYNCHELPER_H */ diff --git a/cryptodev/cryptodev-linux-1.9/tests/cipher-aead-srtp.c b/cryptodev/cryptodev-linux-1.9/tests/cipher-aead-srtp.c new file mode 100644 index 0000000000000..578d2f7dc4d96 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/cipher-aead-srtp.c @@ -0,0 +1,573 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include "testhelper.h" + +#define DATA_SIZE (8*1024) +#define HEADER_SIZE 193 +#define PLAINTEXT_SIZE 1021 +#define FOOTER_SIZE 15 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + +#define MAC_SIZE 20 /* SHA1 */ + +static int debug = 0; + +static int +get_sha1_hmac(int cfd, void* key, int key_size, void* data, int data_size, void* mac) +{ + struct session_op sess; + struct crypt_op cryp; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + sess.cipher = 0; + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = key_size; + sess.mackey = key; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = data_size; + cryp.src = data; + cryp.dst = NULL; + cryp.iv = NULL; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +static void print_buf(char* desc, unsigned char* buf, int size) +{ +int i; + fputs(desc, stderr); + for (i=0;i 1) debug = 1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + + if (test_crypto(cfd)) + return 1; + + if (test_encrypt_decrypt(cfd)) + return 1; + + if (test_encrypt_decrypt_error(cfd,0)) + return 1; + + if (test_encrypt_decrypt_error(cfd,1)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/tests/cipher-aead.c b/cryptodev/cryptodev-linux-1.9/tests/cipher-aead.c new file mode 100644 index 0000000000000..305b7206f872b --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/cipher-aead.c @@ -0,0 +1,575 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include "testhelper.h" + +#define DATA_SIZE (8*1024) +#define AUTH_SIZE 31 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + +#define MAC_SIZE 20 /* SHA1 */ + +static int debug = 0; + +static int +get_sha1_hmac(int cfd, void* key, int key_size, void* data1, int data1_size, void* data2, int data2_size, void* mac) +{ + struct session_op sess; + struct crypt_op cryp; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + sess.cipher = 0; + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = key_size; + sess.mackey = key; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = data1_size; + cryp.src = data1; + cryp.dst = NULL; + cryp.iv = NULL; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_UPDATE; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + cryp.ses = sess.ses; + cryp.len = data2_size; + cryp.src = data2; + cryp.dst = NULL; + cryp.iv = NULL; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_FINAL; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +static void print_buf(char* desc, unsigned char* buf, int size) +{ +int i; + fputs(desc, stdout); + for (i=0;i +#include +#include +#include +#include + +#include +#include +#include "testhelper.h" + +#define DATA_SIZE (8*1024) +#define AUTH_SIZE 31 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + +#define my_perror(x) {fprintf(stderr, "%s: %d\n", __func__, __LINE__); perror(x); } + +static int debug = 0; + +static void print_buf(char *desc, const unsigned char *buf, int size) +{ + int i; + fputs(desc, stdout); + for (i = 0; i < size; i++) { + printf("%.2x", (uint8_t) buf[i]); + } + fputs("\n", stdout); +} + +struct aes_gcm_vectors_st { + const uint8_t *key; + const uint8_t *auth; + int auth_size; + const uint8_t *plaintext; + int plaintext_size; + const uint8_t *iv; + const uint8_t *ciphertext; + const uint8_t *tag; +}; + +struct aes_gcm_vectors_st aes_gcm_vectors[] = { + { + .key = (uint8_t *) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .auth = NULL, + .auth_size = 0, + .plaintext = (uint8_t *) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .plaintext_size = 16, + .ciphertext = (uint8_t *) + "\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78", + .iv = (uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .tag = (uint8_t *) + "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf" + }, + { + .key = (uint8_t *) + "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .auth = NULL, + .auth_size = 0, + .plaintext = (uint8_t *) + "\xd9\x31\x32\x25\xf8\x84\x06\xe5\xa5\x59\x09\xc5\xaf\xf5\x26\x9a\x86\xa7\xa9\x53\x15\x34\xf7\xda\x2e\x4c\x30\x3d\x8a\x31\x8a\x72\x1c\x3c\x0c\x95\x95\x68\x09\x53\x2f\xcf\x0e\x24\x49\xa6\xb5\x25\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57\xba\x63\x7b\x39\x1a\xaf\xd2\x55", + .plaintext_size = 64, + .ciphertext = (uint8_t *) + "\x42\x83\x1e\xc2\x21\x77\x74\x24\x4b\x72\x21\xb7\x84\xd0\xd4\x9c\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0\x35\xc1\x7e\x23\x29\xac\xa1\x2e\x21\xd5\x14\xb2\x54\x66\x93\x1c\x7d\x8f\x6a\x5a\xac\x84\xaa\x05\x1b\xa3\x0b\x39\x6a\x0a\xac\x97\x3d\x58\xe0\x91\x47\x3f\x59\x85", + .iv = (uint8_t *)"\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88", + .tag = (uint8_t *)"\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4" + }, + { + .key = (uint8_t *) + "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .auth = (uint8_t *) + "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2", + .auth_size = 20, + .plaintext = (uint8_t *) + "\xd9\x31\x32\x25\xf8\x84\x06\xe5\xa5\x59\x09\xc5\xaf\xf5\x26\x9a\x86\xa7\xa9\x53\x15\x34\xf7\xda\x2e\x4c\x30\x3d\x8a\x31\x8a\x72\x1c\x3c\x0c\x95\x95\x68\x09\x53\x2f\xcf\x0e\x24\x49\xa6\xb5\x25\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57\xba\x63\x7b\x39", + .plaintext_size = 60, + .ciphertext = (uint8_t *) + "\x42\x83\x1e\xc2\x21\x77\x74\x24\x4b\x72\x21\xb7\x84\xd0\xd4\x9c\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0\x35\xc1\x7e\x23\x29\xac\xa1\x2e\x21\xd5\x14\xb2\x54\x66\x93\x1c\x7d\x8f\x6a\x5a\xac\x84\xaa\x05\x1b\xa3\x0b\x39\x6a\x0a\xac\x97\x3d\x58\xe0\x91", + .iv = (uint8_t *)"\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88", + .tag = (uint8_t *) + "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb\x94\xfa\xe9\x5a\xe7\x12\x1a\x47" + } +}; + + +/* Test against AES-GCM test vectors. + */ +static int test_crypto(int cfd) +{ + int i; + uint8_t tmp[128]; + + struct session_op sess; + struct crypt_auth_op cao; + + /* Get crypto session for AES128 */ + + if (debug) { + fprintf(stdout, "Tests on AES-GCM vectors: "); + fflush(stdout); + } + for (i = 0; + i < sizeof(aes_gcm_vectors) / sizeof(aes_gcm_vectors[0]); + i++) { + memset(&sess, 0, sizeof(sess)); + memset(tmp, 0, sizeof(tmp)); + + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = 16; + sess.key = (void *) aes_gcm_vectors[i].key; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + my_perror("ioctl(CIOCGSESSION)"); + return 1; + } + + memset(&cao, 0, sizeof(cao)); + + cao.ses = sess.ses; + cao.dst = tmp; + cao.iv = (void *) aes_gcm_vectors[i].iv; + cao.iv_len = 12; + cao.op = COP_ENCRYPT; + cao.flags = 0; + + if (aes_gcm_vectors[i].auth_size > 0) { + cao.auth_src = (void *) aes_gcm_vectors[i].auth; + cao.auth_len = aes_gcm_vectors[i].auth_size; + } + + if (aes_gcm_vectors[i].plaintext_size > 0) { + cao.src = (void *) aes_gcm_vectors[i].plaintext; + cao.len = aes_gcm_vectors[i].plaintext_size; + } + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + my_perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + if (aes_gcm_vectors[i].plaintext_size > 0) + if (memcmp + (tmp, aes_gcm_vectors[i].ciphertext, + aes_gcm_vectors[i].plaintext_size) != 0) { + fprintf(stderr, + "AES-GCM test vector %d failed!\n", + i); + + print_buf("Cipher: ", tmp, aes_gcm_vectors[i].plaintext_size); + print_buf("Expected: ", aes_gcm_vectors[i].ciphertext, aes_gcm_vectors[i].plaintext_size); + return 1; + } + + if (memcmp + (&tmp[cao.len - cao.tag_len], aes_gcm_vectors[i].tag, + 16) != 0) { + fprintf(stderr, + "AES-GCM test vector %d failed (tag)!\n", + i); + + print_buf("Tag: ", &tmp[cao.len - cao.tag_len], cao.tag_len); + print_buf("Expected tag: ", + aes_gcm_vectors[i].tag, 16); + return 1; + } + + } + + if (debug) { + fprintf(stdout, "ok\n"); + fprintf(stdout, "\n"); + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +/* Checks if encryption and subsequent decryption + * produces the same data. + */ +static int test_encrypt_decrypt(int cfd) +{ + uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext; + uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext; + uint8_t iv[BLOCK_SIZE]; + uint8_t key[KEY_SIZE]; + uint8_t auth[AUTH_SIZE]; + int enc_len; + + struct session_op sess; + struct crypt_auth_op cao; + struct session_info_op siop; + + if (debug) { + fprintf(stdout, "Tests on AES-GCM encryption/decryption: "); + fflush(stdout); + } + + memset(&sess, 0, sizeof(sess)); + memset(&cao, 0, sizeof(cao)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + memset(auth, 0xf1, sizeof(auth)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = KEY_SIZE; + sess.key = key; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + my_perror("ioctl(CIOCGSESSION)"); + return 1; + } + + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + my_perror("ioctl(CIOCGSESSINFO)"); + return 1; + } +// printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n", +// siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext = (uint8_t *)buf_align(plaintext_raw, siop.alignmask); + ciphertext = (uint8_t *)buf_align(ciphertext_raw, siop.alignmask); + + memset(plaintext, 0x15, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = DATA_SIZE; + cao.src = plaintext; + cao.dst = ciphertext; + cao.iv = iv; + cao.iv_len = 12; + cao.op = COP_ENCRYPT; + cao.flags = 0; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + my_perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + enc_len = cao.len; + //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len); + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + /* Get crypto session for AES128 */ + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = KEY_SIZE; + sess.key = key; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + my_perror("ioctl(CIOCGSESSION)"); + return 1; + } + + /* Decrypt data.encrypted to data.decrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = enc_len; + cao.src = ciphertext; + cao.dst = ciphertext; + cao.iv = iv; + cao.iv_len = 12; + cao.op = COP_DECRYPT; + cao.flags = 0; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + my_perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + if (cao.len != DATA_SIZE) { + fprintf(stderr, "decrypted data size incorrect!\n"); + return 1; + } + + /* Verify the result */ + if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext[i]); + } + printf("ciphertext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext[i]); + } + printf("\n"); + return 1; + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + if (debug) { + fprintf(stdout, "ok\n"); + fprintf(stdout, "\n"); + } + + return 0; +} + +static int test_encrypt_decrypt_error(int cfd, int err) +{ + uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext; + uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext; + uint8_t iv[BLOCK_SIZE]; + uint8_t key[KEY_SIZE]; + uint8_t auth[AUTH_SIZE]; + int enc_len; + + struct session_op sess; + struct crypt_op co; + struct crypt_auth_op cao; + struct session_info_op siop; + + if (debug) { + fprintf(stdout, "Tests on AES-GCM tag verification: "); + fflush(stdout); + } + + memset(&sess, 0, sizeof(sess)); + memset(&cao, 0, sizeof(cao)); + memset(&co, 0, sizeof(co)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + memset(auth, 0xf1, sizeof(auth)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = 16; + sess.mackey = + (uint8_t *) + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + my_perror("ioctl(CIOCGSESSION)"); + return 1; + } + + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + my_perror("ioctl(CIOCGSESSINFO)"); + return 1; + } +// printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n", +// siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext = (uint8_t *)buf_align(plaintext_raw, siop.alignmask); + ciphertext = (uint8_t *)buf_align(ciphertext_raw, siop.alignmask); + + memset(plaintext, 0x15, DATA_SIZE); + memcpy(ciphertext, plaintext, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = DATA_SIZE; + cao.src = ciphertext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_ENCRYPT; + cao.flags = COP_FLAG_AEAD_TLS_TYPE; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + my_perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + enc_len = cao.len; + //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len); + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + /* Get crypto session for AES128 */ + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = 16; + sess.mackey = + (uint8_t *) + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + my_perror("ioctl(CIOCGSESSION)"); + return 1; + } + + if (err == 0) + auth[2]++; + else + ciphertext[4]++; + + /* Decrypt data.encrypted to data.decrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = enc_len; + cao.src = ciphertext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_DECRYPT; + cao.flags = COP_FLAG_AEAD_TLS_TYPE; + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + if (debug) { + fprintf(stdout, "ok\n"); + fprintf(stdout, "\n"); + } + return 0; + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + my_perror("ioctl(CIOCFSESSION)"); + return 1; + } + + + fprintf(stderr, "Modification to ciphertext was not detected\n"); + return 1; +} + +int main(int argc, char** argv) +{ + int fd = -1, cfd = -1; + + if (argc > 1) debug = 1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + my_perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + my_perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + my_perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + + if (test_crypto(cfd)) + return 1; + + if (test_encrypt_decrypt(cfd)) + return 1; + + if (test_encrypt_decrypt_error(cfd, 0)) + return 1; + + if (test_encrypt_decrypt_error(cfd, 1)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + my_perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + my_perror("close(fd)"); + return 1; + } + + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/cipher.c b/cryptodev/cryptodev-linux-1.9/tests/cipher.c new file mode 100644 index 0000000000000..fab3de6bdbd29 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/cipher.c @@ -0,0 +1,327 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "testhelper.h" + +static int debug = 0; + +#define DATA_SIZE 8*1024 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + +static int +test_crypto(int cfd) +{ + uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext; + uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext; + uint8_t iv[BLOCK_SIZE]; + uint8_t key[KEY_SIZE]; + + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + struct crypt_op cryp; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + if (debug) + printf("requested cipher CRYPTO_AES_CBC, got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext = buf_align(plaintext_raw, siop.alignmask); + ciphertext = buf_align(ciphertext_raw, siop.alignmask); +#else + plaintext = plaintext_raw; + ciphertext = ciphertext_raw; +#endif + memset(plaintext, 0x15, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = DATA_SIZE; + cryp.src = plaintext; + cryp.dst = ciphertext; + cryp.iv = iv; + cryp.op = COP_ENCRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + if (debug) + printf("requested cipher CRYPTO_AES_CBC, got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); +#endif + + /* Decrypt data.encrypted to data.decrypted */ + cryp.ses = sess.ses; + cryp.len = DATA_SIZE; + cryp.src = ciphertext; + cryp.dst = ciphertext; + cryp.iv = iv; + cryp.op = COP_DECRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + /* Verify the result */ + if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext[i]); + } + printf("ciphertext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext[i]); + } + printf("\n"); + return 1; + } else if (debug) + printf("Test passed\n"); + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +static int test_aes(int cfd) +{ + uint8_t plaintext1_raw[BLOCK_SIZE + 63], *plaintext1; + uint8_t ciphertext1[BLOCK_SIZE] = { 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 }; + uint8_t iv1[BLOCK_SIZE]; + uint8_t key1[KEY_SIZE] = { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t plaintext2_data[BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 }; + uint8_t plaintext2_raw[BLOCK_SIZE + 63], *plaintext2; + uint8_t ciphertext2[BLOCK_SIZE] = { 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 }; + uint8_t iv2[BLOCK_SIZE]; + uint8_t key2[KEY_SIZE]; + + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + struct crypt_op cryp; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key1; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + plaintext1 = buf_align(plaintext1_raw, siop.alignmask); +#else + plaintext1 = plaintext1_raw; +#endif + memset(plaintext1, 0x0, BLOCK_SIZE); + memset(iv1, 0x0, sizeof(iv1)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = BLOCK_SIZE; + cryp.src = plaintext1; + cryp.dst = plaintext1; + cryp.iv = iv1; + cryp.op = COP_ENCRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + /* Verify the result */ + if (memcmp(plaintext1, ciphertext1, BLOCK_SIZE) != 0) { + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + return 1; + } + + /* Test 2 */ + + memset(key2, 0x0, sizeof(key2)); + memset(iv2, 0x0, sizeof(iv2)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key2; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + if (debug) + printf("requested cipher CRYPTO_AES_CBC, got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext2 = buf_align(plaintext2_raw, siop.alignmask); +#else + plaintext2 = plaintext2_raw; +#endif + memcpy(plaintext2, plaintext2_data, BLOCK_SIZE); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess.ses; + cryp.len = BLOCK_SIZE; + cryp.src = plaintext2; + cryp.dst = plaintext2; + cryp.iv = iv2; + cryp.op = COP_ENCRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + /* Verify the result */ + if (memcmp(plaintext2, ciphertext2, BLOCK_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext2[i]); + } + printf("ciphertext:"); + for (i = 0; i < BLOCK_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext2[i]); + } + printf("\n"); + return 1; + } + + if (debug) printf("AES Test passed\n"); + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +int +main(int argc, char** argv) +{ + int fd = -1, cfd = -1; + + if (argc > 1) debug = 1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + if (test_aes(cfd)) + return 1; + + if (test_crypto(cfd)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/tests/cipher_comp.c b/cryptodev/cryptodev-linux-1.9/tests/cipher_comp.c new file mode 100644 index 0000000000000..dbf9977852bb7 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/cipher_comp.c @@ -0,0 +1,159 @@ +/* + * Compare encryption results with ones from openssl. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "openssl_wrapper.h" + +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 +#define MAX_DATALEN (64 * 1024) + + +static int +test_crypto(int cfd, struct session_op *sess, int datalen) +{ + uint8_t *data, *encrypted; + uint8_t *encrypted_comp; + + uint8_t iv_in[BLOCK_SIZE]; + uint8_t iv[BLOCK_SIZE]; + uint8_t iv_comp[BLOCK_SIZE]; + + struct crypt_op cryp; + + int ret = 0; + + data = malloc(datalen); + encrypted = malloc(datalen); + encrypted_comp = malloc(datalen); + memset(data, datalen & 0xff, datalen); + memset(encrypted, 0x27, datalen); + memset(encrypted_comp, 0x41, datalen); + + memset(iv_in, 0x23, sizeof(iv_in)); + memcpy(iv, iv_in, sizeof(iv)); + memcpy(iv_comp, iv_in, sizeof(iv_comp)); + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess->ses; + cryp.len = datalen; + cryp.src = data; + cryp.dst = encrypted; + cryp.iv = iv; + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_WRITE_IV; + if ((ret = ioctl(cfd, CIOCCRYPT, &cryp))) { + perror("ioctl(CIOCCRYPT)"); + goto out; + } + + cryp.dst = encrypted_comp; + cryp.iv = iv_comp; + + if ((ret = openssl_cioccrypt(sess, &cryp))) { + fprintf(stderr, "openssl_cioccrypt() failed!\n"); + goto out; + } + + if ((ret = memcmp(encrypted, encrypted_comp, cryp.len))) { + printf("fail for datalen %d, cipher texts do not match!\n", datalen); + } + if ((ret = memcmp(iv, iv_comp, BLOCK_SIZE))) { + printf("fail for datalen %d, IVs do not match!\n", datalen); + } +out: + free(data); + free(encrypted); + free(encrypted_comp); + return ret; +} + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +int +main(int argc, char **argv) +{ + int fd; + struct session_op sess; + uint8_t key[KEY_SIZE]; + int datalen = BLOCK_SIZE; + int datalen_end = MAX_DATALEN; + int i; + + if (argc > 1) { + datalen = min(max(atoi(argv[1]), BLOCK_SIZE), MAX_DATALEN); + datalen_end = datalen; + } + if (argc > 2) { + datalen_end = min(atoi(argv[2]), MAX_DATALEN); + if (datalen_end < datalen) + datalen_end = datalen; + } + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + for (i = 0; i < KEY_SIZE; i++) + key[i] = i & 0xff; + memset(&sess, 0, sizeof(sess)); + + /* encryption test */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + if (ioctl(fd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + { + struct session_info_op siop = { + .ses = sess.ses, + }; + + if (ioctl(fd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + } else { + printf("requested cipher CRYPTO_AES_CBC and mac CRYPTO_SHA1_HMAC," + " got cipher %s with driver %s and hash %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name, + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + } + } +#endif + + for (; datalen <= datalen_end; datalen += BLOCK_SIZE) { + if (test_crypto(fd, &sess, datalen)) { + printf("test_crypto() failed for datalen of %d\n", datalen); + return 1; + } + } + + /* Finish crypto session */ + if (ioctl(fd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } + + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/fullspeed.c b/cryptodev/cryptodev-linux-1.9/tests/fullspeed.c new file mode 100644 index 0000000000000..4e97965f9f4ce --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/fullspeed.c @@ -0,0 +1,185 @@ +/* cryptodev_test - simple benchmark tool for cryptodev + * + * Copyright (C) 2010 by Phil Sutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int si = 1; /* SI by default */ + +static double udifftimeval(struct timeval start, struct timeval end) +{ + return (double)(end.tv_usec - start.tv_usec) + + (double)(end.tv_sec - start.tv_sec) * 1000 * 1000; +} + +static int must_finish = 0; + +static void alarm_handler(int signo) +{ + must_finish = 1; +} + +static char *units[] = { "", "Ki", "Mi", "Gi", "Ti", 0}; +static char *si_units[] = { "", "K", "M", "G", "T", 0}; + +static void value2human(int si, double bytes, double time, double* data, double* speed,char* metric) +{ + int unit = 0; + + *data = bytes; + + if (si) { + while (*data > 1000 && si_units[unit + 1]) { + *data /= 1000; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", si_units[unit]); + } else { + while (*data > 1024 && units[unit + 1]) { + *data /= 1024; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", units[unit]); + } +} + +#define MAX(x,y) ((x)>(y)?(x):(y)) + +int encrypt_data(int algo, void* keybuf, int key_size, int fdc, int chunksize) +{ + struct crypt_op cop; + uint8_t *buffer, iv[32]; + static int val = 23; + struct timeval start, end; + double total = 0; + double secs, ddata, dspeed; + char metric[16]; + struct session_op sess; + + if (posix_memalign((void **)&buffer, 16, chunksize)) { + printf("posix_memalign() failed! (mask %x, size: %d)\n", 16, chunksize); + return 1; + } + + memset(iv, 0x23, 32); + + printf("\tEncrypting in chunks of %d bytes: ", chunksize); + fflush(stdout); + + memset(buffer, val++, chunksize); + + must_finish = 0; + alarm(5); + + gettimeofday(&start, NULL); + do { + memset(&sess, 0, sizeof(sess)); + sess.cipher = algo; + sess.keylen = key_size; + sess.key = keybuf; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + memset(&cop, 0, sizeof(cop)); + cop.ses = sess.ses; + cop.len = chunksize; + cop.iv = (unsigned char *)iv; + cop.op = COP_ENCRYPT; + cop.src = (unsigned char *)buffer; + cop.dst = buffer; + + if (ioctl(fdc, CIOCCRYPT, &cop)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + ioctl(fdc, CIOCFSESSION, &sess.ses); + + total+=chunksize; + } while(must_finish==0); + gettimeofday(&end, NULL); + + secs = udifftimeval(start, end)/ 1000000.0; + + value2human(si, total, secs, &ddata, &dspeed, metric); + printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + + free(buffer); + return 0; +} + +int main(int argc, char** argv) +{ + int fd, i, fdc = -1; + char keybuf[32]; + + signal(SIGALRM, alarm_handler); + + if (argc > 1) { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { + printf("Usage: speed [--kib]\n"); + exit(0); + } + if (strcmp(argv[1], "--kib") == 0) { + si = 0; + } + } + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + perror("open()"); + return 1; + } + if (ioctl(fd, CRIOGET, &fdc)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + fprintf(stderr, "Testing NULL cipher: \n"); + + for (i = 512; i <= (64 * 1024); i *= 2) { + if (encrypt_data(CRYPTO_NULL, keybuf, 0, fdc, i)) + break; + } + + fprintf(stderr, "\nTesting AES-128-CBC cipher: \n"); + memset(keybuf, 0x42, 16); + + for (i = 512; i <= (64 * 1024); i *= 2) { + if (encrypt_data(CRYPTO_AES_CBC, keybuf, 16, fdc, i)) + break; + } + + close(fdc); + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/hash_comp.c b/cryptodev/cryptodev-linux-1.9/tests/hash_comp.c new file mode 100644 index 0000000000000..73f85edef7a1a --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/hash_comp.c @@ -0,0 +1,147 @@ +/* + * Compare digest results with ones from openssl. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "openssl_wrapper.h" + +#define BLOCK_SIZE 16 +#define MAX_DATALEN (64 * 1024) + +static void printhex(unsigned char *buf, int buflen) +{ + while (buflen-- > 0) { + printf("\\x%.2x", *(buf++)); + } + printf("\n"); +} + +static int +test_crypto(int cfd, struct session_op *sess, int datalen) +{ + uint8_t *data; + uint8_t mac[AALG_MAX_RESULT_LEN]; + uint8_t mac_comp[AALG_MAX_RESULT_LEN]; + + struct crypt_op cryp; + + int ret = 0; + + data = malloc(datalen); + memset(data, datalen & 0xff, datalen); + + memset(mac, 0, sizeof(mac)); + memset(mac_comp, 0, sizeof(mac_comp)); + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess->ses; + cryp.len = datalen; + cryp.src = data; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + if ((ret = ioctl(cfd, CIOCCRYPT, &cryp))) { + perror("ioctl(CIOCCRYPT)"); + goto out; + } + + cryp.mac = mac_comp; + + if ((ret = openssl_cioccrypt(sess, &cryp))) { + fprintf(stderr, "openssl_cioccrypt() failed!\n"); + goto out; + } + + if (memcmp(mac, mac_comp, AALG_MAX_RESULT_LEN)) { + printf("fail for datalen %d, MACs do not match!\n", datalen); + ret = 1; + printf("wrong mac: "); + printhex(mac, 20); + printf("right mac: "); + printhex(mac_comp, 20); + } + +out: + free(data); + return ret; +} + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +int +main(int argc, char **argv) +{ + int fd; + struct session_op sess; + int datalen = BLOCK_SIZE; + int datalen_end = MAX_DATALEN; + + if (argc > 1) { + datalen = min(max(atoi(argv[1]), BLOCK_SIZE), MAX_DATALEN); + datalen_end = datalen; + } + if (argc > 2) { + datalen_end = min(atoi(argv[2]), MAX_DATALEN); + if (datalen_end < datalen) + datalen_end = datalen; + } + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + memset(&sess, 0, sizeof(sess)); + + /* Hash test */ + sess.mac = CRYPTO_SHA1; + if (ioctl(fd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + { + struct session_info_op siop = { + .ses = sess.ses, + }; + + if (ioctl(fd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + } else { + printf("requested mac CRYPTO_SHA1, got hash %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + } + } +#endif + + for (; datalen <= datalen_end; datalen += BLOCK_SIZE) { + if (test_crypto(fd, &sess, datalen)) { + printf("test_crypto() failed for datalen of %d\n", datalen); + return 1; + } + } + + /* Finish crypto session */ + if (ioctl(fd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } + + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/hashcrypt_speed.c b/cryptodev/cryptodev-linux-1.9/tests/hashcrypt_speed.c new file mode 100644 index 0000000000000..2b49f2b643386 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/hashcrypt_speed.c @@ -0,0 +1,207 @@ +/* hashcrypt_speed - simple SHA+AES benchmark tool for cryptodev + * + * Copyright (C) 2011 by Phil Sutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX(x,y) ((x)>(y)?(x):(y)) + +static double udifftimeval(struct timeval start, struct timeval end) +{ + return (double)(end.tv_usec - start.tv_usec) + + (double)(end.tv_sec - start.tv_sec) * 1000 * 1000; +} + +static int must_finish = 0; + +static void alarm_handler(int signo) +{ + must_finish = 1; +} + +static char *units[] = { "", "Ki", "Mi", "Gi", "Ti", 0}; +static char *si_units[] = { "", "K", "M", "G", "T", 0}; + +static void value2human(int si, double bytes, double time, double* data, double* speed,char* metric) +{ + int unit = 0; + + *data = bytes; + + if (si) { + while (*data > 1000 && si_units[unit + 1]) { + *data /= 1000; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", si_units[unit]); + } else { + while (*data > 1024 && units[unit + 1]) { + *data /= 1024; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", units[unit]); + } +} + + +int hash_data(struct session_op *sess, int fdc, int chunksize, int align) +{ + struct crypt_op cop; + char *buffer; + static int val = 23; + struct timeval start, end; + double total = 0; + double secs, ddata, dspeed; + char metric[16]; + uint8_t mac[AALG_MAX_RESULT_LEN]; + + if (align) { + if (posix_memalign((void **)&buffer, align, chunksize)) { + printf("posix_memalign() failed, align: %d, size: %d!\n", align, chunksize); + return 1; + } + } else { + if (!(buffer = malloc(chunksize))) { + perror("malloc()"); + return 1; + } + } + + printf("\tEncrypting in chunks of %d bytes: ", chunksize); + fflush(stdout); + + memset(buffer, val++, chunksize); + + must_finish = 0; + alarm(5); + + gettimeofday(&start, NULL); + do { + memset(&cop, 0, sizeof(cop)); + cop.ses = sess->ses; + cop.len = chunksize; + cop.op = COP_ENCRYPT; + cop.src = cop.dst = (unsigned char *)buffer; + cop.mac = mac; + + if (ioctl(fdc, CIOCCRYPT, &cop)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + total+=chunksize; + } while(must_finish==0); + gettimeofday(&end, NULL); + + secs = udifftimeval(start, end)/ 1000000.0; + + value2human(1, total, secs, &ddata, &dspeed, metric); + printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + + free(buffer); + return 0; +} + +int main(void) +{ + int fd, i, fdc = -1, align = 0; + struct session_op sess; + char keybuf[32]; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + signal(SIGALRM, alarm_handler); + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + perror("open()"); + return 1; + } + if (ioctl(fd, CRIOGET, &fdc)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + fprintf(stderr, "Testing AES128 with SHA1 Hash: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = 16; + memset(keybuf, 0x42, 32); + sess.key = (unsigned char *)keybuf; + sess.mac = CRYPTO_SHA1; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + printf("requested hash CRYPTO_SHA1, got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + align = MAX(sizeof(void*), siop.alignmask+1); +#endif + + for (i = 256; i <= (64 * 1024); i *= 4) { + if (hash_data(&sess, fdc, i, align)) + break; + } + + fprintf(stderr, "\nTesting AES256 with SHA256 Hash: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = 32; + sess.key = (unsigned char *)keybuf; + sess.mac = CRYPTO_SHA2_256; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + printf("requested hash CRYPTO_SHA2_256, got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + align = MAX(sizeof(void*), siop.alignmask+1); +#endif + + for (i = 256; i <= (64 * 1024); i *= 4) { + if (hash_data(&sess, fdc, i, align)) + break; + } + + close(fdc); + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/hmac.c b/cryptodev/cryptodev-linux-1.9/tests/hmac.c new file mode 100644 index 0000000000000..8d6492e1d769b --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/hmac.c @@ -0,0 +1,336 @@ +/* + * Demo on how to use /dev/crypto device for HMAC. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include + +#include +#include + +static int debug = 0; + +#define DATA_SIZE 4096 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 +#define SHA1_HASH_LEN 20 + +static int +test_crypto(int cfd) +{ + struct { + uint8_t in[DATA_SIZE], + encrypted[DATA_SIZE], + decrypted[DATA_SIZE], + iv[BLOCK_SIZE], + key[KEY_SIZE]; + } data; + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + struct crypt_op cryp; + uint8_t mac[AALG_MAX_RESULT_LEN]; + uint8_t oldmac[AALG_MAX_RESULT_LEN]; + uint8_t md5_hmac_out[] = "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; + uint8_t sha1_out[] = "\x8f\x82\x03\x94\xf9\x53\x35\x18\x20\x45\xda\x24\xf3\x4d\xe5\x2b\xf8\xbc\x34\x32"; + int i; + + memset(&sess, 0, sizeof(sess)); + memset(&cryp, 0, sizeof(cryp)); + + /* Use the garbage that is on the stack :-) */ + /* memset(&data, 0, sizeof(data)); */ + + /* SHA1 plain test */ + memset(mac, 0, sizeof(mac)); + + sess.cipher = 0; + sess.mac = CRYPTO_SHA1; + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + if (debug) printf("requested mac CRYPTO_SHA1, got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); +#endif + + cryp.ses = sess.ses; + cryp.len = sizeof("what do ya want for nothing?")-1; + cryp.src = (uint8_t *)"what do ya want for nothing?"; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + if (ioctl(cfd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + + if (memcmp(mac, sha1_out, 20)!=0) { + printf("mac: "); + for (i=0;i 1) debug = 1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + if (test_crypto(cfd)) + return 1; + + if (test_extras(cfd)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/hmac_comp.c b/cryptodev/cryptodev-linux-1.9/tests/hmac_comp.c new file mode 100644 index 0000000000000..a8709cbbc3fb8 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/hmac_comp.c @@ -0,0 +1,187 @@ +/* + * Compare HMAC results with ones from openssl. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "openssl_wrapper.h" + +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 +#define MACKEY_SIZE 20 +#define MAX_DATALEN (64 * 1024) + +static void printhex(unsigned char *buf, int buflen) +{ + while (buflen-- > 0) { + printf("\\x%.2x", *(buf++)); + } + printf("\n"); +} + +static int +test_crypto(int cfd, struct session_op *sess, int datalen) +{ + unsigned char *data, *encrypted; + unsigned char *encrypted_comp; + + unsigned char iv[BLOCK_SIZE]; + unsigned char mac[AALG_MAX_RESULT_LEN]; + + unsigned char iv_comp[BLOCK_SIZE]; + unsigned char mac_comp[AALG_MAX_RESULT_LEN]; + + struct crypt_op cryp; + + int ret = 0; + + data = malloc(datalen); + encrypted = malloc(datalen); + encrypted_comp = malloc(datalen); + memset(data, datalen & 0xff, datalen); + memset(encrypted, 0x27, datalen); + memset(encrypted_comp, 0x28, datalen); + + memset(iv, 0x23, sizeof(iv)); + memset(iv_comp, 0x23, sizeof(iv)); + memset(mac, 0, sizeof(mac)); + memset(mac_comp, 1, sizeof(mac_comp)); + + memset(&cryp, 0, sizeof(cryp)); + + /* Encrypt data.in to data.encrypted */ + cryp.ses = sess->ses; + cryp.len = datalen; + cryp.src = data; + cryp.dst = encrypted; + cryp.iv = iv; + cryp.mac = mac; + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_WRITE_IV; + if ((ret = ioctl(cfd, CIOCCRYPT, &cryp))) { + perror("ioctl(CIOCCRYPT)"); + goto out; + } + + cryp.dst = encrypted_comp; + cryp.mac = mac_comp; + cryp.iv = iv_comp; + + if ((ret = openssl_cioccrypt(sess, &cryp))) { + fprintf(stderr, "openssl_cioccrypt() failed!\n"); + goto out; + } + + if ((ret = memcmp(encrypted, encrypted_comp, cryp.len))) { + printf("fail for datalen %d, cipher texts do not match!\n", datalen); + } + if ((ret = memcmp(iv, iv_comp, BLOCK_SIZE))) { + printf("fail for datalen %d, updated IVs do not match!\n", datalen); + } + if ((ret = memcmp(mac, mac_comp, AALG_MAX_RESULT_LEN))) { + printf("fail for datalen 0x%x, MACs do not match!\n", datalen); + printf("wrong mac: "); + printhex(mac, 20); + printf("right mac: "); + printhex(mac_comp, 20); + + } + +out: + free(data); + free(encrypted); + free(encrypted_comp); + return ret; +} + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +int +main(int argc, char **argv) +{ + int fd; + struct session_op sess; + unsigned char key[KEY_SIZE], mackey[MACKEY_SIZE]; + int datalen = BLOCK_SIZE; + int datalen_end = MAX_DATALEN; + int i; + + if (argc > 1) { + datalen = min(max(atoi(argv[1]), BLOCK_SIZE), MAX_DATALEN); + datalen_end = datalen; + } + if (argc > 2) { + datalen_end = min(atoi(argv[2]), MAX_DATALEN); + if (datalen_end < datalen) + datalen_end = datalen; + } + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + for (i = 0; i < KEY_SIZE; i++) + key[i] = i & 0xff; + for (i = 0; i < MACKEY_SIZE; i++) + mackey[i] = i & 0xff; + + memset(&sess, 0, sizeof(sess)); + + /* Hash and encryption in one step test */ + sess.cipher = CRYPTO_AES_CBC; + sess.mac = CRYPTO_SHA1_HMAC; + sess.keylen = KEY_SIZE; + sess.key = key; + sess.mackeylen = MACKEY_SIZE; + sess.mackey = mackey; + if (ioctl(fd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + { + struct session_info_op siop = { + .ses = sess.ses, + }; + + if (ioctl(fd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + } else { + printf("requested cipher CRYPTO_AES_CBC and mac CRYPTO_SHA1_HMAC," + " got cipher %s with driver %s and hash %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name, + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + } + } +#endif + + for (; datalen <= datalen_end; datalen += BLOCK_SIZE) { + if (test_crypto(fd, &sess, datalen)) { + printf("test_crypto() failed for datalen of %d\n", datalen); + return 1; + } + } + + /* Finish crypto session */ + if (ioctl(fd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + } + + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.c b/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.c new file mode 100644 index 0000000000000..038c58f2a1d83 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.c @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include + +//#define DEBUG + +#ifdef DEBUG +# define dbgp(...) { \ + fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} +#else +# define dbgp(...) /* nothing */ +#endif + +enum ctx_type { + ctx_type_none = 0, + ctx_type_hmac, + ctx_type_md, +}; + +union openssl_ctx { + HMAC_CTX hmac; + EVP_MD_CTX md; +}; + +struct ctx_mapping { + __u32 ses; + enum ctx_type type; + union openssl_ctx ctx; +}; + +static struct ctx_mapping ctx_map[512]; + +static struct ctx_mapping *find_mapping(__u32 ses) +{ + int i; + + for (i = 0; i < 512; i++) { + if (ctx_map[i].ses == ses) + return &ctx_map[i]; + } + return NULL; +} + +static struct ctx_mapping *new_mapping(void) +{ + return find_mapping(0); +} + +static void remove_mapping(__u32 ses) +{ + struct ctx_mapping *mapping; + + if (!(mapping = find_mapping(ses))) { + printf("%s: failed to find mapping for session %d\n", __func__, ses); + return; + } + switch (mapping->type) { + case ctx_type_none: + break; + case ctx_type_hmac: + dbgp("%s: calling HMAC_CTX_cleanup\n", __func__); + HMAC_CTX_cleanup(&mapping->ctx.hmac); + break; + case ctx_type_md: + dbgp("%s: calling EVP_MD_CTX_cleanup\n", __func__); + EVP_MD_CTX_cleanup(&mapping->ctx.md); + break; + } + memset(mapping, 0, sizeof(*mapping)); +} + +static union openssl_ctx *__ses_to_ctx(__u32 ses) +{ + struct ctx_mapping *mapping; + + if (!(mapping = find_mapping(ses))) + return NULL; + return &mapping->ctx; +} + +static HMAC_CTX *ses_to_hmac(__u32 ses) { return (HMAC_CTX *)__ses_to_ctx(ses); } +static EVP_MD_CTX *ses_to_md(__u32 ses) { return (EVP_MD_CTX *)__ses_to_ctx(ses); } + +static const EVP_MD *sess_to_evp_md(struct session_op *sess) +{ + switch (sess->mac) { +#ifndef OPENSSL_NO_MD5 + case CRYPTO_MD5_HMAC: return EVP_md5(); +#endif +#ifndef OPENSSL_NO_SHA + case CRYPTO_SHA1_HMAC: + case CRYPTO_SHA1: + return EVP_sha1(); +#endif +#ifndef OPENSSL_NO_RIPEMD + case CRYPTO_RIPEMD160_HMAC: return EVP_ripemd160(); +#endif +#ifndef OPENSSL_NO_SHA256 + case CRYPTO_SHA2_256_HMAC: return EVP_sha256(); +#endif +#ifndef OPENSSL_NO_SHA512 + case CRYPTO_SHA2_384_HMAC: return EVP_sha384(); + case CRYPTO_SHA2_512_HMAC: return EVP_sha512(); +#endif + default: + printf("%s: failed to get an EVP, things will be broken!\n", __func__); + return NULL; + } +} + +static int openssl_hmac(struct session_op *sess, struct crypt_op *cop) +{ + HMAC_CTX *ctx = ses_to_hmac(sess->ses); + + if (!ctx) { + struct ctx_mapping *mapping = new_mapping(); + if (!mapping) { + printf("%s: failed to get new mapping\n", __func__); + return 1; + } + + mapping->ses = sess->ses; + mapping->type = ctx_type_hmac; + ctx = &mapping->ctx.hmac; + + dbgp("calling HMAC_CTX_init"); + HMAC_CTX_init(ctx); + dbgp("calling HMAC_Init_ex"); + if (!HMAC_Init_ex(ctx, sess->mackey, sess->mackeylen, + sess_to_evp_md(sess), NULL)) { + printf("%s: HMAC_Init_ex failed\n", __func__); + return 1; + } + } + + if (cop->len) { + dbgp("calling HMAC_Update"); + if (!HMAC_Update(ctx, cop->src, cop->len)) { + printf("%s: HMAC_Update failed\n", __func__); + return 1; + } + } + if (cop->flags & COP_FLAG_FINAL || + (cop->len && !(cop->flags & COP_FLAG_UPDATE))) { + dbgp("calling HMAC_Final"); + if (!HMAC_Final(ctx, cop->mac, 0)) { + printf("%s: HMAC_Final failed\n", __func__); + remove_mapping(sess->ses); + return 1; + } + remove_mapping(sess->ses); + } + return 0; +} + +static int openssl_md(struct session_op *sess, struct crypt_op *cop) +{ + EVP_MD_CTX *ctx = ses_to_md(sess->ses); + + if (!ctx) { + struct ctx_mapping *mapping = new_mapping(); + if (!mapping) { + printf("%s: failed to get new mapping\n", __func__); + return 1; + } + + mapping->ses = sess->ses; + mapping->type = ctx_type_md; + ctx = &mapping->ctx.md; + + dbgp("calling EVP_MD_CTX_init"); + EVP_MD_CTX_init(ctx); + dbgp("calling EVP_DigestInit"); + EVP_DigestInit(ctx, sess_to_evp_md(sess)); + } + + if (cop->len) { + dbgp("calling EVP_DigestUpdate"); + EVP_DigestUpdate(ctx, cop->src, cop->len); + } + if (cop->flags & COP_FLAG_FINAL || + (cop->len && !(cop->flags & COP_FLAG_UPDATE))) { + dbgp("calling EVP_DigestFinal"); + EVP_DigestFinal(ctx, cop->mac, 0); + remove_mapping(sess->ses); + } + + return 0; +} + +static int openssl_aes(struct session_op *sess, struct crypt_op *cop) +{ + AES_KEY key; + int i, enc; + unsigned char ivec[AES_BLOCK_SIZE]; + + if (cop->len % AES_BLOCK_SIZE) { + printf("%s: illegal length passed, " + "not a multiple of AES_BLOCK_SIZE\n", __func__); + return 1; + } + + switch (cop->op) { + case COP_ENCRYPT: + AES_set_encrypt_key(sess->key, sess->keylen * 8, &key); + enc = 1; + break; + case COP_DECRYPT: + AES_set_decrypt_key(sess->key, sess->keylen * 8, &key); + enc = 0; + break; + default: + printf("%s: unknown cop->op received!\n", __func__); + return 1; + } + + switch (sess->cipher) { + case CRYPTO_AES_CBC: + memcpy(ivec, cop->iv, AES_BLOCK_SIZE); + AES_cbc_encrypt(cop->src, cop->dst, cop->len, &key, ivec, enc); + if (cop->flags & COP_FLAG_WRITE_IV) + memcpy(cop->iv, ivec, AES_BLOCK_SIZE); + break; +#if 0 + /* XXX: TODO: implement this stuff */ + case CRYPTO_AES_CTR: + AES_ctr128_encrypt(cop->src, cop->dst, &key, cop->iv, + case CRYPTO_AES_XTS: +#endif + case CRYPTO_AES_ECB: + for (i = 0; i < cop->len; i += AES_BLOCK_SIZE) + AES_ecb_encrypt(cop->src + i, cop->dst + i, &key, enc); + break; + } + return 0; +} + +int openssl_cioccrypt(struct session_op *sess, struct crypt_op *cop) +{ + if (sess->mac && sess->mackey && sess->mackeylen) + openssl_hmac(sess, cop); + else if (sess->mac) + openssl_md(sess, cop); + + switch (sess->cipher) { + case CRYPTO_AES_CBC: + case CRYPTO_AES_CTR: + case CRYPTO_AES_XTS: + case CRYPTO_AES_ECB: + openssl_aes(sess, cop); + break; + case 0: + /* no encryption wanted, everythings fine */ + break; + default: + printf("%s: unknown cipher passed!\n", __func__); + break; + } + + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.h b/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.h new file mode 100644 index 0000000000000..5f1f5162b6747 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/openssl_wrapper.h @@ -0,0 +1,6 @@ +#ifndef __OPENSSL_WRAPPER_H +#define __OPENSSL_WRAPPER_H + +int openssl_cioccrypt(struct session_op *, struct crypt_op *); + +#endif /* __OPENSSL_WRAPPER_H */ diff --git a/cryptodev/cryptodev-linux-1.9/tests/sha_speed.c b/cryptodev/cryptodev-linux-1.9/tests/sha_speed.c new file mode 100644 index 0000000000000..1e672603126e3 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/sha_speed.c @@ -0,0 +1,198 @@ +/* sha_speed - simple SHA benchmark tool for cryptodev + * + * Copyright (C) 2011 by Phil Sutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static double udifftimeval(struct timeval start, struct timeval end) +{ + return (double)(end.tv_usec - start.tv_usec) + + (double)(end.tv_sec - start.tv_sec) * 1000 * 1000; +} + +static int must_finish = 0; + +static void alarm_handler(int signo) +{ + must_finish = 1; +} + +static char *units[] = { "", "Ki", "Mi", "Gi", "Ti", 0}; +static char *si_units[] = { "", "K", "M", "G", "T", 0}; + +static void value2human(int si, double bytes, double time, double* data, double* speed,char* metric) +{ + int unit = 0; + + *data = bytes; + + if (si) { + while (*data > 1000 && si_units[unit + 1]) { + *data /= 1000; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", si_units[unit]); + } else { + while (*data > 1024 && units[unit + 1]) { + *data /= 1024; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", units[unit]); + } +} + + +int hash_data(struct session_op *sess, int fdc, int chunksize, int alignmask) +{ + struct crypt_op cop; + char *buffer; + static int val = 23; + struct timeval start, end; + double total = 0; + double secs, ddata, dspeed; + char metric[16]; + uint8_t mac[AALG_MAX_RESULT_LEN]; + + if (alignmask) { + if (posix_memalign((void **)&buffer, alignmask + 1, chunksize)) { + printf("posix_memalign() failed!\n"); + return 1; + } + } else { + if (!(buffer = malloc(chunksize))) { + perror("malloc()"); + return 1; + } + } + + printf("\tEncrypting in chunks of %d bytes: ", chunksize); + fflush(stdout); + + memset(buffer, val++, chunksize); + + must_finish = 0; + alarm(5); + + gettimeofday(&start, NULL); + do { + memset(&cop, 0, sizeof(cop)); + cop.ses = sess->ses; + cop.len = chunksize; + cop.op = COP_ENCRYPT; + cop.src = (unsigned char *)buffer; + cop.mac = mac; + + if (ioctl(fdc, CIOCCRYPT, &cop)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + total+=chunksize; + } while(must_finish==0); + gettimeofday(&end, NULL); + + secs = udifftimeval(start, end)/ 1000000.0; + + value2human(1, total, secs, &ddata, &dspeed, metric); + printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + + free(buffer); + return 0; +} + +int main(void) +{ + int fd, i, fdc = -1, alignmask = 0; + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + signal(SIGALRM, alarm_handler); + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + perror("open()"); + return 1; + } + if (ioctl(fd, CRIOGET, &fdc)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + fprintf(stderr, "Testing SHA1 Hash: \n"); + memset(&sess, 0, sizeof(sess)); + sess.mac = CRYPTO_SHA1; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + printf("requested hash CRYPTO_SHA1, got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + alignmask = siop.alignmask; +#endif + + for (i = 256; i <= (64 * 1024); i *= 4) { + if (hash_data(&sess, fdc, i, alignmask)) + break; + } + + fprintf(stderr, "\nTesting SHA256 Hash: \n"); + memset(&sess, 0, sizeof(sess)); + sess.mac = CRYPTO_SHA2_256; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + printf("requested hash CRYPTO_SHA2_256, got %s with driver %s\n", + siop.hash_info.cra_name, siop.hash_info.cra_driver_name); + alignmask = siop.alignmask; +#endif + + for (i = 256; i <= (64 * 1024); i *= 4) { + if (hash_data(&sess, fdc, i, alignmask)) + break; + } + + close(fdc); + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/speed.c b/cryptodev/cryptodev-linux-1.9/tests/speed.c new file mode 100644 index 0000000000000..951ae096c95f7 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/speed.c @@ -0,0 +1,213 @@ +/* cryptodev_test - simple benchmark tool for cryptodev + * + * Copyright (C) 2010 by Phil Sutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int si = 1; /* SI by default */ + +static double udifftimeval(struct timeval start, struct timeval end) +{ + return (double)(end.tv_usec - start.tv_usec) + + (double)(end.tv_sec - start.tv_sec) * 1000 * 1000; +} + +static volatile int must_finish; + +static void alarm_handler(int signo) +{ + must_finish = 1; +} + +static char *units[] = { "", "Ki", "Mi", "Gi", "Ti", 0}; +static char *si_units[] = { "", "K", "M", "G", "T", 0}; + +static void value2human(int si, double bytes, double time, double* data, double* speed,char* metric) +{ + int unit = 0; + + *data = bytes; + + if (si) { + while (*data > 1000 && si_units[unit + 1]) { + *data /= 1000; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", si_units[unit]); + } else { + while (*data > 1024 && units[unit + 1]) { + *data /= 1024; + unit++; + } + *speed = *data / time; + sprintf(metric, "%sB", units[unit]); + } +} + +#define MAX(x,y) ((x)>(y)?(x):(y)) + +int encrypt_data(struct session_op *sess, int fdc, int chunksize, int alignmask) +{ + struct crypt_op cop; + char *buffer, iv[32]; + static int val = 23; + struct timeval start, end; + double total = 0; + double secs, ddata, dspeed; + char metric[16]; + + if (alignmask) { + if (posix_memalign((void **)&buffer, MAX(alignmask + 1, sizeof(void*)), chunksize)) { + printf("posix_memalign() failed! (mask %x, size: %d)\n", alignmask+1, chunksize); + return 1; + } + } else { + if (!(buffer = malloc(chunksize))) { + perror("malloc()"); + return 1; + } + } + + memset(iv, 0x23, 32); + + printf("\tEncrypting in chunks of %d bytes: ", chunksize); + fflush(stdout); + + memset(buffer, val++, chunksize); + + must_finish = 0; + alarm(5); + + gettimeofday(&start, NULL); + do { + memset(&cop, 0, sizeof(cop)); + cop.ses = sess->ses; + cop.len = chunksize; + cop.iv = (unsigned char *)iv; + cop.op = COP_ENCRYPT; + cop.src = cop.dst = (unsigned char *)buffer; + + if (ioctl(fdc, CIOCCRYPT, &cop)) { + perror("ioctl(CIOCCRYPT)"); + return 1; + } + total+=chunksize; + } while(must_finish==0); + gettimeofday(&end, NULL); + + secs = udifftimeval(start, end)/ 1000000.0; + + value2human(si, total, secs, &ddata, &dspeed, metric); + printf ("done. %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + + free(buffer); + return 0; +} + +int main(int argc, char** argv) +{ + int fd, i, fdc = -1, alignmask = 0; + struct session_op sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + char keybuf[32]; + + signal(SIGALRM, alarm_handler); + + if (argc > 1) { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { + printf("Usage: speed [--kib]\n"); + exit(0); + } + if (strcmp(argv[1], "--kib") == 0) { + si = 0; + } + } + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + perror("open()"); + return 1; + } + if (ioctl(fd, CRIOGET, &fdc)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + fprintf(stderr, "Testing NULL cipher: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_NULL; + sess.keylen = 0; + sess.key = (unsigned char *)keybuf; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + alignmask = siop.alignmask; +#endif + + for (i = 512; i <= (64 * 1024); i *= 2) { + if (encrypt_data(&sess, fdc, i, alignmask)) + break; + } + + fprintf(stderr, "\nTesting AES-128-CBC cipher: \n"); + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = 16; + memset(keybuf, 0x42, 16); + sess.key = (unsigned char *)keybuf; + if (ioctl(fdc, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(fdc, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + alignmask = siop.alignmask; +#endif + + for (i = 512; i <= (64 * 1024); i *= 2) { + if (encrypt_data(&sess, fdc, i, alignmask)) + break; + } + + close(fdc); + close(fd); + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/tests/testhelper.h b/cryptodev/cryptodev-linux-1.9/tests/testhelper.h new file mode 100644 index 0000000000000..800d10db2f086 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/tests/testhelper.h @@ -0,0 +1,9 @@ +/* + * Some helper stuff shared between the sample programs. + */ +#ifndef __TESTHELPER_H +#define __TESTHELPER_H + +#define buf_align(buf, align) (void *)(((unsigned long)(buf) + (align)) & ~(align)) + +#endif /* __TESTHELPER_H */ diff --git a/cryptodev/cryptodev-linux-1.9/util.c b/cryptodev/cryptodev-linux-1.9/util.c new file mode 100644 index 0000000000000..9eba4836ba6a5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/util.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Maxim Levitsky + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "util.h" + +/* These were taken from Maxim Levitsky's patch to lkml. + */ +struct scatterlist *sg_advance(struct scatterlist *sg, int consumed) +{ + while (consumed >= sg->length) { + consumed -= sg->length; + + sg = sg_next(sg); + if (!sg) + break; + } + + WARN_ON(!sg && consumed); + + if (!sg) + return NULL; + + sg->offset += consumed; + sg->length -= consumed; + + if (sg->offset >= PAGE_SIZE) { + struct page *page = + nth_page(sg_page(sg), sg->offset / PAGE_SIZE); + sg_set_page(sg, page, sg->length, sg->offset % PAGE_SIZE); + } + + return sg; +} + +/** + * sg_copy - copies sg entries from sg_from to sg_to, such + * as sg_to covers first 'len' bytes from sg_from. + */ +int sg_copy(struct scatterlist *sg_from, struct scatterlist *sg_to, int len) +{ + while (len > sg_from->length) { + len -= sg_from->length; + + sg_set_page(sg_to, sg_page(sg_from), + sg_from->length, sg_from->offset); + + sg_to = sg_next(sg_to); + sg_from = sg_next(sg_from); + + if (len && (!sg_from || !sg_to)) + return -ENOMEM; + } + + if (len) + sg_set_page(sg_to, sg_page(sg_from), + len, sg_from->offset); + sg_mark_end(sg_to); + return 0; +} + diff --git a/cryptodev/cryptodev-linux-1.9/util.h b/cryptodev/cryptodev-linux-1.9/util.h new file mode 100644 index 0000000000000..204de7584c25e --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/util.h @@ -0,0 +1,2 @@ +int sg_copy(struct scatterlist *sg_from, struct scatterlist *sg_to, int len); +struct scatterlist *sg_advance(struct scatterlist *sg, int consumed); diff --git a/cryptodev/cryptodev-linux-1.9/zc.c b/cryptodev/cryptodev-linux-1.9/zc.c new file mode 100644 index 0000000000000..ae464ff699923 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/zc.c @@ -0,0 +1,220 @@ +/* + * Driver for /dev/crypto device (aka CryptoDev) + * + * Copyright (c) 2009-2013 Nikos Mavrogiannopoulos + * Copyright (c) 2010 Phil Sutter + * Copyright (c) 2011, 2012 OpenSSL Software Foundation, Inc. + * + * This file is part of linux cryptodev. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cryptodev_int.h" +#include "zc.h" +#include "version.h" + +/* Helper functions to assist zero copy. + * This needs to be redesigned and moved out of the session. --nmav + */ + +/* offset of buf in it's first page */ +#define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK) + +/* fetch the pages addr resides in into pg and initialise sg with them */ +int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, + unsigned int pgcount, struct page **pg, struct scatterlist *sg, + struct task_struct *task, struct mm_struct *mm) +{ + int ret, pglen, i = 0; + struct scatterlist *sgp; + + if (unlikely(!pgcount || !len || !addr)) { + sg_mark_end(sg); + return 0; + } + + down_read(&mm->mmap_sem); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) + ret = get_user_pages(task, mm, + (unsigned long)addr, pgcount, write, 0, pg, NULL); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + ret = get_user_pages_remote(task, mm, + (unsigned long)addr, pgcount, write, 0, pg, NULL); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) + ret = get_user_pages_remote(task, mm, + (unsigned long)addr, pgcount, write ? FOLL_WRITE : 0, + pg, NULL); +#else + ret = get_user_pages_remote(task, mm, + (unsigned long)addr, pgcount, write ? FOLL_WRITE : 0, + pg, NULL, NULL); +#endif + up_read(&mm->mmap_sem); + if (ret != pgcount) + return -EINVAL; + + sg_init_table(sg, pgcount); + + pglen = min((ptrdiff_t)(PAGE_SIZE - PAGEOFFSET(addr)), (ptrdiff_t)len); + sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr)); + + len -= pglen; + for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) { + pglen = min((uint32_t)PAGE_SIZE, len); + sg_set_page(sgp, pg[i++], pglen, 0); + len -= pglen; + } + sg_mark_end(sg_last(sg, pgcount)); + return 0; +} + +int adjust_sg_array(struct csession *ses, int pagecount) +{ + struct scatterlist *sg; + struct page **pages; + int array_size; + + for (array_size = ses->array_size; array_size < pagecount; + array_size *= 2) + ; + ddebug(0, "reallocating from %d to %d pages", + ses->array_size, array_size); + pages = krealloc(ses->pages, array_size * sizeof(struct page *), + GFP_KERNEL); + if (unlikely(!pages)) + return -ENOMEM; + ses->pages = pages; + sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist), + GFP_KERNEL); + if (unlikely(!sg)) + return -ENOMEM; + ses->sg = sg; + ses->array_size = array_size; + + return 0; +} + +void release_user_pages(struct csession *ses) +{ + unsigned int i; + + for (i = 0; i < ses->used_pages; i++) { + if (!PageReserved(ses->pages[i])) + SetPageDirty(ses->pages[i]); + + if (ses->readonly_pages == 0) + flush_dcache_page(ses->pages[i]); + else + ses->readonly_pages--; + + put_page(ses->pages[i]); + } + ses->used_pages = 0; +} + +/* make src and dst available in scatterlists. + * dst might be the same as src. + */ +int get_userbuf(struct csession *ses, + void *__user src, unsigned int src_len, + void *__user dst, unsigned int dst_len, + struct task_struct *task, struct mm_struct *mm, + struct scatterlist **src_sg, + struct scatterlist **dst_sg) +{ + int src_pagecount, dst_pagecount; + int rc; + + /* Empty input is a valid option to many algorithms & is tested by NIST/FIPS */ + /* Make sure NULL input has 0 length */ + if (!src && src_len) + src_len = 0; + + /* I don't know that null output is ever useful, but we can handle it gracefully */ + /* Make sure NULL output has 0 length */ + if (!dst && dst_len) + dst_len = 0; + + src_pagecount = PAGECOUNT(src, src_len); + dst_pagecount = PAGECOUNT(dst, dst_len); + + ses->used_pages = (src == dst) ? max(src_pagecount, dst_pagecount) + : src_pagecount + dst_pagecount; + + ses->readonly_pages = (src == dst) ? 0 : src_pagecount; + + if (ses->used_pages > ses->array_size) { + rc = adjust_sg_array(ses, ses->used_pages); + if (rc) + return rc; + } + + if (src == dst) { /* inplace operation */ + /* When we encrypt for authenc modes we need to write + * more data than the ones we read. */ + if (src_len < dst_len) + src_len = dst_len; + rc = __get_userbuf(src, src_len, 1, ses->used_pages, + ses->pages, ses->sg, task, mm); + if (unlikely(rc)) { + derr(1, "failed to get user pages for data IO"); + return rc; + } + (*src_sg) = (*dst_sg) = ses->sg; + return 0; + } + + *src_sg = NULL; /* default to no input */ + *dst_sg = NULL; /* default to ignore output */ + + if (likely(src)) { + rc = __get_userbuf(src, src_len, 0, ses->readonly_pages, + ses->pages, ses->sg, task, mm); + if (unlikely(rc)) { + derr(1, "failed to get user pages for data input"); + return rc; + } + *src_sg = ses->sg; + } + + if (likely(dst)) { + const unsigned int writable_pages = + ses->used_pages - ses->readonly_pages; + struct page **dst_pages = ses->pages + ses->readonly_pages; + *dst_sg = ses->sg + ses->readonly_pages; + + rc = __get_userbuf(dst, dst_len, 1, writable_pages, + dst_pages, *dst_sg, task, mm); + if (unlikely(rc)) { + derr(1, "failed to get user pages for data output"); + release_user_pages(ses); /* FIXME: use __release_userbuf(src, ...) */ + return rc; + } + } + return 0; +} diff --git a/cryptodev/cryptodev-linux-1.9/zc.h b/cryptodev/cryptodev-linux-1.9/zc.h new file mode 100644 index 0000000000000..6f975d6eb15e5 --- /dev/null +++ b/cryptodev/cryptodev-linux-1.9/zc.h @@ -0,0 +1,27 @@ +#ifndef ZC_H +# define ZC_H + +#include "cryptodev_int.h" + +/* For zero copy */ +int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, + unsigned int pgcount, struct page **pg, struct scatterlist *sg, + struct task_struct *task, struct mm_struct *mm); +void release_user_pages(struct csession *ses); + +int get_userbuf(struct csession *ses, + void *__user src, unsigned int src_len, + void *__user dst, unsigned int dst_len, + struct task_struct *task, struct mm_struct *mm, + struct scatterlist **src_sg, + struct scatterlist **dst_sg); + +/* buflen ? (last page - first page + 1) : 0 */ +#define PAGECOUNT(buf, buflen) ((buflen) \ + ? ((((unsigned long)(buf + buflen - 1)) >> PAGE_SHIFT) - \ + (((unsigned long)(buf )) >> PAGE_SHIFT) + 1) \ + : 0) + +#define DEFAULT_PREALLOC_PAGES 32 + +#endif diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 2c462beee5513..a943cf17faa72 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1007,7 +1007,7 @@ static ssize_t erst_reader(struct pstore_record *record) /* The record may be cleared by others, try read next record */ if (len == -ENOENT) goto skip; - else if (len < sizeof(*rcd)) { + else if (len < 0 || len < sizeof(*rcd)) { rc = -EIO; goto out; } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 3c3a37b8503bd..572b6c7303edc 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -112,7 +113,7 @@ static DEFINE_MUTEX(ghes_list_mutex); * Because the memory area used to transfer hardware error information * from BIOS to Linux can be determined only in NMI, IRQ or timer * handler, but general ioremap can not be used in atomic context, so - * a special version of atomic ioremap is implemented for that. + * the fixmap is used instead. */ /* @@ -126,8 +127,8 @@ static DEFINE_MUTEX(ghes_list_mutex); /* virtual memory area for atomic ioremap */ static struct vm_struct *ghes_ioremap_area; /* - * These 2 spinlock is used to prevent atomic ioremap virtual memory - * area from being mapped simultaneously. + * These 2 spinlocks are used to prevent the fixmap entries from being used + * simultaneously. */ static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); @@ -159,52 +160,36 @@ static void ghes_ioremap_exit(void) static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) { - unsigned long vaddr; phys_addr_t paddr; pgprot_t prot; - vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr); - paddr = pfn << PAGE_SHIFT; prot = arch_apei_get_mem_attribute(paddr); - ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot); + __set_fixmap(FIX_APEI_GHES_NMI, paddr, prot); - return (void __iomem *)vaddr; + return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI); } static void __iomem *ghes_ioremap_pfn_irq(u64 pfn) { - unsigned long vaddr, paddr; + phys_addr_t paddr; pgprot_t prot; - vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr); - paddr = pfn << PAGE_SHIFT; prot = arch_apei_get_mem_attribute(paddr); + __set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot); - ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot); - - return (void __iomem *)vaddr; + return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ); } -static void ghes_iounmap_nmi(void __iomem *vaddr_ptr) +static void ghes_iounmap_nmi(void) { - unsigned long vaddr = (unsigned long __force)vaddr_ptr; - void *base = ghes_ioremap_area->addr; - - BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base)); - unmap_kernel_range_noflush(vaddr, PAGE_SIZE); - arch_apei_flush_tlb_one(vaddr); + clear_fixmap(FIX_APEI_GHES_NMI); } -static void ghes_iounmap_irq(void __iomem *vaddr_ptr) +static void ghes_iounmap_irq(void) { - unsigned long vaddr = (unsigned long __force)vaddr_ptr; - void *base = ghes_ioremap_area->addr; - - BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base)); - unmap_kernel_range_noflush(vaddr, PAGE_SIZE); - arch_apei_flush_tlb_one(vaddr); + clear_fixmap(FIX_APEI_GHES_IRQ); } static int ghes_estatus_pool_init(void) @@ -360,10 +345,10 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, paddr += trunk; buffer += trunk; if (in_nmi) { - ghes_iounmap_nmi(vaddr); + ghes_iounmap_nmi(); raw_spin_unlock(&ghes_ioremap_lock_nmi); } else { - ghes_iounmap_irq(vaddr); + ghes_iounmap_irq(); spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags); } } @@ -851,17 +836,8 @@ static void ghes_sea_remove(struct ghes *ghes) synchronize_rcu(); } #else /* CONFIG_ACPI_APEI_SEA */ -static inline void ghes_sea_add(struct ghes *ghes) -{ - pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n", - ghes->generic->header.source_id); -} - -static inline void ghes_sea_remove(struct ghes *ghes) -{ - pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n", - ghes->generic->header.source_id); -} +static inline void ghes_sea_add(struct ghes *ghes) { } +static inline void ghes_sea_remove(struct ghes *ghes) { } #endif /* CONFIG_ACPI_APEI_SEA */ #ifdef CONFIG_HAVE_ACPI_APEI_NMI @@ -1063,23 +1039,9 @@ static void ghes_nmi_init_cxt(void) init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq); } #else /* CONFIG_HAVE_ACPI_APEI_NMI */ -static inline void ghes_nmi_add(struct ghes *ghes) -{ - pr_err(GHES_PFX "ID: %d, trying to add NMI notification which is not supported!\n", - ghes->generic->header.source_id); - BUG(); -} - -static inline void ghes_nmi_remove(struct ghes *ghes) -{ - pr_err(GHES_PFX "ID: %d, trying to remove NMI notification which is not supported!\n", - ghes->generic->header.source_id); - BUG(); -} - -static inline void ghes_nmi_init_cxt(void) -{ -} +static inline void ghes_nmi_add(struct ghes *ghes) { } +static inline void ghes_nmi_remove(struct ghes *ghes) { } +static inline void ghes_nmi_init_cxt(void) { } #endif /* CONFIG_HAVE_ACPI_APEI_NMI */ static int ghes_probe(struct platform_device *ghes_dev) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index fbcc73f7a0990..18af71057b44e 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -387,6 +387,7 @@ EXPORT_SYMBOL(acpi_bus_power_manageable); #ifdef CONFIG_PM static DEFINE_MUTEX(acpi_pm_notifier_lock); +static DEFINE_MUTEX(acpi_pm_notifier_install_lock); void acpi_pm_wakeup_event(struct device *dev) { @@ -443,24 +444,25 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, if (!dev && !func) return AE_BAD_PARAMETER; - mutex_lock(&acpi_pm_notifier_lock); + mutex_lock(&acpi_pm_notifier_install_lock); if (adev->wakeup.flags.notifier_present) goto out; - adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); - adev->wakeup.context.dev = dev; - adev->wakeup.context.func = func; - status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, acpi_pm_notify_handler, NULL); if (ACPI_FAILURE(status)) goto out; + mutex_lock(&acpi_pm_notifier_lock); + adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); + adev->wakeup.context.dev = dev; + adev->wakeup.context.func = func; adev->wakeup.flags.notifier_present = true; + mutex_unlock(&acpi_pm_notifier_lock); out: - mutex_unlock(&acpi_pm_notifier_lock); + mutex_unlock(&acpi_pm_notifier_install_lock); return status; } @@ -472,7 +474,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) { acpi_status status = AE_BAD_PARAMETER; - mutex_lock(&acpi_pm_notifier_lock); + mutex_lock(&acpi_pm_notifier_install_lock); if (!adev->wakeup.flags.notifier_present) goto out; @@ -483,14 +485,15 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) if (ACPI_FAILURE(status)) goto out; + mutex_lock(&acpi_pm_notifier_lock); adev->wakeup.context.func = NULL; adev->wakeup.context.dev = NULL; wakeup_source_unregister(adev->wakeup.ws); - adev->wakeup.flags.notifier_present = false; + mutex_unlock(&acpi_pm_notifier_lock); out: - mutex_unlock(&acpi_pm_notifier_lock); + mutex_unlock(&acpi_pm_notifier_install_lock); return status; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 236b14324780a..df842465634a9 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec) { if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) ec_log_drv("event unblocked"); - if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - advance_transaction(ec); + /* + * Unconditionally invoke this once after enabling the event + * handling mechanism to detect the pending events. + */ + advance_transaction(ec); } static inline void __acpi_ec_disable_event(struct acpi_ec *ec) @@ -1456,11 +1459,10 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) acpi_ec_enable_gpe(ec, true); - - /* EC is fully operational, allow queries */ - acpi_ec_enable_event(ec); } } + /* EC is fully operational, allow queries */ + acpi_ec_enable_event(ec); return 0; } @@ -1595,32 +1597,41 @@ static int acpi_ec_add(struct acpi_device *device) { struct acpi_ec *ec = NULL; int ret; + bool is_ecdt = false; + acpi_status status; strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); - ec = acpi_ec_alloc(); - if (!ec) - return -ENOMEM; - if (ec_parse_device(device->handle, 0, ec, NULL) != - AE_CTRL_TERMINATE) { + if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { + is_ecdt = true; + ec = boot_ec; + } else { + ec = acpi_ec_alloc(); + if (!ec) + return -ENOMEM; + status = ec_parse_device(device->handle, 0, ec, NULL); + if (status != AE_CTRL_TERMINATE) { ret = -EINVAL; goto err_alloc; + } } if (acpi_is_boot_ec(ec)) { - boot_ec_is_ecdt = false; - /* - * Trust PNP0C09 namespace location rather than ECDT ID. - * - * But trust ECDT GPE rather than _GPE because of ASUS quirks, - * so do not change boot_ec->gpe to ec->gpe. - */ - boot_ec->handle = ec->handle; - acpi_handle_debug(ec->handle, "duplicated.\n"); - acpi_ec_free(ec); - ec = boot_ec; - ret = acpi_config_boot_ec(ec, ec->handle, true, false); + boot_ec_is_ecdt = is_ecdt; + if (!is_ecdt) { + /* + * Trust PNP0C09 namespace location rather than + * ECDT ID. But trust ECDT GPE rather than _GPE + * because of ASUS quirks, so do not change + * boot_ec->gpe to ec->gpe. + */ + boot_ec->handle = ec->handle; + acpi_handle_debug(ec->handle, "duplicated.\n"); + acpi_ec_free(ec); + ec = boot_ec; + } + ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt); } else ret = acpi_ec_setup(ec, true); if (ret) @@ -1633,8 +1644,10 @@ static int acpi_ec_add(struct acpi_device *device) ret = !!request_region(ec->command_addr, 1, "EC cmd"); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); - /* Reprobe devices depending on the EC */ - acpi_walk_dep_device_list(ec->handle); + if (!is_ecdt) { + /* Reprobe devices depending on the EC */ + acpi_walk_dep_device_list(ec->handle); + } acpi_handle_debug(ec->handle, "enumerated.\n"); return 0; @@ -1690,6 +1703,7 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) static const struct acpi_device_id ec_device_ids[] = { {"PNP0C09", 0}, + {ACPI_ECDT_HID, 0}, {"", 0}, }; @@ -1762,11 +1776,14 @@ static int __init acpi_ec_ecdt_start(void) * Note: ec->handle can be valid if this function is called after * acpi_ec_add(), hence the fast path. */ - if (boot_ec->handle != ACPI_ROOT_OBJECT) - handle = boot_ec->handle; - else if (!acpi_ec_ecdt_get_handle(&handle)) - return -ENODEV; - return acpi_config_boot_ec(boot_ec, handle, true, true); + if (boot_ec->handle == ACPI_ROOT_OBJECT) { + if (!acpi_ec_ecdt_get_handle(&handle)) + return -ENODEV; + boot_ec->handle = handle; + } + + /* Register to ACPI bus with PM ops attached */ + return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); } #if 0 @@ -2018,6 +2035,12 @@ int __init acpi_ec_init(void) /* Drivers must be started after acpi_ec_query_init() */ dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); + /* + * Register ECDT to ACPI bus only when PNP0C09 probe fails. This is + * useful for platforms (confirmed on ASUS X550ZE) with valid ECDT + * settings but invalid DSDT settings. + * https://bugzilla.kernel.org/show_bug.cgi?id=196847 + */ ecdt_fail = acpi_ec_ecdt_start(); return ecdt_fail && dsdt_fail ? -ENODEV : 0; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4361c4415b4f4..ede83d38beed5 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -115,6 +115,7 @@ bool acpi_device_is_present(const struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); +int acpi_bus_register_early_device(int type); /* -------------------------------------------------------------------------- Device Matching and Notification diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 9c2c49b6a240d..dea0fb3d6f64a 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1457,6 +1457,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, dev_name(&adev_dimm->dev)); return -ENXIO; } + /* + * Record nfit_mem for the notification path to track back to + * the nfit sysfs attributes for this dimm device object. + */ + dev_set_drvdata(&adev_dimm->dev, nfit_mem); /* * Until standardization materializes we need to consider 4 @@ -1516,9 +1521,11 @@ static void shutdown_dimm_notify(void *data) sysfs_put(nfit_mem->flags_attr); nfit_mem->flags_attr = NULL; } - if (adev_dimm) + if (adev_dimm) { acpi_remove_notify_handler(adev_dimm->handle, ACPI_DEVICE_NOTIFY, acpi_nvdimm_notify); + dev_set_drvdata(&adev_dimm->dev, NULL); + } } mutex_unlock(&acpi_desc->init_mutex); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 602f8ff212f2c..2f2f50322ffb7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1024,6 +1024,9 @@ static void acpi_device_get_busid(struct acpi_device *device) case ACPI_BUS_TYPE_SLEEP_BUTTON: strcpy(device->pnp.bus_id, "SLPF"); break; + case ACPI_BUS_TYPE_ECDT_EC: + strcpy(device->pnp.bus_id, "ECDT"); + break; default: acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); /* Clean up trailing underscores (if any) */ @@ -1304,6 +1307,9 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, case ACPI_BUS_TYPE_SLEEP_BUTTON: acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF); break; + case ACPI_BUS_TYPE_ECDT_EC: + acpi_add_id(pnp, ACPI_ECDT_HID); + break; } } @@ -2049,6 +2055,21 @@ void acpi_bus_trim(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_bus_trim); +int acpi_bus_register_early_device(int type) +{ + struct acpi_device *device = NULL; + int result; + + result = acpi_add_single_object(&device, NULL, + type, ACPI_STA_DEFAULT); + if (result) + return result; + + device->flags.match_driver = true; + return device_attach(&device->dev); +} +EXPORT_SYMBOL_GPL(acpi_bus_register_early_device); + static int acpi_bus_scan_fixed(void) { int result = 0; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index fddf76ef5bd6d..a340766b51fea 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -482,7 +482,8 @@ enum binder_deferred_state { * @tsk task_struct for group_leader of process * (invariant after initialized) * @files files_struct for process - * (invariant after initialized) + * (protected by @files_lock) + * @files_lock mutex to protect @files * @deferred_work_node: element for binder_deferred_list * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform @@ -530,6 +531,7 @@ struct binder_proc { int pid; struct task_struct *tsk; struct files_struct *files; + struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; bool is_dead; @@ -877,20 +879,26 @@ static void binder_inc_node_tmpref_ilocked(struct binder_node *node); static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; unsigned long rlim_cur; unsigned long irqs; + int ret; - if (files == NULL) - return -ESRCH; - - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + ret = -ESRCH; + goto err; + } + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - return __alloc_fd(files, 0, rlim_cur, flags); + ret = __alloc_fd(proc->files, 0, rlim_cur, flags); +err: + mutex_unlock(&proc->files_lock); + return ret; } /* @@ -899,8 +907,10 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { + mutex_lock(&proc->files_lock); if (proc->files) __fd_install(proc->files, fd, file); + mutex_unlock(&proc->files_lock); } /* @@ -910,9 +920,11 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { int retval; - if (proc->files == NULL) - return -ESRCH; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + retval = -ESRCH; + goto err; + } retval = __close_fd(proc->files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || @@ -920,7 +932,8 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; - +err: + mutex_unlock(&proc->files_lock); return retval; } @@ -1947,6 +1960,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, } } +/** + * binder_cleanup_transaction() - cleans up undelivered transaction + * @t: transaction that needs to be cleaned up + * @reason: reason the transaction wasn't delivered + * @error_code: error to return to caller (if synchronous call) + */ +static void binder_cleanup_transaction(struct binder_transaction *t, + const char *reason, + uint32_t error_code) +{ + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { + binder_send_failed_reply(t, error_code); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d, %s\n", + t->debug_id, reason); + binder_free_transaction(t); + } +} + /** * binder_validate_object() - checks for a valid metadata object in a buffer. * @buffer: binder_buffer that we're parsing. @@ -4015,12 +4048,20 @@ static int binder_thread_read(struct binder_proc *proc, if (put_user(cmd, (uint32_t __user *)ptr)) { if (t_from) binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "put_user failed", + BR_FAILED_REPLY); + return -EFAULT; } ptr += sizeof(uint32_t); if (copy_to_user(ptr, &tr, sizeof(tr))) { if (t_from) binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "copy_to_user failed", + BR_FAILED_REPLY); + return -EFAULT; } ptr += sizeof(tr); @@ -4090,15 +4131,9 @@ static void binder_release_work(struct binder_proc *proc, struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && - !(t->flags & TF_ONE_WAY)) { - binder_send_failed_reply(t, BR_DEAD_REPLY); - } else { - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered transaction %d\n", - t->debug_id); - binder_free_transaction(t); - } + + binder_cleanup_transaction(t, "process died.", + BR_DEAD_REPLY); } break; case BINDER_WORK_RETURN_ERROR: { struct binder_error *e = container_of( @@ -4605,7 +4640,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) ret = binder_alloc_mmap_handler(&proc->alloc, vma); if (ret) return ret; + mutex_lock(&proc->files_lock); proc->files = get_files_struct(current); + mutex_unlock(&proc->files_lock); return 0; err_bad_arg: @@ -4629,6 +4666,7 @@ static int binder_open(struct inode *nodp, struct file *filp) spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; + mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); proc->default_priority = task_nice(current); binder_dev = container_of(filp->private_data, struct binder_device, @@ -4881,9 +4919,11 @@ static void binder_deferred_func(struct work_struct *work) files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { + mutex_lock(&proc->files_lock); files = proc->files; if (files) proc->files = NULL; + mutex_unlock(&proc->files_lock); } if (defer & BINDER_DEFERRED_FLUSH) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ee4c1ec9dca0e..e7ded346d94bd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4439,6 +4439,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ { "LITEON CX1-JB*-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + { "LITEON EP1-*", NULL, ATA_HORKAGE_MAX_SEC_1024 }, /* Devices we expect to fail diagnostics */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e4effef0c83f2..ea20e0eb4d5ac 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2264,8 +2264,8 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (dev->flags & ATA_DFLAG_DUBIOUS_XFER) eflags |= ATA_EFLAG_DUBIOUS_XFER; ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); + trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); } - trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); DPRINTK("EXIT\n"); } diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 7e76b35f422c6..e121b84857310 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2803,7 +2803,7 @@ static int hrz_probe(struct pci_dev *pci_dev, return err; out_free_irq: - free_irq(dev->irq, dev); + free_irq(irq, dev); out_free: kfree(dev); out_release: diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 2f6614c9a229a..2415ad9f6dd4f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -91,22 +91,23 @@ config FIRMWARE_IN_KERNEL depends on FW_LOADER default y help - The kernel source tree includes a number of firmware 'blobs' - that are used by various drivers. The recommended way to - use these is to run "make firmware_install", which, after - converting ihex files to binary, copies all of the needed - binary files in firmware/ to /lib/firmware/ on your system so - that they can be loaded by userspace helpers on request. + Various drivers in the kernel source tree may require firmware, + which is generally available in your distribution's linux-firmware + package. + + The linux-firmware package should install firmware into + /lib/firmware/ on your system, so they can be loaded by userspace + helpers on request. Enabling this option will build each required firmware blob - into the kernel directly, where request_firmware() will find - them without having to call out to userspace. This may be - useful if your root file system requires a device that uses - such firmware and do not wish to use an initrd. + specified by EXTRA_FIRMWARE into the kernel directly, where + request_firmware() will find them without having to call out to + userspace. This may be useful if your root file system requires a + device that uses such firmware and you do not wish to use an + initrd. This single option controls the inclusion of firmware for - every driver that uses request_firmware() and ships its - firmware in the kernel source tree, which avoids a + every driver that uses request_firmware(), which avoids a proliferation of 'Include firmware for xxx device' options. Say 'N' and let firmware be loaded from userspace. @@ -235,6 +236,9 @@ config GENERIC_CPU_DEVICES config GENERIC_CPU_AUTOPROBE bool +config GENERIC_CPU_VULNERABILITIES + bool + config SOC_BUS bool select GLOB diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index eb3af2739537a..07532d83be0bc 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -186,6 +186,11 @@ static void cache_associativity(struct cacheinfo *this_leaf) this_leaf->ways_of_associativity = (size / nr_sets) / line_size; } +static bool cache_node_is_unified(struct cacheinfo *this_leaf) +{ + return of_property_read_bool(this_leaf->of_node, "cache-unified"); +} + static void cache_of_override_properties(unsigned int cpu) { int index; @@ -194,6 +199,14 @@ static void cache_of_override_properties(unsigned int cpu) for (index = 0; index < cache_leaves(cpu); index++) { this_leaf = this_cpu_ci->info_list + index; + /* + * init_cache_level must setup the cache level correctly + * overriding the architecturally specified levels, so + * if type is NONE at this stage, it should be unified + */ + if (this_leaf->type == CACHE_TYPE_NOCACHE && + cache_node_is_unified(this_leaf)) + this_leaf->type = CACHE_TYPE_UNIFIED; cache_size(this_leaf); cache_get_line_size(this_leaf); cache_nr_sets(this_leaf); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 321cd7b4d817f..825964efda1dc 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -501,10 +501,58 @@ static void __init cpu_dev_register_generic(void) #endif } +#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES + +ssize_t __weak cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); +static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); + +static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, + &dev_attr_spectre_v1.attr, + &dev_attr_spectre_v2.attr, + NULL +}; + +static const struct attribute_group cpu_root_vulnerabilities_group = { + .name = "vulnerabilities", + .attrs = cpu_root_vulnerabilities_attrs, +}; + +static void __init cpu_register_vulnerabilities(void) +{ + if (sysfs_create_group(&cpu_subsys.dev_root->kobj, + &cpu_root_vulnerabilities_group)) + pr_err("Unable to register CPU vulnerabilities\n"); +} + +#else +static inline void cpu_register_vulnerabilities(void) { } +#endif + void __init cpu_dev_init(void) { if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) panic("Failed to register CPU subsystem"); cpu_dev_register_generic(); + cpu_register_vulnerabilities(); } diff --git a/drivers/base/isa.c b/drivers/base/isa.c index cd6ccdcf9df0c..372d10af26009 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->probe) + if (isa_driver && isa_driver->probe) return isa_driver->probe(dev, to_isa_dev(dev)->id); return 0; @@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->remove) + if (isa_driver && isa_driver->remove) return isa_driver->remove(dev, to_isa_dev(dev)->id); return 0; @@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->shutdown) + if (isa_driver && isa_driver->shutdown) isa_driver->shutdown(dev, to_isa_dev(dev)->id); } @@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->suspend) + if (isa_driver && isa_driver->suspend) return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); return 0; @@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->resume) + if (isa_driver && isa_driver->resume) return isa_driver->resume(dev, to_isa_dev(dev)->id); return 0; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e8ca5e2cf1e51..70f8904f46a31 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -921,7 +921,7 @@ static int pm_genpd_prepare(struct device *dev) genpd_unlock(genpd); ret = pm_generic_prepare(dev); - if (ret) { + if (ret < 0) { genpd_lock(genpd); genpd->prepared_count--; @@ -929,7 +929,8 @@ static int pm_genpd_prepare(struct device *dev) genpd_unlock(genpd); } - return ret; + /* Never return 1, as genpd don't cope with the direct_complete path. */ + return ret >= 0 ? 0 : ret; } /** diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index a6de325306933..0459b12046945 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -296,7 +296,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { count = PTR_ERR(opp_table); - dev_err(dev, "%s: OPP table not found (%d)\n", + dev_dbg(dev, "%s: OPP table not found (%d)\n", __func__, count); return count; } diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index 0b718886479bd..87509cb69f792 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -397,6 +397,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); _dev_pm_opp_remove_table(opp_table, dev, false); + of_node_put(np); goto put_opp_table; } } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 9adfb5445f8dc..5f2a4240a204d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -288,15 +288,6 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, cmd->status = BLK_STS_TIMEOUT; return BLK_EH_HANDLED; } - - /* If we are waiting on our dead timer then we could get timeout - * callbacks for our request. For this we just want to reset the timer - * and let the queue side take care of everything. - */ - if (!completion_done(&cmd->send_complete)) { - nbd_config_put(nbd); - return BLK_EH_RESET_TIMER; - } config = nbd->config; if (config->num_connections > 1) { @@ -723,9 +714,9 @@ static int wait_for_reconnect(struct nbd_device *nbd) return 0; if (test_bit(NBD_DISCONNECTED, &config->runtime_flags)) return 0; - wait_event_interruptible_timeout(config->conn_wait, - atomic_read(&config->live_connections), - config->dead_conn_timeout); + wait_event_timeout(config->conn_wait, + atomic_read(&config->live_connections), + config->dead_conn_timeout); return atomic_read(&config->live_connections); } @@ -740,6 +731,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) if (!refcount_inc_not_zero(&nbd->config_refs)) { dev_err_ratelimited(disk_to_dev(nbd->disk), "Socks array is empty\n"); + blk_mq_start_request(req); return -EINVAL; } config = nbd->config; @@ -748,6 +740,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) dev_err_ratelimited(disk_to_dev(nbd->disk), "Attempted send on invalid socket\n"); nbd_config_put(nbd); + blk_mq_start_request(req); return -EINVAL; } cmd->status = BLK_STS_OK; @@ -771,6 +764,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) */ sock_shutdown(nbd); nbd_config_put(nbd); + blk_mq_start_request(req); return -EIO; } goto again; @@ -781,6 +775,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) * here so that it gets put _after_ the request that is already on the * dispatch list. */ + blk_mq_start_request(req); if (unlikely(nsock->pending && nsock->pending != req)) { blk_mq_requeue_request(req, true); ret = 0; @@ -793,10 +788,10 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) ret = nbd_send_cmd(nbd, cmd, index); if (ret == -EAGAIN) { dev_err_ratelimited(disk_to_dev(nbd->disk), - "Request send failed trying another connection\n"); + "Request send failed, requeueing\n"); nbd_mark_nsock_dead(nbd, nsock, 1); - mutex_unlock(&nsock->tx_lock); - goto again; + blk_mq_requeue_request(req, true); + ret = 0; } out: mutex_unlock(&nsock->tx_lock); @@ -820,7 +815,6 @@ static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, * done sending everything over the wire. */ init_completion(&cmd->send_complete); - blk_mq_start_request(bd->rq); /* We can be called directly from the user space process, which means we * could possibly have signals pending so our sendmsg will fail. In diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 8042c26ea9e6e..4d55af5c6e5b5 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -1985,8 +1985,10 @@ static int __init null_init(void) for (i = 0; i < nr_devices; i++) { dev = null_alloc_dev(); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto err_dev; + } ret = null_add_dev(dev); if (ret) { null_free_dev(dev); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index adc877dfef5c2..609227211295a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3074,13 +3074,21 @@ static void format_lock_cookie(struct rbd_device *rbd_dev, char *buf) mutex_unlock(&rbd_dev->watch_mutex); } +static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie) +{ + struct rbd_client_id cid = rbd_get_cid(rbd_dev); + + strcpy(rbd_dev->lock_cookie, cookie); + rbd_set_owner_cid(rbd_dev, &cid); + queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work); +} + /* * lock_rwsem must be held for write */ static int rbd_lock(struct rbd_device *rbd_dev) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; - struct rbd_client_id cid = rbd_get_cid(rbd_dev); char cookie[32]; int ret; @@ -3095,9 +3103,7 @@ static int rbd_lock(struct rbd_device *rbd_dev) return ret; rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED; - strcpy(rbd_dev->lock_cookie, cookie); - rbd_set_owner_cid(rbd_dev, &cid); - queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work); + __rbd_lock(rbd_dev, cookie); return 0; } @@ -3883,7 +3889,7 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev) queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0); } else { - strcpy(rbd_dev->lock_cookie, cookie); + __rbd_lock(rbd_dev, cookie); } } @@ -4415,7 +4421,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) segment_size = rbd_obj_bytes(&rbd_dev->header); blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE); q->limits.max_sectors = queue_max_hw_sectors(q); - blk_queue_max_segments(q, segment_size / SECTOR_SIZE); + blk_queue_max_segments(q, USHRT_MAX); blk_queue_max_segment_size(q, segment_size); blk_queue_io_min(q, segment_size); blk_queue_io_opt(q, segment_size); diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index d00c4fdae9243..bd810d01538ab 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -26,6 +26,7 @@ struct btqcomsmd { struct hci_dev *hdev; + bdaddr_t bdaddr; struct rpmsg_endpoint *acl_channel; struct rpmsg_endpoint *cmd_channel; }; @@ -100,6 +101,38 @@ static int btqcomsmd_close(struct hci_dev *hdev) return 0; } +static int btqcomsmd_setup(struct hci_dev *hdev) +{ + struct btqcomsmd *btq = hci_get_drvdata(hdev); + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + kfree_skb(skb); + + /* Devices do not have persistent storage for BD address. If no + * BD address has been retrieved during probe, mark the device + * as having an invalid BD address. + */ + if (!bacmp(&btq->bdaddr, BDADDR_ANY)) { + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + return 0; + } + + /* When setting a configured BD address fails, mark the device + * as having an invalid BD address. + */ + err = qca_set_bdaddr_rome(hdev, &btq->bdaddr); + if (err) { + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + return 0; + } + + return 0; +} + static int btqcomsmd_probe(struct platform_device *pdev) { struct btqcomsmd *btq; @@ -135,6 +168,7 @@ static int btqcomsmd_probe(struct platform_device *pdev) hdev->open = btqcomsmd_open; hdev->close = btqcomsmd_close; hdev->send = btqcomsmd_send; + hdev->setup = btqcomsmd_setup; hdev->set_bdaddr = qca_set_bdaddr_rome; ret = hci_register_dev(hdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7a5c06aaa1810..513a7a59d421e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -272,6 +272,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index e2540113d0dac..73d2d88ddc039 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -68,7 +68,7 @@ struct bcm_device { u32 init_speed; u32 oper_speed; int irq; - u8 irq_polarity; + bool irq_active_low; #ifdef CONFIG_PM struct hci_uart *hu; @@ -213,7 +213,9 @@ static int bcm_request_irq(struct bcm_data *bcm) } err = devm_request_irq(&bdev->pdev->dev, bdev->irq, bcm_host_wake, - IRQF_TRIGGER_RISING, "host_wake", bdev); + bdev->irq_active_low ? IRQF_TRIGGER_FALLING : + IRQF_TRIGGER_RISING, + "host_wake", bdev); if (err) goto unlock; @@ -253,7 +255,7 @@ static int bcm_setup_sleep(struct hci_uart *hu) struct sk_buff *skb; struct bcm_set_sleep_mode sleep_params = default_sleep_params; - sleep_params.host_wake_active = !bcm->dev->irq_polarity; + sleep_params.host_wake_active = !bcm->dev->irq_active_low; skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params), &sleep_params, HCI_INIT_TIMEOUT); @@ -690,10 +692,8 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { }; #ifdef CONFIG_ACPI -static u8 acpi_active_low = ACPI_ACTIVE_LOW; - /* IRQ polarity of some chipsets are not defined correctly in ACPI table. */ -static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { +static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = { { .ident = "Asus T100TA", .matches = { @@ -701,7 +701,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), }, - .driver_data = &acpi_active_low, }, { .ident = "Asus T100CHI", @@ -710,7 +709,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"), }, - .driver_data = &acpi_active_low, }, { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ .ident = "Lenovo ThinkPad 8", @@ -718,7 +716,6 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), }, - .driver_data = &acpi_active_low, }, { } }; @@ -733,13 +730,13 @@ static int bcm_resource(struct acpi_resource *ares, void *data) switch (ares->type) { case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: irq = &ares->data.extended_irq; - dev->irq_polarity = irq->polarity; + dev->irq_active_low = irq->polarity == ACPI_ACTIVE_LOW; break; case ACPI_RESOURCE_TYPE_GPIO: gpio = &ares->data.gpio; if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) - dev->irq_polarity = gpio->polarity; + dev->irq_active_low = gpio->polarity == ACPI_ACTIVE_LOW; break; case ACPI_RESOURCE_TYPE_SERIAL_BUS: @@ -834,11 +831,11 @@ static int bcm_acpi_probe(struct bcm_device *dev) return ret; acpi_dev_free_resource_list(&resources); - dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table); + dmi_id = dmi_first_match(bcm_active_low_irq_dmi_table); if (dmi_id) { bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low", dmi_id->ident); - dev->irq_polarity = *(u8 *)dmi_id->driver_data; + dev->irq_active_low = true; } return 0; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index a746627e784e7..6aef3bde10d70 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -298,6 +299,12 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) unsigned int set = 0; unsigned int clear = 0; + if (hu->serdev) { + serdev_device_set_flow_control(hu->serdev, !enable); + serdev_device_set_rts(hu->serdev, !enable); + return; + } + if (enable) { /* Disable hardware flow control */ ktermios = tty->termios; @@ -510,13 +517,13 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); - cancel_work_sync(&hu->write_work); - if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { write_lock_irqsave(&hu->proto_lock, flags); clear_bit(HCI_UART_PROTO_READY, &hu->flags); write_unlock_irqrestore(&hu->proto_lock, flags); + cancel_work_sync(&hu->write_work); + if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 3c29d36702a8e..5426c04fe24bc 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -1755,14 +1755,17 @@ static int cci_pmu_probe(struct platform_device *pdev) raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock); mutex_init(&cci_pmu->reserve_mutex); atomic_set(&cci_pmu->active_events, 0); - cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus); + cpumask_set_cpu(get_cpu(), &cci_pmu->cpus); ret = cci_pmu_init(cci_pmu, pdev); - if (ret) + if (ret) { + put_cpu(); return ret; + } cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_CCI_ONLINE, &cci_pmu->node); + put_cpu(); pr_info("ARM %s PMU driver probed", cci_pmu->model->name); return 0; } diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index e8c6946fed9d2..72fd1750134d2 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -1271,11 +1271,16 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) int len = snprintf(NULL, 0, "ccn_%d", ccn->dt.id); name = devm_kzalloc(ccn->dev, len + 1, GFP_KERNEL); + if (!name) { + err = -ENOMEM; + goto error_choose_name; + } snprintf(name, len + 1, "ccn_%d", ccn->dt.id); } /* Perf driver registration */ ccn->dt.pmu = (struct pmu) { + .module = THIS_MODULE, .attr_groups = arm_ccn_pmu_attr_groups, .task_ctx_nr = perf_invalid_context, .event_init = arm_ccn_pmu_event_init, @@ -1297,7 +1302,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) } /* Pick one CPU which we will use to collect data from CCN... */ - cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu); + cpumask_set_cpu(get_cpu(), &ccn->dt.cpu); /* Also make sure that the overflow interrupt is handled by this CPU */ if (ccn->irq) { @@ -1314,10 +1319,13 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE, &ccn->dt.node); + put_cpu(); return 0; error_pmu_register: error_set_affinity: + put_cpu(); +error_choose_name: ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id); for (i = 0; i < ccn->num_xps; i++) writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); @@ -1580,8 +1588,8 @@ static int __init arm_ccn_init(void) static void __exit arm_ccn_exit(void) { - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_CCN_ONLINE); platform_driver_unregister(&arm_ccn_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_CCN_ONLINE); } module_init(arm_ccn_init); diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 328ca93781cf2..1b76d95859027 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -178,6 +178,7 @@ static struct bus_type sunxi_rsb_bus = { .match = sunxi_rsb_device_match, .probe = sunxi_rsb_device_probe, .remove = sunxi_rsb_device_remove, + .uevent = of_device_uevent_modalias, }; static void sunxi_rsb_dev_release(struct device *dev) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 810b138f5897b..c82d9fd2f05af 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4030,7 +4030,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, } static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, - struct list_head *timeouts, long timeout_period, + struct list_head *timeouts, + unsigned long timeout_period, int slot, unsigned long *flags, unsigned int *waiting_msgs) { @@ -4043,8 +4044,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, if (!ent->inuse) return; - ent->timeout -= timeout_period; - if (ent->timeout > 0) { + if (timeout_period < ent->timeout) { + ent->timeout -= timeout_period; (*waiting_msgs)++; return; } @@ -4110,7 +4111,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, } } -static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period) +static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, + unsigned long timeout_period) { struct list_head timeouts; struct ipmi_recv_msg *msg, *msg2; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 36f47e8d06a3b..c04aa11f0e214 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -242,6 +242,9 @@ struct smi_info { /* The timer for this si. */ struct timer_list si_timer; + /* This flag is set, if the timer can be set */ + bool timer_can_start; + /* This flag is set, if the timer is running (timer_pending() isn't enough) */ bool timer_running; @@ -417,6 +420,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) { + if (!smi_info->timer_can_start) + return; smi_info->last_timeout_jiffies = jiffies; mod_timer(&smi_info->si_timer, new_val); smi_info->timer_running = true; @@ -436,21 +441,18 @@ static void start_new_msg(struct smi_info *smi_info, unsigned char *msg, smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); } -static void start_check_enables(struct smi_info *smi_info, bool start_timer) +static void start_check_enables(struct smi_info *smi_info) { unsigned char msg[2]; msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; - if (start_timer) - start_new_msg(smi_info, msg, 2); - else - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + start_new_msg(smi_info, msg, 2); smi_info->si_state = SI_CHECKING_ENABLES; } -static void start_clear_flags(struct smi_info *smi_info, bool start_timer) +static void start_clear_flags(struct smi_info *smi_info) { unsigned char msg[3]; @@ -459,10 +461,7 @@ static void start_clear_flags(struct smi_info *smi_info, bool start_timer) msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[2] = WDT_PRE_TIMEOUT_INT; - if (start_timer) - start_new_msg(smi_info, msg, 3); - else - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + start_new_msg(smi_info, msg, 3); smi_info->si_state = SI_CLEARING_FLAGS; } @@ -497,11 +496,11 @@ static void start_getting_events(struct smi_info *smi_info) * Note that we cannot just use disable_irq(), since the interrupt may * be shared. */ -static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) +static inline bool disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = true; - start_check_enables(smi_info, start_timer); + start_check_enables(smi_info); return true; } return false; @@ -511,7 +510,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = false; - start_check_enables(smi_info, true); + start_check_enables(smi_info); return true; } return false; @@ -529,7 +528,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) msg = ipmi_alloc_smi_msg(); if (!msg) { - if (!disable_si_irq(smi_info, true)) + if (!disable_si_irq(smi_info)) smi_info->si_state = SI_NORMAL; } else if (enable_si_irq(smi_info)) { ipmi_free_smi_msg(msg); @@ -545,7 +544,7 @@ static void handle_flags(struct smi_info *smi_info) /* Watchdog pre-timeout */ smi_inc_stat(smi_info, watchdog_pretimeouts); - start_clear_flags(smi_info, true); + start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; if (smi_info->intf) ipmi_smi_watchdog_pretimeout(smi_info->intf); @@ -928,7 +927,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, * disable and messages disabled. */ if (smi_info->supports_event_msg_buff || smi_info->irq) { - start_check_enables(smi_info, true); + start_check_enables(smi_info); } else { smi_info->curr_msg = alloc_msg_handle_irq(smi_info); if (!smi_info->curr_msg) @@ -1235,6 +1234,7 @@ static int smi_start_processing(void *send_info, /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); + new_smi->timer_can_start = true; smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); /* Try to claim any interrupts. */ @@ -3416,15 +3416,17 @@ static void check_for_broken_irqs(struct smi_info *smi_info) check_set_rcv_irq(smi_info); } -static inline void wait_for_timer_and_thread(struct smi_info *smi_info) +static inline void stop_timer_and_thread(struct smi_info *smi_info) { if (smi_info->thread != NULL) kthread_stop(smi_info->thread); + + smi_info->timer_can_start = false; if (smi_info->timer_running) del_timer_sync(&smi_info->si_timer); } -static int is_new_interface(struct smi_info *info) +static struct smi_info *find_dup_si(struct smi_info *info) { struct smi_info *e; @@ -3439,24 +3441,36 @@ static int is_new_interface(struct smi_info *info) */ if (info->slave_addr && !e->slave_addr) e->slave_addr = info->slave_addr; - return 0; + return e; } } - return 1; + return NULL; } static int add_smi(struct smi_info *new_smi) { int rv = 0; + struct smi_info *dup; mutex_lock(&smi_infos_lock); - if (!is_new_interface(new_smi)) { - pr_info(PFX "%s-specified %s state machine: duplicate\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type]); - rv = -EBUSY; - goto out_err; + dup = find_dup_si(new_smi); + if (dup) { + if (new_smi->addr_source == SI_ACPI && + dup->addr_source == SI_SMBIOS) { + /* We prefer ACPI over SMBIOS. */ + dev_info(dup->dev, + "Removing SMBIOS-specified %s state machine in favor of ACPI\n", + si_to_str[new_smi->si_type]); + cleanup_one_si(dup); + } else { + dev_info(new_smi->dev, + "%s-specified %s state machine: duplicate\n", + ipmi_addr_src_to_str(new_smi->addr_source), + si_to_str[new_smi->si_type]); + rv = -EBUSY; + goto out_err; + } } pr_info(PFX "Adding %s-specified %s state machine\n", @@ -3593,7 +3607,7 @@ static int try_smi_init(struct smi_info *new_smi) * Start clearing the flags before we enable interrupts or the * timer to avoid racing with the timer. */ - start_clear_flags(new_smi, false); + start_clear_flags(new_smi); /* * IRQ is defined to be set when non-zero. req_events will @@ -3662,7 +3676,7 @@ static int try_smi_init(struct smi_info *new_smi) return 0; out_err_stop_timer: - wait_for_timer_and_thread(new_smi); + stop_timer_and_thread(new_smi); out_err: new_smi->interrupt_disabled = true; @@ -3854,7 +3868,7 @@ static void cleanup_one_si(struct smi_info *to_clean) */ if (to_clean->irq_cleanup) to_clean->irq_cleanup(to_clean); - wait_for_timer_and_thread(to_clean); + stop_timer_and_thread(to_clean); /* * Timeouts are stopped, now make sure the interrupts are off @@ -3865,7 +3879,8 @@ static void cleanup_one_si(struct smi_info *to_clean) poll(to_clean); schedule_timeout_uninterruptible(1); } - disable_si_irq(to_clean, false); + if (to_clean->handlers) + disable_si_irq(to_clean); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 610638a80383d..461bf0b8a0947 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -110,6 +110,12 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, return -EFAULT; } + if (in_size < 6 || + in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) { + mutex_unlock(&priv->buffer_mutex); + return -EINVAL; + } + /* atomic tpm command send and result receive. We only hold the ops * lock during this period so that the tpm can be unregistered even if * the char dev is held open. diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index a94c3f56c5909..61c3e40507d31 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -384,7 +384,7 @@ static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg, mux_ops = div_ops = gate_ops = NULL; mux_hw = div_hw = gate_hw = NULL; - if (gcfg->mux && gcfg->mux) { + if (gcfg->mux && cfg->mux) { mux = _get_cmux(base + cfg->mux->offset, cfg->mux->shift, cfg->mux->width, @@ -410,7 +410,7 @@ static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg, } } - if (gcfg->gate && gcfg->gate) { + if (gcfg->gate && cfg->gate) { gate = _get_cgate(base + cfg->gate->offset, cfg->gate->bit_idx, gcfg->gate->flags, lock); diff --git a/drivers/clk/hisilicon/clk-hi3660.c b/drivers/clk/hisilicon/clk-hi3660.c index a18258eb89cb1..f404199596563 100644 --- a/drivers/clk/hisilicon/clk-hi3660.c +++ b/drivers/clk/hisilicon/clk-hi3660.c @@ -34,7 +34,7 @@ static const struct hisi_fixed_rate_clock hi3660_fixed_rate_clks[] = { /* crgctrl */ static const struct hisi_fixed_factor_clock hi3660_crg_fixed_factor_clks[] = { - { HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 8, 0, }, + { HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 16, 0, }, { HI3660_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys", 1, 6, 0, }, { HI3660_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_iomcu", 1, 4, 0, }, { HI3660_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_iomcu", 1, 4, 0, }, diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index e786d717f75dc..a87809d4bd525 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -145,7 +145,7 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = { { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, }, { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, }, { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, }, - { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, }, + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x270, 12, 0, }, }; static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = { diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index c07df719b8a35..8d518ad5dc13e 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -761,7 +761,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); - clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4); + clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4); clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 2305699db4679..0ac9b30c8b906 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -797,7 +797,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0); clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0); clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0); - clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "axi_post_div", base + 0x4110, 0); + clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0); clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0); clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0); clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f5d6b70ce1893..210ce8e8025ee 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -216,6 +216,7 @@ struct mtk_pll_data { uint32_t pcw_reg; int pcw_shift; const struct mtk_pll_div_table *div_table; + const char *parent_name; }; void mtk_clk_register_plls(struct device_node *node, diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index a409142e93462..7598477ff60f1 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -303,7 +303,10 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, init.name = data->name; init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; init.ops = &mtk_pll_ops; - init.parent_names = &parent_name; + if (data->parent_name) + init.parent_names = &data->parent_name; + else + init.parent_names = &parent_name; init.num_parents = 1; clk = clk_register(NULL, &pll->hw); diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index d523991c945f9..28ceaf1e99371 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -143,8 +143,10 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, int ret; clocks_node = of_find_node_by_path("/clocks"); - if (clocks_node) - node = of_find_node_by_name(clocks_node, path); + if (clocks_node) { + node = of_get_child_by_name(clocks_node, path); + of_node_put(clocks_node); + } if (!node) { fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL); diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index ab9e850b37078..2f385a57cd911 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -982,8 +982,8 @@ static void __init sun5i_ccu_init(struct device_node *node, /* Force the PLL-Audio-1x divider to 4 */ val = readl(reg + SUN5I_PLL_AUDIO_REG); - val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN5I_PLL_AUDIO_REG); + val &= ~GENMASK(29, 26); + writel(val | (3 << 26), reg + SUN5I_PLL_AUDIO_REG); /* * Use the peripheral PLL as the AHB parent, instead of CPU / diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 8af434815fba9..241fb13f1c061 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -608,7 +608,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents, 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); -static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0); +static SUNXI_CCU_GATE(hdmi_ddc_clk, "ddc", "osc24M", 0x150, BIT(30), 0); static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index e43acebdfbcdb..f8203115a6bce 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -354,9 +354,9 @@ static SUNXI_CCU_GATE(bus_tdm_clk, "bus-tdm", "apb1", static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x06c, BIT(0), 0); static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", - 0x06c, BIT(0), 0); + 0x06c, BIT(1), 0); static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", - 0x06c, BIT(0), 0); + 0x06c, BIT(2), 0); static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x06c, BIT(16), 0); static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index a32158e8f2e35..84a5e7f17f6f5 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -99,6 +99,9 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nm *nm = hw_to_ccu_nm(hw); struct _ccu_nm _nm; + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) + return rate; + _nm.min_n = nm->n.min ?: 1; _nm.max_n = nm->n.max ?: 1 << nm->n.width; _nm.min_m = 1; diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c index 6041bdba2e971..f69f9e8c6f380 100644 --- a/drivers/clk/sunxi/clk-sun9i-mmc.c +++ b/drivers/clk/sunxi/clk-sun9i-mmc.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -83,9 +84,20 @@ static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev, return 0; } +static int sun9i_mmc_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + sun9i_mmc_reset_assert(rcdev, id); + udelay(10); + sun9i_mmc_reset_deassert(rcdev, id); + + return 0; +} + static const struct reset_control_ops sun9i_mmc_reset_ops = { .assert = sun9i_mmc_reset_assert, .deassert = sun9i_mmc_reset_deassert, + .reset = sun9i_mmc_reset_reset, }; static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev) diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 6d7a613f2656a..b92867814e2d5 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2566,8 +2566,8 @@ static int tegra210_enable_pllu(void) reg |= PLL_ENABLE; writel(reg, clk_base + PLLU_BASE); - readl_relaxed_poll_timeout(clk_base + PLLU_BASE, reg, - reg & PLL_BASE_LOCK, 2, 1000); + readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg, + reg & PLL_BASE_LOCK, 2, 1000); if (!(reg & PLL_BASE_LOCK)) { pr_err("Timed out waiting for PLL_U to lock\n"); return -ETIMEDOUT; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index a2d163f759b45..07f5203df01c0 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -964,7 +964,7 @@ static void __init tegra30_super_clk_init(void) * U71 divider of cclk_lp. */ clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", - clk_base + SUPER_CCLKG_DIVIDER, 0, + clk_base + SUPER_CCLKLP_DIVIDER, 0, TEGRA_DIVIDER_INT, 16, 8, 1, NULL); clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 13eb04f72389b..1488154704313 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -274,8 +274,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) /* Get configuration for the ATL instances */ snprintf(prop, sizeof(prop), "atl%u", i); - of_node_get(node); - cfg_node = of_find_node_by_name(node, prop); + cfg_node = of_get_child_by_name(node, prop); if (cfg_node) { ret = of_property_read_u32(cfg_node, "bws", &cdesc->bws); diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 07f3b91a7daf3..d244e724e1985 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -123,7 +123,7 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("spll", -1, "ref", 120, 1), /* 2400 MHz */ UNIPHIER_CLK_FACTOR("dapll1", -1, "ref", 128, 1), /* 2560 MHz */ - UNIPHIER_CLK_FACTOR("dapll2", -1, "ref", 144, 125), /* 2949.12 MHz */ + UNIPHIER_CLK_FACTOR("dapll2", -1, "dapll1", 144, 125), /* 2949.12 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fd4b7f684bd03..14e2419063e93 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1268,10 +1268,6 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem) iounmap(cntctlbase); - if (!best_frame) - pr_err("Unable to find a suitable frame in timer @ %pa\n", - &timer_mem->cntctlbase); - return best_frame; } @@ -1372,6 +1368,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np) frame = arch_timer_mem_find_best_frame(timer_mem); if (!frame) { + pr_err("Unable to find a suitable frame in timer @ %pa\n", + &timer_mem->cntctlbase); ret = -EINVAL; goto out; } @@ -1420,7 +1418,7 @@ arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem) static int __init arch_timer_mem_acpi_init(int platform_timer_count) { struct arch_timer_mem *timers, *timer; - struct arch_timer_mem_frame *frame; + struct arch_timer_mem_frame *frame, *best_frame = NULL; int timer_count, i, ret = 0; timers = kcalloc(platform_timer_count, sizeof(*timers), @@ -1432,14 +1430,6 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count) if (ret || !timer_count) goto out; - for (i = 0; i < timer_count; i++) { - ret = arch_timer_mem_verify_cntfrq(&timers[i]); - if (ret) { - pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); - goto out; - } - } - /* * While unlikely, it's theoretically possible that none of the frames * in a timer expose the combination of feature we want. @@ -1448,12 +1438,26 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count) timer = &timers[i]; frame = arch_timer_mem_find_best_frame(timer); - if (frame) - break; + if (!best_frame) + best_frame = frame; + + ret = arch_timer_mem_verify_cntfrq(timer); + if (ret) { + pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); + goto out; + } + + if (!best_frame) /* implies !frame */ + /* + * Only complain about missing suitable frames if we + * haven't already found one in a previous iteration. + */ + pr_err("Unable to find a suitable frame in timer @ %pa\n", + &timer->cntctlbase); } - if (frame) - ret = arch_timer_mem_frame_register(frame); + if (best_frame) + ret = arch_timer_mem_frame_register(best_frame); out: kfree(timers); return ret; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 58d4f4e1ad6a9..ca38229b045ab 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -22,6 +22,8 @@ #include "cpufreq_governor.h" +#define CPUFREQ_DBS_MIN_SAMPLING_INTERVAL (2 * TICK_NSEC / NSEC_PER_USEC) + static DEFINE_PER_CPU(struct cpu_dbs_info, cpu_dbs); static DEFINE_MUTEX(gov_dbs_data_mutex); @@ -47,11 +49,15 @@ ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf, { struct dbs_data *dbs_data = to_dbs_data(attr_set); struct policy_dbs_info *policy_dbs; + unsigned int sampling_interval; int ret; - ret = sscanf(buf, "%u", &dbs_data->sampling_rate); - if (ret != 1) + + ret = sscanf(buf, "%u", &sampling_interval); + if (ret != 1 || sampling_interval < CPUFREQ_DBS_MIN_SAMPLING_INTERVAL) return -EINVAL; + dbs_data->sampling_rate = sampling_interval; + /* * We are operating under dbs_data->mutex and so the list and its * entries can't be freed concurrently. @@ -430,7 +436,14 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) if (ret) goto free_policy_dbs_info; - dbs_data->sampling_rate = cpufreq_policy_transition_delay_us(policy); + /* + * The sampling interval should not be less than the transition latency + * of the CPU and it also cannot be too small for dbs_update() to work + * correctly. + */ + dbs_data->sampling_rate = max_t(unsigned int, + CPUFREQ_DBS_MIN_SAMPLING_INTERVAL, + cpufreq_policy_transition_delay_us(policy)); if (!have_governor_per_policy()) gov->gdbs_data = dbs_data; diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 52a75053ee031..f47c545467522 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -104,13 +104,13 @@ static int __init arm_idle_init(void) ret = dt_init_idle_driver(drv, arm_idle_state_match, 1); if (ret <= 0) { ret = ret ? : -ENODEV; - goto init_fail; + goto out_kfree_drv; } ret = cpuidle_register_driver(drv); if (ret) { pr_err("Failed to register cpuidle driver\n"); - goto init_fail; + goto out_kfree_drv; } /* @@ -128,14 +128,14 @@ static int __init arm_idle_init(void) if (ret) { pr_err("CPU %d failed to init idle CPU ops\n", cpu); - goto out_fail; + goto out_unregister_drv; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { pr_err("Failed to allocate cpuidle device\n"); ret = -ENOMEM; - goto out_fail; + goto out_unregister_drv; } dev->cpu = cpu; @@ -143,21 +143,25 @@ static int __init arm_idle_init(void) if (ret) { pr_err("Failed to register cpuidle device for CPU %d\n", cpu); - kfree(dev); - goto out_fail; + goto out_kfree_dev; } } return 0; -init_fail: + +out_kfree_dev: + kfree(dev); +out_unregister_drv: + cpuidle_unregister_driver(drv); +out_kfree_drv: kfree(drv); out_fail: while (--cpu >= 0) { dev = per_cpu(cpuidle_devices, cpu); + drv = cpuidle_get_cpu_driver(dev); cpuidle_unregister_device(dev); - kfree(dev); - drv = cpuidle_get_driver(); cpuidle_unregister_driver(drv); + kfree(dev); kfree(drv); } diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index ed6531f075c62..e06605b21841a 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -384,9 +384,9 @@ static int powernv_add_idle_states(void) * Firmware passes residency and latency values in ns. * cpuidle expects it in us. */ - exit_latency = latency_ns[i] / 1000; + exit_latency = DIV_ROUND_UP(latency_ns[i], 1000); if (!rc) - target_residency = residency_ns[i] / 1000; + target_residency = DIV_ROUND_UP(residency_ns[i], 1000); else target_residency = 0; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 484cc8909d5c3..ed4df58a855e1 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -208,6 +208,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, return -EBUSY; } target_state = &drv->states[index]; + broadcast = false; } /* Take note of the planned idle state. */ diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index ecfdcfe3698d6..4f41d6da5acca 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -34,12 +34,12 @@ #define PPC405EX_CE_RESET 0x00000008 #define CRYPTO4XX_CRYPTO_PRIORITY 300 -#define PPC4XX_LAST_PD 63 -#define PPC4XX_NUM_PD 64 -#define PPC4XX_LAST_GD 1023 +#define PPC4XX_NUM_PD 256 +#define PPC4XX_LAST_PD (PPC4XX_NUM_PD - 1) #define PPC4XX_NUM_GD 1024 -#define PPC4XX_LAST_SD 63 -#define PPC4XX_NUM_SD 64 +#define PPC4XX_LAST_GD (PPC4XX_NUM_GD - 1) +#define PPC4XX_NUM_SD 256 +#define PPC4XX_LAST_SD (PPC4XX_NUM_SD - 1) #define PPC4XX_SD_BUFFER_SIZE 2048 #define PD_ENTRY_INUSE 1 diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 8685c7e4debdc..ee52c355bee0a 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -256,6 +256,44 @@ spu_ablkcipher_tx_sg_create(struct brcm_message *mssg, return 0; } +static int mailbox_send_message(struct brcm_message *mssg, u32 flags, + u8 chan_idx) +{ + int err; + int retry_cnt = 0; + struct device *dev = &(iproc_priv.pdev->dev); + + err = mbox_send_message(iproc_priv.mbox[chan_idx], mssg); + if (flags & CRYPTO_TFM_REQ_MAY_SLEEP) { + while ((err == -ENOBUFS) && (retry_cnt < SPU_MB_RETRY_MAX)) { + /* + * Mailbox queue is full. Since MAY_SLEEP is set, assume + * not in atomic context and we can wait and try again. + */ + retry_cnt++; + usleep_range(MBOX_SLEEP_MIN, MBOX_SLEEP_MAX); + err = mbox_send_message(iproc_priv.mbox[chan_idx], + mssg); + atomic_inc(&iproc_priv.mb_no_spc); + } + } + if (err < 0) { + atomic_inc(&iproc_priv.mb_send_fail); + return err; + } + + /* Check error returned by mailbox controller */ + err = mssg->error; + if (unlikely(err < 0)) { + dev_err(dev, "message error %d", err); + /* Signal txdone for mailbox channel */ + } + + /* Signal txdone for mailbox channel */ + mbox_client_txdone(iproc_priv.mbox[chan_idx], err); + return err; +} + /** * handle_ablkcipher_req() - Submit as much of a block cipher request as fits in * a single SPU request message, starting at the current position in the request @@ -293,7 +331,6 @@ static int handle_ablkcipher_req(struct iproc_reqctx_s *rctx) u32 pad_len; /* total length of all padding */ bool update_key = false; struct brcm_message *mssg; /* mailbox message */ - int retry_cnt = 0; /* number of entries in src and dst sg in mailbox message. */ u8 rx_frag_num = 2; /* response header and STATUS */ @@ -462,24 +499,9 @@ static int handle_ablkcipher_req(struct iproc_reqctx_s *rctx) if (err) return err; - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], mssg); - if (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) { - while ((err == -ENOBUFS) && (retry_cnt < SPU_MB_RETRY_MAX)) { - /* - * Mailbox queue is full. Since MAY_SLEEP is set, assume - * not in atomic context and we can wait and try again. - */ - retry_cnt++; - usleep_range(MBOX_SLEEP_MIN, MBOX_SLEEP_MAX); - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], - mssg); - atomic_inc(&iproc_priv.mb_no_spc); - } - } - if (unlikely(err < 0)) { - atomic_inc(&iproc_priv.mb_send_fail); + err = mailbox_send_message(mssg, req->base.flags, rctx->chan_idx); + if (unlikely(err < 0)) return err; - } return -EINPROGRESS; } @@ -710,7 +732,6 @@ static int handle_ahash_req(struct iproc_reqctx_s *rctx) u32 spu_hdr_len; unsigned int digestsize; u16 rem = 0; - int retry_cnt = 0; /* * number of entries in src and dst sg. Always includes SPU msg header. @@ -904,24 +925,10 @@ static int handle_ahash_req(struct iproc_reqctx_s *rctx) if (err) return err; - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], mssg); - if (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) { - while ((err == -ENOBUFS) && (retry_cnt < SPU_MB_RETRY_MAX)) { - /* - * Mailbox queue is full. Since MAY_SLEEP is set, assume - * not in atomic context and we can wait and try again. - */ - retry_cnt++; - usleep_range(MBOX_SLEEP_MIN, MBOX_SLEEP_MAX); - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], - mssg); - atomic_inc(&iproc_priv.mb_no_spc); - } - } - if (err < 0) { - atomic_inc(&iproc_priv.mb_send_fail); + err = mailbox_send_message(mssg, req->base.flags, rctx->chan_idx); + if (unlikely(err < 0)) return err; - } + return -EINPROGRESS; } @@ -1320,7 +1327,6 @@ static int handle_aead_req(struct iproc_reqctx_s *rctx) int assoc_nents = 0; bool incl_icv = false; unsigned int digestsize = ctx->digestsize; - int retry_cnt = 0; /* number of entries in src and dst sg. Always includes SPU msg header. */ @@ -1558,24 +1564,9 @@ static int handle_aead_req(struct iproc_reqctx_s *rctx) if (err) return err; - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], mssg); - if (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) { - while ((err == -ENOBUFS) && (retry_cnt < SPU_MB_RETRY_MAX)) { - /* - * Mailbox queue is full. Since MAY_SLEEP is set, assume - * not in atomic context and we can wait and try again. - */ - retry_cnt++; - usleep_range(MBOX_SLEEP_MIN, MBOX_SLEEP_MAX); - err = mbox_send_message(iproc_priv.mbox[rctx->chan_idx], - mssg); - atomic_inc(&iproc_priv.mb_no_spc); - } - } - if (err < 0) { - atomic_inc(&iproc_priv.mb_send_fail); + err = mailbox_send_message(mssg, req->base.flags, rctx->chan_idx); + if (unlikely(err < 0)) return err; - } return -EINPROGRESS; } @@ -4537,7 +4528,7 @@ static int spu_mb_init(struct device *dev) mcl->dev = dev; mcl->tx_block = false; mcl->tx_tout = 0; - mcl->knows_txdone = false; + mcl->knows_txdone = true; mcl->rx_callback = spu_rx_callback; mcl->tx_done = NULL; diff --git a/drivers/crypto/chelsio/Kconfig b/drivers/crypto/chelsio/Kconfig index 3e104f5aa0c2f..b56b3f711d941 100644 --- a/drivers/crypto/chelsio/Kconfig +++ b/drivers/crypto/chelsio/Kconfig @@ -5,6 +5,7 @@ config CRYPTO_DEV_CHELSIO select CRYPTO_SHA256 select CRYPTO_SHA512 select CRYPTO_AUTHENC + select CRYPTO_GF128MUL ---help--- The Chelsio Crypto Co-processor driver for T6 adapters. diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index a9fd8b9e86cde..699ee5a9a8f99 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1625,6 +1625,7 @@ static int queue_cache_init(void) CWQ_ENTRY_SIZE, 0, NULL); if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; return -ENOMEM; } return 0; @@ -1634,6 +1635,8 @@ static void queue_cache_destroy(void) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; + queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL; } static long spu_queue_register_workfn(void *arg) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index dff88838dce76..a19b5d0300a95 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1232,12 +1232,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sg_link_tbl_len += authsize; } - sg_count = talitos_sg_map(dev, areq->src, cryptlen, edesc, - &desc->ptr[4], sg_count, areq->assoclen, - tbl_off); + ret = talitos_sg_map(dev, areq->src, sg_link_tbl_len, edesc, + &desc->ptr[4], sg_count, areq->assoclen, tbl_off); - if (sg_count > 1) { - tbl_off += sg_count; + if (ret > 1) { + tbl_off += ret; sync_needed = true; } @@ -1248,14 +1247,15 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, dma_map_sg(dev, areq->dst, sg_count, DMA_FROM_DEVICE); } - sg_count = talitos_sg_map(dev, areq->dst, cryptlen, edesc, - &desc->ptr[5], sg_count, areq->assoclen, - tbl_off); + ret = talitos_sg_map(dev, areq->dst, cryptlen, edesc, &desc->ptr[5], + sg_count, areq->assoclen, tbl_off); if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1); - if (sg_count > 1) { + /* ICV data */ + if (ret > 1) { + tbl_off += ret; edesc->icv_ool = true; sync_needed = true; @@ -1265,9 +1265,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sizeof(struct talitos_ptr) + authsize; /* Add an entry to the link table for ICV data */ - tbl_ptr += sg_count - 1; - to_talitos_ptr_ext_set(tbl_ptr, 0, is_sec1); - tbl_ptr++; + to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1); to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RETURN, is_sec1); to_talitos_ptr_len(tbl_ptr, authsize, is_sec1); @@ -1275,18 +1273,33 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, /* icv data follows link tables */ to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + offset, is_sec1); + } else { + dma_addr_t addr = edesc->dma_link_tbl; + + if (is_sec1) + addr += areq->assoclen + cryptlen; + else + addr += sizeof(struct talitos_ptr) * tbl_off; + + to_talitos_ptr(&desc->ptr[6], addr, is_sec1); + to_talitos_ptr_len(&desc->ptr[6], authsize, is_sec1); + } + } else if (!(desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)) { + ret = talitos_sg_map(dev, areq->dst, authsize, edesc, + &desc->ptr[6], sg_count, areq->assoclen + + cryptlen, + tbl_off); + if (ret > 1) { + tbl_off += ret; + edesc->icv_ool = true; + sync_needed = true; + } else { + edesc->icv_ool = false; } } else { edesc->icv_ool = false; } - /* ICV data */ - if (!(desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)) { - to_talitos_ptr_len(&desc->ptr[6], authsize, is_sec1); - to_talitos_ptr(&desc->ptr[6], edesc->dma_link_tbl + - areq->assoclen + cryptlen, is_sec1); - } - /* iv out */ if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, @@ -1494,12 +1507,20 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + u32 tmp[DES_EXPKEY_WORDS]; if (keylen > TALITOS_MAX_KEY_SIZE) { crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } + if (unlikely(crypto_ablkcipher_get_flags(cipher) & + CRYPTO_TFM_REQ_WEAK_KEY) && + !des_ekey(tmp, key)) { + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_WEAK_KEY); + return -EINVAL; + } + memcpy(&ctx->key, key, keylen); ctx->keylen = keylen; @@ -2614,7 +2635,7 @@ static struct talitos_alg_template driver_algs[] = { .ivsize = AES_BLOCK_SIZE, } }, - .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + .desc_hdr_template = DESC_HDR_TYPE_AESU_CTR_NONSNOOP | DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_AESU_CTR, }, @@ -3047,6 +3068,11 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, t_alg->algt.alg.aead.setkey = aead_setkey; t_alg->algt.alg.aead.encrypt = aead_encrypt; t_alg->algt.alg.aead.decrypt = aead_decrypt; + if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) && + !strncmp(alg->cra_name, "authenc(hmac(sha224)", 20)) { + kfree(t_alg); + return ERR_PTR(-ENOTSUPP); + } break; case CRYPTO_ALG_TYPE_AHASH: alg = &t_alg->algt.alg.hash.halg.base; diff --git a/drivers/dax/device.c b/drivers/dax/device.c index e9f3b3e4bbf45..7b0bf825c4e73 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -222,7 +222,8 @@ __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, unsigned long size) { struct resource *res; - phys_addr_t phys; + /* gcc-4.6.3-nolibc for i386 complains that this is uninitialized */ + phys_addr_t uninitialized_var(phys); int i; for (i = 0; i < dev_dax->num_resources; i++) { @@ -427,9 +428,21 @@ static int dev_dax_fault(struct vm_fault *vmf) return dev_dax_huge_fault(vmf, PE_SIZE_PTE); } +static int dev_dax_split(struct vm_area_struct *vma, unsigned long addr) +{ + struct file *filp = vma->vm_file; + struct dev_dax *dev_dax = filp->private_data; + struct dax_region *dax_region = dev_dax->region; + + if (!IS_ALIGNED(addr, dax_region->align)) + return -EINVAL; + return 0; +} + static const struct vm_operations_struct dax_vm_ops = { .fault = dev_dax_fault, .huge_fault = dev_dax_huge_fault, + .split = dev_dax_split, }; static int dax_mmap(struct file *filp, struct vm_area_struct *vma) diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 557b937035328..c4cd034a38205 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -344,6 +344,9 @@ static struct inode *dax_alloc_inode(struct super_block *sb) struct inode *inode; dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL); + if (!dax_dev) + return NULL; + inode = &dax_dev->inode; inode->i_rdev = 0; return inode; diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index dec3a815455d6..b44d9d7db347b 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -266,8 +266,7 @@ EXPORT_SYMBOL(reservation_object_add_excl_fence); * @dst: the destination reservation object * @src: the source reservation object * -* Copy all fences from src to dst. Both src->lock as well as dst-lock must be -* held. +* Copy all fences from src to dst. dst-lock must be held. */ int reservation_object_copy_fences(struct reservation_object *dst, struct reservation_object *src) @@ -277,33 +276,62 @@ int reservation_object_copy_fences(struct reservation_object *dst, size_t size; unsigned i; - src_list = reservation_object_get_list(src); + rcu_read_lock(); + src_list = rcu_dereference(src->fence); +retry: if (src_list) { - size = offsetof(typeof(*src_list), - shared[src_list->shared_count]); + unsigned shared_count = src_list->shared_count; + + size = offsetof(typeof(*src_list), shared[shared_count]); + rcu_read_unlock(); + dst_list = kmalloc(size, GFP_KERNEL); if (!dst_list) return -ENOMEM; - dst_list->shared_count = src_list->shared_count; - dst_list->shared_max = src_list->shared_count; - for (i = 0; i < src_list->shared_count; ++i) - dst_list->shared[i] = - dma_fence_get(src_list->shared[i]); + rcu_read_lock(); + src_list = rcu_dereference(src->fence); + if (!src_list || src_list->shared_count > shared_count) { + kfree(dst_list); + goto retry; + } + + dst_list->shared_count = 0; + dst_list->shared_max = shared_count; + for (i = 0; i < src_list->shared_count; ++i) { + struct dma_fence *fence; + + fence = rcu_dereference(src_list->shared[i]); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, + &fence->flags)) + continue; + + if (!dma_fence_get_rcu(fence)) { + kfree(dst_list); + src_list = rcu_dereference(src->fence); + goto retry; + } + + if (dma_fence_is_signaled(fence)) { + dma_fence_put(fence); + continue; + } + + dst_list->shared[dst_list->shared_count++] = fence; + } } else { dst_list = NULL; } + new = dma_fence_get_rcu_safe(&src->fence_excl); + rcu_read_unlock(); + kfree(dst->staged); dst->staged = NULL; src_list = reservation_object_get_list(dst); - old = reservation_object_get_excl(dst); - new = reservation_object_get_excl(src); - - dma_fence_get(new); preempt_disable(); write_seqcount_begin(&dst->seq); diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 38cc7389a6c17..24f83f9eeaedc 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -321,8 +321,16 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) static int sw_sync_debugfs_release(struct inode *inode, struct file *file) { struct sync_timeline *obj = file->private_data; + struct sync_pt *pt, *next; + + spin_lock_irq(&obj->lock); + + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { + dma_fence_set_error(&pt->base, -ENOENT); + dma_fence_signal_locked(&pt->base); + } - smp_wmb(); + spin_unlock_irq(&obj->lock); sync_timeline_put(obj); return 0; diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 34ff53290b037..ec5f9d2bc8202 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -155,6 +155,12 @@ MODULE_PARM_DESC(run, "Run the test (default: false)"); #define PATTERN_COUNT_MASK 0x1f #define PATTERN_MEMSET_IDX 0x01 +/* poor man's completion - we want to use wait_event_freezable() on it */ +struct dmatest_done { + bool done; + wait_queue_head_t *wait; +}; + struct dmatest_thread { struct list_head node; struct dmatest_info *info; @@ -165,6 +171,8 @@ struct dmatest_thread { u8 **dsts; u8 **udsts; enum dma_transaction_type type; + wait_queue_head_t done_wait; + struct dmatest_done test_done; bool done; }; @@ -342,18 +350,25 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start, return error_count; } -/* poor man's completion - we want to use wait_event_freezable() on it */ -struct dmatest_done { - bool done; - wait_queue_head_t *wait; -}; static void dmatest_callback(void *arg) { struct dmatest_done *done = arg; - - done->done = true; - wake_up_all(done->wait); + struct dmatest_thread *thread = + container_of(arg, struct dmatest_thread, done_wait); + if (!thread->done) { + done->done = true; + wake_up_all(done->wait); + } else { + /* + * If thread->done, it means that this callback occurred + * after the parent thread has cleaned up. This can + * happen in the case that driver doesn't implement + * the terminate_all() functionality and a dma operation + * did not occur within the timeout period + */ + WARN(1, "dmatest: Kernel memory may be corrupted!!\n"); + } } static unsigned int min_odd(unsigned int x, unsigned int y) @@ -424,9 +439,8 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len) */ static int dmatest_func(void *data) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait); struct dmatest_thread *thread = data; - struct dmatest_done done = { .wait = &done_wait }; + struct dmatest_done *done = &thread->test_done; struct dmatest_info *info; struct dmatest_params *params; struct dma_chan *chan; @@ -673,9 +687,9 @@ static int dmatest_func(void *data) continue; } - done.done = false; + done->done = false; tx->callback = dmatest_callback; - tx->callback_param = &done; + tx->callback_param = done; cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { @@ -688,20 +702,12 @@ static int dmatest_func(void *data) } dma_async_issue_pending(chan); - wait_event_freezable_timeout(done_wait, done.done, + wait_event_freezable_timeout(thread->done_wait, done->done, msecs_to_jiffies(params->timeout)); status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); - if (!done.done) { - /* - * We're leaving the timed out dma operation with - * dangling pointer to done_wait. To make this - * correct, we'll need to allocate wait_done for - * each test iteration and perform "who's gonna - * free it this time?" dancing. For now, just - * leave it dangling. - */ + if (!done->done) { dmaengine_unmap_put(um); result("test timed out", total_tests, src_off, dst_off, len, 0); @@ -788,7 +794,7 @@ static int dmatest_func(void *data) dmatest_KBs(runtime, total_len), ret); /* terminate all transfers on specified channels */ - if (ret) + if (ret || failed_tests) dmaengine_terminate_all(chan); thread->done = true; @@ -848,6 +854,8 @@ static int dmatest_add_threads(struct dmatest_info *info, thread->info = info; thread->chan = dtc->chan; thread->type = type; + thread->test_done.wait = &thread->done_wait; + init_waitqueue_head(&thread->done_wait); smp_wmb(); thread->task = kthread_create(dmatest_func, thread, "%s-%s%u", dma_chan_name(chan), op, i); diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index f1d04b70ee672..7df910e7c3488 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -49,12 +49,12 @@ struct ti_am335x_xbar_data { struct ti_am335x_xbar_map { u16 dma_line; - u16 mux_val; + u8 mux_val; }; -static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val) +static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val) { - writeb_relaxed(val & 0x1f, iomem + event); + writeb_relaxed(val, iomem + event); } static void ti_am335x_xbar_free(struct device *dev, void *route_data) @@ -105,7 +105,7 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, } map->dma_line = (u16)dma_spec->args[0]; - map->mux_val = (u16)dma_spec->args[2]; + map->mux_val = (u8)dma_spec->args[2]; dma_spec->args[2] = 0; dma_spec->args_count = 2; diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index dc05916540116..cd9d6ba035791 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -462,6 +462,7 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = { static const struct pci_id_descr pci_dev_descr_ibridge[] = { /* Processor Home Agent */ { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0, IMC0) }, + { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1, IMC1) }, /* Memory controller */ { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0, IMC0) }, @@ -472,7 +473,6 @@ static const struct pci_id_descr pci_dev_descr_ibridge[] = { { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0, IMC0) }, /* Optional, mode 2HA */ - { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1, IMC1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1, IMC1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1, IMC1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1, IMC1) }, @@ -2291,6 +2291,13 @@ static int sbridge_get_onedevice(struct pci_dev **prev, next_imc: sbridge_dev = get_sbridge_dev(bus, dev_descr->dom, multi_bus, sbridge_dev); if (!sbridge_dev) { + /* If the HA1 wasn't found, don't create EDAC second memory controller */ + if (dev_descr->dom == IMC1 && devno != 1) { + edac_dbg(0, "Skip IMC1: %04x:%04x (since HA1 was absent)\n", + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); + pci_dev_put(pdev); + return 0; + } if (dev_descr->dom == SOCK) goto out_imc; @@ -2491,6 +2498,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA: pvt->pci_ta = pdev; + break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS: case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS: pvt->pci_ras = pdev; diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index ec8ac5c4dd84f..055e2e8f985a3 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -20,10 +20,6 @@ #define NO_FURTHER_WRITE_ACTION -1 -#ifndef phys_to_page -#define phys_to_page(x) pfn_to_page((x) >> PAGE_SHIFT) -#endif - /** * efi_free_all_buff_pages - free all previous allocated buffer pages * @cap_info: pointer to current instance of capsule_info structure @@ -35,7 +31,7 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) { while (cap_info->index > 0) - __free_page(phys_to_page(cap_info->pages[--cap_info->index])); + __free_page(cap_info->pages[--cap_info->index]); cap_info->index = NO_FURTHER_WRITE_ACTION; } @@ -71,6 +67,14 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) cap_info->pages = temp_page; + temp_page = krealloc(cap_info->phys, + pages_needed * sizeof(phys_addr_t *), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; + + cap_info->phys = temp_page; + return 0; } @@ -105,9 +109,24 @@ int __weak efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff, **/ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) { + bool do_vunmap = false; int ret; - ret = efi_capsule_update(&cap_info->header, cap_info->pages); + /* + * cap_info->capsule may have been assigned already by a quirk + * handler, so only overwrite it if it is NULL + */ + if (!cap_info->capsule) { + cap_info->capsule = vmap(cap_info->pages, cap_info->index, + VM_MAP, PAGE_KERNEL); + if (!cap_info->capsule) + return -ENOMEM; + do_vunmap = true; + } + + ret = efi_capsule_update(cap_info->capsule, cap_info->phys); + if (do_vunmap) + vunmap(cap_info->capsule); if (ret) { pr_err("capsule update failed\n"); return ret; @@ -165,10 +184,12 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, goto failed; } - cap_info->pages[cap_info->index++] = page_to_phys(page); + cap_info->pages[cap_info->index] = page; + cap_info->phys[cap_info->index] = page_to_phys(page); cap_info->page_bytes_remain = PAGE_SIZE; + cap_info->index++; } else { - page = phys_to_page(cap_info->pages[cap_info->index - 1]); + page = cap_info->pages[cap_info->index - 1]; } kbuff = kmap(page); @@ -252,6 +273,7 @@ static int efi_capsule_release(struct inode *inode, struct file *file) struct capsule_info *cap_info = file->private_data; kfree(cap_info->pages); + kfree(cap_info->phys); kfree(file->private_data); file->private_data = NULL; return 0; @@ -281,6 +303,13 @@ static int efi_capsule_open(struct inode *inode, struct file *file) return -ENOMEM; } + cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL); + if (!cap_info->phys) { + kfree(cap_info->pages); + kfree(cap_info); + return -ENOMEM; + } + file->private_data = cap_info; return 0; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index f70febf680c39..c3eefa126e3b0 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -143,8 +143,7 @@ static ssize_t systab_show(struct kobject *kobj, return str - buf; } -static struct kobj_attribute efi_attr_systab = - __ATTR(systab, 0400, systab_show, NULL); +static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400); #define EFI_FIELD(var) efi.var diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index bd7ed3c1148a7..c47e0c6ec00f8 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -106,7 +106,7 @@ static const struct sysfs_ops esre_attr_ops = { }; /* Generic ESRT Entry ("ESRE") support. */ -static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf) +static ssize_t fw_class_show(struct esre_entry *entry, char *buf) { char *str = buf; @@ -117,18 +117,16 @@ static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf) return str - buf; } -static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400, - esre_fw_class_show, NULL); +static struct esre_attribute esre_fw_class = __ATTR_RO_MODE(fw_class, 0400); #define esre_attr_decl(name, size, fmt) \ -static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \ +static ssize_t name##_show(struct esre_entry *entry, char *buf) \ { \ return sprintf(buf, fmt "\n", \ le##size##_to_cpu(entry->esre.esre1->name)); \ } \ \ -static struct esre_attribute esre_##name = __ATTR(name, 0400, \ - esre_##name##_show, NULL) +static struct esre_attribute esre_##name = __ATTR_RO_MODE(name, 0400) esre_attr_decl(fw_type, 32, "%u"); esre_attr_decl(fw_version, 32, "%u"); @@ -193,14 +191,13 @@ static int esre_create_sysfs_entry(void *esre, int entry_num) /* support for displaying ESRT fields at the top level */ #define esrt_attr_decl(name, size, fmt) \ -static ssize_t esrt_##name##_show(struct kobject *kobj, \ +static ssize_t name##_show(struct kobject *kobj, \ struct kobj_attribute *attr, char *buf)\ { \ return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \ } \ \ -static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \ - esrt_##name##_show, NULL) +static struct kobj_attribute esrt_##name = __ATTR_RO_MODE(name, 0400) esrt_attr_decl(fw_resource_count, 32, "%u"); esrt_attr_decl(fw_resource_count_max, 32, "%u"); @@ -431,7 +428,7 @@ static int __init esrt_sysfs_init(void) err_remove_esrt: kobject_put(esrt_kobj); err: - kfree(esrt); + memunmap(esrt); esrt = NULL; return error; } diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 8e64b77aeac95..f377609ff141b 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -63,11 +63,11 @@ static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, return map_attr->show(entry, buf); } -static struct map_attribute map_type_attr = __ATTR_RO(type); -static struct map_attribute map_phys_addr_attr = __ATTR_RO(phys_addr); -static struct map_attribute map_virt_addr_attr = __ATTR_RO(virt_addr); -static struct map_attribute map_num_pages_attr = __ATTR_RO(num_pages); -static struct map_attribute map_attribute_attr = __ATTR_RO(attribute); +static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400); +static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400); +static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400); +static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400); +static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400); /* * These are default attributes that are added for every memmap entry. diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 35e553b3b1905..e4b40f2b46274 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -295,38 +295,60 @@ static int vpd_probe(struct platform_device *pdev) if (ret) return ret; - return vpd_sections_init(entry.cbmem_addr); + vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); + if (!vpd_kobj) + return -ENOMEM; + + ret = vpd_sections_init(entry.cbmem_addr); + if (ret) { + kobject_put(vpd_kobj); + return ret; + } + + return 0; +} + +static int vpd_remove(struct platform_device *pdev) +{ + vpd_section_destroy(&ro_vpd); + vpd_section_destroy(&rw_vpd); + + kobject_put(vpd_kobj); + + return 0; } static struct platform_driver vpd_driver = { .probe = vpd_probe, + .remove = vpd_remove, .driver = { .name = "vpd", }, }; +static struct platform_device *vpd_pdev; + static int __init vpd_platform_init(void) { - struct platform_device *pdev; - - pdev = platform_device_register_simple("vpd", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); + int ret; - vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); - if (!vpd_kobj) - return -ENOMEM; + ret = platform_driver_register(&vpd_driver); + if (ret) + return ret; - platform_driver_register(&vpd_driver); + vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0); + if (IS_ERR(vpd_pdev)) { + platform_driver_unregister(&vpd_driver); + return PTR_ERR(vpd_pdev); + } return 0; } static void __exit vpd_platform_exit(void) { - vpd_section_destroy(&ro_vpd); - vpd_section_destroy(&rw_vpd); - kobject_put(vpd_kobj); + platform_device_unregister(vpd_pdev); + platform_driver_unregister(&vpd_driver); } module_init(vpd_platform_init); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index eb4528c87c0b3..d6f3d9ee1350e 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1074,7 +1074,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) } if (!chip->names) - devprop_gpiochip_set_names(chip); + devprop_gpiochip_set_names(chip, dev_fwnode(chip->parent)); acpi_gpiochip_request_regions(acpi_gpio); acpi_gpiochip_scan_gpios(acpi_gpio); diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c index 27f383bda7d96..f748aa3e77f72 100644 --- a/drivers/gpio/gpiolib-devprop.c +++ b/drivers/gpio/gpiolib-devprop.c @@ -19,30 +19,27 @@ /** * devprop_gpiochip_set_names - Set GPIO line names using device properties * @chip: GPIO chip whose lines should be named, if possible + * @fwnode: Property Node containing the gpio-line-names property * * Looks for device property "gpio-line-names" and if it exists assigns * GPIO line names for the chip. The memory allocated for the assigned * names belong to the underlying firmware node and should not be released * by the caller. */ -void devprop_gpiochip_set_names(struct gpio_chip *chip) +void devprop_gpiochip_set_names(struct gpio_chip *chip, + const struct fwnode_handle *fwnode) { struct gpio_device *gdev = chip->gpiodev; const char **names; int ret, i; - if (!chip->parent) { - dev_warn(&gdev->dev, "GPIO chip parent is NULL\n"); - return; - } - - ret = device_property_read_string_array(chip->parent, "gpio-line-names", + ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", NULL, 0); if (ret < 0) return; if (ret != gdev->ngpio) { - dev_warn(chip->parent, + dev_warn(&gdev->dev, "names %d do not match number of GPIOs %d\n", ret, gdev->ngpio); return; @@ -52,10 +49,10 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip) if (!names) return; - ret = device_property_read_string_array(chip->parent, "gpio-line-names", + ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", names, gdev->ngpio); if (ret < 0) { - dev_warn(chip->parent, "failed to read GPIO line names\n"); + dev_warn(&gdev->dev, "failed to read GPIO line names\n"); kfree(names); return; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index bfcd20699ec88..ba38f530e4037 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -493,7 +493,8 @@ int of_gpiochip_add(struct gpio_chip *chip) /* If the chip defines names itself, these take precedence */ if (!chip->names) - devprop_gpiochip_set_names(chip); + devprop_gpiochip_set_names(chip, + of_fwnode_handle(chip->of_node)); of_node_get(chip->of_node); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index d003ccb127816..3d4d0634c9ddd 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -224,7 +224,8 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc) return desc - &desc->gdev->descs[0]; } -void devprop_gpiochip_set_names(struct gpio_chip *chip); +void devprop_gpiochip_set_names(struct gpio_chip *chip, + const struct fwnode_handle *fwnode); /* With descriptor prefix */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 103635ab784c9..712ad8c2bdc5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -697,7 +697,7 @@ int amdgpu_queue_mgr_fini(struct amdgpu_device *adev, struct amdgpu_queue_mgr *mgr); int amdgpu_queue_mgr_map(struct amdgpu_device *adev, struct amdgpu_queue_mgr *mgr, - int hw_ip, int instance, int ring, + u32 hw_ip, u32 instance, u32 ring, struct amdgpu_ring **out_ring); /* @@ -1536,18 +1536,14 @@ struct amdgpu_device { /* sdma */ struct amdgpu_sdma sdma; - union { - struct { - /* uvd */ - struct amdgpu_uvd uvd; + /* uvd */ + struct amdgpu_uvd uvd; - /* vce */ - struct amdgpu_vce vce; - }; + /* vce */ + struct amdgpu_vce vce; - /* vcn */ - struct amdgpu_vcn vcn; - }; + /* vcn */ + struct amdgpu_vcn vcn; /* firmwares */ struct amdgpu_firmware firmware; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index ce443586a0c71..cc4e18dcd8b6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1766,34 +1766,32 @@ bool amdgpu_atombios_scratch_need_asic_init(struct amdgpu_device *adev) return true; } -/* Atom needs data in little endian format - * so swap as appropriate when copying data to - * or from atom. Note that atom operates on - * dw units. +/* Atom needs data in little endian format so swap as appropriate when copying + * data to or from atom. Note that atom operates on dw units. + * + * Use to_le=true when sending data to atom and provide at least + * ALIGN(num_bytes,4) bytes in the dst buffer. + * + * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4) + * byes in the src buffer. */ void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le) { #ifdef __BIG_ENDIAN - u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */ - u32 *dst32, *src32; + u32 src_tmp[5], dst_tmp[5]; int i; + u8 align_num_bytes = ALIGN(num_bytes, 4); - memcpy(src_tmp, src, num_bytes); - src32 = (u32 *)src_tmp; - dst32 = (u32 *)dst_tmp; if (to_le) { - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = cpu_to_le32(src32[i]); - memcpy(dst, dst_tmp, num_bytes); + memcpy(src_tmp, src, num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = cpu_to_le32(src_tmp[i]); + memcpy(dst, dst_tmp, align_num_bytes); } else { - u8 dws = num_bytes & ~3; - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = le32_to_cpu(src32[i]); - memcpy(dst, dst_tmp, dws); - if (num_bytes % 4) { - for (i = 0; i < (num_bytes % 4); i++) - dst[dws+i] = dst_tmp[dws+i]; - } + memcpy(src_tmp, src, align_num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = le32_to_cpu(src_tmp[i]); + memcpy(dst, dst_tmp, num_bytes); } #else memcpy(dst, src, num_bytes); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index c21adf60a7f20..057e1ecd83cec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -59,12 +59,6 @@ static bool check_atom_bios(uint8_t *bios, size_t size) return false; } - tmp = bios[0x18] | (bios[0x19] << 8); - if (bios[tmp + 0x14] != 0x0) { - DRM_INFO("Not an x86 BIOS ROM\n"); - return false; - } - bios_header_start = bios[0x48] | (bios[0x49] << 8); if (!bios_header_start) { DRM_INFO("Can't locate bios header\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 9e495da0bb03c..ffe4839803623 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -391,6 +391,9 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, type, &bo->placement, page_align, !kernel, NULL, acc_size, sg, resv, &amdgpu_ttm_bo_destroy); + if (unlikely(r != 0)) + return r; + bytes_moved = atomic64_read(&adev->num_bytes_moved) - initial_bytes_moved; if (adev->mc.visible_vram_size < adev->mc.real_vram_size && @@ -400,9 +403,6 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, else amdgpu_cs_report_moved_bytes(adev, bytes_moved, 0); - if (unlikely(r != 0)) - return r; - if (kernel) bo->tbo.priority = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c index befc09b68543c..b293380bd46c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c @@ -63,7 +63,7 @@ static int amdgpu_update_cached_map(struct amdgpu_queue_mapper *mapper, static int amdgpu_identity_map(struct amdgpu_device *adev, struct amdgpu_queue_mapper *mapper, - int ring, + u32 ring, struct amdgpu_ring **out_ring) { switch (mapper->hw_ip) { @@ -121,7 +121,7 @@ static enum amdgpu_ring_type amdgpu_hw_ip_to_ring_type(int hw_ip) static int amdgpu_lru_map(struct amdgpu_device *adev, struct amdgpu_queue_mapper *mapper, - int user_ring, + u32 user_ring, struct amdgpu_ring **out_ring) { int r, i, j; @@ -208,7 +208,7 @@ int amdgpu_queue_mgr_fini(struct amdgpu_device *adev, */ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, struct amdgpu_queue_mgr *mgr, - int hw_ip, int instance, int ring, + u32 hw_ip, u32 instance, u32 ring, struct amdgpu_ring **out_ring) { int r, ip_num_rings; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 5ce65280b3960..90adff83e4898 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -136,7 +136,8 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring) if (ring->funcs->end_use) ring->funcs->end_use(ring); - amdgpu_ring_lru_touch(ring->adev, ring); + if (ring->funcs->type != AMDGPU_RING_TYPE_KIQ) + amdgpu_ring_lru_touch(ring->adev, ring); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index c855366521abc..9fc3d387eae3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -647,7 +647,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) uint32_t allocated = 0; uint32_t tmp, handle = 0; uint32_t *size = &tmp; - int i, r, idx = 0; + int i, r = 0, idx = 0; p->job->vm = NULL; ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index bd20ff0185122..863c6dd0123a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1201,7 +1201,7 @@ static void amdgpu_vm_invalidate_level(struct amdgpu_vm_pt *parent) int amdgpu_vm_update_directories(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - int r; + int r = 0; r = amdgpu_vm_update_level(adev, vm, &vm->root, 0); if (r) @@ -2586,7 +2586,8 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo_va_mapping *mapping, *tmp; bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; - int i; + struct amdgpu_bo *root; + int i, r; amd_sched_entity_fini(vm->entity.sched, &vm->entity); @@ -2609,7 +2610,15 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) amdgpu_vm_free_mapping(adev, vm, mapping, NULL); } - amdgpu_vm_free_levels(&vm->root); + root = amdgpu_bo_ref(vm->root.bo); + r = amdgpu_bo_reserve(root, true); + if (r) { + dev_err(adev->dev, "Leaking page tables because BO reservation failed\n"); + } else { + amdgpu_vm_free_levels(&vm->root); + amdgpu_bo_unreserve(root); + } + amdgpu_bo_unref(&root); dma_fence_put(vm->last_dir_update); for (i = 0; i < AMDGPU_MAX_VMHUBS; i++) amdgpu_vm_free_reserved_vmid(adev, vm, i); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index d04d0b1232120..6dc0f6e346e7f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -395,7 +395,16 @@ static int gmc_v9_0_early_init(void *handle) static int gmc_v9_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 3, 3 }; + /* + * The latest engine allocation on gfx9 is: + * Engine 0, 1: idle + * Engine 2, 3: firmware + * Engine 4~13: amdgpu ring, subject to change when ring number changes + * Engine 14~15: idle + * Engine 16: kfd tlb invalidation + * Engine 17: Gart flushes + */ + unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 4, 4 }; unsigned i; for(i = 0; i < adev->num_rings; ++i) { @@ -408,9 +417,9 @@ static int gmc_v9_0_late_init(void *handle) ring->funcs->vmhub); } - /* Engine 17 is used for GART flushes */ + /* Engine 16 is used for KFD and 17 for GART flushes */ for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i) - BUG_ON(vm_inv_eng[i] > 17); + BUG_ON(vm_inv_eng[i] > 16); return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); } diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index f2c3a49f73a00..3e59c766722cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -279,10 +279,7 @@ static void soc15_init_golden_registers(struct amdgpu_device *adev) } static u32 soc15_get_xclk(struct amdgpu_device *adev) { - if (adev->asic_type == CHIP_VEGA10) - return adev->clock.spll.reference_freq/4; - else - return adev->clock.spll.reference_freq; + return adev->clock.spll.reference_freq; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 21e7b88401e1e..a098712bdd2ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1175,7 +1175,7 @@ static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = { static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->uvd.irq.num_types = adev->vcn.num_enc_rings + 1; + adev->vcn.irq.num_types = adev->vcn.num_enc_rings + 1; adev->vcn.irq.funcs = &vcn_v1_0_irq_funcs; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index 84f01fd33aff7..b50aa292d0266 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -850,9 +850,9 @@ static int init_over_drive_limits( const ATOM_Tonga_POWERPLAYTABLE *powerplay_table) { hwmgr->platform_descriptor.overdriveLimit.engineClock = - le16_to_cpu(powerplay_table->ulMaxODEngineClock); + le32_to_cpu(powerplay_table->ulMaxODEngineClock); hwmgr->platform_descriptor.overdriveLimit.memoryClock = - le16_to_cpu(powerplay_table->ulMaxODMemoryClock); + le32_to_cpu(powerplay_table->ulMaxODMemoryClock); hwmgr->platform_descriptor.minOverdriveVDDC = 0; hwmgr->platform_descriptor.maxOverdriveVDDC = 0; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5dd3f1cd074a1..a8905049b9da0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -946,7 +946,9 @@ static int analogix_dp_get_modes(struct drm_connector *connector) return 0; } + pm_runtime_get_sync(dp->dev); edid = drm_get_edid(connector, &dp->aux.ddc); + pm_runtime_put(dp->dev); if (edid) { drm_mode_connector_update_edid_property(&dp->connector, edid); diff --git a/drivers/gpu/drm/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/drm_dp_dual_mode_helper.c index 0ef9011a18563..02a50929af675 100644 --- a/drivers/gpu/drm/drm_dp_dual_mode_helper.c +++ b/drivers/gpu/drm/drm_dp_dual_mode_helper.c @@ -410,6 +410,7 @@ int drm_lspcon_get_mode(struct i2c_adapter *adapter, { u8 data; int ret = 0; + int retry; if (!mode) { DRM_ERROR("NULL input\n"); @@ -417,10 +418,19 @@ int drm_lspcon_get_mode(struct i2c_adapter *adapter, } /* Read Status: i2c over aux */ - ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_LSPCON_CURRENT_MODE, - &data, sizeof(data)); + for (retry = 0; retry < 6; retry++) { + if (retry) + usleep_range(500, 1000); + + ret = drm_dp_dual_mode_read(adapter, + DP_DUAL_MODE_LSPCON_CURRENT_MODE, + &data, sizeof(data)); + if (!ret) + break; + } + if (ret < 0) { - DRM_ERROR("LSPCON read(0x80, 0x41) failed\n"); + DRM_DEBUG_KMS("LSPCON read(0x80, 0x41) failed\n"); return -EFAULT; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6bb6337be920c..fc7946eb6665c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4809,7 +4809,8 @@ void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, const struct drm_display_mode *mode, enum hdmi_quantization_range rgb_quant_range, - bool rgb_quant_range_selectable) + bool rgb_quant_range_selectable, + bool is_hdmi2_sink) { /* * CEA-861: @@ -4833,8 +4834,15 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, * YQ-field to match the RGB Quantization Range being transmitted * (e.g., when Limited Range RGB, set YQ=0 or when Full Range RGB, * set YQ=1) and the Sink shall ignore the YQ-field." + * + * Unfortunate certain sinks (eg. VIZ Model 67/E261VA) get confused + * by non-zero YQ when receiving RGB. There doesn't seem to be any + * good way to tell which version of CEA-861 the sink supports, so + * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based + * on on CEA-861-F. */ - if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) + if (!is_hdmi2_sink || + rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) frame->ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; else diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1b8f013ffa650..5e93589c335cb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1809,6 +1809,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { DRM_INFO("Cannot find any crtc or sizes\n"); + + /* First time: disable all crtc's.. */ + if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master)) + restore_fbdev_mode(fb_helper); return -EAGAIN; } diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 70f2b9593edcb..17e8ef9a1c112 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -311,8 +311,8 @@ u32 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc) u32 vblank; unsigned long flags; - WARN(!dev->driver->get_vblank_timestamp, - "This function requires support for accurate vblank timestamps."); + WARN_ONCE(drm_debug & DRM_UT_VBL && !dev->driver->get_vblank_timestamp, + "This function requires support for accurate vblank timestamps."); spin_lock_irqsave(&dev->vblank_time_lock, flags); @@ -869,7 +869,7 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, assert_spin_locked(&dev->event_lock); e->pipe = pipe; - e->event.sequence = drm_vblank_count(dev, pipe); + e->event.sequence = drm_crtc_accurate_vblank_count(crtc) + 1; e->event.crtc_id = crtc->base.id; list_add_tail(&e->base.link, &dev->vblank_event_list); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 077de014d6101..4400efe3974a3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -247,6 +247,15 @@ struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, if (IS_ERR(exynos_gem)) return exynos_gem; + if (!is_drm_iommu_supported(dev) && (flags & EXYNOS_BO_NONCONTIG)) { + /* + * when no IOMMU is available, all allocated buffers are + * contiguous anyway, so drop EXYNOS_BO_NONCONTIG flag + */ + flags &= ~EXYNOS_BO_NONCONTIG; + DRM_WARN("Non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n"); + } + /* set memory type and cache attribute from user side. */ exynos_gem->flags = flags; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 58e9e0601a616..faf17b83b910d 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -210,7 +210,6 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev) return PTR_ERR(fsl_dev->state); } - clk_disable_unprepare(fsl_dev->pix_clk); clk_disable_unprepare(fsl_dev->clk); return 0; @@ -233,6 +232,7 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) if (fsl_dev->tcon) fsl_tcon_bypass_enable(fsl_dev->tcon); fsl_dcu_drm_init_planes(fsl_dev->drm); + enable_irq(fsl_dev->irq); drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state); console_lock(); @@ -240,7 +240,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) console_unlock(); drm_kms_helper_poll_enable(fsl_dev->drm); - enable_irq(fsl_dev->irq); return 0; } diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index edd7d8127d194..c54806d08dd78 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -102,7 +102,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, { struct drm_encoder *encoder = &fsl_dev->encoder; struct drm_connector *connector = &fsl_dev->connector.base; - struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config; int ret; fsl_dev->connector.encoder = encoder; @@ -122,10 +121,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, if (ret < 0) goto err_sysfs; - drm_object_property_set_value(&connector->base, - mode_config->dpms_property, - DRM_MODE_DPMS_OFF); - ret = drm_panel_attach(panel, connector); if (ret) { dev_err(fsl_dev->dev, "failed to attach panel\n"); diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 9823477b1855c..2269be91f3e16 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -534,9 +534,12 @@ static void ade_crtc_atomic_begin(struct drm_crtc *crtc, { struct ade_crtc *acrtc = to_ade_crtc(crtc); struct ade_hw_ctx *ctx = acrtc->ctx; + struct drm_display_mode *mode = &crtc->state->mode; + struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); + ade_ldi_set_mode(acrtc, mode, adj_mode); } static void ade_crtc_atomic_flush(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index e6dfc3331f4bb..dadacbe558abe 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -311,9 +311,9 @@ static inline int gtt_set_entry64(void *pt, #define GTT_HAW 46 -#define ADDR_1G_MASK (((1UL << (GTT_HAW - 30 + 1)) - 1) << 30) -#define ADDR_2M_MASK (((1UL << (GTT_HAW - 21 + 1)) - 1) << 21) -#define ADDR_4K_MASK (((1UL << (GTT_HAW - 12 + 1)) - 1) << 12) +#define ADDR_1G_MASK (((1UL << (GTT_HAW - 30)) - 1) << 30) +#define ADDR_2M_MASK (((1UL << (GTT_HAW - 21)) - 1) << 21) +#define ADDR_4K_MASK (((1UL << (GTT_HAW - 12)) - 1) << 12) static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e) { @@ -1359,12 +1359,15 @@ static int ppgtt_handle_guest_write_page_table_bytes(void *gp, return ret; } else { if (!test_bit(index, spt->post_shadow_bitmap)) { + int type = spt->shadow_page.type; + ppgtt_get_shadow_entry(spt, &se, index); ret = ppgtt_handle_guest_entry_removal(gpt, &se, index); if (ret) return ret; + ops->set_pfn(&se, vgpu->gtt.scratch_pt[type].page_mfn); + ppgtt_set_shadow_entry(spt, &se, index); } - ppgtt_set_post_shadow(spt, index); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9f45cfeae7755..5c5cb2ceee49a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1693,6 +1693,7 @@ static int i915_drm_resume(struct drm_device *dev) intel_guc_resume(dev_priv); intel_modeset_init_hw(dev); + intel_init_clock_gating(dev_priv); spin_lock_irq(&dev_priv->irq_lock); if (dev_priv->display.hpd_irq_setup) @@ -2591,6 +2592,8 @@ static int intel_runtime_resume(struct device *kdev) ret = vlv_resume_prepare(dev_priv, true); } + intel_uncore_runtime_resume(dev_priv); + /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dc1faa49687d1..3b2c0538e48d7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -325,17 +325,10 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj) * must wait for all rendering to complete to the object (as unbinding * must anyway), and retire the requests. */ - ret = i915_gem_object_wait(obj, - I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED | - I915_WAIT_ALL, - MAX_SCHEDULE_TIMEOUT, - NULL); + ret = i915_gem_object_set_to_cpu_domain(obj, false); if (ret) return ret; - i915_gem_retire_requests(to_i915(obj->base.dev)); - while ((vma = list_first_entry_or_null(&obj->vma_list, struct i915_vma, obj_link))) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c9bcc6c450126..920c8914cec17 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6944,6 +6944,7 @@ enum { #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) #define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430) +#define SKL_SELECT_ALTERNATE_DC_EXIT (1<<30) #define MASK_WAKEMEM (1<<13) #define SKL_DFSM _MMIO(0x51000) @@ -6986,6 +6987,8 @@ enum { #define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) #define DISABLE_PIXEL_MASK_CAMMING (1<<14) +#define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) + #define GEN7_L3SQCREG1 _MMIO(0xB010) #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 @@ -8475,6 +8478,7 @@ enum skl_power_gate { #define BXT_CDCLK_CD2X_DIV_SEL_2 (2<<22) #define BXT_CDCLK_CD2X_DIV_SEL_4 (3<<22) #define BXT_CDCLK_CD2X_PIPE(pipe) ((pipe)<<20) +#define CDCLK_DIVMUX_CD_OVERRIDE (1<<19) #define BXT_CDCLK_CD2X_PIPE_NONE BXT_CDCLK_CD2X_PIPE(3) #define BXT_CDCLK_SSA_PRECHARGE_ENABLE (1<<16) #define CDCLK_FREQ_DECIMAL_MASK (0x7ff) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 1241e5891b295..26a8dcd2c5494 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -859,16 +859,10 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) { - int min_cdclk = skl_calc_cdclk(0, vco); u32 val; WARN_ON(vco != 8100000 && vco != 8640000); - /* select the minimum CDCLK before enabling DPLL 0 */ - val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); - I915_WRITE(CDCLK_CTL, val); - POSTING_READ(CDCLK_CTL); - /* * We always enable DPLL0 with the lowest link rate possible, but still * taking into account the VCO required to operate the eDP panel at the @@ -922,7 +916,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, { int cdclk = cdclk_state->cdclk; int vco = cdclk_state->vco; - u32 freq_select, pcu_ack; + u32 freq_select, pcu_ack, cdclk_ctl; int ret; WARN_ON((cdclk == 24000) != (vco == 0)); @@ -939,7 +933,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, return; } - /* set CDCLK_CTL */ + /* Choose frequency for this cdclk */ switch (cdclk) { case 450000: case 432000: @@ -967,10 +961,33 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, dev_priv->cdclk.hw.vco != vco) skl_dpll0_disable(dev_priv); + cdclk_ctl = I915_READ(CDCLK_CTL); + + if (dev_priv->cdclk.hw.vco != vco) { + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); + cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + } + + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl |= CDCLK_DIVMUX_CD_OVERRIDE; + I915_WRITE(CDCLK_CTL, cdclk_ctl); + POSTING_READ(CDCLK_CTL); + if (dev_priv->cdclk.hw.vco != vco) skl_dpll0_enable(dev_priv, vco); - I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk)); + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + + cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~CDCLK_DIVMUX_CD_OVERRIDE; + I915_WRITE(CDCLK_CTL, cdclk_ctl); POSTING_READ(CDCLK_CTL); /* inform PCU of the change */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5ebdb63330ddf..095a2240af4f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1000,7 +1000,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, return crtc->config->cpu_transcoder; } -static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe) +static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv, + enum pipe pipe) { i915_reg_t reg = PIPEDSL(pipe); u32 line1, line2; @@ -1015,7 +1016,28 @@ static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe) msleep(5); line2 = I915_READ(reg) & line_mask; - return line1 == line2; + return line1 != line2; +} + +static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + /* Wait for the display line to settle/start moving */ + if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100)) + DRM_ERROR("pipe %c scanline %s wait timed out\n", + pipe_name(pipe), onoff(state)); +} + +static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc) +{ + wait_for_pipe_scanline_moving(crtc, false); +} + +static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc) +{ + wait_for_pipe_scanline_moving(crtc, true); } /* @@ -1038,7 +1060,6 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; - enum pipe pipe = crtc->pipe; if (INTEL_GEN(dev_priv) >= 4) { i915_reg_t reg = PIPECONF(cpu_transcoder); @@ -1049,9 +1070,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc) 100)) WARN(1, "pipe_off wait timed out\n"); } else { - /* Wait for the display line to settle */ - if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) - WARN(1, "pipe_off wait timed out\n"); + intel_wait_for_pipe_scanline_stopped(crtc); } } @@ -1944,15 +1963,14 @@ static void intel_enable_pipe(struct intel_crtc *crtc) POSTING_READ(reg); /* - * Until the pipe starts DSL will read as 0, which would cause - * an apparent vblank timestamp jump, which messes up also the - * frame count when it's derived from the timestamps. So let's - * wait for the pipe to start properly before we call - * drm_crtc_vblank_on() + * Until the pipe starts PIPEDSL reads will return a stale value, + * which causes an apparent vblank timestamp jump when PIPEDSL + * resets to its proper value. That also messes up the frame count + * when it's derived from the timestamps. So let's wait for the + * pipe to start properly before we call drm_crtc_vblank_on() */ - if (dev->max_vblank_count == 0 && - wait_for(intel_get_crtc_scanline(crtc) != crtc->scanline_offset, 50)) - DRM_ERROR("pipe %c didn't start\n", pipe_name(pipe)); + if (dev->max_vblank_count == 0) + intel_wait_for_pipe_scanline_moving(crtc); } /** @@ -3782,6 +3800,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) intel_pps_unlock_regs_wa(dev_priv); intel_modeset_init_hw(dev); + intel_init_clock_gating(dev_priv); spin_lock_irq(&dev_priv->irq_lock); if (dev_priv->display.hpd_irq_setup) @@ -14388,8 +14407,6 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_update_cdclk(dev_priv); dev_priv->cdclk.logical = dev_priv->cdclk.actual = dev_priv->cdclk.hw; - - intel_init_clock_gating(dev_priv); } /* @@ -14682,6 +14699,8 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) { + struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n", pipe_name(pipe)); @@ -14691,8 +14710,7 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) I915_WRITE(PIPECONF(pipe), 0); POSTING_READ(PIPECONF(pipe)); - if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) - DRM_ERROR("pipe %c off wait timed out\n", pipe_name(pipe)); + intel_wait_for_pipe_scanline_stopped(crtc); I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS); POSTING_READ(DPLL(pipe)); @@ -15105,6 +15123,15 @@ intel_modeset_setup_hw_state(struct drm_device *dev, struct intel_encoder *encoder; int i; + if (IS_HASWELL(dev_priv)) { + /* + * WaRsPkgCStateDisplayPMReq:hsw + * System hang if this isn't done before disabling all planes! + */ + I915_WRITE(CHICKEN_PAR1_1, + I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES); + } + intel_modeset_readout_hw_state(dev); /* HW state is read out, now we need to sanitize this mess. */ @@ -15201,6 +15228,8 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_init_gt_powersave(dev_priv); + intel_init_clock_gating(dev_priv); + intel_setup_overlay(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 3c2d9cf22ed5a..b6a7e492c1a31 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1125,6 +1125,11 @@ static int glk_init_workarounds(struct intel_engine_cs *engine) if (ret) return ret; + /* WA #0862: Userspace has to set "Barrier Mode" to avoid hangs. */ + ret = wa_ring_whitelist_reg(engine, GEN9_SLICE_COMMON_ECO_CHICKEN1); + if (ret) + return ret; + /* WaToEnableHwFixForPushConstHWBug:glk */ WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 262e75c00dd2f..da2d309574ba9 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -694,10 +694,8 @@ static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) /* Due to peculiar init order wrt to hpd handling this is separate. */ if (drm_fb_helper_initial_config(&ifbdev->helper, - ifbdev->preferred_bpp)) { + ifbdev->preferred_bpp)) intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); - intel_fbdev_fini(to_i915(ifbdev->helper.dev)); - } } void intel_fbdev_initial_config_async(struct drm_device *dev) @@ -797,7 +795,11 @@ void intel_fbdev_output_poll_changed(struct drm_device *dev) { struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; - if (ifbdev) + if (!ifbdev) + return; + + intel_fbdev_sync(ifbdev); + if (ifbdev->vma) drm_fb_helper_hotplug_event(&ifbdev->helper); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e8abea7594ec4..3fed1d3ecdedf 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -481,7 +481,8 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, crtc_state->limited_color_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL, - intel_hdmi->rgb_quant_range_selectable); + intel_hdmi->rgb_quant_range_selectable, + is_hdmi2_sink); /* TODO: handle pixel repetition for YCBCR420 outputs */ intel_write_infoframe(encoder, crtc_state, &frame); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index eb5827110d8ff..49fdf09f9919c 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -438,7 +438,9 @@ static bool gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) { return (i + 1 < num && - !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && + msgs[i].addr == msgs[i + 1].addr && + !(msgs[i].flags & I2C_M_RD) && + (msgs[i].len == 1 || msgs[i].len == 2) && (msgs[i + 1].flags & I2C_M_RD)); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cb950752c3469..014e5c08571a4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5669,12 +5669,30 @@ void vlv_wm_sanitize(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->wm.wm_mutex); } +/* + * FIXME should probably kill this and improve + * the real watermark readout/sanitation instead + */ +static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv) +{ + I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); + + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ +} + void ilk_wm_get_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct ilk_wm_values *hw = &dev_priv->wm.hw; struct drm_crtc *crtc; + ilk_init_lp_watermarks(dev_priv); + for_each_crtc(dev, crtc) ilk_pipe_wm_get_hw_state(crtc); @@ -7959,18 +7977,6 @@ static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv) } } -static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv) -{ - I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN); - I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN); - I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); - - /* - * Don't touch WM1S_LP_EN here. - * Doing so could cause underruns. - */ -} - static void ironlake_init_clock_gating(struct drm_i915_private *dev_priv) { uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; @@ -8004,8 +8010,6 @@ static void ironlake_init_clock_gating(struct drm_i915_private *dev_priv) (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); - ilk_init_lp_watermarks(dev_priv); - /* * Based on the document from hardware guys the following bits * should be set unconditionally in order to enable FBC. @@ -8118,8 +8122,6 @@ static void gen6_init_clock_gating(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_GT_MODE, _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4)); - ilk_init_lp_watermarks(dev_priv); - I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); @@ -8293,8 +8295,6 @@ static void broadwell_init_clock_gating(struct drm_i915_private *dev_priv) { enum pipe pipe; - ilk_init_lp_watermarks(dev_priv); - /* WaSwitchSolVfFArbitrationPriority:bdw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); @@ -8349,8 +8349,6 @@ static void broadwell_init_clock_gating(struct drm_i915_private *dev_priv) static void haswell_init_clock_gating(struct drm_i915_private *dev_priv) { - ilk_init_lp_watermarks(dev_priv); - /* L3 caching of data atomics doesn't work -- disable it. */ I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE); I915_WRITE(HSW_ROW_CHICKEN3, @@ -8394,10 +8392,6 @@ static void haswell_init_clock_gating(struct drm_i915_private *dev_priv) /* WaSwitchSolVfFArbitrationPriority:hsw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); - /* WaRsPkgCStateDisplayPMReq:hsw */ - I915_WRITE(CHICKEN_PAR1_1, - I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES); - lpt_init_clock_gating(dev_priv); } @@ -8405,8 +8399,6 @@ static void ivybridge_init_clock_gating(struct drm_i915_private *dev_priv) { uint32_t snpcr; - ilk_init_lp_watermarks(dev_priv); - I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); /* WaDisableEarlyCull:ivb */ diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 49577eba8e7ef..51cb5293bf43a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -598,6 +598,11 @@ void gen9_enable_dc5(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Enabling DC5\n"); + /* Wa Display #1183: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) + I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | + SKL_SELECT_ALTERNATE_DC_EXIT); + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5); } @@ -625,6 +630,11 @@ void skl_disable_dc6(struct drm_i915_private *dev_priv) { DRM_DEBUG_KMS("Disabling DC6\n"); + /* Wa Display #1183: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) + I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | + SKL_SELECT_ALTERNATE_DC_EXIT); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } @@ -1786,6 +1796,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, GLK_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ BIT_ULL(POWER_DOMAIN_MODESET) | \ BIT_ULL(POWER_DOMAIN_AUX_A) | \ + BIT_ULL(POWER_DOMAIN_GMBUS) | \ BIT_ULL(POWER_DOMAIN_INIT)) #define CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS ( \ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 1d7b879cc68c6..e9ed025184068 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -434,6 +434,12 @@ void intel_uncore_resume_early(struct drm_i915_private *dev_priv) i915_check_and_clear_faults(dev_priv); } +void intel_uncore_runtime_resume(struct drm_i915_private *dev_priv) +{ + iosf_mbi_register_pmic_bus_access_notifier( + &dev_priv->uncore.pmic_bus_access_nb); +} + void intel_uncore_sanitize(struct drm_i915_private *dev_priv) { i915.enable_rc6 = sanitize_rc6_option(dev_priv, i915.enable_rc6); @@ -1171,8 +1177,15 @@ static int i915_pmic_bus_access_notifier(struct notifier_block *nb, * bus, which will be busy after this notification, leading to: * "render: timed out waiting for forcewake ack request." * errors. + * + * The notifier is unregistered during intel_runtime_suspend(), + * so it's ok to access the HW here without holding a RPM + * wake reference -> disable wakeref asserts for the time of + * the access. */ + disable_rpm_wakeref_asserts(dev_priv); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); + enable_rpm_wakeref_asserts(dev_priv); break; case MBI_PMIC_BUS_ACCESS_END: intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 5f90278da4612..0bdc3fcc0e64d 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -121,6 +121,7 @@ bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv void intel_uncore_fini(struct drm_i915_private *dev_priv); void intel_uncore_suspend(struct drm_i915_private *dev_priv); void intel_uncore_resume_early(struct drm_i915_private *dev_priv); +void intel_uncore_runtime_resume(struct drm_i915_private *dev_priv); u64 intel_uncore_edram_size(struct drm_i915_private *dev_priv); void assert_forcewakes_inactive(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index a2978a37b4f3c..700fc754f28a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -174,6 +174,7 @@ gf119_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, + .drive = gf119_sor_dp_drive, .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, .audio_sym = gf119_sor_dp_audio_sym, diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index daf286fc8a408..ca1e3b489540f 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -566,8 +566,8 @@ static int dpi_verify_pll(struct dss_pll *pll) } static const struct soc_device_attribute dpi_soc_devices[] = { - { .family = "OMAP3[456]*" }, - { .family = "[AD]M37*" }, + { .machine = "OMAP3[456]*" }, + { .machine = "[AD]M37*" }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index 365cf07daa017..c3453f3bd603f 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -889,25 +889,36 @@ struct hdmi4_features { bool audio_use_mclk; }; -static const struct hdmi4_features hdmi4_es1_features = { +static const struct hdmi4_features hdmi4430_es1_features = { .cts_swmode = false, .audio_use_mclk = false, }; -static const struct hdmi4_features hdmi4_es2_features = { +static const struct hdmi4_features hdmi4430_es2_features = { .cts_swmode = true, .audio_use_mclk = false, }; -static const struct hdmi4_features hdmi4_es3_features = { +static const struct hdmi4_features hdmi4_features = { .cts_swmode = true, .audio_use_mclk = true, }; static const struct soc_device_attribute hdmi4_soc_devices[] = { - { .family = "OMAP4", .revision = "ES1.?", .data = &hdmi4_es1_features }, - { .family = "OMAP4", .revision = "ES2.?", .data = &hdmi4_es2_features }, - { .family = "OMAP4", .data = &hdmi4_es3_features }, + { + .machine = "OMAP4430", + .revision = "ES1.?", + .data = &hdmi4430_es1_features, + }, + { + .machine = "OMAP4430", + .revision = "ES2.?", + .data = &hdmi4430_es2_features, + }, + { + .family = "OMAP4", + .data = &hdmi4_features, + }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 474fa759e06ec..234af81fb3d01 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -369,6 +369,7 @@ static int panel_simple_remove(struct device *dev) drm_panel_remove(&panel->base); panel_simple_disable(&panel->base); + panel_simple_unprepare(&panel->base); if (panel->ddc) put_device(&panel->ddc->dev); @@ -384,6 +385,7 @@ static void panel_simple_shutdown(struct device *dev) struct panel_simple *panel = dev_get_drvdata(dev); panel_simple_disable(&panel->base); + panel_simple_unprepare(&panel->base); } static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 432cb46f6a34a..fd7682bf335dc 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -45,34 +45,32 @@ static char *pre_emph_names[] = { /***** radeon AUX functions *****/ -/* Atom needs data in little endian format - * so swap as appropriate when copying data to - * or from atom. Note that atom operates on - * dw units. +/* Atom needs data in little endian format so swap as appropriate when copying + * data to or from atom. Note that atom operates on dw units. + * + * Use to_le=true when sending data to atom and provide at least + * ALIGN(num_bytes,4) bytes in the dst buffer. + * + * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4) + * byes in the src buffer. */ void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le) { #ifdef __BIG_ENDIAN - u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */ - u32 *dst32, *src32; + u32 src_tmp[5], dst_tmp[5]; int i; + u8 align_num_bytes = ALIGN(num_bytes, 4); - memcpy(src_tmp, src, num_bytes); - src32 = (u32 *)src_tmp; - dst32 = (u32 *)dst_tmp; if (to_le) { - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = cpu_to_le32(src32[i]); - memcpy(dst, dst_tmp, num_bytes); + memcpy(src_tmp, src, num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = cpu_to_le32(src_tmp[i]); + memcpy(dst, dst_tmp, align_num_bytes); } else { - u8 dws = num_bytes & ~3; - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = le32_to_cpu(src32[i]); - memcpy(dst, dst_tmp, dws); - if (num_bytes % 4) { - for (i = 0; i < (num_bytes % 4); i++) - dst[dws+i] = dst_tmp[dws+i]; - } + memcpy(src_tmp, src, align_num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = le32_to_cpu(src_tmp[i]); + memcpy(dst, dst_tmp, num_bytes); } #else memcpy(dst, src, num_bytes); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index fd25361ac681b..4ef967d1a9dec 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -245,7 +245,6 @@ static int radeonfb_create(struct drm_fb_helper *helper, } info->par = rfbdev; - info->skip_vt_switch = true; ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index d9791292553ef..7b909d814d38c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -567,12 +567,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, if (IS_ERR(tcon->crtc)) { dev_err(dev, "Couldn't create our CRTC\n"); ret = PTR_ERR(tcon->crtc); - goto err_free_clocks; + goto err_free_dotclock; } ret = sun4i_rgb_init(drm, tcon); if (ret < 0) - goto err_free_clocks; + goto err_free_dotclock; list_add_tail(&tcon->list, &drv->tcon_list); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 406fe4544b83d..06d6e785c9209 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -48,6 +49,7 @@ struct tilcdc_crtc { unsigned int lcd_fck_rate; ktime_t last_vblank; + unsigned int hvtotal_us; struct drm_framebuffer *curr_fb; struct drm_framebuffer *next_fb; @@ -292,6 +294,12 @@ static void tilcdc_crtc_set_clk(struct drm_crtc *crtc) LCDC_V2_CORE_CLK_EN); } +uint tilcdc_mode_hvtotal(const struct drm_display_mode *mode) +{ + return (uint) div_u64(1000llu * mode->htotal * mode->vtotal, + mode->clock); +} + static void tilcdc_crtc_set_mode(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); @@ -459,6 +467,9 @@ static void tilcdc_crtc_set_mode(struct drm_crtc *crtc) drm_framebuffer_reference(fb); crtc->hwmode = crtc->state->adjusted_mode; + + tilcdc_crtc->hvtotal_us = + tilcdc_mode_hvtotal(&crtc->hwmode); } static void tilcdc_crtc_enable(struct drm_crtc *crtc) @@ -648,7 +659,7 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc, spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags); next_vblank = ktime_add_us(tilcdc_crtc->last_vblank, - 1000000 / crtc->hwmode.vrefresh); + tilcdc_crtc->hvtotal_us); tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get())); if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 180ce62964161..c088703777e26 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -150,8 +150,7 @@ static void ttm_bo_release_list(struct kref *list_kref) ttm_tt_destroy(bo->ttm); atomic_dec(&bo->glob->bo_count); dma_fence_put(bo->moving); - if (bo->resv == &bo->ttm_resv) - reservation_object_fini(&bo->ttm_resv); + reservation_object_fini(&bo->ttm_resv); mutex_destroy(&bo->wu_mutex); if (bo->destroy) bo->destroy(bo); @@ -402,14 +401,11 @@ static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) if (bo->resv == &bo->ttm_resv) return 0; - reservation_object_init(&bo->ttm_resv); BUG_ON(!reservation_object_trylock(&bo->ttm_resv)); r = reservation_object_copy_fences(&bo->ttm_resv, bo->resv); - if (r) { + if (r) reservation_object_unlock(&bo->ttm_resv); - reservation_object_fini(&bo->ttm_resv); - } return r; } @@ -440,28 +436,30 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) struct ttm_bo_global *glob = bo->glob; int ret; + ret = ttm_bo_individualize_resv(bo); + if (ret) { + /* Last resort, if we fail to allocate memory for the + * fences block for the BO to become idle + */ + reservation_object_wait_timeout_rcu(bo->resv, true, false, + 30 * HZ); + spin_lock(&glob->lru_lock); + goto error; + } + spin_lock(&glob->lru_lock); ret = __ttm_bo_reserve(bo, false, true, NULL); - if (!ret) { - if (!ttm_bo_wait(bo, false, true)) { + if (reservation_object_test_signaled_rcu(&bo->ttm_resv, true)) { ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); - ttm_bo_cleanup_memtype_use(bo); + if (bo->resv != &bo->ttm_resv) + reservation_object_unlock(&bo->ttm_resv); - return; - } - - ret = ttm_bo_individualize_resv(bo); - if (ret) { - /* Last resort, if we fail to allocate memory for the - * fences block for the BO to become idle and free it. - */ - spin_unlock(&glob->lru_lock); - ttm_bo_wait(bo, true, true); ttm_bo_cleanup_memtype_use(bo); return; } + ttm_bo_flush_all_fences(bo); /* @@ -474,11 +472,12 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) ttm_bo_add_to_lru(bo); } - if (bo->resv != &bo->ttm_resv) - reservation_object_unlock(&bo->ttm_resv); __ttm_bo_unreserve(bo); } + if (bo->resv != &bo->ttm_resv) + reservation_object_unlock(&bo->ttm_resv); +error: kref_get(&bo->list_kref); list_add_tail(&bo->ddestroy, &bdev->ddestroy); spin_unlock(&glob->lru_lock); @@ -1203,8 +1202,8 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, lockdep_assert_held(&bo->resv->lock.base); } else { bo->resv = &bo->ttm_resv; - reservation_object_init(&bo->ttm_resv); } + reservation_object_init(&bo->ttm_resv); atomic_inc(&bo->glob->bo_count); drm_vma_node_reset(&bo->vma_node); bo->priority = 0; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index c934ad5b39036..7c2fbdbbd0488 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -474,6 +474,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, INIT_LIST_HEAD(&fbo->lru); INIT_LIST_HEAD(&fbo->swap); INIT_LIST_HEAD(&fbo->io_reserve_lru); + mutex_init(&fbo->wu_mutex); fbo->moving = NULL; drm_vma_node_reset(&fbo->vma_node); atomic_set(&fbo->cpu_writers, 0); diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index d1e0dc9080482..04796d7d0fdbb 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -866,7 +866,8 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, adjusted_mode->clock = pixel_clock_hz / 1000 + 1; /* Given the new pixel clock, adjust HFP to keep vrefresh the same. */ - adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal); + adjusted_mode->htotal = adjusted_mode->clock * mode->htotal / + mode->clock; adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal; adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal; diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index d0c6bfb68c4ee..c50debb1986f0 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -146,7 +146,7 @@ vc4_save_hang_state(struct drm_device *dev) struct vc4_exec_info *exec[2]; struct vc4_bo *bo; unsigned long irqflags; - unsigned int i, j, unref_list_count, prev_idx; + unsigned int i, j, k, unref_list_count; kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL); if (!kernel_state) @@ -182,24 +182,24 @@ vc4_save_hang_state(struct drm_device *dev) return; } - prev_idx = 0; + k = 0; for (i = 0; i < 2; i++) { if (!exec[i]) continue; for (j = 0; j < exec[i]->bo_count; j++) { drm_gem_object_get(&exec[i]->bo[j]->base); - kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base; + kernel_state->bo[k++] = &exec[i]->bo[j]->base; } list_for_each_entry(bo, &exec[i]->unref_list, unref_head) { drm_gem_object_get(&bo->base.base); - kernel_state->bo[j + prev_idx] = &bo->base.base; - j++; + kernel_state->bo[k++] = &bo->base.base; } - prev_idx = j + 1; } + WARN_ON_ONCE(k != state->bo_count); + if (exec[0]) state->start_bin = exec[0]->ct0ca; if (exec[1]) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 937da8dd65b8b..8f71157a2b063 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -433,7 +433,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) vc4_encoder->limited_rgb_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL, - vc4_encoder->rgb_range_selectable); + vc4_encoder->rgb_range_selectable, + false); vc4_hdmi_write_infoframe(encoder, &frame); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 21c62a34e5580..87e8af5776a38 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2731,6 +2731,8 @@ static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv, } view_type = vmw_view_cmd_to_type(header->id); + if (view_type == vmw_view_max) + return -EINVAL; cmd = container_of(header, typeof(*cmd), header); ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b850562fbdd65..62c2f4be8012b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -697,7 +697,6 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) vps->pinned = 0; /* Mapping is managed by prepare_fb/cleanup_fb */ - memset(&vps->guest_map, 0, sizeof(vps->guest_map)); memset(&vps->host_map, 0, sizeof(vps->host_map)); vps->cpp = 0; @@ -760,11 +759,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, /* Should have been freed by cleanup_fb */ - if (vps->guest_map.virtual) { - DRM_ERROR("Guest mapping not freed\n"); - ttm_bo_kunmap(&vps->guest_map); - } - if (vps->host_map.virtual) { DRM_ERROR("Host mapping not freed\n"); ttm_bo_kunmap(&vps->host_map); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index ff9c8389ff21c..cd9da2dd79af1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -175,7 +175,7 @@ struct vmw_plane_state { int pinned; /* For CPU Blit */ - struct ttm_bo_kmap_obj host_map, guest_map; + struct ttm_bo_kmap_obj host_map; unsigned int cpp; }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b8a09807c5de8..3824595fece12 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -266,8 +266,8 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = { .set_property = vmw_du_connector_set_property, .destroy = vmw_ldu_connector_destroy, .reset = vmw_du_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = vmw_du_connector_duplicate_state, + .atomic_destroy_state = vmw_du_connector_destroy_state, .atomic_set_property = vmw_du_connector_atomic_set_property, .atomic_get_property = vmw_du_connector_atomic_get_property, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index d1552d3e0652b..7ae38a67388c4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -420,8 +420,8 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = { .set_property = vmw_du_connector_set_property, .destroy = vmw_sou_connector_destroy, .reset = vmw_du_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = vmw_du_connector_duplicate_state, + .atomic_destroy_state = vmw_du_connector_destroy_state, .atomic_set_property = vmw_du_connector_atomic_set_property, .atomic_get_property = vmw_du_connector_atomic_get_property, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ca3afae2db1f1..4dee05b15552b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -114,7 +114,7 @@ struct vmw_screen_target_display_unit { bool defined; /* For CPU Blit */ - struct ttm_bo_kmap_obj host_map, guest_map; + struct ttm_bo_kmap_obj host_map; unsigned int cpp; }; @@ -695,7 +695,8 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) s32 src_pitch, dst_pitch; u8 *src, *dst; bool not_used; - + struct ttm_bo_kmap_obj guest_map; + int ret; if (!dirty->num_hits) return; @@ -706,6 +707,13 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) if (width == 0 || height == 0) return; + ret = ttm_bo_kmap(&ddirty->buf->base, 0, ddirty->buf->base.num_pages, + &guest_map); + if (ret) { + DRM_ERROR("Failed mapping framebuffer for blit: %d\n", + ret); + goto out_cleanup; + } /* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */ src_pitch = stdu->display_srf->base_size.width * stdu->cpp; @@ -713,7 +721,7 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) src += ddirty->top * src_pitch + ddirty->left * stdu->cpp; dst_pitch = ddirty->pitch; - dst = ttm_kmap_obj_virtual(&stdu->guest_map, ¬_used); + dst = ttm_kmap_obj_virtual(&guest_map, ¬_used); dst += ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp; @@ -772,6 +780,7 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) vmw_fifo_commit(dev_priv, sizeof(*cmd)); } + ttm_bo_kunmap(&guest_map); out_cleanup: ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; ddirty->right = ddirty->bottom = S32_MIN; @@ -1109,9 +1118,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, { struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); - if (vps->guest_map.virtual) - ttm_bo_kunmap(&vps->guest_map); - if (vps->host_map.virtual) ttm_bo_kunmap(&vps->host_map); @@ -1277,33 +1283,11 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, */ if (vps->content_fb_type == SEPARATE_DMA && !(dev_priv->capabilities & SVGA_CAP_3D)) { - - struct vmw_framebuffer_dmabuf *new_vfbd; - - new_vfbd = vmw_framebuffer_to_vfbd(new_fb); - - ret = ttm_bo_reserve(&new_vfbd->buffer->base, false, false, - NULL); - if (ret) - goto out_srf_unpin; - - ret = ttm_bo_kmap(&new_vfbd->buffer->base, 0, - new_vfbd->buffer->base.num_pages, - &vps->guest_map); - - ttm_bo_unreserve(&new_vfbd->buffer->base); - - if (ret) { - DRM_ERROR("Failed to map content buffer to CPU\n"); - goto out_srf_unpin; - } - ret = ttm_bo_kmap(&vps->surf->res.backup->base, 0, vps->surf->res.backup->base.num_pages, &vps->host_map); if (ret) { DRM_ERROR("Failed to map display buffer to CPU\n"); - ttm_bo_kunmap(&vps->guest_map); goto out_srf_unpin; } @@ -1350,7 +1334,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, stdu->display_srf = vps->surf; stdu->content_fb_type = vps->content_fb_type; stdu->cpp = vps->cpp; - memcpy(&stdu->guest_map, &vps->guest_map, sizeof(vps->guest_map)); memcpy(&stdu->host_map, &vps->host_map, sizeof(vps->host_map)); if (!stdu->defined) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 374301fcbc867..8c7a0ce147a13 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -230,7 +230,7 @@ config HID_CMEDIA config HID_CP2112 tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" - depends on USB_HID && I2C && GPIOLIB + depends on USB_HID && HIDRAW && I2C && GPIOLIB select GPIOLIB_IRQCHIP ---help--- Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 078026f63b6f4..4e940a096b2ac 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -196,6 +196,8 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) HID_REQ_GET_REPORT); if (ret != CP2112_GPIO_CONFIG_LENGTH) { hid_err(hdev, "error requesting GPIO config: %d\n", ret); + if (ret >= 0) + ret = -EIO; goto exit; } @@ -205,8 +207,10 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); - if (ret < 0) { + if (ret != CP2112_GPIO_CONFIG_LENGTH) { hid_err(hdev, "error setting GPIO config: %d\n", ret); + if (ret >= 0) + ret = -EIO; goto exit; } @@ -214,7 +218,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) exit: mutex_unlock(&dev->lock); - return ret < 0 ? ret : -EIO; + return ret; } static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 8a03654048bf6..feb62fd4dfc3e 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -166,6 +166,7 @@ ((f)->physical == HID_DG_PEN) || \ ((f)->application == HID_DG_PEN) || \ ((f)->application == HID_DG_DIGITIZER) || \ + ((f)->application == WACOM_HID_WD_PEN) || \ ((f)->application == WACOM_HID_WD_DIGITIZER) || \ ((f)->application == WACOM_HID_G9_PEN) || \ ((f)->application == WACOM_HID_G11_PEN)) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 894b67ac2cae5..05964347008d9 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -640,22 +640,28 @@ void vmbus_close(struct vmbus_channel *channel) */ return; } - mutex_lock(&vmbus_connection.channel_mutex); /* * Close all the sub-channels first and then close the * primary channel. */ list_for_each_safe(cur, tmp, &channel->sc_list) { cur_channel = list_entry(cur, struct vmbus_channel, sc_list); - vmbus_close_internal(cur_channel); if (cur_channel->rescind) { + wait_for_completion(&cur_channel->rescind_event); + mutex_lock(&vmbus_connection.channel_mutex); + vmbus_close_internal(cur_channel); hv_process_channel_removal( cur_channel->offermsg.child_relid); + } else { + mutex_lock(&vmbus_connection.channel_mutex); + vmbus_close_internal(cur_channel); } + mutex_unlock(&vmbus_connection.channel_mutex); } /* * Now close the primary. */ + mutex_lock(&vmbus_connection.channel_mutex); vmbus_close_internal(channel); mutex_unlock(&vmbus_connection.channel_mutex); } diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 379b0df123bee..65c6d6bdce4cc 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -333,6 +333,7 @@ static struct vmbus_channel *alloc_channel(void) return NULL; spin_lock_init(&channel->lock); + init_completion(&channel->rescind_event); INIT_LIST_HEAD(&channel->sc_list); INIT_LIST_HEAD(&channel->percpu_list); @@ -883,6 +884,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) /* * Now wait for offer handling to complete. */ + vmbus_rescind_cleanup(channel); while (READ_ONCE(channel->probe_done) == false) { /* * We wait here until any channel offer is currently @@ -898,7 +900,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) if (channel->device_obj) { if (channel->chn_rescind_callback) { channel->chn_rescind_callback(channel); - vmbus_rescind_cleanup(channel); return; } /* @@ -907,7 +908,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) */ dev = get_device(&channel->device_obj->device); if (dev) { - vmbus_rescind_cleanup(channel); vmbus_device_unregister(channel->device_obj); put_device(dev); } @@ -921,13 +921,14 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) * 2. Then close the primary channel. */ mutex_lock(&vmbus_connection.channel_mutex); - vmbus_rescind_cleanup(channel); if (channel->state == CHANNEL_OPEN_STATE) { /* * The channel is currently not open; * it is safe for us to cleanup the channel. */ hv_process_channel_removal(rescind->child_relid); + } else { + complete(&channel->rescind_event); } mutex_unlock(&vmbus_connection.channel_mutex); } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 937801ac2fe0e..2cd134dd94d21 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1534,7 +1534,7 @@ static int __init hv_acpi_init(void) { int ret, t; - if (x86_hyper != &x86_hyper_ms_hyperv) + if (x86_hyper_type != X86_HYPER_MS_HYPERV) return -ENODEV; init_completion(&probe_event); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 5f11dc014ed61..e5234f953a6d1 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -22,6 +22,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -45,6 +46,7 @@ static const unsigned short normal_i2c[] = { #define JC42_REG_TEMP 0x05 #define JC42_REG_MANID 0x06 #define JC42_REG_DEVICEID 0x07 +#define JC42_REG_SMBUS 0x22 /* NXP and Atmel, possibly others? */ /* Status bits in temperature register */ #define JC42_ALARM_CRIT_BIT 15 @@ -75,6 +77,9 @@ static const unsigned short normal_i2c[] = { #define GT_MANID 0x1c68 /* Giantec */ #define GT_MANID2 0x132d /* Giantec, 2nd mfg ID */ +/* SMBUS register */ +#define SMBUS_STMOUT BIT(7) /* SMBus time-out, active low */ + /* Supported chips */ /* Analog Devices */ @@ -495,6 +500,22 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) data->extended = !!(cap & JC42_CAP_RANGE); + if (device_property_read_bool(dev, "smbus-timeout-disable")) { + int smbus; + + /* + * Not all chips support this register, but from a + * quick read of various datasheets no chip appears + * incompatible with the below attempt to disable + * the timeout. And the whole thing is opt-in... + */ + smbus = i2c_smbus_read_word_swapped(client, JC42_REG_SMBUS); + if (smbus < 0) + return smbus; + i2c_smbus_write_word_swapped(client, JC42_REG_SMBUS, + smbus | SMBUS_STMOUT); + } + config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG); if (config < 0) return config; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 4efa2bd4f6d8a..fa613bd209e34 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -404,9 +404,9 @@ extern const struct regulator_ops pmbus_regulator_ops; /* Function declarations */ void pmbus_clear_cache(struct i2c_client *client); -int pmbus_set_page(struct i2c_client *client, u8 page); -int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); -int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word); +int pmbus_set_page(struct i2c_client *client, int page); +int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg); +int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, u16 word); int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); int pmbus_write_byte(struct i2c_client *client, int page, u8 value); int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 302f0aef59ded..52a58b8b6e1bd 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -136,13 +136,13 @@ void pmbus_clear_cache(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_clear_cache); -int pmbus_set_page(struct i2c_client *client, u8 page) +int pmbus_set_page(struct i2c_client *client, int page) { struct pmbus_data *data = i2c_get_clientdata(client); int rv = 0; int newpage; - if (page != data->currpage) { + if (page >= 0 && page != data->currpage) { rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE); if (newpage != page) @@ -158,11 +158,9 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value) { int rv; - if (page >= 0) { - rv = pmbus_set_page(client, page); - if (rv < 0) - return rv; - } + rv = pmbus_set_page(client, page); + if (rv < 0) + return rv; return i2c_smbus_write_byte(client, value); } @@ -186,7 +184,8 @@ static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) return pmbus_write_byte(client, page, value); } -int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word) +int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word) { int rv; @@ -219,7 +218,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, return pmbus_write_word_data(client, page, reg, word); } -int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg) +int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg) { int rv; @@ -255,11 +254,9 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) { int rv; - if (page >= 0) { - rv = pmbus_set_page(client, page); - if (rv < 0) - return rv; - } + rv = pmbus_set_page(client, page); + if (rv < 0) + return rv; return i2c_smbus_read_byte_data(client, reg); } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 9e12a53ef7b8c..8eac00efadc1a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1617,6 +1617,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Default timeout in interrupt mode: 200 ms */ priv->adapter.timeout = HZ / 5; + if (dev->irq == IRQ_NOTCONNECTED) + priv->features &= ~FEATURE_IRQ; + if (priv->features & FEATURE_IRQ) { u16 pcictl, pcists; diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 10f00a82ec9db..e54a9b835b62e 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -396,16 +396,17 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, the underlying bus driver */ break; case I2C_SMBUS_I2C_BLOCK_DATA: + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, "Invalid block %s size %d\n", + read_write == I2C_SMBUS_READ ? "read" : "write", + data->block[0]); + return -EINVAL; + } + if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; } else { msg[0].len = data->block[0] + 1; - if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { - dev_err(&adapter->dev, - "Invalid block write size %d\n", - data->block[0]); - return -EINVAL; - } for (i = 1; i <= data->block[0]; i++) msgbuf0[i] = data->block[i]; } diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 14d1e7d9a1d6f..0e6bc631a1caf 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -282,7 +282,7 @@ int ide_cd_expiry(ide_drive_t *drive) struct request *rq = drive->hwif->rq; unsigned long wait = 0; - debug_log("%s: rq->cmd[0]: 0x%x\n", __func__, rq->cmd[0]); + debug_log("%s: scsi_req(rq)->cmd[0]: 0x%x\n", __func__, scsi_req(rq)->cmd[0]); /* * Some commands are *slow* and normally take a long time to complete. @@ -463,7 +463,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } - debug_log("[cmd %x]: check condition\n", rq->cmd[0]); + debug_log("[cmd %x]: check condition\n", scsi_req(rq)->cmd[0]); /* Retry operation */ ide_retry_pc(drive); @@ -531,7 +531,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) ide_pad_transfer(drive, write, bcount); debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", - rq->cmd[0], done, bcount, scsi_req(rq)->resid_len); + scsi_req(rq)->cmd[0], done, bcount, scsi_req(rq)->resid_len); /* And set the interrupt handler again */ ide_set_handler(drive, ide_pc_intr, timeout); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 752856b3a8497..379de1829cdb4 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -164,7 +164,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_int2 = 0x00, .addr_ihl = 0x25, .mask_ihl = 0x02, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x23, @@ -236,7 +239,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_ihl = 0x80, .addr_od = 0x22, .mask_od = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x23, @@ -318,7 +324,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_int2 = 0x00, .addr_ihl = 0x23, .mask_ihl = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, .ig1 = { .en_addr = 0x23, .en_mask = 0x08, @@ -389,7 +398,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .drdy_irq = { .addr = 0x21, .mask_int1 = 0x04, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x21, @@ -451,7 +463,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_ihl = 0x80, .addr_od = 0x22, .mask_od = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x21, @@ -569,7 +584,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .drdy_irq = { .addr = 0x21, .mask_int1 = 0x04, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x21, @@ -640,7 +658,10 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .mask_int2 = 0x00, .addr_ihl = 0x25, .mask_ihl = 0x02, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .sim = { .addr = 0x23, diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index 6e419d5a7c146..f153e02686a08 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -1012,7 +1012,7 @@ static int cpcap_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); ddata->irq = platform_get_irq_byname(pdev, "adcdone"); - if (!ddata->irq) + if (ddata->irq < 0) return -ENODEV; error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL, diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 2e8dbb89c8c96..7dc7d297a0fc4 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -221,8 +221,10 @@ enum meson_sar_adc_chan7_mux_sel { struct meson_sar_adc_data { bool has_bl30_integration; + u32 bandgap_reg; unsigned int resolution; const char *name; + const struct regmap_config *regmap_config; }; struct meson_sar_adc_priv { @@ -242,13 +244,20 @@ struct meson_sar_adc_priv { int calibscale; }; -static const struct regmap_config meson_sar_adc_regmap_config = { +static const struct regmap_config meson_sar_adc_regmap_config_gxbb = { .reg_bits = 8, .val_bits = 32, .reg_stride = 4, .max_register = MESON_SAR_ADC_REG13, }; +static const struct regmap_config meson_sar_adc_regmap_config_meson8 = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = MESON_SAR_ADC_DELTA_10, +}; + static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); @@ -600,7 +609,7 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, init.num_parents = 1; priv->clk_gate.reg = base + MESON_SAR_ADC_REG3; - priv->clk_gate.bit_idx = fls(MESON_SAR_ADC_REG3_CLK_EN); + priv->clk_gate.bit_idx = __ffs(MESON_SAR_ADC_REG3_CLK_EN); priv->clk_gate.hw.init = &init; priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw); @@ -685,6 +694,20 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) return 0; } +static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 enable_mask; + + if (priv->data->bandgap_reg == MESON_SAR_ADC_REG11) + enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN; + else + enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN; + + regmap_update_bits(priv->regmap, priv->data->bandgap_reg, enable_mask, + on_off ? enable_mask : 0); +} + static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); @@ -717,9 +740,9 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, - MESON_SAR_ADC_REG11_BANDGAP_EN, - MESON_SAR_ADC_REG11_BANDGAP_EN); + + meson_sar_adc_set_bandgap(indio_dev, true); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, MESON_SAR_ADC_REG3_ADC_EN, MESON_SAR_ADC_REG3_ADC_EN); @@ -739,8 +762,7 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) err_adc_clk: regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, MESON_SAR_ADC_REG3_ADC_EN, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, - MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + meson_sar_adc_set_bandgap(indio_dev, false); clk_disable_unprepare(priv->sana_clk); err_sana_clk: clk_disable_unprepare(priv->core_clk); @@ -765,8 +787,8 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, MESON_SAR_ADC_REG3_ADC_EN, 0); - regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, - MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + + meson_sar_adc_set_bandgap(indio_dev, false); clk_disable_unprepare(priv->sana_clk); clk_disable_unprepare(priv->core_clk); @@ -845,30 +867,40 @@ static const struct iio_info meson_sar_adc_iio_info = { static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { .has_bl30_integration = false, + .bandgap_reg = MESON_SAR_ADC_DELTA_10, + .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, .name = "meson-meson8-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { .has_bl30_integration = false, + .bandgap_reg = MESON_SAR_ADC_DELTA_10, + .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, .name = "meson-meson8b-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { .has_bl30_integration = true, + .bandgap_reg = MESON_SAR_ADC_REG11, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 10, .name = "meson-gxbb-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { .has_bl30_integration = true, + .bandgap_reg = MESON_SAR_ADC_REG11, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, .name = "meson-gxl-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { .has_bl30_integration = true, + .bandgap_reg = MESON_SAR_ADC_REG11, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, .name = "meson-gxm-saradc", }; @@ -946,7 +978,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) return ret; priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &meson_sar_adc_regmap_config); + priv->data->regmap_config); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index e0dc204883357..9ac2fb032df6b 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -369,6 +369,7 @@ int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val) conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr_old]); conv_time += DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]); + conv_time += conv_time / 10; /* 10% internal clock inaccuracy */ usleep_range(conv_time, conv_time + 1); data->conv_invalid = false; } diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 02e833b14db08..34115f05d5c46 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -470,7 +470,7 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) * different one. Take into account irq status register * to understand if irq trigger can be properly supported */ - if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) + if (sdata->sensor_settings->drdy_irq.stat_drdy.addr) sdata->hw_irq_trigger = enable; return 0; } diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index fa73e67953598..fdcc5a8919587 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -31,7 +31,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, int ret; /* How would I know if I can't check it? */ - if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy) + if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) return -EINVAL; /* No scan mask, no interrupt */ @@ -39,23 +39,15 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, return 0; ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.addr_stat_drdy, + sdata->sensor_settings->drdy_irq.stat_drdy.addr, &status); if (ret < 0) { dev_err(sdata->dev, "error checking samples available\n"); return ret; } - /* - * the lower bits of .active_scan_mask[0] is directly mapped - * to the channels on the sensor: either bit 0 for - * one-dimensional sensors, or e.g. x,y,z for accelerometers, - * gyroscopes or magnetometers. No sensor use more than 3 - * channels, so cut the other status bits here. - */ - status &= 0x07; - if (status & (u8)indio_dev->active_scan_mask[0]) + if (status & sdata->sensor_settings->drdy_irq.stat_drdy.mask) return 1; return 0; @@ -212,7 +204,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, * it was "our" interrupt. */ if (sdata->int_pin_open_drain && - sdata->sensor_settings->drdy_irq.addr_stat_drdy) + sdata->sensor_settings->drdy_irq.stat_drdy.addr) irq_trig |= IRQF_SHARED; err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e366422e85127..2536a8400c989 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -118,7 +118,10 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { * drain settings, but only for INT1 and not * for the DRDY line on INT2. */ - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .multi_read_bit = true, .bootime = 2, @@ -188,7 +191,10 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { * drain settings, but only for INT1 and not * for the DRDY line on INT2. */ - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .multi_read_bit = true, .bootime = 2, @@ -253,7 +259,10 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { * drain settings, but only for INT1 and not * for the DRDY line on INT2. */ - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .multi_read_bit = true, .bootime = 2, diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 839b875c29b9d..9fb4bc73a6bc7 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -371,7 +371,7 @@ static int max30102_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); break; case IIO_CHAN_INFO_SCALE: - *val = 1; /* 0.0625 */ + *val = 1000; /* 62.5 */ *val2 = 16; ret = IIO_VAL_FRACTIONAL; break; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 08aafba4481c6..19031a7bce235 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -317,7 +317,10 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, .drdy_irq = { /* drdy line is routed drdy pin */ - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, }, .multi_read_bit = true, .bootime = 2, @@ -361,7 +364,10 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .drdy_irq = { .addr = 0x62, .mask_int1 = 0x01, - .addr_stat_drdy = 0x67, + .stat_drdy = { + .addr = 0x67, + .mask = 0x07, + }, }, .multi_read_bit = false, .bootime = 2, diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index 37ba007f8dcaa..74831fcd03136 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -285,6 +285,9 @@ static int mux_configure_channel(struct device *dev, struct mux *mux, child->ext_info_cache = devm_kzalloc(dev, sizeof(*child->ext_info_cache) * num_ext_info, GFP_KERNEL); + if (!child->ext_info_cache) + return -ENOMEM; + for (i = 0; i < num_ext_info; ++i) { child->ext_info_cache[i].size = -1; @@ -309,6 +312,9 @@ static int mux_configure_channel(struct device *dev, struct mux *mux, child->ext_info_cache[i].data = devm_kmemdup(dev, page, ret + 1, GFP_KERNEL); + if (!child->ext_info_cache[i].data) + return -ENOMEM; + child->ext_info_cache[i].data[ret] = 0; child->ext_info_cache[i].size = ret; } diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 34611a8ea2cea..ea075fcd5a6f6 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -287,7 +287,10 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .mask_ihl = 0x80, .addr_od = 0x22, .mask_od = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x03, + }, }, .multi_read_bit = true, .bootime = 2, @@ -395,7 +398,10 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .mask_ihl = 0x80, .addr_od = 0x22, .mask_od = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x03, + }, }, .multi_read_bit = true, .bootime = 2, @@ -454,7 +460,10 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .mask_ihl = 0x80, .addr_od = 0x12, .mask_od = 0x40, - .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x03, + }, }, .multi_read_bit = false, .bootime = 2, diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 12523f630b614..d2f74721b3ba6 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -852,7 +852,7 @@ static struct notifier_block nb = { int addr_init(void) { - addr_wq = alloc_ordered_workqueue("ib_addr", WQ_MEM_RECLAIM); + addr_wq = alloc_ordered_workqueue("ib_addr", 0); if (!addr_wq) return -ENOMEM; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4c4b46586af2b..2af79e4f32359 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1575,7 +1575,7 @@ static void cm_format_req_event(struct cm_work *work, param->bth_pkey = cm_get_bth_pkey(work); param->port = cm_id_priv->av.port->port_num; param->primary_path = &work->path[0]; - if (req_msg->alt_local_lid) + if (cm_req_has_alt_path(req_msg)) param->alternate_path = &work->path[1]; else param->alternate_path = NULL; @@ -1856,7 +1856,8 @@ static int cm_req_handler(struct cm_work *work) cm_process_routed_req(req_msg, work->mad_recv_wc->wc); memset(&work->path[0], 0, sizeof(work->path[0])); - memset(&work->path[1], 0, sizeof(work->path[1])); + if (cm_req_has_alt_path(req_msg)) + memset(&work->path[1], 0, sizeof(work->path[1])); grh = rdma_ah_read_grh(&cm_id_priv->av.ah_attr); ret = ib_get_cached_gid(work->port->cm_dev->ib_device, work->port->port_num, @@ -3817,14 +3818,16 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, struct cm_port *port = mad_agent->context; struct cm_work *work; enum ib_cm_event_type event; + bool alt_path = false; u16 attr_id; int paths = 0; int going_down = 0; switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { case CM_REQ_ATTR_ID: - paths = 1 + (((struct cm_req_msg *) mad_recv_wc->recv_buf.mad)-> - alt_local_lid != 0); + alt_path = cm_req_has_alt_path((struct cm_req_msg *) + mad_recv_wc->recv_buf.mad); + paths = 1 + (alt_path != 0); event = IB_CM_REQ_RECEIVED; break; case CM_MRA_ATTR_ID: diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 852c8fec80885..fa79c7076ccd1 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1540,7 +1540,7 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, return id_priv; } -static inline int cma_user_data_offset(struct rdma_id_private *id_priv) +static inline u8 cma_user_data_offset(struct rdma_id_private *id_priv) { return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); } @@ -1942,7 +1942,8 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) struct rdma_id_private *listen_id, *conn_id = NULL; struct rdma_cm_event event; struct net_device *net_dev; - int offset, ret; + u8 offset; + int ret; listen_id = cma_id_from_event(cm_id, ib_event, &net_dev); if (IS_ERR(listen_id)) @@ -3440,7 +3441,8 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, struct ib_cm_sidr_req_param req; struct ib_cm_id *id; void *private_data; - int offset, ret; + u8 offset; + int ret; memset(&req, 0, sizeof req); offset = cma_user_data_offset(id_priv); @@ -3497,7 +3499,8 @@ static int cma_connect_ib(struct rdma_id_private *id_priv, struct rdma_route *route; void *private_data; struct ib_cm_id *id; - int offset, ret; + u8 offset; + int ret; memset(&req, 0, sizeof req); offset = cma_user_data_offset(id_priv); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index f8f53bb90837c..cb91245e91633 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1974,14 +1974,15 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, unsigned long flags; int ret; + INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); ret = ib_mad_enforce_security(mad_agent_priv, mad_recv_wc->wc->pkey_index); if (ret) { ib_free_recv_mad(mad_recv_wc); deref_mad_agent(mad_agent_priv); + return; } - INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) { mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c index 88bdafb297f5f..59b2f96d986aa 100644 --- a/drivers/infiniband/core/security.c +++ b/drivers/infiniband/core/security.c @@ -87,16 +87,14 @@ static int enforce_qp_pkey_security(u16 pkey, if (ret) return ret; - if (qp_sec->qp == qp_sec->qp->real_qp) { - list_for_each_entry(shared_qp_sec, - &qp_sec->shared_qp_list, - shared_qp_list) { - ret = security_ib_pkey_access(shared_qp_sec->security, - subnet_prefix, - pkey); - if (ret) - return ret; - } + list_for_each_entry(shared_qp_sec, + &qp_sec->shared_qp_list, + shared_qp_list) { + ret = security_ib_pkey_access(shared_qp_sec->security, + subnet_prefix, + pkey); + if (ret) + return ret; } return 0; } @@ -388,6 +386,9 @@ int ib_open_shared_qp_security(struct ib_qp *qp, struct ib_device *dev) if (ret) return ret; + if (!qp->qp_sec) + return 0; + mutex_lock(&real_qp->qp_sec->mutex); ret = check_qp_port_pkey_settings(real_qp->qp_sec->ports_pkeys, qp->qp_sec); @@ -419,8 +420,17 @@ void ib_close_shared_qp_security(struct ib_qp_security *sec) int ib_create_qp_security(struct ib_qp *qp, struct ib_device *dev) { + u8 i = rdma_start_port(dev); + bool is_ib = false; int ret; + while (i <= rdma_end_port(dev) && !is_ib) + is_ib = rdma_protocol_ib(dev, i++); + + /* If this isn't an IB device don't create the security context */ + if (!is_ib) + return 0; + qp->qp_sec = kzalloc(sizeof(*qp->qp_sec), GFP_KERNEL); if (!qp->qp_sec) return -ENOMEM; @@ -443,6 +453,10 @@ EXPORT_SYMBOL(ib_create_qp_security); void ib_destroy_qp_security_begin(struct ib_qp_security *sec) { + /* Return if not IB */ + if (!sec) + return; + mutex_lock(&sec->mutex); /* Remove the QP from the lists so it won't get added to @@ -472,6 +486,10 @@ void ib_destroy_qp_security_abort(struct ib_qp_security *sec) int ret; int i; + /* Return if not IB */ + if (!sec) + return; + /* If a concurrent cache update is in progress this * QP security could be marked for an error state * transition. Wait for this to complete. @@ -507,6 +525,10 @@ void ib_destroy_qp_security_end(struct ib_qp_security *sec) { int i; + /* Return if not IB */ + if (!sec) + return; + /* If a concurrent cache update is occurring we must * wait until this QP security structure is processed * in the QP to error flow before destroying it because @@ -559,19 +581,35 @@ int ib_security_modify_qp(struct ib_qp *qp, { int ret = 0; struct ib_ports_pkeys *tmp_pps; - struct ib_ports_pkeys *new_pps; - bool special_qp = (qp->qp_type == IB_QPT_SMI || - qp->qp_type == IB_QPT_GSI || - qp->qp_type >= IB_QPT_RESERVED1); + struct ib_ports_pkeys *new_pps = NULL; + struct ib_qp *real_qp = qp->real_qp; + bool special_qp = (real_qp->qp_type == IB_QPT_SMI || + real_qp->qp_type == IB_QPT_GSI || + real_qp->qp_type >= IB_QPT_RESERVED1); bool pps_change = ((qp_attr_mask & (IB_QP_PKEY_INDEX | IB_QP_PORT)) || (qp_attr_mask & IB_QP_ALT_PATH)); - if (pps_change && !special_qp) { - mutex_lock(&qp->qp_sec->mutex); - new_pps = get_new_pps(qp, + WARN_ONCE((qp_attr_mask & IB_QP_PORT && + rdma_protocol_ib(real_qp->device, qp_attr->port_num) && + !real_qp->qp_sec), + "%s: QP security is not initialized for IB QP: %d\n", + __func__, real_qp->qp_num); + + /* The port/pkey settings are maintained only for the real QP. Open + * handles on the real QP will be in the shared_qp_list. When + * enforcing security on the real QP all the shared QPs will be + * checked as well. + */ + + if (pps_change && !special_qp && real_qp->qp_sec) { + mutex_lock(&real_qp->qp_sec->mutex); + new_pps = get_new_pps(real_qp, qp_attr, qp_attr_mask); - + if (!new_pps) { + mutex_unlock(&real_qp->qp_sec->mutex); + return -ENOMEM; + } /* Add this QP to the lists for the new port * and pkey settings before checking for permission * in case there is a concurrent cache update @@ -586,24 +624,24 @@ int ib_security_modify_qp(struct ib_qp *qp, if (!ret) ret = check_qp_port_pkey_settings(new_pps, - qp->qp_sec); + real_qp->qp_sec); } if (!ret) - ret = qp->device->modify_qp(qp->real_qp, - qp_attr, - qp_attr_mask, - udata); + ret = real_qp->device->modify_qp(real_qp, + qp_attr, + qp_attr_mask, + udata); - if (pps_change && !special_qp) { + if (new_pps) { /* Clean up the lists and free the appropriate * ports_pkeys structure. */ if (ret) { tmp_pps = new_pps; } else { - tmp_pps = qp->qp_sec->ports_pkeys; - qp->qp_sec->ports_pkeys = new_pps; + tmp_pps = real_qp->qp_sec->ports_pkeys; + real_qp->qp_sec->ports_pkeys = new_pps; } if (tmp_pps) { @@ -611,7 +649,7 @@ int ib_security_modify_qp(struct ib_qp *qp, port_pkey_list_remove(&tmp_pps->alt); } kfree(tmp_pps); - mutex_unlock(&qp->qp_sec->mutex); + mutex_unlock(&real_qp->qp_sec->mutex); } return ret; } @@ -626,6 +664,9 @@ int ib_security_pkey_access(struct ib_device *dev, u16 pkey; int ret; + if (!rdma_protocol_ib(dev, port_num)) + return 0; + ret = ib_get_cached_pkey(dev, port_num, pkey_index, &pkey); if (ret) return ret; @@ -660,6 +701,9 @@ int ib_mad_agent_security_setup(struct ib_mad_agent *agent, { int ret; + if (!rdma_protocol_ib(agent->device, agent->port_num)) + return 0; + ret = security_ib_alloc_security(&agent->security); if (ret) return ret; @@ -685,6 +729,9 @@ int ib_mad_agent_security_setup(struct ib_mad_agent *agent, void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) { + if (!rdma_protocol_ib(agent->device, agent->port_num)) + return; + security_ib_free_security(agent->security); if (agent->lsm_nb_reg) unregister_lsm_notifier(&agent->lsm_nb); @@ -692,20 +739,19 @@ void ib_mad_agent_security_cleanup(struct ib_mad_agent *agent) int ib_mad_enforce_security(struct ib_mad_agent_private *map, u16 pkey_index) { - int ret; - - if (map->agent.qp->qp_type == IB_QPT_SMI && !map->agent.smp_allowed) - return -EACCES; - - ret = ib_security_pkey_access(map->agent.device, - map->agent.port_num, - pkey_index, - map->agent.security); + if (!rdma_protocol_ib(map->agent.device, map->agent.port_num)) + return 0; - if (ret) - return ret; + if (map->agent.qp->qp_type == IB_QPT_SMI) { + if (!map->agent.smp_allowed) + return -EACCES; + return 0; + } - return 0; + return ib_security_pkey_access(map->agent.device, + map->agent.port_num, + pkey_index, + map->agent.security); } #endif /* CONFIG_SECURITY_INFINIBAND */ diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 21e60b1e2ff41..130606c3b07c1 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -191,7 +191,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_list_start = umem->sg_head.sgl; while (npages) { - ret = get_user_pages(cur_base, + ret = get_user_pages_longterm(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof (struct page *)), gup_flags, page_list, vma_list); diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index c1696e6084b2b..603acaf91828a 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -229,7 +229,16 @@ static void recv_handler(struct ib_mad_agent *agent, packet->mad.hdr.status = 0; packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len; packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); - packet->mad.hdr.lid = ib_lid_be16(mad_recv_wc->wc->slid); + /* + * On OPA devices it is okay to lose the upper 16 bits of LID as this + * information is obtained elsewhere. Mask off the upper 16 bits. + */ + if (agent->device->port_immutable[agent->port_num].core_cap_flags & + RDMA_CORE_PORT_INTEL_OPA) + packet->mad.hdr.lid = ib_lid_be16(0xFFFF & + mad_recv_wc->wc->slid); + else + packet->mad.hdr.lid = ib_lid_be16(mad_recv_wc->wc->slid); packet->mad.hdr.sl = mad_recv_wc->wc->sl; packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 52a2cf2d83aaf..93c1a57dbff1b 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1982,6 +1982,12 @@ static int modify_qp(struct ib_uverbs_file *file, goto release_qp; } + if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && + !rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) { + ret = -EINVAL; + goto release_qp; + } + attr->qp_state = cmd->base.qp_state; attr->cur_qp_state = cmd->base.cur_qp_state; attr->path_mtu = cmd->base.path_mtu; @@ -2079,8 +2085,8 @@ int ib_uverbs_ex_modify_qp(struct ib_uverbs_file *file, return -EOPNOTSUPP; if (ucore->inlen > sizeof(cmd)) { - if (ib_is_udata_cleared(ucore, sizeof(cmd), - ucore->inlen - sizeof(cmd))) + if (!ib_is_udata_cleared(ucore, sizeof(cmd), + ucore->inlen - sizeof(cmd))) return -EOPNOTSUPP; } diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index de57d6c11a254..9032f77cc38d2 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1400,7 +1400,8 @@ int ib_close_qp(struct ib_qp *qp) spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags); atomic_dec(&real_qp->usecnt); - ib_close_shared_qp_security(qp->qp_sec); + if (qp->qp_sec) + ib_close_shared_qp_security(qp->qp_sec); kfree(qp); return 0; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 0d89621d9fe8e..b210495ff33c0 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -394,6 +394,7 @@ int bnxt_re_add_gid(struct ib_device *ibdev, u8 port_num, ctx->idx = tbl_idx; ctx->refcnt = 1; ctx_tbl[tbl_idx] = ctx; + *context = ctx; return rc; } diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index be07da1997e68..73feeeeb42830 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -410,6 +410,11 @@ void c4iw_flush_hw_cq(struct c4iw_cq *chp) static int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq) { + if (DRAIN_CQE(cqe)) { + WARN_ONCE(1, "Unexpected DRAIN CQE qp id %u!\n", wq->sq.qid); + return 0; + } + if (CQE_OPCODE(cqe) == FW_RI_TERMINATE) return 0; @@ -504,7 +509,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, /* * Special cqe for drain WR completions... */ - if (CQE_OPCODE(hw_cqe) == C4IW_DRAIN_OPCODE) { + if (DRAIN_CQE(hw_cqe)) { *cookie = CQE_DRAIN_COOKIE(hw_cqe); *cqe = *hw_cqe; goto skip_cqe; @@ -581,10 +586,10 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, ret = -EAGAIN; goto skip_cqe; } - if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) { + if (unlikely(!CQE_STATUS(hw_cqe) && + CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) { t4_set_wq_in_error(wq); - hw_cqe->header |= htonl(CQE_STATUS_V(T4_ERR_MSN)); - goto proc_cqe; + hw_cqe->header |= cpu_to_be32(CQE_STATUS_V(T4_ERR_MSN)); } goto proc_cqe; } @@ -761,9 +766,6 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) c4iw_invalidate_mr(qhp->rhp, CQE_WRID_FR_STAG(&cqe)); break; - case C4IW_DRAIN_OPCODE: - wc->opcode = IB_WC_SEND; - break; default: pr_err("Unexpected opcode %d in the CQE received for QPID=0x%0x\n", CQE_OPCODE(&cqe), CQE_QPID(&cqe)); diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c index 8f963df0bffce..9d25298d96faf 100644 --- a/drivers/infiniband/hw/cxgb4/ev.c +++ b/drivers/infiniband/hw/cxgb4/ev.c @@ -109,9 +109,11 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, if (qhp->ibqp.event_handler) (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); - spin_lock_irqsave(&chp->comp_handler_lock, flag); - (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); - spin_unlock_irqrestore(&chp->comp_handler_lock, flag); + if (t4_clear_cq_armed(&chp->cq)) { + spin_lock_irqsave(&chp->comp_handler_lock, flag); + (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); + spin_unlock_irqrestore(&chp->comp_handler_lock, flag); + } } void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe) diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 819a30635d53b..20c481115a996 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -631,8 +631,6 @@ static inline int to_ib_qp_state(int c4iw_qp_state) return IB_QPS_ERR; } -#define C4IW_DRAIN_OPCODE FW_RI_SGE_EC_CR_RETURN - static inline u32 c4iw_ib_to_tpt_access(int a) { return (a & IB_ACCESS_REMOTE_WRITE ? FW_RI_MEM_ACCESS_REM_WRITE : 0) | diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index cb7fc0d35d1d1..f311ea73c806f 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -794,21 +794,57 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) return 0; } -static void complete_sq_drain_wr(struct c4iw_qp *qhp, struct ib_send_wr *wr) +static int ib_to_fw_opcode(int ib_opcode) +{ + int opcode; + + switch (ib_opcode) { + case IB_WR_SEND_WITH_INV: + opcode = FW_RI_SEND_WITH_INV; + break; + case IB_WR_SEND: + opcode = FW_RI_SEND; + break; + case IB_WR_RDMA_WRITE: + opcode = FW_RI_RDMA_WRITE; + break; + case IB_WR_RDMA_READ: + case IB_WR_RDMA_READ_WITH_INV: + opcode = FW_RI_READ_REQ; + break; + case IB_WR_REG_MR: + opcode = FW_RI_FAST_REGISTER; + break; + case IB_WR_LOCAL_INV: + opcode = FW_RI_LOCAL_INV; + break; + default: + opcode = -EINVAL; + } + return opcode; +} + +static int complete_sq_drain_wr(struct c4iw_qp *qhp, struct ib_send_wr *wr) { struct t4_cqe cqe = {}; struct c4iw_cq *schp; unsigned long flag; struct t4_cq *cq; + int opcode; schp = to_c4iw_cq(qhp->ibqp.send_cq); cq = &schp->cq; + opcode = ib_to_fw_opcode(wr->opcode); + if (opcode < 0) + return opcode; + cqe.u.drain_cookie = wr->wr_id; cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | - CQE_OPCODE_V(C4IW_DRAIN_OPCODE) | + CQE_OPCODE_V(opcode) | CQE_TYPE_V(1) | CQE_SWCQE_V(1) | + CQE_DRAIN_V(1) | CQE_QPID_V(qhp->wq.sq.qid)); spin_lock_irqsave(&schp->lock, flag); @@ -817,10 +853,29 @@ static void complete_sq_drain_wr(struct c4iw_qp *qhp, struct ib_send_wr *wr) t4_swcq_produce(cq); spin_unlock_irqrestore(&schp->lock, flag); - spin_lock_irqsave(&schp->comp_handler_lock, flag); - (*schp->ibcq.comp_handler)(&schp->ibcq, - schp->ibcq.cq_context); - spin_unlock_irqrestore(&schp->comp_handler_lock, flag); + if (t4_clear_cq_armed(&schp->cq)) { + spin_lock_irqsave(&schp->comp_handler_lock, flag); + (*schp->ibcq.comp_handler)(&schp->ibcq, + schp->ibcq.cq_context); + spin_unlock_irqrestore(&schp->comp_handler_lock, flag); + } + return 0; +} + +static int complete_sq_drain_wrs(struct c4iw_qp *qhp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + int ret = 0; + + while (wr) { + ret = complete_sq_drain_wr(qhp, wr); + if (ret) { + *bad_wr = wr; + break; + } + wr = wr->next; + } + return ret; } static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr) @@ -835,9 +890,10 @@ static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr) cqe.u.drain_cookie = wr->wr_id; cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | - CQE_OPCODE_V(C4IW_DRAIN_OPCODE) | + CQE_OPCODE_V(FW_RI_SEND) | CQE_TYPE_V(0) | CQE_SWCQE_V(1) | + CQE_DRAIN_V(1) | CQE_QPID_V(qhp->wq.sq.qid)); spin_lock_irqsave(&rchp->lock, flag); @@ -846,10 +902,20 @@ static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr) t4_swcq_produce(cq); spin_unlock_irqrestore(&rchp->lock, flag); - spin_lock_irqsave(&rchp->comp_handler_lock, flag); - (*rchp->ibcq.comp_handler)(&rchp->ibcq, - rchp->ibcq.cq_context); - spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); + if (t4_clear_cq_armed(&rchp->cq)) { + spin_lock_irqsave(&rchp->comp_handler_lock, flag); + (*rchp->ibcq.comp_handler)(&rchp->ibcq, + rchp->ibcq.cq_context); + spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); + } +} + +static void complete_rq_drain_wrs(struct c4iw_qp *qhp, struct ib_recv_wr *wr) +{ + while (wr) { + complete_rq_drain_wr(qhp, wr); + wr = wr->next; + } } int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, @@ -868,9 +934,14 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, qhp = to_c4iw_qp(ibqp); spin_lock_irqsave(&qhp->lock, flag); - if (t4_wq_in_error(&qhp->wq)) { + + /* + * If the qp has been flushed, then just insert a special + * drain cqe. + */ + if (qhp->wq.flushed) { spin_unlock_irqrestore(&qhp->lock, flag); - complete_sq_drain_wr(qhp, wr); + err = complete_sq_drain_wrs(qhp, wr, bad_wr); return err; } num_wrs = t4_sq_avail(&qhp->wq); @@ -1012,9 +1083,14 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, qhp = to_c4iw_qp(ibqp); spin_lock_irqsave(&qhp->lock, flag); - if (t4_wq_in_error(&qhp->wq)) { + + /* + * If the qp has been flushed, then just insert a special + * drain cqe. + */ + if (qhp->wq.flushed) { spin_unlock_irqrestore(&qhp->lock, flag); - complete_rq_drain_wr(qhp, wr); + complete_rq_drain_wrs(qhp, wr); return err; } num_wrs = t4_rq_avail(&qhp->wq); @@ -1257,48 +1333,51 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp, pr_debug("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp); - /* locking hierarchy: cq lock first, then qp lock. */ + /* locking hierarchy: cqs lock first, then qp lock. */ spin_lock_irqsave(&rchp->lock, flag); + if (schp != rchp) + spin_lock(&schp->lock); spin_lock(&qhp->lock); if (qhp->wq.flushed) { spin_unlock(&qhp->lock); + if (schp != rchp) + spin_unlock(&schp->lock); spin_unlock_irqrestore(&rchp->lock, flag); return; } qhp->wq.flushed = 1; + t4_set_wq_in_error(&qhp->wq); c4iw_flush_hw_cq(rchp); c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count); rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count); - spin_unlock(&qhp->lock); - spin_unlock_irqrestore(&rchp->lock, flag); - /* locking hierarchy: cq lock first, then qp lock. */ - spin_lock_irqsave(&schp->lock, flag); - spin_lock(&qhp->lock); if (schp != rchp) c4iw_flush_hw_cq(schp); sq_flushed = c4iw_flush_sq(qhp); + spin_unlock(&qhp->lock); - spin_unlock_irqrestore(&schp->lock, flag); + if (schp != rchp) + spin_unlock(&schp->lock); + spin_unlock_irqrestore(&rchp->lock, flag); if (schp == rchp) { - if (t4_clear_cq_armed(&rchp->cq) && - (rq_flushed || sq_flushed)) { + if ((rq_flushed || sq_flushed) && + t4_clear_cq_armed(&rchp->cq)) { spin_lock_irqsave(&rchp->comp_handler_lock, flag); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); } } else { - if (t4_clear_cq_armed(&rchp->cq) && rq_flushed) { + if (rq_flushed && t4_clear_cq_armed(&rchp->cq)) { spin_lock_irqsave(&rchp->comp_handler_lock, flag); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); } - if (t4_clear_cq_armed(&schp->cq) && sq_flushed) { + if (sq_flushed && t4_clear_cq_armed(&schp->cq)) { spin_lock_irqsave(&schp->comp_handler_lock, flag); (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); @@ -1315,8 +1394,8 @@ static void flush_qp(struct c4iw_qp *qhp) rchp = to_c4iw_cq(qhp->ibqp.recv_cq); schp = to_c4iw_cq(qhp->ibqp.send_cq); - t4_set_wq_in_error(&qhp->wq); if (qhp->ibqp.uobject) { + t4_set_wq_in_error(&qhp->wq); t4_set_cq_in_error(&rchp->cq); spin_lock_irqsave(&rchp->comp_handler_lock, flag); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index e765c00303cda..80b390e861dcf 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -171,7 +171,7 @@ struct t4_cqe { __be32 msn; } rcqe; struct { - u32 stag; + __be32 stag; u16 nada2; u16 cidx; } scqe; @@ -197,6 +197,11 @@ struct t4_cqe { #define CQE_SWCQE_G(x) ((((x) >> CQE_SWCQE_S)) & CQE_SWCQE_M) #define CQE_SWCQE_V(x) ((x)<> CQE_DRAIN_S)) & CQE_DRAIN_M) +#define CQE_DRAIN_V(x) ((x)<> CQE_STATUS_S)) & CQE_STATUS_M) @@ -213,6 +218,7 @@ struct t4_cqe { #define CQE_OPCODE_V(x) ((x)<header))) +#define DRAIN_CQE(x) (CQE_DRAIN_G(be32_to_cpu((x)->header))) #define CQE_QPID(x) (CQE_QPID_G(be32_to_cpu((x)->header))) #define CQE_TYPE(x) (CQE_TYPE_G(be32_to_cpu((x)->header))) #define SQ_TYPE(x) (CQE_TYPE((x))) diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h index 010c709ba3bb5..58c531db4f4aa 100644 --- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h +++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h @@ -675,8 +675,8 @@ struct fw_ri_fr_nsmr_tpte_wr { __u16 wrid; __u8 r1[3]; __u8 len16; - __u32 r2; - __u32 stag; + __be32 r2; + __be32 stag; struct fw_ri_tpte tpte; __u64 pbl[2]; }; diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 0be42787759fa..0e17d03ef1cb2 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -9952,7 +9952,7 @@ int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which) goto unimplemented; case HFI1_IB_CFG_OP_VLS: - val = ppd->vls_operational; + val = ppd->actual_vls_operational; break; case HFI1_IB_CFG_VL_HIGH_CAP: /* VL arb high priority table size */ val = VL_ARB_HIGH_PRIO_TABLE_SIZE; @@ -13074,7 +13074,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd) first_sdma = last_general; last_sdma = first_sdma + dd->num_sdma; first_rx = last_sdma; - last_rx = first_rx + dd->n_krcv_queues + HFI1_NUM_VNIC_CTXT; + last_rx = first_rx + dd->n_krcv_queues + dd->num_vnic_contexts; /* VNIC MSIx interrupts get mapped when VNIC contexts are created */ dd->first_dyn_msix_idx = first_rx + dd->n_krcv_queues; @@ -13294,8 +13294,9 @@ static int set_up_interrupts(struct hfi1_devdata *dd) * slow source, SDMACleanupDone) * N interrupts - one per used SDMA engine * M interrupt - one per kernel receive context + * V interrupt - one for each VNIC context */ - total = 1 + dd->num_sdma + dd->n_krcv_queues + HFI1_NUM_VNIC_CTXT; + total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts; /* ask for MSI-X interrupts */ request = request_msix(dd, total); @@ -13356,10 +13357,12 @@ static int set_up_interrupts(struct hfi1_devdata *dd) * in array of contexts * freectxts - number of free user contexts * num_send_contexts - number of PIO send contexts being used + * num_vnic_contexts - number of contexts reserved for VNIC */ static int set_up_context_variables(struct hfi1_devdata *dd) { unsigned long num_kernel_contexts; + u16 num_vnic_contexts = HFI1_NUM_VNIC_CTXT; int total_contexts; int ret; unsigned ngroups; @@ -13393,6 +13396,14 @@ static int set_up_context_variables(struct hfi1_devdata *dd) num_kernel_contexts); num_kernel_contexts = dd->chip_send_contexts - num_vls - 1; } + + /* Accommodate VNIC contexts if possible */ + if ((num_kernel_contexts + num_vnic_contexts) > dd->chip_rcv_contexts) { + dd_dev_err(dd, "No receive contexts available for VNIC\n"); + num_vnic_contexts = 0; + } + total_contexts = num_kernel_contexts + num_vnic_contexts; + /* * User contexts: * - default to 1 user context per real (non-HT) CPU core if @@ -13402,19 +13413,16 @@ static int set_up_context_variables(struct hfi1_devdata *dd) num_user_contexts = cpumask_weight(&node_affinity.real_cpu_mask); - total_contexts = num_kernel_contexts + num_user_contexts; - /* * Adjust the counts given a global max. */ - if (total_contexts > dd->chip_rcv_contexts) { + if (total_contexts + num_user_contexts > dd->chip_rcv_contexts) { dd_dev_err(dd, "Reducing # user receive contexts to: %d, from %d\n", - (int)(dd->chip_rcv_contexts - num_kernel_contexts), + (int)(dd->chip_rcv_contexts - total_contexts), (int)num_user_contexts); - num_user_contexts = dd->chip_rcv_contexts - num_kernel_contexts; /* recalculate */ - total_contexts = num_kernel_contexts + num_user_contexts; + num_user_contexts = dd->chip_rcv_contexts - total_contexts; } /* each user context requires an entry in the RMT */ @@ -13427,25 +13435,24 @@ static int set_up_context_variables(struct hfi1_devdata *dd) user_rmt_reduced); /* recalculate */ num_user_contexts = user_rmt_reduced; - total_contexts = num_kernel_contexts + num_user_contexts; } - /* Accommodate VNIC contexts */ - if ((total_contexts + HFI1_NUM_VNIC_CTXT) <= dd->chip_rcv_contexts) - total_contexts += HFI1_NUM_VNIC_CTXT; + total_contexts += num_user_contexts; /* the first N are kernel contexts, the rest are user/vnic contexts */ dd->num_rcv_contexts = total_contexts; dd->n_krcv_queues = num_kernel_contexts; dd->first_dyn_alloc_ctxt = num_kernel_contexts; + dd->num_vnic_contexts = num_vnic_contexts; dd->num_user_contexts = num_user_contexts; dd->freectxts = num_user_contexts; dd_dev_info(dd, - "rcv contexts: chip %d, used %d (kernel %d, user %d)\n", + "rcv contexts: chip %d, used %d (kernel %d, vnic %u, user %u)\n", (int)dd->chip_rcv_contexts, (int)dd->num_rcv_contexts, (int)dd->n_krcv_queues, - (int)dd->num_rcv_contexts - dd->n_krcv_queues); + dd->num_vnic_contexts, + dd->num_user_contexts); /* * Receive array allocation: diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index d9a1e98931364..fd28f09b44452 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -881,11 +881,11 @@ static int complete_subctxt(struct hfi1_filedata *fd) } if (ret) { - hfi1_rcd_put(fd->uctxt); - fd->uctxt = NULL; spin_lock_irqsave(&fd->dd->uctxt_lock, flags); __clear_bit(fd->subctxt, fd->uctxt->in_use_ctxts); spin_unlock_irqrestore(&fd->dd->uctxt_lock, flags); + hfi1_rcd_put(fd->uctxt); + fd->uctxt = NULL; } return ret; diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 3ac9c307a285f..3409eee160925 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1047,6 +1047,8 @@ struct hfi1_devdata { u64 z_send_schedule; u64 __percpu *send_schedule; + /* number of reserved contexts for VNIC usage */ + u16 num_vnic_contexts; /* number of receive contexts in use by the driver */ u32 num_rcv_contexts; /* number of pio send contexts in use by the driver */ @@ -1127,7 +1129,6 @@ struct hfi1_devdata { u16 pcie_lnkctl; u16 pcie_devctl2; u32 pci_msix0; - u32 pci_lnkctl3; u32 pci_tph2; /* diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c index f4c0ffc040cc5..07b80faf16752 100644 --- a/drivers/infiniband/hw/hfi1/mad.c +++ b/drivers/infiniband/hw/hfi1/mad.c @@ -4293,7 +4293,6 @@ static int opa_local_smp_check(struct hfi1_ibport *ibp, const struct ib_wc *in_wc) { struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); - u16 slid = ib_lid_cpu16(in_wc->slid); u16 pkey; if (in_wc->pkey_index >= ARRAY_SIZE(ppd->pkeys)) @@ -4320,7 +4319,11 @@ static int opa_local_smp_check(struct hfi1_ibport *ibp, */ if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) return 0; - ingress_pkey_table_fail(ppd, pkey, slid); + /* + * On OPA devices it is okay to lose the upper 16 bits of LID as this + * information is obtained elsewhere. Mask off the upper 16 bits. + */ + ingress_pkey_table_fail(ppd, pkey, ib_lid_cpu16(0xFFFF & in_wc->slid)); return 1; } diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index 09e50fd2a08f0..8c7e7a60b7158 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -411,15 +411,12 @@ int restore_pci_variables(struct hfi1_devdata *dd) if (ret) goto error; - ret = pci_write_config_dword(dd->pcidev, PCIE_CFG_SPCIE1, - dd->pci_lnkctl3); - if (ret) - goto error; - - ret = pci_write_config_dword(dd->pcidev, PCIE_CFG_TPH2, dd->pci_tph2); - if (ret) - goto error; - + if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) { + ret = pci_write_config_dword(dd->pcidev, PCIE_CFG_TPH2, + dd->pci_tph2); + if (ret) + goto error; + } return 0; error: @@ -469,15 +466,12 @@ int save_pci_variables(struct hfi1_devdata *dd) if (ret) goto error; - ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_SPCIE1, - &dd->pci_lnkctl3); - if (ret) - goto error; - - ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_TPH2, &dd->pci_tph2); - if (ret) - goto error; - + if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) { + ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_TPH2, + &dd->pci_tph2); + if (ret) + goto error; + } return 0; error: diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index 6d2702ef34ac4..25e867393463e 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -543,7 +543,7 @@ static ssize_t show_nctxts(struct device *device, * give a more accurate picture of total contexts available. */ return scnprintf(buf, PAGE_SIZE, "%u\n", - min(dd->num_rcv_contexts - dd->first_dyn_alloc_ctxt, + min(dd->num_user_contexts, (u32)dd->sc_sizes[SC_USER].count)); } diff --git a/drivers/infiniband/hw/hfi1/trace.c b/drivers/infiniband/hw/hfi1/trace.c index 9938bb983ce6f..9749ec9dd9f2a 100644 --- a/drivers/infiniband/hw/hfi1/trace.c +++ b/drivers/infiniband/hw/hfi1/trace.c @@ -154,7 +154,7 @@ void hfi1_trace_parse_9b_bth(struct ib_other_headers *ohdr, *opcode = ib_bth_get_opcode(ohdr); *tver = ib_bth_get_tver(ohdr); *pkey = ib_bth_get_pkey(ohdr); - *psn = ib_bth_get_psn(ohdr); + *psn = mask_psn(ib_bth_get_psn(ohdr)); *qpn = ib_bth_get_qpn(ohdr); } @@ -169,7 +169,7 @@ void hfi1_trace_parse_16b_bth(struct ib_other_headers *ohdr, *pad = ib_bth_get_pad(ohdr); *se = ib_bth_get_se(ohdr); *tver = ib_bth_get_tver(ohdr); - *psn = ib_bth_get_psn(ohdr); + *psn = mask_psn(ib_bth_get_psn(ohdr)); *qpn = ib_bth_get_qpn(ohdr); } diff --git a/drivers/infiniband/hw/hfi1/vnic_main.c b/drivers/infiniband/hw/hfi1/vnic_main.c index f419cbb059288..1a17708be46a9 100644 --- a/drivers/infiniband/hw/hfi1/vnic_main.c +++ b/drivers/infiniband/hw/hfi1/vnic_main.c @@ -840,6 +840,9 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, struct rdma_netdev *rn; int i, size, rc; + if (!dd->num_vnic_contexts) + return ERR_PTR(-ENOMEM); + if (!port_num || (port_num > dd->num_pports)) return ERR_PTR(-EINVAL); @@ -848,7 +851,7 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, size = sizeof(struct opa_vnic_rdma_netdev) + sizeof(*vinfo); netdev = alloc_netdev_mqs(size, name, name_assign_type, setup, - dd->chip_sdma_engines, HFI1_NUM_VNIC_CTXT); + dd->chip_sdma_engines, dd->num_vnic_contexts); if (!netdev) return ERR_PTR(-ENOMEM); @@ -856,7 +859,7 @@ struct net_device *hfi1_vnic_alloc_rn(struct ib_device *device, vinfo = opa_vnic_dev_priv(netdev); vinfo->dd = dd; vinfo->num_tx_q = dd->chip_sdma_engines; - vinfo->num_rx_q = HFI1_NUM_VNIC_CTXT; + vinfo->num_rx_q = dd->num_vnic_contexts; vinfo->netdev = netdev; rn->free_rdma_netdev = hfi1_vnic_free_rn; rn->set_id = hfi1_vnic_set_vesw_id; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 747efd1ae5a6c..8208c30f03c5a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1001,6 +1001,11 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work) } } + if (!ne) { + dev_err(dev, "Reseved loop qp is absent!\n"); + goto free_work; + } + do { ret = hns_roce_v1_poll_cq(&mr_free_cq->ib_cq, ne, wc); if (ret < 0) { diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index b6b33d99b0b41..fcfa087478995 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -2182,11 +2182,6 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | (to_mlx4_st(dev, qp->mlx4_ib_qp_type) << 16)); - if (rwq_ind_tbl) { - fill_qp_rss_context(context, qp); - context->flags |= cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET); - } - if (!(attr_mask & IB_QP_PATH_MIG_STATE)) context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); else { @@ -2216,7 +2211,7 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, context->mtu_msgmax = (IB_MTU_4096 << 5) | ilog2(dev->dev->caps.max_gso_sz); else - context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; + context->mtu_msgmax = (IB_MTU_4096 << 5) | 13; } else if (attr_mask & IB_QP_PATH_MTU) { if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { pr_err("path MTU (%u) is invalid\n", @@ -2387,6 +2382,7 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, context->pd = cpu_to_be32(pd->pdn); if (!rwq_ind_tbl) { + context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); get_cqs(qp, src_type, &send_cq, &recv_cq); } else { /* Set dummy CQs to be compatible with HV and PRM */ send_cq = to_mcq(rwq_ind_tbl->ind_tbl[0]->cq); @@ -2394,7 +2390,6 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, } context->cqn_send = cpu_to_be32(send_cq->mcq.cqn); context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn); - context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); /* Set "fast registration enabled" for all kernel QPs */ if (!ibuobject) @@ -2513,7 +2508,7 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, MLX4_IB_LINK_TYPE_ETH; if (dev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { /* set QP to receive both tunneled & non-tunneled packets */ - if (!(context->flags & cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET))) + if (!rwq_ind_tbl) context->srqn = cpu_to_be32(7 << 28); } } @@ -2562,6 +2557,13 @@ static int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type, } } + if (rwq_ind_tbl && + cur_state == IB_QPS_RESET && + new_state == IB_QPS_INIT) { + fill_qp_rss_context(context, qp); + context->flags |= cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET); + } + err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state), to_mlx4_state(new_state), context, optpar, sqd_event, &qp->mqp); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 552f7bd4ecc38..fb5302ee57c75 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1276,7 +1276,8 @@ static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) return err; if ((MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) || - !MLX5_CAP_GEN(dev->mdev, disable_local_lb)) + (!MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) && + !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return err; mutex_lock(&dev->lb_mutex); @@ -1294,7 +1295,8 @@ static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) mlx5_core_dealloc_transport_domain(dev->mdev, tdn); if ((MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) || - !MLX5_CAP_GEN(dev->mdev, disable_local_lb)) + (!MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) && + !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return; mutex_lock(&dev->lb_mutex); @@ -1415,6 +1417,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, } INIT_LIST_HEAD(&context->vma_private_list); + mutex_init(&context->vma_private_list_mutex); INIT_LIST_HEAD(&context->db_page_list); mutex_init(&context->db_page_mutex); @@ -1576,7 +1579,9 @@ static void mlx5_ib_vma_close(struct vm_area_struct *area) * mlx5_ib_disassociate_ucontext(). */ mlx5_ib_vma_priv_data->vma = NULL; + mutex_lock(mlx5_ib_vma_priv_data->vma_private_list_mutex); list_del(&mlx5_ib_vma_priv_data->list); + mutex_unlock(mlx5_ib_vma_priv_data->vma_private_list_mutex); kfree(mlx5_ib_vma_priv_data); } @@ -1596,10 +1601,13 @@ static int mlx5_ib_set_vma_data(struct vm_area_struct *vma, return -ENOMEM; vma_prv->vma = vma; + vma_prv->vma_private_list_mutex = &ctx->vma_private_list_mutex; vma->vm_private_data = vma_prv; vma->vm_ops = &mlx5_ib_vm_ops; + mutex_lock(&ctx->vma_private_list_mutex); list_add(&vma_prv->list, vma_head); + mutex_unlock(&ctx->vma_private_list_mutex); return 0; } @@ -1642,6 +1650,7 @@ static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) * mlx5_ib_vma_close. */ down_write(&owning_mm->mmap_sem); + mutex_lock(&context->vma_private_list_mutex); list_for_each_entry_safe(vma_private, n, &context->vma_private_list, list) { vma = vma_private->vma; @@ -1656,6 +1665,7 @@ static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) list_del(&vma_private->list); kfree(vma_private); } + mutex_unlock(&context->vma_private_list_mutex); up_write(&owning_mm->mmap_sem); mmput(owning_mm); put_task_struct(owning_process); @@ -3097,6 +3107,8 @@ static int create_umr_res(struct mlx5_ib_dev *dev) qp->real_qp = qp; qp->uobject = NULL; qp->qp_type = MLX5_IB_QPT_REG_UMR; + qp->send_cq = init_attr->send_cq; + qp->recv_cq = init_attr->recv_cq; attr->qp_state = IB_QPS_INIT; attr->port_num = 1; @@ -4151,7 +4163,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) } if ((MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH) && - MLX5_CAP_GEN(mdev, disable_local_lb)) + (MLX5_CAP_GEN(mdev, disable_local_lb_uc) || + MLX5_CAP_GEN(mdev, disable_local_lb_mc))) mutex_init(&dev->lb_mutex); dev->ib_active = true; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 189e80cd6b2f3..754103372faa2 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -115,6 +115,8 @@ enum { struct mlx5_ib_vma_private_data { struct list_head list; struct vm_area_struct *vma; + /* protect vma_private_list add/del */ + struct mutex *vma_private_list_mutex; }; struct mlx5_ib_ucontext { @@ -129,6 +131,8 @@ struct mlx5_ib_ucontext { /* Transport Domain number */ u32 tdn; struct list_head vma_private_list; + /* protect vma_private_list add/del */ + struct mutex vma_private_list_mutex; unsigned long upd_xlt_page; /* protect ODP/KSM */ diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index acb79d3a4f1d3..756ece6118c0f 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -4303,12 +4303,11 @@ static void to_rdma_ah_attr(struct mlx5_ib_dev *ibdev, memset(ah_attr, 0, sizeof(*ah_attr)); - ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, path->port); - rdma_ah_set_port_num(ah_attr, path->port); - if (rdma_ah_get_port_num(ah_attr) == 0 || - rdma_ah_get_port_num(ah_attr) > MLX5_CAP_GEN(dev, num_ports)) + if (!path->port || path->port > MLX5_CAP_GEN(dev, num_ports)) return; + ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, path->port); + rdma_ah_set_port_num(ah_attr, path->port); rdma_ah_set_sl(ah_attr, path->dci_cfi_prio_sl & 0xf); diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index c1b5f38f31a58..3b4916680018a 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -404,6 +404,8 @@ void *rxe_alloc(struct rxe_pool *pool) elem = kmem_cache_zalloc(pool_cache(pool), (pool->flags & RXE_POOL_ATOMIC) ? GFP_ATOMIC : GFP_KERNEL); + if (!elem) + return NULL; elem->pool = pool; kref_init(&elem->ref_cnt); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 6cd61638b4414..c97384c914a42 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -1203,10 +1203,15 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, ipoib_ib_dev_down(dev); if (level == IPOIB_FLUSH_HEAVY) { + rtnl_lock(); if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) ipoib_ib_dev_stop(dev); - if (ipoib_ib_dev_open(dev) != 0) + + result = ipoib_ib_dev_open(dev); + rtnl_unlock(); + if (result) return; + if (netif_queue_stopped(dev)) netif_start_queue(dev); } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index ceabdb85df8bd..9d4785ba24cbc 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -741,6 +741,7 @@ isert_connect_error(struct rdma_cm_id *cma_id) { struct isert_conn *isert_conn = cma_id->qp->qp_context; + ib_drain_qp(isert_conn->qp); list_del_init(&isert_conn->node); isert_conn->cm_id = NULL; isert_put_conn(isert_conn); diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c index afa938bd26d61..a72278e9cd274 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c @@ -139,6 +139,7 @@ void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter) rcu_assign_pointer(adapter->mactbl, NULL); synchronize_rcu(); opa_vnic_free_mac_tbl(mactbl); + adapter->info.vport.mac_tbl_digest = 0; mutex_unlock(&adapter->mactbl_lock); } diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c index c2733964379ca..9655cc3aa3a07 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c @@ -348,7 +348,7 @@ void opa_vnic_query_mcast_macs(struct opa_vnic_adapter *adapter, void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter, struct opa_veswport_iface_macs *macs) { - u16 start_idx, tot_macs, num_macs, idx = 0, count = 0; + u16 start_idx, tot_macs, num_macs, idx = 0, count = 0, em_macs = 0; struct netdev_hw_addr *ha; start_idx = be16_to_cpu(macs->start_idx); @@ -359,8 +359,10 @@ void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter, /* Do not include EM specified MAC address */ if (!memcmp(adapter->info.vport.base_mac_addr, ha->addr, - ARRAY_SIZE(adapter->info.vport.base_mac_addr))) + ARRAY_SIZE(adapter->info.vport.base_mac_addr))) { + em_macs++; continue; + } if (start_idx > idx++) continue; @@ -383,7 +385,7 @@ void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter, } tot_macs = netdev_hw_addr_list_count(&adapter->netdev->dev_addrs) + - netdev_uc_count(adapter->netdev); + netdev_uc_count(adapter->netdev) - em_macs; macs->tot_macs_in_lst = cpu_to_be16(tot_macs); macs->num_macs_in_msg = cpu_to_be16(count); macs->gen_count = cpu_to_be16(adapter->info.vport.uc_macs_gen_count); diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index fa5ccdb3bb2a0..60d7b493ed2dc 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -665,12 +665,19 @@ static void srp_path_rec_completion(int status, static int srp_lookup_path(struct srp_rdma_ch *ch) { struct srp_target_port *target = ch->target; - int ret; + int ret = -ENODEV; ch->path.numb_path = 1; init_completion(&ch->done); + /* + * Avoid that the SCSI host can be removed by srp_remove_target() + * before srp_path_rec_completion() is called. + */ + if (!scsi_host_get(target->scsi_host)) + goto out; + ch->path_query_id = ib_sa_path_rec_get(&srp_sa_client, target->srp_host->srp_dev->dev, target->srp_host->port, @@ -684,18 +691,24 @@ static int srp_lookup_path(struct srp_rdma_ch *ch) GFP_KERNEL, srp_path_rec_completion, ch, &ch->path_query); - if (ch->path_query_id < 0) - return ch->path_query_id; + ret = ch->path_query_id; + if (ret < 0) + goto put; ret = wait_for_completion_interruptible(&ch->done); if (ret < 0) - return ret; + goto put; - if (ch->status < 0) + ret = ch->status; + if (ret < 0) shost_printk(KERN_WARNING, target->scsi_host, PFX "Path record query failed\n"); - return ch->status; +put: + scsi_host_put(target->scsi_host); + +out: + return ret; } static int srp_send_req(struct srp_rdma_ch *ch, bool multich) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9e8e9220f8167..ee578fa713c28 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1000,8 +1000,7 @@ static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp) return -ENOMEM; attr->qp_state = IB_QPS_INIT; - attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | - IB_ACCESS_REMOTE_WRITE; + attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; attr->port_num = ch->sport->port; attr->pkey_index = 0; @@ -1992,7 +1991,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto destroy_ib; } - guid = (__be16 *)¶m->primary_path->sgid.global.interface_id; + guid = (__be16 *)¶m->primary_path->dgid.global.interface_id; snprintf(ch->ini_guid, sizeof(ch->ini_guid), "%04x:%04x:%04x:%04x", be16_to_cpu(guid[0]), be16_to_cpu(guid[1]), be16_to_cpu(guid[2]), be16_to_cpu(guid[3])); @@ -2777,7 +2776,7 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name) { const char *p; unsigned len, count, leading_zero_bytes; - int ret, rc; + int ret; p = name; if (strncasecmp(p, "0x", 2) == 0) @@ -2789,10 +2788,9 @@ static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name) count = min(len / 2, 16U); leading_zero_bytes = 16 - count; memset(i_port_id, 0, leading_zero_bytes); - rc = hex2bin(i_port_id + leading_zero_bytes, p, count); - if (rc < 0) - pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", rc); - ret = 0; + ret = hex2bin(i_port_id + leading_zero_bytes, p, count); + if (ret < 0) + pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", ret); out: return ret; } diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index d86e59515b9c9..d88d3e0f59fb8 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -229,6 +229,7 @@ static const struct xpad_device { { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 }, @@ -475,6 +476,22 @@ static const u8 xboxone_hori_init[] = { 0x00, 0x00, 0x00, 0x80, 0x00 }; +/* + * This packet is required for some of the PDP pads to start + * sending input reports. One of those pads is (0x0e6f:0x02ab). + */ +static const u8 xboxone_pdp_init1[] = { + 0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14 +}; + +/* + * This packet is required for some of the PDP pads to start + * sending input reports. One of those pads is (0x0e6f:0x02ab). + */ +static const u8 xboxone_pdp_init2[] = { + 0x06, 0x20, 0x00, 0x02, 0x01, 0x00 +}; + /* * A specific rumble packet is required for some PowerA pads to start * sending input reports. One of those pads is (0x24c6:0x543a). @@ -505,6 +522,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = { XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init1), + XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init2), XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 6c51d404874bb..c37aea9ac272a 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -178,12 +178,14 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, twl4030_vibra_suspend, twl4030_vibra_resume); static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, - struct device_node *node) + struct device_node *parent) { + struct device_node *node; + if (pdata && pdata->coexist) return true; - node = of_find_node_by_name(node, "codec"); + node = of_get_child_by_name(parent, "codec"); if (node) { of_node_put(node); return true; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 5690eb7ff954d..15e0d352c4cc2 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -248,8 +248,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev) int vddvibr_uV = 0; int error; - of_node_get(twl6040_core_dev->of_node); - twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node, + twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node, "vibra"); if (!twl6040_core_node) { dev_err(&pdev->dev, "parent of node is missing?\n"); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 850b00e3ad8ec..3d9c294e84db6 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1250,29 +1250,32 @@ static int alps_decode_ss4_v2(struct alps_fields *f, case SS4_PACKET_ID_MULTI: if (priv->flags & ALPS_BUTTONPAD) { if (IS_SS4PLUS_DEV(priv->dev_id)) { - f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0); - f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1); + f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0); + f->mt[3].x = SS4_PLUS_BTL_MF_X_V2(p, 1); + no_data_x = SS4_PLUS_MFPACKET_NO_AX_BL; } else { f->mt[2].x = SS4_BTL_MF_X_V2(p, 0); f->mt[3].x = SS4_BTL_MF_X_V2(p, 1); + no_data_x = SS4_MFPACKET_NO_AX_BL; } + no_data_y = SS4_MFPACKET_NO_AY_BL; f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0); f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1); - no_data_x = SS4_MFPACKET_NO_AX_BL; - no_data_y = SS4_MFPACKET_NO_AY_BL; } else { if (IS_SS4PLUS_DEV(priv->dev_id)) { - f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0); - f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1); + f->mt[2].x = SS4_PLUS_STD_MF_X_V2(p, 0); + f->mt[3].x = SS4_PLUS_STD_MF_X_V2(p, 1); + no_data_x = SS4_PLUS_MFPACKET_NO_AX; } else { - f->mt[0].x = SS4_STD_MF_X_V2(p, 0); - f->mt[1].x = SS4_STD_MF_X_V2(p, 1); + f->mt[2].x = SS4_STD_MF_X_V2(p, 0); + f->mt[3].x = SS4_STD_MF_X_V2(p, 1); + no_data_x = SS4_MFPACKET_NO_AX; } + no_data_y = SS4_MFPACKET_NO_AY; + f->mt[2].y = SS4_STD_MF_Y_V2(p, 0); f->mt[3].y = SS4_STD_MF_Y_V2(p, 1); - no_data_x = SS4_MFPACKET_NO_AX; - no_data_y = SS4_MFPACKET_NO_AY; } f->first_mp = 0; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index c80a7c76cb767..79b6d69d1486a 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -141,10 +141,12 @@ enum SS4_PACKET_ID { #define SS4_TS_Z_V2(_b) (s8)(_b[4] & 0x7F) -#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ -#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ -#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */ -#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */ +#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ +#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ +#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coord value */ +#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coord value */ +#define SS4_PLUS_MFPACKET_NO_AX 4080 /* SS4 PLUS, X */ +#define SS4_PLUS_MFPACKET_NO_AX_BL 4088 /* Buttonless SS4 PLUS, X */ /* * enum V7_PACKET_ID - defines the packet type for V7 diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index b84cd978fce2d..a4aaa748e987f 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1613,7 +1613,7 @@ static int elantech_set_properties(struct elantech_data *etd) case 5: etd->hw_version = 3; break; - case 6 ... 14: + case 6 ... 15: etd->hw_version = 4; break; default: diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 0871010f18d5f..bbd29220dbe99 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -19,6 +19,13 @@ #include "psmouse.h" #include "trackpoint.h" +static const char * const trackpoint_variants[] = { + [TP_VARIANT_IBM] = "IBM", + [TP_VARIANT_ALPS] = "ALPS", + [TP_VARIANT_ELAN] = "Elan", + [TP_VARIANT_NXP] = "NXP", +}; + /* * Power-on Reset: Resets all trackpoint parameters, including RAM values, * to defaults. @@ -26,7 +33,7 @@ */ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) { - unsigned char results[2]; + u8 results[2]; int tries = 0; /* Issue POR command, and repeat up to once if 0xFC00 received */ @@ -38,7 +45,7 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) /* Check for success response -- 0xAA00 */ if (results[0] != 0xAA || results[1] != 0x00) - return -1; + return -ENODEV; return 0; } @@ -46,8 +53,7 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev) /* * Device IO: read, write and toggle bit */ -static int trackpoint_read(struct ps2dev *ps2dev, - unsigned char loc, unsigned char *results) +static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results) { if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { @@ -57,8 +63,7 @@ static int trackpoint_read(struct ps2dev *ps2dev, return 0; } -static int trackpoint_write(struct ps2dev *ps2dev, - unsigned char loc, unsigned char val) +static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val) { if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || @@ -70,8 +75,7 @@ static int trackpoint_write(struct ps2dev *ps2dev, return 0; } -static int trackpoint_toggle_bit(struct ps2dev *ps2dev, - unsigned char loc, unsigned char mask) +static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask) { /* Bad things will happen if the loc param isn't in this range */ if (loc < 0x20 || loc >= 0x2F) @@ -87,11 +91,11 @@ static int trackpoint_toggle_bit(struct ps2dev *ps2dev, return 0; } -static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc, - unsigned char mask, unsigned char value) +static int trackpoint_update_bit(struct ps2dev *ps2dev, + u8 loc, u8 mask, u8 value) { int retval = 0; - unsigned char data; + u8 data; trackpoint_read(ps2dev, loc, &data); if (((data & mask) == mask) != !!value) @@ -105,17 +109,18 @@ static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc, */ struct trackpoint_attr_data { size_t field_offset; - unsigned char command; - unsigned char mask; - unsigned char inverted; - unsigned char power_on_default; + u8 command; + u8 mask; + bool inverted; + u8 power_on_default; }; -static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) +static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, + void *data, char *buf) { struct trackpoint_data *tp = psmouse->private; struct trackpoint_attr_data *attr = data; - unsigned char value = *(unsigned char *)((char *)tp + attr->field_offset); + u8 value = *(u8 *)((void *)tp + attr->field_offset); if (attr->inverted) value = !value; @@ -128,8 +133,8 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, { struct trackpoint_data *tp = psmouse->private; struct trackpoint_attr_data *attr = data; - unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); - unsigned char value; + u8 *field = (void *)tp + attr->field_offset; + u8 value; int err; err = kstrtou8(buf, 10, &value); @@ -157,17 +162,14 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, { struct trackpoint_data *tp = psmouse->private; struct trackpoint_attr_data *attr = data; - unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); - unsigned int value; + bool *field = (void *)tp + attr->field_offset; + bool value; int err; - err = kstrtouint(buf, 10, &value); + err = kstrtobool(buf, &value); if (err) return err; - if (value > 1) - return -EINVAL; - if (attr->inverted) value = !value; @@ -193,30 +195,6 @@ PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ &trackpoint_attr_##_name, \ trackpoint_show_int_attr, trackpoint_set_bit_attr) -#define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name) \ -do { \ - struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \ - \ - trackpoint_update_bit(&_psmouse->ps2dev, \ - _attr->command, _attr->mask, _tp->_name); \ -} while (0) - -#define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \ -do { \ - if (!_power_on || \ - _tp->_name != trackpoint_attr_##_name.power_on_default) { \ - if (!trackpoint_attr_##_name.mask) \ - trackpoint_write(&_psmouse->ps2dev, \ - trackpoint_attr_##_name.command, \ - _tp->_name); \ - else \ - TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name); \ - } \ -} while (0) - -#define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \ - (_tp->_name = trackpoint_attr_##_name.power_on_default) - TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS); TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED); TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA); @@ -229,13 +207,33 @@ TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME); TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV); TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME); -TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0, +TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, false, TP_DEF_PTSON); -TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0, +TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, false, TP_DEF_SKIPBACK); -TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1, +TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, true, TP_DEF_EXT_DEV); +static bool trackpoint_is_attr_available(struct psmouse *psmouse, + struct attribute *attr) +{ + struct trackpoint_data *tp = psmouse->private; + + return tp->variant_id == TP_VARIANT_IBM || + attr == &psmouse_attr_sensitivity.dattr.attr || + attr == &psmouse_attr_press_to_select.dattr.attr; +} + +static umode_t trackpoint_is_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct serio *serio = to_serio_port(dev); + struct psmouse *psmouse = serio_get_drvdata(serio); + + return trackpoint_is_attr_available(psmouse, attr) ? attr->mode : 0; +} + static struct attribute *trackpoint_attrs[] = { &psmouse_attr_sensitivity.dattr.attr, &psmouse_attr_speed.dattr.attr, @@ -255,24 +253,56 @@ static struct attribute *trackpoint_attrs[] = { }; static struct attribute_group trackpoint_attr_group = { - .attrs = trackpoint_attrs, + .is_visible = trackpoint_is_attr_visible, + .attrs = trackpoint_attrs, }; -static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id) -{ - unsigned char param[2] = { 0 }; +#define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \ +do { \ + struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \ + \ + if ((!_power_on || _tp->_name != _attr->power_on_default) && \ + trackpoint_is_attr_available(_psmouse, \ + &psmouse_attr_##_name.dattr.attr)) { \ + if (!_attr->mask) \ + trackpoint_write(&_psmouse->ps2dev, \ + _attr->command, _tp->_name); \ + else \ + trackpoint_update_bit(&_psmouse->ps2dev, \ + _attr->command, _attr->mask, \ + _tp->_name); \ + } \ +} while (0) - if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) - return -1; +#define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \ +do { \ + _tp->_name = trackpoint_attr_##_name.power_on_default; \ +} while (0) - /* add new TP ID. */ - if (!(param[0] & TP_MAGIC_IDENT)) - return -1; +static int trackpoint_start_protocol(struct psmouse *psmouse, + u8 *variant_id, u8 *firmware_id) +{ + u8 param[2] = { 0 }; + int error; - if (firmware_id) - *firmware_id = param[1]; + error = ps2_command(&psmouse->ps2dev, + param, MAKE_PS2_CMD(0, 2, TP_READ_ID)); + if (error) + return error; + + switch (param[0]) { + case TP_VARIANT_IBM: + case TP_VARIANT_ALPS: + case TP_VARIANT_ELAN: + case TP_VARIANT_NXP: + if (variant_id) + *variant_id = param[0]; + if (firmware_id) + *firmware_id = param[1]; + return 0; + } - return 0; + return -ENODEV; } /* @@ -285,7 +315,7 @@ static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state) { struct trackpoint_data *tp = psmouse->private; - if (!in_power_on_state) { + if (!in_power_on_state && tp->variant_id == TP_VARIANT_IBM) { /* * Disable features that may make device unusable * with this driver. @@ -347,7 +377,8 @@ static void trackpoint_defaults(struct trackpoint_data *tp) static void trackpoint_disconnect(struct psmouse *psmouse) { - sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); + device_remove_group(&psmouse->ps2dev.serio->dev, + &trackpoint_attr_group); kfree(psmouse->private); psmouse->private = NULL; @@ -355,14 +386,20 @@ static void trackpoint_disconnect(struct psmouse *psmouse) static int trackpoint_reconnect(struct psmouse *psmouse) { - int reset_fail; + struct trackpoint_data *tp = psmouse->private; + int error; + bool was_reset; - if (trackpoint_start_protocol(psmouse, NULL)) - return -1; + error = trackpoint_start_protocol(psmouse, NULL, NULL); + if (error) + return error; - reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev); - if (trackpoint_sync(psmouse, !reset_fail)) - return -1; + was_reset = tp->variant_id == TP_VARIANT_IBM && + trackpoint_power_on_reset(&psmouse->ps2dev) == 0; + + error = trackpoint_sync(psmouse, was_reset); + if (error) + return error; return 0; } @@ -370,46 +407,66 @@ static int trackpoint_reconnect(struct psmouse *psmouse) int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char firmware_id; - unsigned char button_info; + struct trackpoint_data *tp; + u8 variant_id; + u8 firmware_id; + u8 button_info; int error; - if (trackpoint_start_protocol(psmouse, &firmware_id)) - return -1; + error = trackpoint_start_protocol(psmouse, &variant_id, &firmware_id); + if (error) + return error; if (!set_properties) return 0; - if (trackpoint_read(ps2dev, TP_EXT_BTN, &button_info)) { - psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n"); - button_info = 0x33; - } - - psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); - if (!psmouse->private) + tp = kzalloc(sizeof(*tp), GFP_KERNEL); + if (!tp) return -ENOMEM; - psmouse->vendor = "IBM"; + trackpoint_defaults(tp); + tp->variant_id = variant_id; + tp->firmware_id = firmware_id; + + psmouse->private = tp; + + psmouse->vendor = trackpoint_variants[variant_id]; psmouse->name = "TrackPoint"; psmouse->reconnect = trackpoint_reconnect; psmouse->disconnect = trackpoint_disconnect; + if (variant_id != TP_VARIANT_IBM) { + /* Newer variants do not support extended button query. */ + button_info = 0x33; + } else { + error = trackpoint_read(ps2dev, TP_EXT_BTN, &button_info); + if (error) { + psmouse_warn(psmouse, + "failed to get extended button data, assuming 3 buttons\n"); + button_info = 0x33; + } else if (!button_info) { + psmouse_warn(psmouse, + "got 0 in extended button data, assuming 3 buttons\n"); + button_info = 0x33; + } + } + if ((button_info & 0x0f) >= 3) - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE); __set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit); __set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit); - trackpoint_defaults(psmouse->private); - - error = trackpoint_power_on_reset(ps2dev); - - /* Write defaults to TP only if reset fails. */ - if (error) + if (variant_id != TP_VARIANT_IBM || + trackpoint_power_on_reset(ps2dev) != 0) { + /* + * Write defaults to TP if we did not reset the trackpoint. + */ trackpoint_sync(psmouse, false); + } - error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); + error = device_add_group(&ps2dev->serio->dev, &trackpoint_attr_group); if (error) { psmouse_err(psmouse, "failed to create sysfs attributes, error: %d\n", @@ -420,8 +477,8 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) } psmouse_info(psmouse, - "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", - firmware_id, + "%s TrackPoint firmware: 0x%02x, buttons: %d/%d\n", + psmouse->vendor, firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); return 0; diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index 88055755f82e2..10a0391482343 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -21,10 +21,16 @@ #define TP_COMMAND 0xE2 /* Commands start with this */ #define TP_READ_ID 0xE1 /* Sent for device identification */ -#define TP_MAGIC_IDENT 0x03 /* Sent after a TP_READ_ID followed */ - /* by the firmware ID */ - /* Firmware ID includes 0x1, 0x2, 0x3 */ +/* + * Valid first byte responses to the "Read Secondary ID" (0xE1) command. + * 0x01 was the original IBM trackpoint, others implement very limited + * subset of trackpoint features. + */ +#define TP_VARIANT_IBM 0x01 +#define TP_VARIANT_ALPS 0x02 +#define TP_VARIANT_ELAN 0x03 +#define TP_VARIANT_NXP 0x04 /* * Commands @@ -136,18 +142,20 @@ #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) -struct trackpoint_data -{ - unsigned char sensitivity, speed, inertia, reach; - unsigned char draghys, mindrag; - unsigned char thresh, upthresh; - unsigned char ztime, jenks; - unsigned char drift_time; +struct trackpoint_data { + u8 variant_id; + u8 firmware_id; + + u8 sensitivity, speed, inertia, reach; + u8 draghys, mindrag; + u8 thresh, upthresh; + u8 ztime, jenks; + u8 drift_time; /* toggles */ - unsigned char press_to_select; - unsigned char skipback; - unsigned char ext_dev; + bool press_to_select; + bool skipback; + bool ext_dev; }; #ifdef CONFIG_MOUSE_PS2_TRACKPOINT diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index 0f586780ceb4b..1ae5c1ef3f5bb 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -316,11 +316,9 @@ static int vmmouse_enable(struct psmouse *psmouse) /* * Array of supported hypervisors. */ -static const struct hypervisor_x86 *vmmouse_supported_hypervisors[] = { - &x86_hyper_vmware, -#ifdef CONFIG_KVM_GUEST - &x86_hyper_kvm, -#endif +static enum x86_hypervisor_type vmmouse_supported_hypervisors[] = { + X86_HYPER_VMWARE, + X86_HYPER_KVM, }; /** @@ -331,7 +329,7 @@ static bool vmmouse_check_hypervisor(void) int i; for (i = 0; i < ARRAY_SIZE(vmmouse_supported_hypervisors); i++) - if (vmmouse_supported_hypervisors[i] == x86_hyper) + if (vmmouse_supported_hypervisors[i] == x86_hyper_type) return true; return false; diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 4f2bb5947a4ea..141ea228aac6a 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -230,8 +230,10 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id) rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Failed to process interrupt request: %d\n", ret); - if (count) + if (count) { kfree(attn_data.data); + attn_data.data = NULL; + } if (!kfifo_is_empty(&drvdata->attn_fifo)) return rmi_irq_fn(irq, dev_id); diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 7ed828a51f4c8..3486d94038056 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -126,7 +126,7 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, int data, n, ret; if (!np) return -ENODEV; - np = of_find_node_by_name(np, "touch"); + np = of_get_child_by_name(np, "touch"); if (!np) { dev_err(&pdev->dev, "Can't find touch node\n"); return -EINVAL; @@ -144,13 +144,13 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } /* set tsi prebias time */ if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) { ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } /* set prebias & prechg time of pen detect */ data = 0; @@ -161,10 +161,18 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); if (ret < 0) - return -EINVAL; + goto err_put_node; } of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); + + of_node_put(np); + return 0; + +err_put_node: + of_node_put(np); + + return -EINVAL; } #else #define pm860x_touch_dt_init(x, y, z) (-1) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 8e8874d23717a..99a2a57b6cfda 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3155,7 +3155,7 @@ static void amd_iommu_apply_resv_region(struct device *dev, unsigned long start, end; start = IOVA_PFN(region->start); - end = IOVA_PFN(region->start + region->length); + end = IOVA_PFN(region->start + region->length - 1); WARN_ON_ONCE(reserve_iova(&dma_dom->iovad, start, end) == NULL); } diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index e67ba6c40faff..8f7a3c00b6cf3 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1611,13 +1611,15 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; domain->geometry.aperture_end = (1UL << ias) - 1; domain->geometry.force_aperture = true; - smmu_domain->pgtbl_ops = pgtbl_ops; ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg); - if (ret < 0) + if (ret < 0) { free_io_pgtable_ops(pgtbl_ops); + return ret; + } - return ret; + smmu_domain->pgtbl_ops = pgtbl_ops; + return 0; } static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) @@ -1644,7 +1646,7 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) { - int i; + int i, j; struct arm_smmu_master_data *master = fwspec->iommu_priv; struct arm_smmu_device *smmu = master->smmu; @@ -1652,6 +1654,13 @@ static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec) u32 sid = fwspec->ids[i]; __le64 *step = arm_smmu_get_step_for_sid(smmu, sid); + /* Bridged PCI devices may end up with duplicated IDs */ + for (j = 0; j < i; j++) + if (fwspec->ids[j] == sid) + break; + if (j < i) + continue; + arm_smmu_write_strtab_ent(smmu, sid, step, &master->ste); } } diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 6784a05dd6b2d..83f3d4831f943 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2254,10 +2254,12 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, uint64_t tmp; if (!sg_res) { + unsigned int pgoff = sg->offset & ~PAGE_MASK; + sg_res = aligned_nrpages(sg->offset, sg->length); - sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset; + sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff; sg->dma_length = sg->length; - pteval = page_to_phys(sg_page(sg)) | prot; + pteval = (sg_phys(sg) - pgoff) | prot; phys_pfn = pteval >> VTD_PAGE_SHIFT; } @@ -3790,7 +3792,7 @@ static int intel_nontranslate_map_sg(struct device *hddev, for_each_sg(sglist, sg, nelems, i) { BUG_ON(!sg_page(sg)); - sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset; + sg->dma_address = sg_phys(sg); sg->dma_length = sg->length; } return nelems; diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index bc1efbfb9ddf0..542930cd183d0 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -708,7 +708,7 @@ static struct platform_driver mtk_iommu_driver = { .probe = mtk_iommu_probe, .remove = mtk_iommu_remove, .driver = { - .name = "mtk-iommu", + .name = "mtk-iommu-v1", .of_match_table = mtk_iommu_of_ids, .pm = &mtk_iommu_pm_ops, } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index b5df99c6f680f..3b35271114eef 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1071,18 +1071,18 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) int nr_parts; struct partition_affinity *parts; - parts_node = of_find_node_by_name(gic_node, "ppi-partitions"); + parts_node = of_get_child_by_name(gic_node, "ppi-partitions"); if (!parts_node) return; nr_parts = of_get_child_count(parts_node); if (!nr_parts) - return; + goto out_put_node; parts = kzalloc(sizeof(*parts) * nr_parts, GFP_KERNEL); if (WARN_ON(!parts)) - return; + goto out_put_node; for_each_child_of_node(parts_node, child_part) { struct partition_affinity *part; @@ -1149,6 +1149,9 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) gic_data.ppi_descs[i] = desc; } + +out_put_node: + of_node_put(parts_node); } static void __init gic_of_setup_kvm_info(struct device_node *node) diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index 6aa3ea4792148..f312659374396 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -238,7 +238,7 @@ static int __init combiner_probe(struct platform_device *pdev) { struct combiner *combiner; size_t alloc_sz; - u32 nregs; + int nregs; int err; nregs = count_registers(pdev); diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 905729191d3e9..78183f90820ea 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -61,6 +61,10 @@ #define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */ #define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */ +#define PCA955X_GPIO_INPUT LED_OFF +#define PCA955X_GPIO_HIGH LED_OFF +#define PCA955X_GPIO_LOW LED_FULL + enum pca955x_type { pca9550, pca9551, @@ -329,9 +333,9 @@ static int pca955x_set_value(struct gpio_chip *gc, unsigned int offset, struct pca955x_led *led = &pca955x->leds[offset]; if (val) - return pca955x_led_set(&led->led_cdev, LED_FULL); - else - return pca955x_led_set(&led->led_cdev, LED_OFF); + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_HIGH); + + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_LOW); } static void pca955x_gpio_set_value(struct gpio_chip *gc, unsigned int offset, @@ -355,8 +359,11 @@ static int pca955x_gpio_get_value(struct gpio_chip *gc, unsigned int offset) static int pca955x_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) { - /* To use as input ensure pin is not driven */ - return pca955x_set_value(gc, offset, 0); + struct pca955x *pca955x = gpiochip_get_data(gc); + struct pca955x_led *led = &pca955x->leds[offset]; + + /* To use as input ensure pin is not driven. */ + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_INPUT); } static int pca955x_gpio_direction_output(struct gpio_chip *gc, diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 81501644fb158..3f0ddc0d7393f 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -193,7 +193,7 @@ void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, bio_advance(bio, off * PBLK_EXPOSED_PAGE_SIZE); for (i = off; i < nr_pages + off; i++) { bv = bio->bi_io_vec[i]; - mempool_free(bv.bv_page, pblk->page_pool); + mempool_free(bv.bv_page, pblk->page_bio_pool); } } @@ -205,14 +205,14 @@ int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags, int i, ret; for (i = 0; i < nr_pages; i++) { - page = mempool_alloc(pblk->page_pool, flags); + page = mempool_alloc(pblk->page_bio_pool, flags); if (!page) goto err; ret = bio_add_pc_page(q, bio, page, PBLK_EXPOSED_PAGE_SIZE, 0); if (ret != PBLK_EXPOSED_PAGE_SIZE) { pr_err("pblk: could not add page to bio\n"); - mempool_free(page, pblk->page_pool); + mempool_free(page, pblk->page_bio_pool); goto err; } } @@ -486,12 +486,14 @@ void pblk_dealloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs) u64 addr; int i; + spin_lock(&line->lock); addr = find_next_zero_bit(line->map_bitmap, pblk->lm.sec_per_line, line->cur_sec); line->cur_sec = addr - nr_secs; for (i = 0; i < nr_secs; i++, line->cur_sec--) WARN_ON(!test_and_clear_bit(line->cur_sec, line->map_bitmap)); + spin_unlock(&line->lock); } u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs) diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index 6090d28f7995a..d6bae085e1d27 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -486,10 +486,10 @@ void pblk_gc_should_start(struct pblk *pblk) { struct pblk_gc *gc = &pblk->gc; - if (gc->gc_enabled && !gc->gc_active) + if (gc->gc_enabled && !gc->gc_active) { pblk_gc_start(pblk); - - pblk_gc_kick(pblk); + pblk_gc_kick(pblk); + } } /* @@ -628,7 +628,8 @@ void pblk_gc_exit(struct pblk *pblk) flush_workqueue(gc->gc_reader_wq); flush_workqueue(gc->gc_line_reader_wq); - del_timer(&gc->gc_timer); + gc->gc_enabled = 0; + del_timer_sync(&gc->gc_timer); pblk_gc_stop(pblk, 1); if (gc->gc_ts) diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 1b0f61233c216..1b75675ee67b8 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -132,7 +132,6 @@ static int pblk_rwb_init(struct pblk *pblk) } /* Minimum pages needed within a lun */ -#define PAGE_POOL_SIZE 16 #define ADDR_POOL_SIZE 64 static int pblk_set_ppaf(struct pblk *pblk) @@ -247,14 +246,16 @@ static int pblk_core_init(struct pblk *pblk) if (pblk_init_global_caches(pblk)) return -ENOMEM; - pblk->page_pool = mempool_create_page_pool(PAGE_POOL_SIZE, 0); - if (!pblk->page_pool) + /* internal bios can be at most the sectors signaled by the device. */ + pblk->page_bio_pool = mempool_create_page_pool(nvm_max_phys_sects(dev), + 0); + if (!pblk->page_bio_pool) return -ENOMEM; pblk->line_ws_pool = mempool_create_slab_pool(PBLK_WS_POOL_SIZE, pblk_blk_ws_cache); if (!pblk->line_ws_pool) - goto free_page_pool; + goto free_page_bio_pool; pblk->rec_pool = mempool_create_slab_pool(geo->nr_luns, pblk_rec_cache); if (!pblk->rec_pool) @@ -309,8 +310,8 @@ static int pblk_core_init(struct pblk *pblk) mempool_destroy(pblk->rec_pool); free_blk_ws_pool: mempool_destroy(pblk->line_ws_pool); -free_page_pool: - mempool_destroy(pblk->page_pool); +free_page_bio_pool: + mempool_destroy(pblk->page_bio_pool); return -ENOMEM; } @@ -322,7 +323,7 @@ static void pblk_core_free(struct pblk *pblk) if (pblk->bb_wq) destroy_workqueue(pblk->bb_wq); - mempool_destroy(pblk->page_pool); + mempool_destroy(pblk->page_bio_pool); mempool_destroy(pblk->line_ws_pool); mempool_destroy(pblk->rec_pool); mempool_destroy(pblk->g_rq_pool); @@ -681,8 +682,8 @@ static int pblk_lines_init(struct pblk *pblk) lm->blk_bitmap_len = BITS_TO_LONGS(geo->nr_luns) * sizeof(long); lm->sec_bitmap_len = BITS_TO_LONGS(lm->sec_per_line) * sizeof(long); lm->lun_bitmap_len = BITS_TO_LONGS(geo->nr_luns) * sizeof(long); - lm->high_thrs = lm->sec_per_line / 2; - lm->mid_thrs = lm->sec_per_line / 4; + lm->mid_thrs = lm->sec_per_line / 2; + lm->high_thrs = lm->sec_per_line / 4; lm->meta_distance = (geo->nr_luns / 2) * pblk->min_write_pgs; /* Calculate necessary pages for smeta. See comment over struct @@ -923,6 +924,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, pblk->dev = dev; pblk->disk = tdisk; pblk->state = PBLK_STATE_RUNNING; + pblk->gc.gc_enabled = 0; spin_lock_init(&pblk->trans_lock); spin_lock_init(&pblk->lock); @@ -944,6 +946,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, atomic_long_set(&pblk->recov_writes, 0); atomic_long_set(&pblk->recov_writes, 0); atomic_long_set(&pblk->recov_gc_writes, 0); + atomic_long_set(&pblk->recov_gc_reads, 0); #endif atomic_long_set(&pblk->read_failed, 0); diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c index d682e89e64935..402c732f0970a 100644 --- a/drivers/lightnvm/pblk-read.c +++ b/drivers/lightnvm/pblk-read.c @@ -238,7 +238,7 @@ static int pblk_fill_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, kunmap_atomic(src_p); kunmap_atomic(dst_p); - mempool_free(src_bv.bv_page, pblk->page_pool); + mempool_free(src_bv.bv_page, pblk->page_bio_pool); hole = find_next_zero_bit(read_bitmap, nr_secs, hole + 1); } while (hole < nr_secs); @@ -499,7 +499,7 @@ int pblk_submit_read_gc(struct pblk *pblk, u64 *lba_list, void *data, data_len = (*secs_to_gc) * geo->sec_size; bio = pblk_bio_map_addr(pblk, data, *secs_to_gc, data_len, - PBLK_KMALLOC_META, GFP_KERNEL); + PBLK_VMALLOC_META, GFP_KERNEL); if (IS_ERR(bio)) { pr_err("pblk: could not allocate GC bio (%lu)\n", PTR_ERR(bio)); goto err_free_dma; @@ -519,7 +519,7 @@ int pblk_submit_read_gc(struct pblk *pblk, u64 *lba_list, void *data, if (ret) { bio_endio(bio); pr_err("pblk: GC read request failed\n"); - goto err_free_dma; + goto err_free_bio; } if (!wait_for_completion_io_timeout(&wait, @@ -541,10 +541,13 @@ int pblk_submit_read_gc(struct pblk *pblk, u64 *lba_list, void *data, atomic_long_sub(*secs_to_gc, &pblk->inflight_reads); #endif + bio_put(bio); out: nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); return NVM_IO_OK; +err_free_bio: + bio_put(bio); err_free_dma: nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); return NVM_IO_ERR; diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index 67e623bd5c2df..053164deb0721 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h @@ -618,7 +618,7 @@ struct pblk { struct list_head compl_list; - mempool_t *page_pool; + mempool_t *page_bio_pool; mempool_t *line_ws_pool; mempool_t *rec_pool; mempool_t *g_rq_pool; diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index ae6146311934d..f052a3eb20983 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -1365,8 +1365,8 @@ static void flexrm_shutdown(struct mbox_chan *chan) /* Disable/inactivate ring */ writel_relaxed(0x0, ring->regs + RING_CONTROL); - /* Flush ring with timeout of 1s */ - timeout = 1000; + /* Set ring flush state */ + timeout = 1000; /* timeout of 1s */ writel_relaxed(BIT(CONTROL_FLUSH_SHIFT), ring->regs + RING_CONTROL); do { @@ -1374,7 +1374,23 @@ static void flexrm_shutdown(struct mbox_chan *chan) FLUSH_DONE_MASK) break; mdelay(1); - } while (timeout--); + } while (--timeout); + if (!timeout) + dev_err(ring->mbox->dev, + "setting ring%d flush state timedout\n", ring->num); + + /* Clear ring flush state */ + timeout = 1000; /* timeout of 1s */ + writel_relaxed(0x0, ring + RING_CONTROL); + do { + if (!(readl_relaxed(ring + RING_FLUSH_DONE) & + FLUSH_DONE_MASK)) + break; + mdelay(1); + } while (--timeout); + if (!timeout) + dev_err(ring->mbox->dev, + "clearing ring%d flush state timedout\n", ring->num); /* Abort all in-flight requests */ for (reqid = 0; reqid < RING_MAX_REQ_COUNT; reqid++) { diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 97fb956bb6e04..93f3d4d61fa7a 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -30,6 +30,7 @@ #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) +static bool mbox_data_ready; static struct dentry *root_debugfs_dir; struct mbox_test_device { @@ -152,16 +153,14 @@ static ssize_t mbox_test_message_write(struct file *filp, static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) { - unsigned char data; + bool data_ready; unsigned long flags; spin_lock_irqsave(&tdev->lock, flags); - data = tdev->rx_buffer[0]; + data_ready = mbox_data_ready; spin_unlock_irqrestore(&tdev->lock, flags); - if (data != '\0') - return true; - return false; + return data_ready; } static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, @@ -223,6 +222,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, *(touser + l) = '\0'; memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); + mbox_data_ready = false; spin_unlock_irqrestore(&tdev->lock, flags); @@ -292,6 +292,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) message, MBOX_MAX_MSG_LEN); memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); } + mbox_data_ready = true; spin_unlock_irqrestore(&tdev->lock, flags); wake_up_interruptible(&tdev->waitq); diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 08035634795c1..934b1fce4ce1f 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -407,7 +407,8 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait) finish_wait(&ca->set->bucket_wait, &w); out: - wake_up_process(ca->alloc_thread); + if (ca->alloc_thread) + wake_up_process(ca->alloc_thread); trace_bcache_alloc(ca, reserve); @@ -479,7 +480,7 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned reserve, if (b == -1) goto err; - k->ptr[i] = PTR(ca->buckets[b].gen, + k->ptr[i] = MAKE_PTR(ca->buckets[b].gen, bucket_to_sector(c, b), ca->sb.nr_this_dev); diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index 41c238fc37338..f9d391711595f 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -585,7 +585,7 @@ static bool bch_extent_merge(struct btree_keys *bk, struct bkey *l, struct bkey return false; for (i = 0; i < KEY_PTRS(l); i++) - if (l->ptr[i] + PTR(0, KEY_SIZE(l), 0) != r->ptr[i] || + if (l->ptr[i] + MAKE_PTR(0, KEY_SIZE(l), 0) != r->ptr[i] || PTR_BUCKET_NR(b->c, l, i) != PTR_BUCKET_NR(b->c, r, i)) return false; diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 02a98ddb592d3..03cc0722ae486 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -507,7 +507,7 @@ static void journal_reclaim(struct cache_set *c) continue; ja->cur_idx = next; - k->ptr[n++] = PTR(0, + k->ptr[n++] = MAKE_PTR(0, bucket_to_sector(c, ca->sb.d[ja->cur_idx]), ca->sb.nr_this_dev); } diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 3475d6628e219..e9fbf2bcd122b 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -463,6 +463,7 @@ struct search { unsigned recoverable:1; unsigned write:1; unsigned read_dirty_data:1; + unsigned cache_missed:1; unsigned long start_time; @@ -649,6 +650,7 @@ static inline struct search *search_alloc(struct bio *bio, s->orig_bio = bio; s->cache_miss = NULL; + s->cache_missed = 0; s->d = d; s->recoverable = 1; s->write = op_is_write(bio_op(bio)); @@ -699,7 +701,14 @@ static void cached_dev_read_error(struct closure *cl) struct search *s = container_of(cl, struct search, cl); struct bio *bio = &s->bio.bio; - if (s->recoverable) { + /* + * If read request hit dirty data (s->read_dirty_data is true), + * then recovery a failed read request from cached device may + * get a stale data back. So read failure recovery is only + * permitted when read request hit clean data in cache device, + * or when cache read race happened. + */ + if (s->recoverable && !s->read_dirty_data) { /* Retry from the backing device: */ trace_bcache_read_retry(s->orig_bio); @@ -760,7 +769,7 @@ static void cached_dev_read_done_bh(struct closure *cl) struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); bch_mark_cache_accounting(s->iop.c, s->d, - !s->cache_miss, s->iop.bypass); + !s->cache_missed, s->iop.bypass); trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass); if (s->iop.status) @@ -779,6 +788,8 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); struct bio *miss, *cache_bio; + s->cache_missed = 1; + if (s->cache_miss || s->iop.bypass) { miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); ret = miss == bio ? MAP_DONE : MAP_CONTINUE; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index fc0a31b13ac42..25bf003fb198b 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2085,6 +2085,7 @@ static void bcache_exit(void) if (bcache_major) unregister_blkdev(bcache_major, "bcache"); unregister_reboot_notifier(&reboot); + mutex_destroy(&bch_register_lock); } static int __init bcache_init(void) @@ -2103,14 +2104,15 @@ static int __init bcache_init(void) bcache_major = register_blkdev(0, "bcache"); if (bcache_major < 0) { unregister_reboot_notifier(&reboot); + mutex_destroy(&bch_register_lock); return bcache_major; } if (!(bcache_wq = alloc_workqueue("bcache", WQ_MEM_RECLAIM, 0)) || !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) || - sysfs_create_files(bcache_kobj, files) || bch_request_init() || - bch_debug_init(bcache_kobj)) + bch_debug_init(bcache_kobj) || + sysfs_create_files(bcache_kobj, files)) goto err; return 0; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d2121637b4abc..0cabf31fb163a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -625,7 +625,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) err = read_sb_page(bitmap->mddev, offset, sb_page, - 0, PAGE_SIZE); + 0, sizeof(bitmap_super_t)); } if (err) return err; @@ -1816,6 +1816,12 @@ struct bitmap *bitmap_create(struct mddev *mddev, int slot) BUG_ON(file && mddev->bitmap_info.offset); + if (test_bit(MD_HAS_JOURNAL, &mddev->flags)) { + pr_notice("md/raid:%s: array with journal cannot have bitmap\n", + mdname(mddev)); + return ERR_PTR(-EBUSY); + } + bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); if (!bitmap) return ERR_PTR(-ENOMEM); @@ -2123,7 +2129,7 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, if (store.sb_page && bitmap->storage.sb_page) memcpy(page_address(store.sb_page), page_address(bitmap->storage.sb_page), - PAGE_SIZE); + sizeof(bitmap_super_t)); bitmap_file_unmap(&bitmap->storage); bitmap->storage = store; @@ -2152,6 +2158,7 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, for (k = 0; k < page; k++) { kfree(new_bp[k].map); } + kfree(new_bp); /* restore some fields from old_counts */ bitmap->counts.bp = old_counts.bp; @@ -2202,6 +2209,14 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, block += old_blocks; } + if (bitmap->counts.bp != old_counts.bp) { + unsigned long k; + for (k = 0; k < old_counts.pages; k++) + if (!old_counts.bp[k].hijacked) + kfree(old_counts.bp[k].map); + kfree(old_counts.bp); + } + if (!init) { int i; while (block < (chunks << chunkshift)) { diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index d216a8f7bc224..6d416fdc25cb2 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -974,7 +974,8 @@ static void __get_memory_limit(struct dm_bufio_client *c, buffers = c->minimum_buffers; *limit_buffers = buffers; - *threshold_buffers = buffers * DM_BUFIO_WRITEBACK_PERCENT / 100; + *threshold_buffers = mult_frac(buffers, + DM_BUFIO_WRITEBACK_PERCENT, 100); } /* @@ -1610,7 +1611,8 @@ static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan, int l; struct dm_buffer *b, *tmp; unsigned long freed = 0; - unsigned long count = nr_to_scan; + unsigned long count = c->n_buffers[LIST_CLEAN] + + c->n_buffers[LIST_DIRTY]; unsigned long retain_target = get_retain_buffers(c); for (l = 0; l < LIST_SIZE; l++) { @@ -1646,8 +1648,11 @@ static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc) { struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker); + unsigned long count = ACCESS_ONCE(c->n_buffers[LIST_CLEAN]) + + ACCESS_ONCE(c->n_buffers[LIST_DIRTY]); + unsigned long retain_target = get_retain_buffers(c); - return ACCESS_ONCE(c->n_buffers[LIST_CLEAN]) + ACCESS_ONCE(c->n_buffers[LIST_DIRTY]); + return (count < retain_target) ? 0 : (count - retain_target); } /* @@ -1910,19 +1915,15 @@ static int __init dm_bufio_init(void) memset(&dm_bufio_caches, 0, sizeof dm_bufio_caches); memset(&dm_bufio_cache_names, 0, sizeof dm_bufio_cache_names); - mem = (__u64)((totalram_pages - totalhigh_pages) * - DM_BUFIO_MEMORY_PERCENT / 100) << PAGE_SHIFT; + mem = (__u64)mult_frac(totalram_pages - totalhigh_pages, + DM_BUFIO_MEMORY_PERCENT, 100) << PAGE_SHIFT; if (mem > ULONG_MAX) mem = ULONG_MAX; #ifdef CONFIG_MMU - /* - * Get the size of vmalloc space the same way as VMALLOC_TOTAL - * in fs/proc/internal.h - */ - if (mem > (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100) - mem = (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100; + if (mem > mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100)) + mem = mult_frac(VMALLOC_TOTAL, DM_BUFIO_VMALLOC_PERCENT, 100); #endif dm_bufio_default_cache_size = mem; diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 8785134c9f1f1..71c3507df9a0e 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -1201,6 +1201,18 @@ static void background_work_end(struct cache *cache) /*----------------------------------------------------------------*/ +static bool bio_writes_complete_block(struct cache *cache, struct bio *bio) +{ + return (bio_data_dir(bio) == WRITE) && + (bio->bi_iter.bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); +} + +static bool optimisable_bio(struct cache *cache, struct bio *bio, dm_oblock_t block) +{ + return writeback_mode(&cache->features) && + (is_discarded_oblock(cache, block) || bio_writes_complete_block(cache, bio)); +} + static void quiesce(struct dm_cache_migration *mg, void (*continuation)(struct work_struct *)) { @@ -1474,12 +1486,50 @@ static void mg_upgrade_lock(struct work_struct *ws) } } +static void mg_full_copy(struct work_struct *ws) +{ + struct dm_cache_migration *mg = ws_to_mg(ws); + struct cache *cache = mg->cache; + struct policy_work *op = mg->op; + bool is_policy_promote = (op->op == POLICY_PROMOTE); + + if ((!is_policy_promote && !is_dirty(cache, op->cblock)) || + is_discarded_oblock(cache, op->oblock)) { + mg_upgrade_lock(ws); + return; + } + + init_continuation(&mg->k, mg_upgrade_lock); + + if (copy(mg, is_policy_promote)) { + DMERR_LIMIT("%s: migration copy failed", cache_device_name(cache)); + mg->k.input = BLK_STS_IOERR; + mg_complete(mg, false); + } +} + static void mg_copy(struct work_struct *ws) { - int r; struct dm_cache_migration *mg = ws_to_mg(ws); if (mg->overwrite_bio) { + /* + * No exclusive lock was held when we last checked if the bio + * was optimisable. So we have to check again in case things + * have changed (eg, the block may no longer be discarded). + */ + if (!optimisable_bio(mg->cache, mg->overwrite_bio, mg->op->oblock)) { + /* + * Fallback to a real full copy after doing some tidying up. + */ + bool rb = bio_detain_shared(mg->cache, mg->op->oblock, mg->overwrite_bio); + BUG_ON(rb); /* An exclussive lock must _not_ be held for this block */ + mg->overwrite_bio = NULL; + inc_io_migrations(mg->cache); + mg_full_copy(ws); + return; + } + /* * It's safe to do this here, even though it's new data * because all IO has been locked out of the block. @@ -1489,26 +1539,8 @@ static void mg_copy(struct work_struct *ws) */ overwrite(mg, mg_update_metadata_after_copy); - } else { - struct cache *cache = mg->cache; - struct policy_work *op = mg->op; - bool is_policy_promote = (op->op == POLICY_PROMOTE); - - if ((!is_policy_promote && !is_dirty(cache, op->cblock)) || - is_discarded_oblock(cache, op->oblock)) { - mg_upgrade_lock(ws); - return; - } - - init_continuation(&mg->k, mg_upgrade_lock); - - r = copy(mg, is_policy_promote); - if (r) { - DMERR_LIMIT("%s: migration copy failed", cache_device_name(cache)); - mg->k.input = BLK_STS_IOERR; - mg_complete(mg, false); - } - } + } else + mg_full_copy(ws); } static int mg_lock_writes(struct dm_cache_migration *mg) @@ -1748,18 +1780,6 @@ static void inc_miss_counter(struct cache *cache, struct bio *bio) /*----------------------------------------------------------------*/ -static bool bio_writes_complete_block(struct cache *cache, struct bio *bio) -{ - return (bio_data_dir(bio) == WRITE) && - (bio->bi_iter.bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); -} - -static bool optimisable_bio(struct cache *cache, struct bio *bio, dm_oblock_t block) -{ - return writeback_mode(&cache->features) && - (is_discarded_oblock(cache, block) || bio_writes_complete_block(cache, bio)); -} - static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, bool *commit_needed) { @@ -3534,18 +3554,18 @@ static int __init dm_cache_init(void) { int r; - r = dm_register_target(&cache_target); - if (r) { - DMERR("cache target registration failed: %d", r); - return r; - } - migration_cache = KMEM_CACHE(dm_cache_migration, 0); if (!migration_cache) { dm_unregister_target(&cache_target); return -ENOMEM; } + r = dm_register_target(&cache_target); + if (r) { + DMERR("cache target registration failed: %d", r); + return r; + } + return 0; } diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 203144762f368..6a14f945783c6 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -29,7 +29,6 @@ struct dm_kobject_holder { * DM targets must _not_ deference a mapped_device to directly access its members! */ struct mapped_device { - struct srcu_struct io_barrier; struct mutex suspend_lock; /* @@ -127,6 +126,8 @@ struct mapped_device { struct blk_mq_tag_set *tag_set; bool use_blk_mq:1; bool init_tio_pdu:1; + + struct srcu_struct io_barrier; }; void dm_init_md_queue(struct mapped_device *md); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 96ab46512e1fd..554d60394c066 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1075,7 +1075,7 @@ static int crypt_convert_block_aead(struct crypt_config *cc, BUG_ON(cc->integrity_iv_size && cc->integrity_iv_size != cc->iv_size); /* Reject unexpected unaligned bio. */ - if (unlikely(bv_in.bv_offset & (cc->sector_size - 1))) + if (unlikely(bv_in.bv_len & (cc->sector_size - 1))) return -EIO; dmreq = dmreq_of_req(cc, req); @@ -1168,7 +1168,7 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc, int r = 0; /* Reject unexpected unaligned bio. */ - if (unlikely(bv_in.bv_offset & (cc->sector_size - 1))) + if (unlikely(bv_in.bv_len & (cc->sector_size - 1))) return -EIO; dmreq = dmreq_of_req(cc, req); @@ -1954,10 +1954,15 @@ static int crypt_setkey(struct crypt_config *cc) /* Ignore extra keys (which are used for IV etc) */ subkey_size = crypt_subkey_size(cc); - if (crypt_integrity_hmac(cc)) + if (crypt_integrity_hmac(cc)) { + if (subkey_size < cc->key_mac_size) + return -EINVAL; + crypt_copy_authenckey(cc->authenc_key, cc->key, subkey_size - cc->key_mac_size, cc->key_mac_size); + } + for (i = 0; i < cc->tfms_count; i++) { if (crypt_integrity_hmac(cc)) r = crypto_aead_setkey(cc->cipher_tfm.tfms_aead[i], @@ -2053,9 +2058,6 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string ret = crypt_setkey(cc); - /* wipe the kernel key payload copy in each case */ - memset(cc->key, 0, cc->key_size * sizeof(u8)); - if (!ret) { set_bit(DM_CRYPT_KEY_VALID, &cc->flags); kzfree(cc->key_string); @@ -2523,6 +2525,10 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key) } } + /* wipe the kernel key payload copy */ + if (cc->key_string) + memset(cc->key, 0, cc->key_size * sizeof(u8)); + return ret; } @@ -2740,6 +2746,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) cc->tag_pool_max_sectors * cc->on_disk_tag_size); if (!cc->tag_pool) { ti->error = "Cannot allocate integrity tags mempool"; + ret = -ENOMEM; goto bad; } @@ -2961,6 +2968,9 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) return ret; if (cc->iv_gen_ops && cc->iv_gen_ops->init) ret = cc->iv_gen_ops->init(cc); + /* wipe the kernel key payload copy */ + if (cc->key_string) + memset(cc->key, 0, cc->key_size * sizeof(u8)); return ret; } if (argc == 2 && !strcasecmp(argv[1], "wipe")) { @@ -3007,7 +3017,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits) static struct target_type crypt_target = { .name = "crypt", - .version = {1, 18, 0}, + .version = {1, 18, 1}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 096fe9b66c507..3cc2052f972c9 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -1376,7 +1376,7 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio) struct bvec_iter iter; struct bio_vec bv; bio_for_each_segment(bv, bio, iter) { - if (unlikely((bv.bv_offset | bv.bv_len) & ((ic->sectors_per_block << SECTOR_SHIFT) - 1))) { + if (unlikely(bv.bv_len & ((ic->sectors_per_block << SECTOR_SHIFT) - 1))) { DMERR("Bio vector (%u,%u) is not aligned on %u-sector boundary", bv.bv_offset, bv.bv_len, ic->sectors_per_block); return DM_MAPIO_KILL; @@ -2558,7 +2558,8 @@ static int create_journal(struct dm_integrity_c *ic, char **error) int r = 0; unsigned i; __u64 journal_pages, journal_desc_size, journal_tree_size; - unsigned char *crypt_data = NULL; + unsigned char *crypt_data = NULL, *crypt_iv = NULL; + struct skcipher_request *req = NULL; ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL); ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL); @@ -2616,9 +2617,20 @@ static int create_journal(struct dm_integrity_c *ic, char **error) if (blocksize == 1) { struct scatterlist *sg; - SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt); - unsigned char iv[ivsize]; - skcipher_request_set_tfm(req, ic->journal_crypt); + + req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL); + if (!req) { + *error = "Could not allocate crypt request"; + r = -ENOMEM; + goto bad; + } + + crypt_iv = kmalloc(ivsize, GFP_KERNEL); + if (!crypt_iv) { + *error = "Could not allocate iv"; + r = -ENOMEM; + goto bad; + } ic->journal_xor = dm_integrity_alloc_page_list(ic); if (!ic->journal_xor) { @@ -2640,9 +2652,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error) sg_set_buf(&sg[i], va, PAGE_SIZE); } sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids); - memset(iv, 0x00, ivsize); + memset(crypt_iv, 0x00, ivsize); - skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, iv); + skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv); init_completion(&comp.comp); comp.in_flight = (atomic_t)ATOMIC_INIT(1); if (do_crypt(true, req, &comp)) @@ -2658,10 +2670,22 @@ static int create_journal(struct dm_integrity_c *ic, char **error) crypto_free_skcipher(ic->journal_crypt); ic->journal_crypt = NULL; } else { - SKCIPHER_REQUEST_ON_STACK(req, ic->journal_crypt); - unsigned char iv[ivsize]; unsigned crypt_len = roundup(ivsize, blocksize); + req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL); + if (!req) { + *error = "Could not allocate crypt request"; + r = -ENOMEM; + goto bad; + } + + crypt_iv = kmalloc(ivsize, GFP_KERNEL); + if (!crypt_iv) { + *error = "Could not allocate iv"; + r = -ENOMEM; + goto bad; + } + crypt_data = kmalloc(crypt_len, GFP_KERNEL); if (!crypt_data) { *error = "Unable to allocate crypt data"; @@ -2669,8 +2693,6 @@ static int create_journal(struct dm_integrity_c *ic, char **error) goto bad; } - skcipher_request_set_tfm(req, ic->journal_crypt); - ic->journal_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal); if (!ic->journal_scatterlist) { *error = "Unable to allocate sg list"; @@ -2694,12 +2716,12 @@ static int create_journal(struct dm_integrity_c *ic, char **error) struct skcipher_request *section_req; __u32 section_le = cpu_to_le32(i); - memset(iv, 0x00, ivsize); + memset(crypt_iv, 0x00, ivsize); memset(crypt_data, 0x00, crypt_len); memcpy(crypt_data, §ion_le, min((size_t)crypt_len, sizeof(section_le))); sg_init_one(&sg, crypt_data, crypt_len); - skcipher_request_set_crypt(req, &sg, &sg, crypt_len, iv); + skcipher_request_set_crypt(req, &sg, &sg, crypt_len, crypt_iv); init_completion(&comp.comp); comp.in_flight = (atomic_t)ATOMIC_INIT(1); if (do_crypt(true, req, &comp)) @@ -2757,6 +2779,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error) } bad: kfree(crypt_data); + kfree(crypt_iv); + skcipher_request_free(req); + return r; } diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 11f273d2f018e..ddf0a4341ae29 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -366,7 +366,7 @@ static struct pgpath *choose_path_in_pg(struct multipath *m, pgpath = path_to_pgpath(path); - if (unlikely(lockless_dereference(m->current_pg) != pg)) { + if (unlikely(READ_ONCE(m->current_pg) != pg)) { /* Only update current_pgpath if pg changed */ spin_lock_irqsave(&m->lock, flags); m->current_pgpath = pgpath; @@ -390,7 +390,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) } /* Were we instructed to switch PG? */ - if (lockless_dereference(m->next_pg)) { + if (READ_ONCE(m->next_pg)) { spin_lock_irqsave(&m->lock, flags); pg = m->next_pg; if (!pg) { @@ -406,7 +406,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) /* Don't change PG until it has no remaining paths */ check_current_pg: - pg = lockless_dereference(m->current_pg); + pg = READ_ONCE(m->current_pg); if (pg) { pgpath = choose_path_in_pg(m, pg, nr_bytes); if (!IS_ERR_OR_NULL(pgpath)) @@ -473,7 +473,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, struct request *clone; /* Do we need to select a new pgpath? */ - pgpath = lockless_dereference(m->current_pgpath); + pgpath = READ_ONCE(m->current_pgpath); if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags)) pgpath = choose_pgpath(m, nr_bytes); @@ -499,8 +499,6 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, if (IS_ERR(clone)) { /* EBUSY, ENODEV or EWOULDBLOCK: requeue */ bool queue_dying = blk_queue_dying(q); - DMERR_LIMIT("blk_get_request() returned %ld%s - requeuing", - PTR_ERR(clone), queue_dying ? " (path offline)" : ""); if (queue_dying) { atomic_inc(&m->pg_init_in_progress); activate_or_offline_path(pgpath); @@ -535,7 +533,7 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, struct dm_m bool queue_io; /* Do we need to select a new pgpath? */ - pgpath = lockless_dereference(m->current_pgpath); + pgpath = READ_ONCE(m->current_pgpath); queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags); if (!pgpath || !queue_io) pgpath = choose_pgpath(m, nr_bytes); @@ -1804,7 +1802,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti, struct pgpath *current_pgpath; int r; - current_pgpath = lockless_dereference(m->current_pgpath); + current_pgpath = READ_ONCE(m->current_pgpath); if (!current_pgpath) current_pgpath = choose_pgpath(m, 0); @@ -1826,7 +1824,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti, } if (r == -ENOTCONN) { - if (!lockless_dereference(m->current_pg)) { + if (!READ_ONCE(m->current_pg)) { /* Path status changed, redo selection */ (void) choose_pgpath(m, 0); } @@ -1895,9 +1893,9 @@ static int multipath_busy(struct dm_target *ti) return (m->queue_mode != DM_TYPE_MQ_REQUEST_BASED); /* Guess which priority_group will be used at next mapping time */ - pg = lockless_dereference(m->current_pg); - next_pg = lockless_dereference(m->next_pg); - if (unlikely(!lockless_dereference(m->current_pgpath) && next_pg)) + pg = READ_ONCE(m->current_pg); + next_pg = READ_ONCE(m->next_pg); + if (unlikely(!READ_ONCE(m->current_pgpath) && next_pg)) pg = next_pg; if (!pg) { @@ -1967,13 +1965,6 @@ static int __init dm_multipath_init(void) { int r; - r = dm_register_target(&multipath_target); - if (r < 0) { - DMERR("request-based register failed %d", r); - r = -EINVAL; - goto bad_register_target; - } - kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); if (!kmultipathd) { DMERR("failed to create workqueue kmpathd"); @@ -1995,13 +1986,20 @@ static int __init dm_multipath_init(void) goto bad_alloc_kmpath_handlerd; } + r = dm_register_target(&multipath_target); + if (r < 0) { + DMERR("request-based register failed %d", r); + r = -EINVAL; + goto bad_register_target; + } + return 0; +bad_register_target: + destroy_workqueue(kmpath_handlerd); bad_alloc_kmpath_handlerd: destroy_workqueue(kmultipathd); bad_alloc_kmultipathd: - dm_unregister_target(&multipath_target); -bad_register_target: return r; } diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 2245d06d20459..a25eebd989969 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -2143,13 +2143,6 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev) struct dm_raid_superblock *refsb; uint64_t events_sb, events_refsb; - rdev->sb_start = 0; - rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev); - if (rdev->sb_size < sizeof(*sb) || rdev->sb_size > PAGE_SIZE) { - DMERR("superblock size of a logical block is no longer valid"); - return -EINVAL; - } - r = read_disk_sb(rdev, rdev->sb_size, false); if (r) return r; @@ -2494,6 +2487,17 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) if (test_bit(Journal, &rdev->flags)) continue; + if (!rdev->meta_bdev) + continue; + + /* Set superblock offset/size for metadata device. */ + rdev->sb_start = 0; + rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev); + if (rdev->sb_size < sizeof(struct dm_raid_superblock) || rdev->sb_size > PAGE_SIZE) { + DMERR("superblock size of a logical block is no longer valid"); + return -EINVAL; + } + /* * Skipping super_load due to CTR_FLAG_SYNC will cause * the array to undergo initialization again as @@ -2506,9 +2510,6 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) if (test_bit(__CTR_FLAG_SYNC, &rs->ctr_flags)) continue; - if (!rdev->meta_bdev) - continue; - r = super_load(rdev, freshest); switch (r) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 1113b42e1edae..a0613bd8ed00e 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -2411,24 +2411,6 @@ static int __init dm_snapshot_init(void) return r; } - r = dm_register_target(&snapshot_target); - if (r < 0) { - DMERR("snapshot target register failed %d", r); - goto bad_register_snapshot_target; - } - - r = dm_register_target(&origin_target); - if (r < 0) { - DMERR("Origin target register failed %d", r); - goto bad_register_origin_target; - } - - r = dm_register_target(&merge_target); - if (r < 0) { - DMERR("Merge target register failed %d", r); - goto bad_register_merge_target; - } - r = init_origin_hash(); if (r) { DMERR("init_origin_hash failed."); @@ -2449,19 +2431,37 @@ static int __init dm_snapshot_init(void) goto bad_pending_cache; } + r = dm_register_target(&snapshot_target); + if (r < 0) { + DMERR("snapshot target register failed %d", r); + goto bad_register_snapshot_target; + } + + r = dm_register_target(&origin_target); + if (r < 0) { + DMERR("Origin target register failed %d", r); + goto bad_register_origin_target; + } + + r = dm_register_target(&merge_target); + if (r < 0) { + DMERR("Merge target register failed %d", r); + goto bad_register_merge_target; + } + return 0; -bad_pending_cache: - kmem_cache_destroy(exception_cache); -bad_exception_cache: - exit_origin_hash(); -bad_origin_hash: - dm_unregister_target(&merge_target); bad_register_merge_target: dm_unregister_target(&origin_target); bad_register_origin_target: dm_unregister_target(&snapshot_target); bad_register_snapshot_target: + kmem_cache_destroy(pending_cache); +bad_pending_cache: + kmem_cache_destroy(exception_cache); +bad_exception_cache: + exit_origin_hash(); +bad_origin_hash: dm_exception_store_exit(); return r; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index ef7b8f201f73a..4287fc9f3527f 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1758,13 +1758,12 @@ static bool dm_table_supports_write_zeroes(struct dm_table *t) return true; } - -static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev, - sector_t start, sector_t len, void *data) +static int device_not_discard_capable(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) { struct request_queue *q = bdev_get_queue(dev->bdev); - return q && blk_queue_discard(q); + return q && !blk_queue_discard(q); } static bool dm_table_supports_discards(struct dm_table *t) @@ -1772,28 +1771,24 @@ static bool dm_table_supports_discards(struct dm_table *t) struct dm_target *ti; unsigned i; - /* - * Unless any target used by the table set discards_supported, - * require at least one underlying device to support discards. - * t->devices includes internal dm devices such as mirror logs - * so we need to use iterate_devices here, which targets - * supporting discard selectively must provide. - */ for (i = 0; i < dm_table_get_num_targets(t); i++) { ti = dm_table_get_target(t, i); if (!ti->num_discard_bios) - continue; - - if (ti->discards_supported) - return true; + return false; - if (ti->type->iterate_devices && - ti->type->iterate_devices(ti, device_discard_capable, NULL)) - return true; + /* + * Either the target provides discard support (as implied by setting + * 'discards_supported') or it relies on _all_ data devices having + * discard support. + */ + if (!ti->discards_supported && + (!ti->type->iterate_devices || + ti->type->iterate_devices(ti, device_not_discard_capable, NULL))) + return false; } - return false; + return true; } void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index d31d18d9727c6..36ef284ad086b 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -80,10 +80,14 @@ #define SECTOR_TO_BLOCK_SHIFT 3 /* + * For btree insert: * 3 for btree insert + * 2 for btree lookup used within space map + * For btree remove: + * 2 for shadow spine + + * 4 for rebalance 3 child node */ -#define THIN_MAX_CONCURRENT_LOCKS 5 +#define THIN_MAX_CONCURRENT_LOCKS 6 /* This should be plenty */ #define SPACE_MAP_ROOT_SIZE 128 diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 1e25705209c27..02e42ba2ecbcd 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -4355,30 +4355,28 @@ static struct target_type thin_target = { static int __init dm_thin_init(void) { - int r; + int r = -ENOMEM; pool_table_init(); + _new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0); + if (!_new_mapping_cache) + return r; + r = dm_register_target(&thin_target); if (r) - return r; + goto bad_new_mapping_cache; r = dm_register_target(&pool_target); if (r) - goto bad_pool_target; - - r = -ENOMEM; - - _new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0); - if (!_new_mapping_cache) - goto bad_new_mapping_cache; + goto bad_thin_target; return 0; -bad_new_mapping_cache: - dm_unregister_target(&pool_target); -bad_pool_target: +bad_thin_target: dm_unregister_target(&thin_target); +bad_new_mapping_cache: + kmem_cache_destroy(_new_mapping_cache); return r; } diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c index b87c1741da4b8..6d7bda6f81905 100644 --- a/drivers/md/dm-zoned-target.c +++ b/drivers/md/dm-zoned-target.c @@ -660,6 +660,7 @@ static int dmz_get_zoned_device(struct dm_target *ti, char *path) struct dmz_target *dmz = ti->private; struct request_queue *q; struct dmz_dev *dev; + sector_t aligned_capacity; int ret; /* Get the target device */ @@ -685,15 +686,17 @@ static int dmz_get_zoned_device(struct dm_target *ti, char *path) goto err; } + q = bdev_get_queue(dev->bdev); dev->capacity = i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT; - if (ti->begin || (ti->len != dev->capacity)) { + aligned_capacity = dev->capacity & ~(blk_queue_zone_sectors(q) - 1); + if (ti->begin || + ((ti->len != dev->capacity) && (ti->len != aligned_capacity))) { ti->error = "Partial mapping not supported"; ret = -EINVAL; goto err; } - q = bdev_get_queue(dev->bdev); - dev->zone_nr_sectors = q->limits.chunk_sectors; + dev->zone_nr_sectors = blk_queue_zone_sectors(q); dev->zone_nr_sectors_shift = ilog2(dev->zone_nr_sectors); dev->zone_nr_blocks = dmz_sect2blk(dev->zone_nr_sectors); @@ -929,8 +932,10 @@ static int dmz_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { struct dmz_target *dmz = ti->private; + struct dmz_dev *dev = dmz->dev; + sector_t capacity = dev->capacity & ~(dev->zone_nr_sectors - 1); - return fn(ti, dmz->ddev, 0, dmz->dev->capacity, data); + return fn(ti, dmz->ddev, 0, capacity, data); } static struct target_type dmz_type = { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4be85324f44dc..804419635cc7d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1695,7 +1695,7 @@ static struct mapped_device *alloc_dev(int minor) struct mapped_device *md; void *old_md; - md = kzalloc_node(sizeof(*md), GFP_KERNEL, numa_node_id); + md = kvzalloc_node(sizeof(*md), GFP_KERNEL, numa_node_id); if (!md) { DMWARN("unable to allocate device, out of memory."); return NULL; @@ -1795,7 +1795,7 @@ static struct mapped_device *alloc_dev(int minor) bad_minor: module_put(THIS_MODULE); bad_module_get: - kfree(md); + kvfree(md); return NULL; } @@ -1814,7 +1814,7 @@ static void free_dev(struct mapped_device *md) free_minor(minor); module_put(THIS_MODULE); - kfree(md); + kvfree(md); } static void __bind_mempools(struct mapped_device *md, struct dm_table *t) @@ -2709,11 +2709,15 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) md = container_of(kobj, struct mapped_device, kobj_holder.kobj); - if (test_bit(DMF_FREEING, &md->flags) || - dm_deleting_md(md)) - return NULL; - + spin_lock(&_minor_lock); + if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) { + md = NULL; + goto out; + } dm_get(md); +out: + spin_unlock(&_minor_lock); + return md; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 0ff1bbf6c90e5..6bf093cef9584 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6362,7 +6362,7 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info) break; } } - if (has_journal) { + if (has_journal || mddev->bitmap) { export_rdev(rdev); return -EBUSY; } @@ -7468,8 +7468,8 @@ void md_wakeup_thread(struct md_thread *thread) { if (thread) { pr_debug("md: waking up MD thread %s.\n", thread->tsk->comm); - if (!test_and_set_bit(THREAD_WAKEUP, &thread->flags)) - wake_up(&thread->wqueue); + set_bit(THREAD_WAKEUP, &thread->flags); + wake_up(&thread->wqueue); } } EXPORT_SYMBOL(md_wakeup_thread); @@ -8039,7 +8039,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi) if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); wait_event(mddev->sb_wait, - !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) && !mddev->suspended); + !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) || + mddev->suspended); if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) { percpu_ref_put(&mddev->writes_pending); return false; @@ -8110,7 +8111,6 @@ void md_allow_write(struct mddev *mddev) sysfs_notify_dirent_safe(mddev->sysfs_state); /* wait for the dirty state to be recorded in the metadata */ wait_event(mddev->sb_wait, - !test_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags) && !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)); } else spin_unlock(&mddev->lock); diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index f21ce6a3d4cf5..58b319757b1e5 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -683,23 +683,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key) pn->keys[1] = rn->keys[0]; memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64)); - /* - * rejig the spine. This is ugly, since it knows too - * much about the spine - */ - if (s->nodes[0] != new_parent) { - unlock_block(s->info, s->nodes[0]); - s->nodes[0] = new_parent; - } - if (key < le64_to_cpu(rn->keys[0])) { - unlock_block(s->info, right); - s->nodes[1] = left; - } else { - unlock_block(s->info, left); - s->nodes[1] = right; - } - s->count = 2; - + unlock_block(s->info, left); + unlock_block(s->info, right); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f3f3e40dc9d8f..5a8216b50e381 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -990,14 +990,6 @@ static void wait_barrier(struct r1conf *conf, sector_t sector_nr) _wait_barrier(conf, idx); } -static void wait_all_barriers(struct r1conf *conf) -{ - int idx; - - for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) - _wait_barrier(conf, idx); -} - static void _allow_barrier(struct r1conf *conf, int idx) { atomic_dec(&conf->nr_pending[idx]); @@ -1011,14 +1003,6 @@ static void allow_barrier(struct r1conf *conf, sector_t sector_nr) _allow_barrier(conf, idx); } -static void allow_all_barriers(struct r1conf *conf) -{ - int idx; - - for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) - _allow_barrier(conf, idx); -} - /* conf->resync_lock should be held */ static int get_unqueued_pending(struct r1conf *conf) { @@ -1325,12 +1309,12 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, sigset_t full, old; prepare_to_wait(&conf->wait_barrier, &w, TASK_INTERRUPTIBLE); - if (bio_end_sector(bio) <= mddev->suspend_lo || - bio->bi_iter.bi_sector >= mddev->suspend_hi || - (mddev_is_clustered(mddev) && + if ((bio_end_sector(bio) <= mddev->suspend_lo || + bio->bi_iter.bi_sector >= mddev->suspend_hi) && + (!mddev_is_clustered(mddev) || !md_cluster_ops->area_resyncing(mddev, WRITE, - bio->bi_iter.bi_sector, - bio_end_sector(bio)))) + bio->bi_iter.bi_sector, + bio_end_sector(bio)))) break; sigfillset(&full); sigprocmask(SIG_BLOCK, &full, &old); @@ -1654,8 +1638,12 @@ static void print_conf(struct r1conf *conf) static void close_sync(struct r1conf *conf) { - wait_all_barriers(conf); - allow_all_barriers(conf); + int idx; + + for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++) { + _wait_barrier(conf, idx); + _allow_barrier(conf, idx); + } mempool_destroy(conf->r1buf_pool); conf->r1buf_pool = NULL; diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 0b7406ac8ce1d..9a340728b8469 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -2571,31 +2571,22 @@ static ssize_t r5c_journal_mode_show(struct mddev *mddev, char *page) int r5c_journal_mode_set(struct mddev *mddev, int mode) { struct r5conf *conf; - int err; if (mode < R5C_JOURNAL_MODE_WRITE_THROUGH || mode > R5C_JOURNAL_MODE_WRITE_BACK) return -EINVAL; - err = mddev_lock(mddev); - if (err) - return err; conf = mddev->private; - if (!conf || !conf->log) { - mddev_unlock(mddev); + if (!conf || !conf->log) return -ENODEV; - } if (raid5_calc_degraded(conf) > 0 && - mode == R5C_JOURNAL_MODE_WRITE_BACK) { - mddev_unlock(mddev); + mode == R5C_JOURNAL_MODE_WRITE_BACK) return -EINVAL; - } mddev_suspend(mddev); conf->log->r5c_journal_mode = mode; mddev_resume(mddev); - mddev_unlock(mddev); pr_debug("md/raid:%s: setting r5c cache mode to %d: %s\n", mdname(mddev), mode, r5c_journal_mode_str[mode]); @@ -2608,6 +2599,7 @@ static ssize_t r5c_journal_mode_store(struct mddev *mddev, { int mode = ARRAY_SIZE(r5c_journal_mode_str); size_t len = length; + int ret; if (len < 2) return -EINVAL; @@ -2619,8 +2611,12 @@ static ssize_t r5c_journal_mode_store(struct mddev *mddev, if (strlen(r5c_journal_mode_str[mode]) == len && !strncmp(page, r5c_journal_mode_str[mode], len)) break; - - return r5c_journal_mode_set(mddev, mode) ?: length; + ret = mddev_lock(mddev); + if (ret) + return ret; + ret = r5c_journal_mode_set(mddev, mode); + mddev_unlock(mddev); + return ret ?: length; } struct md_sysfs_entry diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index cd026c88f7efa..702b760088869 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -758,7 +758,8 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e, (unsigned long long)sector); rdev = conf->disks[dd_idx].rdev; - if (!rdev) { + if (!rdev || (!test_bit(In_sync, &rdev->flags) && + sector >= rdev->recovery_offset)) { pr_debug("%s:%*s data member disk %d missing\n", __func__, indent, "", dd_idx); update_parity = false; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 928e24a071338..c406f16f52957 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1818,8 +1818,11 @@ static void ops_complete_reconstruct(void *stripe_head_ref) struct r5dev *dev = &sh->dev[i]; if (dev->written || i == pd_idx || i == qd_idx) { - if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) + if (!discard && !test_bit(R5_SkipCopy, &dev->flags)) { set_bit(R5_UPTODATE, &dev->flags); + if (test_bit(STRIPE_EXPAND_READY, &sh->state)) + set_bit(R5_Expanded, &dev->flags); + } if (fua) set_bit(R5_WantFUA, &dev->flags); if (sync) @@ -7156,6 +7159,13 @@ static int raid5_run(struct mddev *mddev) min_offset_diff = diff; } + if ((test_bit(MD_HAS_JOURNAL, &mddev->flags) || journal_dev) && + (mddev->bitmap_info.offset || mddev->bitmap_info.file)) { + pr_notice("md/raid:%s: array cannot have both journal and bitmap\n", + mdname(mddev)); + return -EINVAL; + } + if (mddev->reshape_position != MaxSector) { /* Check that we can continue the reshape. * Difficulties arise if the stripe we would write to diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 9139d01ba7ed6..33d844fe2e703 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -145,15 +145,13 @@ static void __dvb_frontend_free(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; - if (!fepriv) - return; - - dvb_free_device(fepriv->dvbdev); + if (fepriv) + dvb_free_device(fepriv->dvbdev); dvb_frontend_invoke_release(fe, fe->ops.release); - kfree(fepriv); - fe->frontend_priv = NULL; + if (fepriv) + kfree(fepriv); } static void dvb_frontend_free(struct kref *ref) diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c index b22d2dfcd3c29..55232a9129503 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c @@ -622,6 +622,9 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + } else { + /* On current devices output->wm_num is always <= 2 */ + break; } if (output->wm_idx[i] % 2 == 1) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index cba092bcb76dd..a0fe80df0cbd5 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -194,7 +194,6 @@ struct venus_buffer { * @fh: a holder of v4l file handle structure * @streamon_cap: stream on flag for capture queue * @streamon_out: stream on flag for output queue - * @cmd_stop: a flag to signal encoder/decoder commands * @width: current capture width * @height: current capture height * @out_width: current output width @@ -258,7 +257,6 @@ struct venus_inst { } controls; struct v4l2_fh fh; unsigned int streamon_cap, streamon_out; - bool cmd_stop; u32 width; u32 height; u32 out_width; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 9b2a401a4891c..0ce9559a2924f 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -623,13 +623,6 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) mutex_lock(&inst->lock); - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); - inst->cmd_stop = false; - goto unlock; - } - v4l2_m2m_buf_queue(m2m_ctx, vbuf); if (!(inst->streamon_out & inst->streamon_cap)) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index c09490876516f..ba29fd4d49847 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -484,6 +484,7 @@ int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) return -EINVAL; } +EXPORT_SYMBOL_GPL(hfi_session_process_buf); irqreturn_t hfi_isr_thread(int irq, void *dev_id) { diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 1caae8feaa36b..734ce11b0ed0e 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -344,7 +344,7 @@ static int venus_alloc(struct venus_hfi_device *hdev, struct mem_desc *desc, desc->attrs = DMA_ATTR_WRITE_COMBINE; desc->size = ALIGN(size, SZ_4K); - desc->kva = dma_alloc_attrs(dev, size, &desc->da, GFP_KERNEL, + desc->kva = dma_alloc_attrs(dev, desc->size, &desc->da, GFP_KERNEL, desc->attrs); if (!desc->kva) return -ENOMEM; @@ -710,10 +710,8 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) return ret; - hdev->ifaceq_table.kva = desc.kva; - hdev->ifaceq_table.da = desc.da; - hdev->ifaceq_table.size = IFACEQ_TABLE_SIZE; - offset = hdev->ifaceq_table.size; + hdev->ifaceq_table = desc; + offset = IFACEQ_TABLE_SIZE; for (i = 0; i < IFACEQ_NUM; i++) { queue = &hdev->queues[i]; @@ -755,9 +753,7 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) { hdev->sfr.da = 0; } else { - hdev->sfr.da = desc.da; - hdev->sfr.kva = desc.kva; - hdev->sfr.size = ALIGNED_SFR_SIZE; + hdev->sfr = desc; sfr = hdev->sfr.kva; sfr->buf_size = ALIGNED_SFR_SIZE; } diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index da611a5eb6703..c9e9576bb08a4 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -469,8 +469,14 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, static int vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - if (cmd->cmd != V4L2_DEC_CMD_STOP) + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) + return -EINVAL; + break; + default: return -EINVAL; + } return 0; } @@ -479,6 +485,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct venus_inst *inst = to_inst(file); + struct hfi_frame_data fdata = {0}; int ret; ret = vdec_try_decoder_cmd(file, fh, cmd); @@ -486,12 +493,23 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) return ret; mutex_lock(&inst->lock); - inst->cmd_stop = true; - mutex_unlock(&inst->lock); - hfi_session_flush(inst); + /* + * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder + * input to signal EOS. + */ + if (!(inst->streamon_out & inst->streamon_cap)) + goto unlock; + + fdata.buffer_type = HFI_BUFFER_INPUT; + fdata.flags |= HFI_BUFFERFLAG_EOS; + fdata.device_addr = 0xdeadbeef; - return 0; + ret = hfi_session_process_buf(inst, &fdata); + +unlock: + mutex_unlock(&inst->lock); + return ret; } static const struct v4l2_ioctl_ops vdec_ioctl_ops = { @@ -718,7 +736,6 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) inst->reconfig = false; inst->sequence_cap = 0; inst->sequence_out = 0; - inst->cmd_stop = false; ret = vdec_init_session(inst); if (ret) @@ -807,11 +824,6 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - inst->cmd_stop = false; - } - if (vbuf->flags & V4L2_BUF_FLAG_LAST) { const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 6f123a387cf9e..3fcf0e9b7b291 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -963,13 +963,12 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, if (!vbuf) return; - vb = &vbuf->vb2_buf; - vb->planes[0].bytesused = bytesused; - vb->planes[0].data_offset = data_offset; - vbuf->flags = flags; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + vb = &vbuf->vb2_buf; + vb2_set_plane_payload(vb, 0, bytesused + data_offset); + vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; } else { diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7b3f31cc63d25..0c46155a8e9da 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2517,6 +2517,11 @@ static int imon_probe(struct usb_interface *interface, mutex_lock(&driver_lock); first_if = usb_ifnum_to_if(usbdev, 0); + if (!first_if) { + ret = -ENODEV; + goto fail; + } + first_if_ctx = usb_get_intfdata(first_if); if (ifnum == 0) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index d2223c04e9ad0..4c8f456238bca 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -298,11 +298,14 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!dev->max_timeout) return -ENOTTY; + /* Check for multiply overflow */ + if (val > U32_MAX / 1000) + return -EINVAL; + tmp = val * 1000; - if (tmp < dev->min_timeout || - tmp > dev->max_timeout) - return -EINVAL; + if (tmp < dev->min_timeout || tmp > dev->max_timeout) + return -EINVAL; if (dev->s_timeout) ret = dev->s_timeout(dev, tmp); diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 817c18f2ddd15..a95d09acc22a5 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -87,8 +87,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) data->state = STATE_BIT_PULSE; return 0; } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { - rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); data->state = STATE_TRAILER_PULSE; return 0; } @@ -151,19 +149,26 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) break; - address = bitrev8((data->bits >> 24) & 0xff); - not_address = bitrev8((data->bits >> 16) & 0xff); - command = bitrev8((data->bits >> 8) & 0xff); - not_command = bitrev8((data->bits >> 0) & 0xff); + if (data->count == NEC_NBITS) { + address = bitrev8((data->bits >> 24) & 0xff); + not_address = bitrev8((data->bits >> 16) & 0xff); + command = bitrev8((data->bits >> 8) & 0xff); + not_command = bitrev8((data->bits >> 0) & 0xff); + + scancode = ir_nec_bytes_to_scancode(address, + not_address, + command, + not_command, + &rc_proto); - scancode = ir_nec_bytes_to_scancode(address, not_address, - command, not_command, - &rc_proto); + if (data->is_nec_x) + data->necx_repeat = true; - if (data->is_nec_x) - data->necx_repeat = true; + rc_keydown(dev, rc_proto, scancode, 0); + } else { + rc_repeat(dev); + } - rc_keydown(dev, rc_proto, scancode, 0); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 981cccd6b988e..72f381522cb26 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -38,41 +38,41 @@ static const struct { [RC_PROTO_UNKNOWN] = { .name = "unknown", .repeat_period = 250 }, [RC_PROTO_OTHER] = { .name = "other", .repeat_period = 250 }, [RC_PROTO_RC5] = { .name = "rc-5", - .scancode_bits = 0x1f7f, .repeat_period = 164 }, + .scancode_bits = 0x1f7f, .repeat_period = 250 }, [RC_PROTO_RC5X_20] = { .name = "rc-5x-20", - .scancode_bits = 0x1f7f3f, .repeat_period = 164 }, + .scancode_bits = 0x1f7f3f, .repeat_period = 250 }, [RC_PROTO_RC5_SZ] = { .name = "rc-5-sz", - .scancode_bits = 0x2fff, .repeat_period = 164 }, + .scancode_bits = 0x2fff, .repeat_period = 250 }, [RC_PROTO_JVC] = { .name = "jvc", .scancode_bits = 0xffff, .repeat_period = 250 }, [RC_PROTO_SONY12] = { .name = "sony-12", - .scancode_bits = 0x1f007f, .repeat_period = 100 }, + .scancode_bits = 0x1f007f, .repeat_period = 250 }, [RC_PROTO_SONY15] = { .name = "sony-15", - .scancode_bits = 0xff007f, .repeat_period = 100 }, + .scancode_bits = 0xff007f, .repeat_period = 250 }, [RC_PROTO_SONY20] = { .name = "sony-20", - .scancode_bits = 0x1fff7f, .repeat_period = 100 }, + .scancode_bits = 0x1fff7f, .repeat_period = 250 }, [RC_PROTO_NEC] = { .name = "nec", - .scancode_bits = 0xffff, .repeat_period = 160 }, + .scancode_bits = 0xffff, .repeat_period = 250 }, [RC_PROTO_NECX] = { .name = "nec-x", - .scancode_bits = 0xffffff, .repeat_period = 160 }, + .scancode_bits = 0xffffff, .repeat_period = 250 }, [RC_PROTO_NEC32] = { .name = "nec-32", - .scancode_bits = 0xffffffff, .repeat_period = 160 }, + .scancode_bits = 0xffffffff, .repeat_period = 250 }, [RC_PROTO_SANYO] = { .name = "sanyo", .scancode_bits = 0x1fffff, .repeat_period = 250 }, [RC_PROTO_MCIR2_KBD] = { .name = "mcir2-kbd", - .scancode_bits = 0xffff, .repeat_period = 150 }, + .scancode_bits = 0xffff, .repeat_period = 250 }, [RC_PROTO_MCIR2_MSE] = { .name = "mcir2-mse", - .scancode_bits = 0x1fffff, .repeat_period = 150 }, + .scancode_bits = 0x1fffff, .repeat_period = 250 }, [RC_PROTO_RC6_0] = { .name = "rc-6-0", - .scancode_bits = 0xffff, .repeat_period = 164 }, + .scancode_bits = 0xffff, .repeat_period = 250 }, [RC_PROTO_RC6_6A_20] = { .name = "rc-6-6a-20", - .scancode_bits = 0xfffff, .repeat_period = 164 }, + .scancode_bits = 0xfffff, .repeat_period = 250 }, [RC_PROTO_RC6_6A_24] = { .name = "rc-6-6a-24", - .scancode_bits = 0xffffff, .repeat_period = 164 }, + .scancode_bits = 0xffffff, .repeat_period = 250 }, [RC_PROTO_RC6_6A_32] = { .name = "rc-6-6a-32", - .scancode_bits = 0xffffffff, .repeat_period = 164 }, + .scancode_bits = 0xffffffff, .repeat_period = 250 }, [RC_PROTO_RC6_MCE] = { .name = "rc-6-mce", - .scancode_bits = 0xffff7fff, .repeat_period = 164 }, + .scancode_bits = 0xffff7fff, .repeat_period = 250 }, [RC_PROTO_SHARP] = { .name = "sharp", .scancode_bits = 0x1fff, .repeat_period = 250 }, [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c index bc906fb128d51..d59918878eb26 100644 --- a/drivers/media/rc/sir_ir.c +++ b/drivers/media/rc/sir_ir.c @@ -57,7 +57,7 @@ static void add_read_queue(int flag, unsigned long val); static irqreturn_t sir_interrupt(int irq, void *dev_id); static void send_space(unsigned long len); static void send_pulse(unsigned long len); -static void init_hardware(void); +static int init_hardware(void); static void drop_hardware(void); /* Initialisation */ @@ -263,11 +263,36 @@ static void send_pulse(unsigned long len) } } -static void init_hardware(void) +static int init_hardware(void) { + u8 scratch, scratch2, scratch3; unsigned long flags; spin_lock_irqsave(&hardware_lock, flags); + + /* + * This is a simple port existence test, borrowed from the autoconfig + * function in drivers/tty/serial/8250/8250_port.c + */ + scratch = sinp(UART_IER); + soutp(UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, 0x0f); +#ifdef __i386__ + outb(0x00, 0x080); +#endif + scratch3 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0f) { + /* we fail, there's nothing here */ + spin_unlock_irqrestore(&hardware_lock, flags); + pr_err("port existence test failed, cannot continue\n"); + return -ENODEV; + } + /* reset UART */ outb(0, io + UART_MCR); outb(0, io + UART_IER); @@ -285,6 +310,8 @@ static void init_hardware(void) /* turn on UART */ outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR); spin_unlock_irqrestore(&hardware_lock, flags); + + return 0; } static void drop_hardware(void) @@ -334,14 +361,19 @@ static int sir_ir_probe(struct platform_device *dev) pr_err("IRQ %d already in use.\n", irq); return retval; } + + retval = init_hardware(); + if (retval) { + del_timer_sync(&timerlist); + return retval; + } + pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq); retval = devm_rc_register_device(&sir_ir_dev->dev, rcdev); if (retval < 0) return retval; - init_hardware(); - return 0; } diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index 5a28ce3a1d492..38dbc128340d2 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -101,18 +101,23 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, unsigned char *cmd, const struct firmware *firmware) { - struct as10x_fw_pkt_t fw_pkt; + struct as10x_fw_pkt_t *fw_pkt; int total_read_bytes = 0, errno = 0; unsigned char addr_has_changed = 0; + fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL); + if (!fw_pkt) + return -ENOMEM; + + for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { int read_bytes = 0, data_len = 0; /* parse intel hex line */ read_bytes = parse_hex_line( (u8 *) (firmware->data + total_read_bytes), - fw_pkt.raw.address, - fw_pkt.raw.data, + fw_pkt->raw.address, + fw_pkt->raw.data, &data_len, &addr_has_changed); @@ -122,28 +127,28 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, /* detect the end of file */ total_read_bytes += read_bytes; if (total_read_bytes == firmware->size) { - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x03; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x03; /* send EOF command */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, 2, 0); + fw_pkt, 2, 0); if (errno < 0) goto error; } else { if (!addr_has_changed) { /* prepare command to send */ - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x01; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x01; - data_len += sizeof(fw_pkt.u.request); - data_len += sizeof(fw_pkt.raw.address); + data_len += sizeof(fw_pkt->u.request); + data_len += sizeof(fw_pkt->raw.address); /* send cmd to device */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, + fw_pkt, data_len, 0); if (errno < 0) @@ -152,6 +157,7 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, } } error: + kfree(fw_pkt); return (errno == 0) ? total_read_bytes : errno; } diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index e0daa9b6c2a0e..9b742d569fb51 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1684,7 +1684,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, nr = dev->devno; assoc_desc = udev->actconfig->intf_assoc[0]; - if (assoc_desc->bFirstInterface != ifnum) { + if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) { dev_err(d, "Not found matching IAD interface\n"); retval = -ENODEV; goto err_if; diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 6020170fe99a3..92098c1b78e51 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -291,7 +291,7 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -325,7 +325,7 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -478,7 +478,7 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) &stk7700ph_dib7700_xc3028_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1010,7 +1010,7 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) &dib7070p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1068,7 +1068,7 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) &dib7770p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3056,7 +3056,7 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); @@ -3109,7 +3109,7 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) /* initialize IC 0 */ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3139,7 +3139,7 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3214,7 +3214,7 @@ static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) 1, 0x10, &tfe7790p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, @@ -3309,7 +3309,7 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3384,7 +3384,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -3620,7 +3620,7 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { /* Demodulator not found for some reason? */ - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index 8207e6900656b..bcacb0f220282 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -223,8 +223,20 @@ EXPORT_SYMBOL(dibusb_i2c_algo); int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) { - u8 wbuf[1] = { offs }; - return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); + u8 *buf; + int rc; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = offs; + + rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1); + *val = buf[1]; + kfree(buf); + + return rc; } EXPORT_SYMBOL(dibusb_read_eeprom_byte); diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 95b5f4319ec25..3668a04359e80 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -718,8 +718,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) */ if (ctrl->id == V4L2_CID_BRIGHTNESS || ctrl->id == V4L2_CID_CONTRAST) { ret = usb_control_msg(usbtv->udev, - usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); if (ret < 0) goto error; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index dd1db678718c8..8033d6f73501b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1227,6 +1227,16 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, } EXPORT_SYMBOL(v4l2_ctrl_fill); +static u32 user_flags(const struct v4l2_ctrl *ctrl) +{ + u32 flags = ctrl->flags; + + if (ctrl->is_ptr) + flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + + return flags; +} + static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { memset(ev->reserved, 0, sizeof(ev->reserved)); @@ -1234,7 +1244,7 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change ev->id = ctrl->id; ev->u.ctrl.changes = changes; ev->u.ctrl.type = ctrl->type; - ev->u.ctrl.flags = ctrl->flags; + ev->u.ctrl.flags = user_flags(ctrl); if (ctrl->is_ptr) ev->u.ctrl.value64 = 0; else @@ -2577,10 +2587,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr else qc->id = ctrl->id; strlcpy(qc->name, ctrl->name, sizeof(qc->name)); - qc->flags = ctrl->flags; + qc->flags = user_flags(ctrl); qc->type = ctrl->type; - if (ctrl->is_ptr) - qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; qc->elem_size = ctrl->elem_size; qc->elems = ctrl->elems; qc->nr_of_dims = ctrl->nr_of_dims; diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 0b5c43f7e020d..f412429cf5ba5 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -185,12 +185,13 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", data, size, dma->nr_pages); - err = get_user_pages(data & PAGE_MASK, dma->nr_pages, + err = get_user_pages_longterm(data & PAGE_MASK, dma->nr_pages, flags, dma->pages, NULL); if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages); + dprintk(1, "get_user_pages_longterm: err=%d [%d]\n", err, + dma->nr_pages); return err < 0 ? err : -EINVAL; } return 0; diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index c9714072e2246..a14196e95e9b3 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -667,6 +667,7 @@ static int cros_ec_spi_probe(struct spi_device *spi) sizeof(struct ec_response_get_protocol_info); ec_dev->dout_size = sizeof(struct ec_host_request); + ec_spi->last_transfer_ns = ktime_get_ns(); err = cros_ec_register(ec_dev); if (err) { diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index b3767c3141e58..461b0990b56fc 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -180,6 +180,19 @@ static int mx25_tsadc_probe(struct platform_device *pdev) return devm_of_platform_populate(dev); } +static int mx25_tsadc_remove(struct platform_device *pdev) +{ + struct mx25_tsadc *tsadc = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + if (irq) { + irq_set_chained_handler_and_data(irq, NULL, NULL); + irq_domain_remove(tsadc->domain); + } + + return 0; +} + static const struct of_device_id mx25_tsadc_ids[] = { { .compatible = "fsl,imx25-tsadc" }, { /* Sentinel */ } @@ -192,6 +205,7 @@ static struct platform_driver mx25_tsadc_driver = { .of_match_table = of_match_ptr(mx25_tsadc_ids), }, .probe = mx25_tsadc_probe, + .remove = mx25_tsadc_remove, }; module_platform_driver(mx25_tsadc_driver); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 450ae36645aa2..cf1120abbf521 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -522,6 +522,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { .name = "Avoton SoC", .iTCO_version = 3, .gpio_version = AVOTON_GPIO, + .spi_type = INTEL_SPI_BYT, }, [LPC_BAYTRAIL] = { .name = "Bay Trail SoC", diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c index 630bd19b2c0a5..98e732a7ae96f 100644 --- a/drivers/mfd/mxs-lradc.c +++ b/drivers/mfd/mxs-lradc.c @@ -196,8 +196,10 @@ static int mxs_lradc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, lradc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOMEM; + if (!res) { + ret = -ENOMEM; + goto err_clk; + } switch (lradc->soc) { case IMX23_LRADC: diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index da16bf45fab43..dc94ffc6321a8 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -159,13 +159,18 @@ unsigned int twl4030_audio_get_mclk(void) EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata, - struct device_node *node) + struct device_node *parent) { + struct device_node *node; + if (pdata && pdata->codec) return true; - if (of_find_node_by_name(node, "codec")) + node = of_get_child_by_name(parent, "codec"); + if (node) { + of_node_put(node); return true; + } return false; } diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index d66502d36ba0b..dd19f17a1b637 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -97,12 +97,16 @@ static struct reg_sequence twl6040_patch[] = { }; -static bool twl6040_has_vibra(struct device_node *node) +static bool twl6040_has_vibra(struct device_node *parent) { -#ifdef CONFIG_OF - if (of_find_node_by_name(node, "vibra")) + struct device_node *node; + + node = of_get_child_by_name(parent, "vibra"); + if (node) { + of_node_put(node); return true; -#endif + } + return false; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8136dc7e863d7..11ef310bd1c77 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -518,4 +518,5 @@ source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" +source "drivers/misc/mediatek/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ad0e64fdba348..c25aa08d17f55 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -74,3 +74,5 @@ OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o $(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE $(call if_changed,objcopy) + +obj-$(CONFIG_MTK_COMBO) += mediatek/ diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 3ba04f371380d..81093f8157a9e 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -2043,6 +2043,9 @@ static pci_ers_result_t cxl_vphb_error_detected(struct cxl_afu *afu, /* There should only be one entry, but go through the list * anyway */ + if (afu->phb == NULL) + return result; + list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) { if (!afu_dev->driver) continue; @@ -2084,8 +2087,7 @@ static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev, * Tell the AFU drivers; but we don't care what they * say, we're going away. */ - if (afu->phb != NULL) - cxl_vphb_error_detected(afu, state); + cxl_vphb_error_detected(afu, state); } return PCI_ERS_RESULT_DISCONNECT; } @@ -2225,6 +2227,9 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev) if (cxl_afu_select_best_mode(afu)) goto err; + if (afu->phb == NULL) + continue; + list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) { /* Reset the device context. * TODO: make this less disruptive @@ -2287,6 +2292,9 @@ static void cxl_pci_resume(struct pci_dev *pdev) for (i = 0; i < adapter->slices; i++) { afu = adapter->afu[i]; + if (afu->phb == NULL) + continue; + list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) { if (afu_dev->driver && afu_dev->driver->err_handler && afu_dev->driver->err_handler->resume) diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 764ff5df0dbc3..4cc0b42f2acc5 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -365,7 +365,8 @@ static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, memset(msg, 0, sizeof(msg)); msg[0].addr = client->addr; msg[0].buf = addrbuf; - addrbuf[0] = 0x90 + offset; + /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ + addrbuf[0] = 0xa0 - at24->chip.byte_len + offset; msg[0].len = 1; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; @@ -506,6 +507,9 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) if (unlikely(!count)) return count; + if (off + count > at24->chip.byte_len) + return -EINVAL; + /* * Read data from chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -538,6 +542,9 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) if (unlikely(!count)) return -EINVAL; + if (off + count > at24->chip.byte_len) + return -EINVAL; + /* * Write data to chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -631,6 +638,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_warn(&client->dev, "page_size looks suspicious (no power of 2)!\n"); + /* + * REVISIT: the size of the EUI-48 byte array is 6 in at24mac402, while + * the call to ilog2() in AT24_DEVICE_MAGIC() rounds it down to 4. + * + * Eventually we'll get rid of the magic values altoghether in favor of + * real structs, but for now just manually set the right size. + */ + if (chip.flags & AT24_FLAG_MAC && chip.byte_len == 4) + chip.byte_len = 6; + /* Use I2C operations unless we're stuck with SMBus extensions. */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { if (chip.flags & AT24_FLAG_ADDR16) @@ -759,7 +776,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->nvmem_config.reg_read = at24_read; at24->nvmem_config.reg_write = at24_write; at24->nvmem_config.priv = at24; - at24->nvmem_config.stride = 4; + at24->nvmem_config.stride = 1; at24->nvmem_config.word_size = 1; at24->nvmem_config.size = chip.byte_len; diff --git a/drivers/misc/mediatek/Kconfig b/drivers/misc/mediatek/Kconfig new file mode 100644 index 0000000000000..4829a6598c7aa --- /dev/null +++ b/drivers/misc/mediatek/Kconfig @@ -0,0 +1,11 @@ +menu "Mediatek Peripherals " + +config MTK_PLATFORM + string "MTK platform name" +source "drivers/misc/mediatek/btif/Kconfig" + +menu "Modem & Connectivity related configs" +source "drivers/misc/mediatek/connectivity/Kconfig" +endmenu + +endmenu # CONN diff --git a/drivers/misc/mediatek/Makefile b/drivers/misc/mediatek/Makefile new file mode 100644 index 0000000000000..5e7f06db38f28 --- /dev/null +++ b/drivers/misc/mediatek/Makefile @@ -0,0 +1,19 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +#$(call all-subdir-src-or-makefile) +subdir-ccflags-y += -Werror +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/ + +obj-$(CONFIG_MTK_COMBO) += connectivity/ +obj-$(CONFIG_MTK_BTIF) += btif/ diff --git a/drivers/misc/mediatek/btif/Kconfig b/drivers/misc/mediatek/btif/Kconfig new file mode 100644 index 0000000000000..908898bd95c3d --- /dev/null +++ b/drivers/misc/mediatek/btif/Kconfig @@ -0,0 +1,4 @@ +config MTK_BTIF + tristate"MediaTek BTIF Driver" + help + MTK connectivity BTIF driver for A/D die diff --git a/drivers/misc/mediatek/btif/Makefile b/drivers/misc/mediatek/btif/Makefile new file mode 100644 index 0000000000000..2be3ab66f4268 --- /dev/null +++ b/drivers/misc/mediatek/btif/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# BTIF driver for AD DIE +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) + #subdir-ccflags-y can be used in 2.6.34 in the future + MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM)) + subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include + subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/include/mach + subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat + + obj-y += common/ + +# Otherwise we were called directly from the command +# line; invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +endif diff --git a/drivers/misc/mediatek/btif/common/Makefile b/drivers/misc/mediatek/btif/common/Makefile new file mode 100644 index 0000000000000..61e9d4ea9e890 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# BTIF driver for AD DIE +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) + ccflags-y += -I$(src)/inc + ccflags-y += -I$(src)/plat_inc + + obj-y += btif.o + btif-y := mtk_btif.o mtk_btif_exp.o btif_dma_plat.o btif_plat.o + +# Otherwise we were called directly from the command +# line; invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +endif diff --git a/drivers/misc/mediatek/btif/common/btif_dma_plat.c b/drivers/misc/mediatek/btif/common/btif_dma_plat.c new file mode 100644 index 0000000000000..58be46927953b --- /dev/null +++ b/drivers/misc/mediatek/btif/common/btif_dma_plat.c @@ -0,0 +1,1436 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF-DMA" + +#include "btif_dma_priv.h" + +#define DMA_USER_ID "btif_driver" + +/************************************Global variable***********************************/ + +static MTK_BTIF_DMA_VFIFO mtk_tx_dma_vfifo = { + .vfifo = { + .p_vir_addr = NULL, + .phy_addr = 0, + .vfifo_size = TX_DMA_VFF_SIZE, + .thre = DMA_TX_THRE(TX_DMA_VFF_SIZE), + }, + .wpt = 0, + .last_wpt_wrap = 0, + .rpt = 0, + .last_rpt_wrap = 0, +}; + +static MTK_BTIF_IRQ_STR mtk_btif_tx_dma_irq = { + .name = "mtk btif tx dma irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_DMA_BTIF_TX_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +static MTK_BTIF_DMA_VFIFO mtk_rx_dma_vfifo = { + .vfifo = { + .p_vir_addr = NULL, + .phy_addr = 0, + .vfifo_size = RX_DMA_VFF_SIZE, + .thre = DMA_RX_THRE(RX_DMA_VFF_SIZE), + }, + + .wpt = 0, + .last_wpt_wrap = 0, + .rpt = 0, + .last_rpt_wrap = 0, +}; + +static MTK_BTIF_IRQ_STR mtk_btif_rx_dma_irq = { + .name = "mtk btif rx dma irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_DMA_BTIF_RX_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +static MTK_DMA_INFO_STR mtk_btif_tx_dma = { +#ifndef CONFIG_OF + .base = AP_DMA_BASE + BTIF_TX_DMA_OFFSET, +#endif + .dir = DMA_DIR_TX, + .p_irq = &mtk_btif_tx_dma_irq, + .p_vfifo = &(mtk_tx_dma_vfifo.vfifo), +}; + +static MTK_DMA_INFO_STR mtk_btif_rx_dma = { +#ifndef CONFIG_OF + .base = AP_DMA_BASE + BTIF_RX_DMA_OFFSET, +#endif + .dir = DMA_DIR_RX, + .p_irq = &mtk_btif_rx_dma_irq, + .p_vfifo = &(mtk_rx_dma_vfifo.vfifo), +}; + +static spinlock_t g_clk_cg_spinlock; /*dma clock's spinlock */ + +/************************************Function declearation***********************************/ +static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info); +static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info); +static int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_DMA_CTRL ctrl_id); +static int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_DMA_CTRL ctrl_id); +static int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); +static int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); +static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag); +static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag); +static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info); +static int _btif_dma_dump_dbg_reg(void); +static void hal_btif_tx_dma_vff_set_for_4g(void); +static void hal_btif_rx_dma_vff_set_for_4g(void); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ier_ctrl +* DESCRIPTION +* BTIF Tx DMA's interrupt enable/disable +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* enable [IN] control if tx interrupt enabled or not +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); + +/***************************************************************************** +* FUNCTION +* hal_dma_receive_data +* DESCRIPTION +* receive data from btif module in DMA polling mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +#ifndef MTK_BTIF_MARK_UNUSED_API +static int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + const unsigned int max_len); + +/************************************Function***********************************/ +#endif + +#ifdef CONFIG_OF +static void hal_dma_set_default_setting(ENUM_DMA_DIR dma_dir) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = {0, 0, 0}; + unsigned int phy_base; + + if (dma_dir == DMA_DIR_RX) { + node = of_find_compatible_node(NULL, NULL, "mediatek,btif_rx"); + if (node) { + mtk_btif_rx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif_rx_dma.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get rx_dma irq(%d),register base(0x%lx)\n", + mtk_btif_rx_dma.p_irq->irq_id, mtk_btif_rx_dma.base); + } else { + BTIF_ERR_FUNC("get rx_dma device node fail\n"); + } + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif_rx_dma.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", + mtk_btif_rx_dma.p_irq->irq_flags); + } + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { + BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", + dma_dir); + } else { + BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", + dma_dir, (unsigned int)phy_base); + } + } else if (dma_dir == DMA_DIR_TX) { + node = of_find_compatible_node(NULL, NULL, "mediatek,btif_tx"); + if (node) { + mtk_btif_tx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif_tx_dma.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get tx_dma irq(%d),register base(0x%lx)\n", + mtk_btif_tx_dma.p_irq->irq_id, mtk_btif_tx_dma.base); + } else { + BTIF_ERR_FUNC("get tx_dma device node fail\n"); + } + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif_tx_dma.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", + mtk_btif_tx_dma.p_irq->irq_flags); + } + + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { + BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", + dma_dir); + } else { + BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", + dma_dir, (unsigned int)phy_base); + } + } + +} +#endif + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_info_get +* DESCRIPTION +* get btif tx dma channel's information +* PARAMETERS +* dma_dir [IN] DMA's direction +* RETURNS +* pointer to btif dma's information structure +*****************************************************************************/ +P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) +{ + P_MTK_DMA_INFO_STR p_dma_info = NULL; + + BTIF_TRC_FUNC(); +#ifdef CONFIG_OF + hal_dma_set_default_setting(dma_dir); +#endif + if (dma_dir == DMA_DIR_RX) + /*Rx DMA*/ + p_dma_info = &mtk_btif_rx_dma; + else if (dma_dir == DMA_DIR_TX) + /*Tx DMA*/ + p_dma_info = &mtk_btif_tx_dma; + else + /*print error log*/ + BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); + spin_lock_init(&g_clk_cg_spinlock); + BTIF_TRC_FUNC(); + return p_dma_info; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag) +{ +/*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/ +/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ + int i_ret = 0; + unsigned long irq_flag = 0; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + static atomic_t s_clk_ref = ATOMIC_INIT(0); +#else + static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; +#endif + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_CTL + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + + if (flag == CLK_OUT_ENABLE) { + if (atomic_inc_return(&s_clk_ref) == 1) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); + i_ret = clk_enable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } + } + } else if (flag == CLK_OUT_DISABLE) { + if (atomic_dec_return(&s_clk_ref) == 0) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif_apdma) calling\n"); + clk_disable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + +#else + + if (status == flag) { + i_ret = 0; + BTIF_DBG_FUNC("dma clock already %s\n", + CLK_OUT_ENABLE == + status ? "enabled" : "disabled"); + } else { + if (flag == CLK_OUT_ENABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); + i_ret = clk_enable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } + } else if (flag == CLK_OUT_DISABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); + clk_disable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + } +#endif + +#else + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + +#else + + status = flag; +#endif + + i_ret = 0; +#endif + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + if (i_ret == 0) { + BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#else + + if (i_ret == 0) { + BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#endif +#if defined(CONFIG_MTK_CLKMGR) + BTIF_DBG_FUNC("DMA's clock is %s\n", (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) ? "off" : "on"); +#endif + return i_ret; +} + +int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) +{ + int i_ret = 0; + unsigned int dat = 0; + unsigned long base = p_dma_info->base; + unsigned long addr_h = 0; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + if (p_dma_info->dir == DMA_DIR_RX) { + /*Rx DMA*/ + /*do hardware reset*/ + /* BTIF_SET_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ + /* BTIF_CLR_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ + BTIF_SET_BIT(RX_DMA_RST(base), DMA_WARM_RST); + do { + dat = BTIF_READ32(RX_DMA_EN(base)); + } while (0x01 & dat); + /*write vfifo base address to VFF_ADDR*/ + btif_reg_sync_writel(p_vfifo->phy_addr, RX_DMA_VFF_ADDR(base)); + if (enable_4G()) + hal_btif_rx_dma_vff_set_for_4g(); + else { + addr_h = p_vfifo->phy_addr >> 16; + addr_h = addr_h >> 16; + btif_reg_sync_writel(addr_h, RX_DMA_VFF_ADDR_H(base)); + } + /*write vfifo length to VFF_LEN*/ + btif_reg_sync_writel(p_vfifo->vfifo_size, RX_DMA_VFF_LEN(base)); + /*write wpt to VFF_WPT*/ + btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, + RX_DMA_VFF_WPT(base)); + btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, + RX_DMA_VFF_RPT(base)); + /*write vff_thre to VFF_THRESHOLD*/ + btif_reg_sync_writel(p_vfifo->thre, RX_DMA_VFF_THRE(base)); + /*clear Rx DMA's interrupt status*/ + BTIF_SET_BIT(RX_DMA_INT_FLAG(base), + RX_DMA_INT_DONE | RX_DMA_INT_THRE); + + /*enable Rx IER by default*/ + btif_rx_dma_ier_ctrl(p_dma_info, true); + } else { +/*Tx DMA*/ +/*do hardware reset*/ +/* BTIF_SET_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ +/* BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ + BTIF_SET_BIT(TX_DMA_RST(base), DMA_WARM_RST); + do { + dat = BTIF_READ32(TX_DMA_EN(base)); + } while (0x01 & dat); +/*write vfifo base address to VFF_ADDR*/ + btif_reg_sync_writel(p_vfifo->phy_addr, TX_DMA_VFF_ADDR(base)); + if (enable_4G()) + hal_btif_tx_dma_vff_set_for_4g(); + else { + addr_h = p_vfifo->phy_addr >> 16; + addr_h = addr_h >> 16; + btif_reg_sync_writel(addr_h, TX_DMA_VFF_ADDR_H(base)); + } +/*write vfifo length to VFF_LEN*/ + btif_reg_sync_writel(p_vfifo->vfifo_size, TX_DMA_VFF_LEN(base)); +/*write wpt to VFF_WPT*/ + btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, + TX_DMA_VFF_WPT(base)); + btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, + TX_DMA_VFF_RPT(base)); +/*write vff_thre to VFF_THRESHOLD*/ + btif_reg_sync_writel(p_vfifo->thre, TX_DMA_VFF_THRE(base)); + + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); + + hal_btif_dma_ier_ctrl(p_dma_info, false); + } + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ctrl +* DESCRIPTION +* enable/disable Tx DMA channel +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* ctrl_id [IN] enable/disable ID +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + ENUM_DMA_DIR dir = p_dma_info->dir; + + if (dir == DMA_DIR_RX) + i_ret = btif_rx_dma_ctrl(p_dma_info, ctrl_id); + else if (dir == DMA_DIR_TX) + i_ret = btif_tx_dma_ctrl(p_dma_info, ctrl_id); + else { + /*TODO: print error log*/ + BTIF_ERR_FUNC("invalid dma ctrl id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + return i_ret; +} + +int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, + dma_rx_buf_write rx_cb) +{ + if (p_dma_info->rx_cb != NULL) { + BTIF_DBG_FUNC + ("rx_cb already registered, replace (0x%p) with (0x%p)\n", + p_dma_info->rx_cb, rx_cb); + } + p_dma_info->rx_cb = rx_cb; + return 0; +} + +int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int dat; + + BTIF_TRC_FUNC(); + if (ctrl_id == DMA_CTRL_DISABLE) { + /*if write 0 to EN bit, DMA will be stopped imediately*/ + /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ + /*BTIF_CLR_BIT(TX_DMA_EN(base), DMA_EN_BIT);*/ + BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT); + do { + dat = BTIF_READ32(TX_DMA_STOP(base)); + } while (0x1 & dat); + BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n", + BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base))); + i_ret = 0; + } else if (ctrl_id == DMA_CTRL_ENABLE) { + BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT); + BTIF_DBG_FUNC("BTIF Tx DMA enabled\n"); + i_ret = 0; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + BTIF_TRC_FUNC(); + return i_ret; +} + +int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int dat; + + BTIF_TRC_FUNC(); + + if (ctrl_id == DMA_CTRL_DISABLE) { + /*if write 0 to EN bit, DMA will be stopped imediately*/ + /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ + /*BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT);*/ + BTIF_SET_BIT(RX_DMA_STOP(base), DMA_STOP_BIT); + do { + dat = BTIF_READ32(RX_DMA_STOP(base)); + } while (0x1 & dat); + BTIF_DBG_FUNC("BTIF Rx DMA disabled,EN(0x%x),STOP(0x%x)\n", + BTIF_READ32(RX_DMA_EN(base)), BTIF_READ32(RX_DMA_STOP(base))); + i_ret = 0; + } else if (ctrl_id == DMA_CTRL_ENABLE) { + BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT); + BTIF_DBG_FUNC("BTIF Rx DMA enabled\n"); + i_ret = 0; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + BTIF_TRC_FUNC(); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_vfifo_reset +* DESCRIPTION +* reset tx virtual fifo information, except memory information +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info) +{ + unsigned int i_ret = -1; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + BTIF_TRC_FUNC(); + p_mtk_dma_vfifo->rpt = 0; + p_mtk_dma_vfifo->last_rpt_wrap = 0; + p_mtk_dma_vfifo->wpt = 0; + p_mtk_dma_vfifo->last_wpt_wrap = 0; + BTIF_TRC_FUNC(); + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ier_ctrl +* DESCRIPTION +* BTIF Tx DMA's interrupt enable/disable +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + ENUM_DMA_DIR dir = p_dma_info->dir; + + if (dir == DMA_DIR_RX) { + i_ret = btif_rx_dma_ier_ctrl(p_dma_info, en); + } else if (dir == DMA_DIR_TX) { + i_ret = btif_tx_dma_ier_ctrl(p_dma_info, en); + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA dma dir (%d)\n", dir); + i_ret = ERR_INVALID_PAR; + } + + return i_ret; +} + +int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + + BTIF_TRC_FUNC(); + if (!en) { + BTIF_CLR_BIT(RX_DMA_INT_EN(base), + (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); + } else { + BTIF_SET_BIT(RX_DMA_INT_EN(base), + (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); + } + i_ret = 0; + BTIF_TRC_FUNC(); + + return i_ret; +} + +int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + + BTIF_TRC_FUNC(); + if (!en) + BTIF_CLR_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); + else + BTIF_SET_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); + i_ret = 0; + BTIF_TRC_FUNC(); + + return i_ret; +} + +static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info) +{ + int tx_irq_done = 0; +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER +/*if we enable this clock reference couner, just return , because when enter IRQ handler, DMA's clock will be opened*/ + tx_irq_done = 1; +#else + unsigned long flag = 0; + unsigned long base = p_dma_info->base; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); + tx_irq_done = ((BTIF_READ32(TX_DMA_INT_FLAG(base)) & TX_DMA_INT_FLAG_MASK) == 0) ? 1 : 0; + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); +#endif + return tx_irq_done; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info) +{ +#define MAX_CONTINIOUS_TIMES 512 + unsigned int i_ret = -1; + unsigned int valid_size = 0; + unsigned int vff_len = 0; + unsigned int left_len = 0; + unsigned long base = p_dma_info->base; + static int flush_irq_counter; + static struct timeval start_timer; + static struct timeval end_timer; + unsigned long flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); + +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + BTIF_ERR_FUNC + ("%s: clock is off before irq status clear done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*check if Tx VFF Left Size equal to VFIFO size or not*/ + vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base)); + valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + if (flush_irq_counter == 0) + do_gettimeofday(&start_timer); + if ((valid_size > 0) && (valid_size < 8)) { + i_ret = _tx_dma_flush(p_dma_info); + flush_irq_counter++; + if (flush_irq_counter >= MAX_CONTINIOUS_TIMES) { + do_gettimeofday(&end_timer); +/* + * when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while + * we assume that btif cannot send data for a long time + * in order not to generate interrupt continiously, which may effect system's performance. + * we clear tx flag and disable btif tx interrupt + */ +/*clear interrupt flag*/ + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), + TX_DMA_INT_FLAG_MASK); +/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ + i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); + BTIF_ERR_FUNC + ("**********************ERROR, ERROR, ERROR**************************\n"); + BTIF_ERR_FUNC + ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n", + MAX_CONTINIOUS_TIMES, start_timer.tv_sec, + start_timer.tv_usec, end_timer.tv_usec, + end_timer.tv_usec); + } + } else if (vff_len == left_len) { + flush_irq_counter = 0; +/*clear interrupt flag*/ + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); +/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ + i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); + } else { +#if 0 + BTIF_ERR_FUNC + ("**********************WARNING**************************\n"); + BTIF_ERR_FUNC("invalid irq condition, dump register\n"); + hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL); +#endif + BTIF_DBG_FUNC + ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n", + vff_len, valid_size, left_len); + } + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_send_data +* DESCRIPTION +* send data through btif in DMA mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, + const unsigned char *p_buf, const unsigned int buf_len) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + unsigned int len_to_send = buf_len; + unsigned int ava_len = 0; + unsigned int wpt = 0; + unsigned int last_wpt_wrap = 0; + unsigned int vff_size = 0; + unsigned char *p_data = (unsigned char *)p_buf; + P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + BTIF_TRC_FUNC(); + if ((p_buf == NULL) || (buf_len == 0)) { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid parameters, p_buf:0x%p, buf_len:%d\n", + p_buf, buf_len); + return i_ret; + } +/*check if tx dma in flush operation? if yes, should wait until DMA finish flush operation*/ +/*currently uplayer logic will make sure this pre-condition*/ +/*disable Tx IER, in case Tx irq happens, flush bit may be set in irq handler*/ + btif_tx_dma_ier_ctrl(p_dma_info, false); + + vff_size = p_mtk_vfifo->vfifo.vfifo_size; + ava_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_MASK; + last_wpt_wrap = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_WRAP; + +/* + * copy data to vFIFO, Note: ava_len should always large than buf_len, + * otherwise common logic layer will not call hal_dma_send_data + */ + if (buf_len > ava_len) { + BTIF_ERR_FUNC + ("length to send:(%d) < length available(%d), abnormal!!!---!!!\n", + buf_len, ava_len); + WARN_ON(buf_len > ava_len); /* this will cause kernel panic */ + } + + len_to_send = buf_len < ava_len ? buf_len : ava_len; + if (len_to_send + wpt >= vff_size) { + unsigned int tail_len = vff_size - wpt; + + memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, tail_len); + p_data += tail_len; + memcpy(p_mtk_vfifo->vfifo.p_vir_addr, + p_data, len_to_send - tail_len); +/*make sure all data write to memory area tx vfifo locates*/ + mb(); + +/*calculate WPT*/ + wpt = wpt + len_to_send - vff_size; + last_wpt_wrap ^= DMA_WPT_WRAP; + } else { + memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), + p_data, len_to_send); +/*make sure all data write to memory area tx vfifo locates*/ + mb(); + +/*calculate WPT*/ + wpt += len_to_send; + } + p_mtk_vfifo->wpt = wpt; + p_mtk_vfifo->last_wpt_wrap = last_wpt_wrap; + +/*make sure tx dma is allowed(tx flush bit is not set) to use before update WPT*/ + if (hal_dma_is_tx_allow(p_dma_info)) { + /*make sure tx dma enabled*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + + /*update WTP to Tx DMA controller's control register*/ + btif_reg_sync_writel(wpt | last_wpt_wrap, TX_DMA_VFF_WPT(base)); + + if ((BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) < 8) && + (BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) > 0)) { + /* + * 0 < valid size in Tx vFIFO < 8 && TX Flush is not in process? + * if yes, set flush bit to DMA + */ + _tx_dma_flush(p_dma_info); + } + i_ret = len_to_send; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("Tx DMA flush operation is in process, this case should never happen,", + "please check if tx operation is allowed before call this API\n"); +/*if flush operation is in process , we will return 0*/ + i_ret = 0; + } + +/*Enable Tx IER*/ + btif_tx_dma_ier_ctrl(p_dma_info, true); + + BTIF_TRC_FUNC(); + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info) +{ + bool b_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); + unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info); + +/* + * only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0, + * we can identify tx operation finished + * confirmed with DE. + */ + if ((valid_size == 0) && (inter_size == 0) && (tx_done == 1)) { + b_ret = true; + BTIF_DBG_FUNC("DMA tx finished.\n"); + } else { + BTIF_DBG_FUNC + ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n", + valid_size, inter_size, tx_done); + b_ret = false; + } + + return b_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_get_ava_room +* DESCRIPTION +* get tx available room +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* available room size +*****************************************************************************/ +int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + +/*read vFIFO's left size*/ + i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret); + if (i_ret == 0) + BTIF_INFO_FUNC("DMA tx vfifo is full.\n"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_allow +* DESCRIPTION +* is tx operation allowed by DMA +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info) +{ +#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) +#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) + + bool b_ret = false; + unsigned int wait_us = 8 / MIN_TX_MB; /*only ava length */ +/*see if flush operation is in process*/ + b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; + if (!b_ret) { + usleep_range(wait_us, 2 * wait_us); + b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; + } + if (!b_ret) + BTIF_WARN_FUNC("btif tx dma is not allowed\n"); +/*after Tx flush operation finished, HW will set DMA_EN back to 0 and stop DMA*/ + return b_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_rx_dma_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len) +{ + int i_ret = -1; + unsigned int valid_len = 0; + unsigned int wpt_wrap = 0; + unsigned int rpt_wrap = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int tail_len = 0; + unsigned int real_len = 0; + unsigned long base = p_dma_info->base; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + dma_rx_buf_write rx_cb = p_dma_info->rx_cb; + unsigned char *p_vff_buf = NULL; + unsigned char *vff_base = p_vfifo->p_vir_addr; + unsigned int vff_size = p_vfifo->vfifo_size; + P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + unsigned long flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*disable DMA Rx IER*/ + hal_btif_dma_ier_ctrl(p_dma_info, false); + +/*clear Rx DMA's interrupt status*/ + BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); + + valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + if ((valid_len == 0) && (rpt == wpt)) { + BTIF_DBG_FUNC + ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n", + rpt, wpt); + } + + i_ret = 0; + + while ((valid_len > 0) || (rpt != wpt)) { + rpt_wrap = rpt & DMA_RPT_WRAP; + wpt_wrap = wpt & DMA_WPT_WRAP; + rpt &= DMA_RPT_MASK; + wpt &= DMA_WPT_MASK; + +/*calcaute length of available data in vFIFO*/ + if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) + real_len = wpt + vff_size - rpt; + else + real_len = wpt - rpt; + + if (rx_cb != NULL) { + tail_len = vff_size - rpt; + p_vff_buf = vff_base + rpt; + if (tail_len >= real_len) { + (*rx_cb) (p_dma_info, p_vff_buf, real_len); + } else { + (*rx_cb) (p_dma_info, p_vff_buf, tail_len); + p_vff_buf = vff_base; + (*rx_cb) (p_dma_info, p_vff_buf, real_len - + tail_len); + } + i_ret += real_len; + } else + BTIF_ERR_FUNC("no rx_cb found, please check your init process\n"); + mb(); + rpt += real_len; + if (rpt >= vff_size) { + /*read wrap bit should be revert*/ + rpt_wrap ^= DMA_RPT_WRAP; + rpt %= vff_size; + } + rpt |= rpt_wrap; +/*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/ + p_mtk_vfifo->wpt = wpt; + p_mtk_vfifo->last_wpt_wrap = wpt_wrap; + + p_mtk_vfifo->rpt = rpt; + p_mtk_vfifo->last_rpt_wrap = rpt_wrap; + +/*update rpt information to DMA controller*/ + btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base)); + +/*get vff valid size again and check if rx data is processed completely*/ + valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + } + +/*enable DMA Rx IER*/ + hal_btif_dma_ier_ctrl(p_dma_info, true); + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + + return i_ret; +} + +static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int int_flag = 0; + unsigned int enable = 0; + unsigned int stop = 0; + unsigned int flush = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int int_buf = 0; + unsigned int valid_size = 0; + /*unsigned long irq_flag = 0;*/ + +#if defined(CONFIG_MTK_CLKMGR) + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + int_flag = BTIF_READ32(TX_DMA_INT_FLAG(base)); + enable = BTIF_READ32(TX_DMA_EN(base)); + stop = BTIF_READ32(TX_DMA_STOP(base)); + flush = BTIF_READ32(TX_DMA_FLUSH(base)); + wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)); + rpt = BTIF_READ32(TX_DMA_VFF_RPT(base)); + int_buf = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); + valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + + BTIF_INFO_FUNC("DMA's clock is on\n"); + BTIF_INFO_FUNC("Tx DMA's base address: 0x%lx\n", base); + + if (flag == REG_TX_DMA_ALL) { + BTIF_INFO_FUNC("TX_EN(:0x%x\n", enable); + BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); + BTIF_INFO_FUNC("TX_STOP:0x%x\n", stop); + BTIF_INFO_FUNC("TX_FLUSH:0x%x\n", flush); + BTIF_INFO_FUNC("TX_WPT:0x%x\n", wpt); + BTIF_INFO_FUNC("TX_RPT:0x%x\n", rpt); + BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); + BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); + BTIF_INFO_FUNC("INT_EN:0x%x\n", + BTIF_READ32(TX_DMA_INT_EN(base))); + BTIF_INFO_FUNC("TX_RST:0x%x\n", BTIF_READ32(TX_DMA_RST(base))); + BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", + BTIF_READ32(TX_DMA_VFF_ADDR(base))); + BTIF_INFO_FUNC("VFF_LEN:0x%x\n", + BTIF_READ32(TX_DMA_VFF_LEN(base))); + BTIF_INFO_FUNC("TX_THRE:0x%x\n", + BTIF_READ32(TX_DMA_VFF_THRE(base))); + BTIF_INFO_FUNC("W_INT_BUF_SIZE:0x%x\n", + BTIF_READ32(TX_DMA_W_INT_BUF_SIZE(base))); + BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", + BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base))); + BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", + BTIF_READ32(TX_DMA_DEBUG_STATUS(base))); + i_ret = 0; + } else { + BTIF_WARN_FUNC("unknown flag:%d\n", flag); + } + BTIF_INFO_FUNC("tx dma %s\n", (enable & DMA_EN_BIT) && + (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); + BTIF_INFO_FUNC("data in tx dma is %s sent by HW\n", + ((wpt == rpt) && + (int_buf == 0)) ? "completely" : "not completely"); + + return i_ret; +} + +static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int int_flag = 0; + unsigned int enable = 0; + unsigned int stop = 0; + unsigned int flush = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int int_buf = 0; + unsigned int valid_size = 0; + /*unsigned long irq_flag = 0;*/ +#if defined(CONFIG_MTK_CLKMGR) + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + BTIF_INFO_FUNC("dump DMA status register\n"); + _btif_dma_dump_dbg_reg(); + + int_flag = BTIF_READ32(RX_DMA_INT_FLAG(base)); + enable = BTIF_READ32(RX_DMA_EN(base)); + stop = BTIF_READ32(RX_DMA_STOP(base)); + flush = BTIF_READ32(RX_DMA_FLUSH(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + int_buf = BTIF_READ32(RX_DMA_INT_BUF_SIZE(base)); + valid_size = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + + BTIF_INFO_FUNC("DMA's clock is on\n"); + BTIF_INFO_FUNC("Rx DMA's base address: 0x%lx\n", base); + + if (flag == REG_RX_DMA_ALL) { + BTIF_INFO_FUNC("RX_EN(:0x%x\n", enable); + BTIF_INFO_FUNC("RX_STOP:0x%x\n", stop); + BTIF_INFO_FUNC("RX_FLUSH:0x%x\n", flush); + BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); + BTIF_INFO_FUNC("RX_WPT:0x%x\n", wpt); + BTIF_INFO_FUNC("RX_RPT:0x%x\n", rpt); + BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); + BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); + BTIF_INFO_FUNC("INT_EN:0x%x\n", + BTIF_READ32(RX_DMA_INT_EN(base))); + BTIF_INFO_FUNC("RX_RST:0x%x\n", BTIF_READ32(RX_DMA_RST(base))); + BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", + BTIF_READ32(RX_DMA_VFF_ADDR(base))); + BTIF_INFO_FUNC("VFF_LEN:0x%x\n", + BTIF_READ32(RX_DMA_VFF_LEN(base))); + BTIF_INFO_FUNC("RX_THRE:0x%x\n", + BTIF_READ32(RX_DMA_VFF_THRE(base))); + BTIF_INFO_FUNC("RX_FLOW_CTRL_THRE:0x%x\n", + BTIF_READ32(RX_DMA_FLOW_CTRL_THRE(base))); + BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", + BTIF_READ32(RX_DMA_VFF_LEFT_SIZE(base))); + BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", + BTIF_READ32(RX_DMA_DEBUG_STATUS(base))); + i_ret = 0; + } else { + BTIF_WARN_FUNC("unknown flag:%d\n", flag); + } + BTIF_INFO_FUNC("rx dma %s\n", (enable & DMA_EN_BIT) && + (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); + BTIF_INFO_FUNC("data in rx dma is %s by driver\n", + ((wpt == rpt) && + (int_buf == 0)) ? "received" : "not received"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag) +{ + unsigned int i_ret = -1; + + if (p_dma_info->dir == DMA_DIR_TX) + i_ret = hal_tx_dma_dump_reg(p_dma_info, flag); + else if (p_dma_info->dir == DMA_DIR_RX) + i_ret = hal_rx_dma_dump_reg(p_dma_info, flag); + else + BTIF_WARN_FUNC("unknown dir:%d\n", p_dma_info->dir); + + return i_ret; +} + +static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int stop = BTIF_READ32(TX_DMA_STOP(base)); + +/*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/ + if ((stop && DMA_STOP_BIT) != 0) + BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n"); + else { + BTIF_DBG_FUNC("flush tx dma\n"); + BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT); + i_ret = 0; + } + return i_ret; +} + +static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info) +{ + bool b_ret = true; + unsigned long base = p_dma_info->base; + +/*see if flush operation is in process*/ + b_ret = ((DMA_FLUSH_BIT & BTIF_READ32(TX_DMA_FLUSH(base))) != 0) ? true : false; + + return b_ret; +} + +int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("op id: %d\n", opid); + switch (opid) { + case BTIF_PM_DPIDLE_EN: + i_ret = 0; + break; + case BTIF_PM_DPIDLE_DIS: + i_ret = 0; + break; + case BTIF_PM_SUSPEND: + i_ret = 0; + break; + case BTIF_PM_RESUME: + i_ret = 0; + break; + case BTIF_PM_RESTORE_NOIRQ:{ + unsigned int flag = 0; + P_MTK_BTIF_IRQ_STR p_irq = p_dma_info->p_irq; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + else + flag = IRQF_TRIGGER_FALLING; /*make this as default type */ + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + default: + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + } +#endif +/* irq_set_irq_type(p_irq->irq_id, flag); */ + i_ret = 0; + } + i_ret = 0; + break; + default: + i_ret = ERR_INVALID_PAR; + break; + } + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_receive_data +* DESCRIPTION +* receive data from btif module in DMA polling mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +#ifndef MTK_BTIF_MARK_UNUSED_API +int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len) +{ + unsigned int i_ret = -1; + + return i_ret; +} +#endif + +int _btif_dma_dump_dbg_reg(void) +{ +#if 0 + static MTK_BTIF_DMA_REG_DMP_DBG g_dma_dbg_regs[] = { + {0x10201180, 0x0}, + {0x10201184, 0x0}, + {0x10201188, 0x0}, + {0x1020118C, 0x0}, + {0x10201190, 0x0}, + {0x1000320C, 0x0}, + {0x10003210, 0x0}, + {0x10003214, 0x0}, + }; + + int i = 0; + char *addr1 = NULL; + char *addr2 = NULL; + + int array_num = ARRAY_SIZE(g_dma_dbg_regs) + + addr1 = ioremap(g_dma_dbg_regs[0].reg_addr, 0x20); + if (addr1) { + for (i = 0; i < 5; i++) + g_dma_dbg_regs[i].reg_val = *(volatile unsigned int*)(addr1 + i*4); + iounmap(addr1); + } + + addr2 = ioremap(g_dma_dbg_regs[5].reg_addr, 0x10); + if (addr2) { + g_dma_dbg_regs[5].reg_val = *(volatile unsigned int*)(addr2); + g_dma_dbg_regs[6].reg_val = *(volatile unsigned int*)(addr2+4); + g_dma_dbg_regs[7].reg_val = *(volatile unsigned int*)(addr2+8); + iounmap(addr2); + } + + for (i = 0; i < array_num; i++) + BTIF_INFO_FUNC("-<0x%lx, 0x%08x>\n", g_dma_dbg_regs[i].reg_addr, g_dma_dbg_regs[i].reg_val); +#endif + return 0; +} + +static void hal_btif_tx_dma_vff_set_for_4g(void) +{ + BTIF_DBG_FUNC("Set btif tx_vff_addr bit29\n"); + BTIF_SET_BIT(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), DMA_VFF_BIT29_OFFSET); + BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), + BTIF_READ32(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base))); +} +static void hal_btif_rx_dma_vff_set_for_4g(void) +{ + BTIF_DBG_FUNC("Set btif rx_vff_addr bit29\n"); + BTIF_SET_BIT(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), DMA_VFF_BIT29_OFFSET); + BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), + BTIF_READ32(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base))); +} + diff --git a/drivers/misc/mediatek/btif/common/btif_plat.c b/drivers/misc/mediatek/btif/common/btif_plat.c new file mode 100644 index 0000000000000..baf2a0b6d0c89 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/btif_plat.c @@ -0,0 +1,1396 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF" + +#define NEW_TX_HANDLING_SUPPORT 1 + +#include "btif_pub.h" +#include "btif_priv.h" + +#define BTIF_USER_ID "btif_driver" + +static spinlock_t g_clk_cg_spinlock; /*BTIF clock's spinlock */ + +/*-----------------------------BTIF Module Clock and Power Control Defination------------------*/ + +MTK_BTIF_IRQ_STR mtk_btif_irq = { + .name = "mtk btif irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_BTIF_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +/* + * will call clock manager's API export by WCP to control BTIF's clock, + * but we may need to access these registers in case of btif clock control logic is wrong in clock manager + */ + +MTK_BTIF_INFO_STR mtk_btif = { +#ifndef CONFIG_OF + .base = MTK_BTIF_REG_BASE, +#endif + .p_irq = &mtk_btif_irq, + .tx_fifo_size = BTIF_TX_FIFO_SIZE, + .rx_fifo_size = BTIF_RX_FIFO_SIZE, + .tx_tri_lvl = BTIF_TX_FIFO_THRE, + .rx_tri_lvl = BTIF_RX_FIFO_THRE, + .rx_data_len = 0, + .p_tx_fifo = NULL, +}; +#if !(NEW_TX_HANDLING_SUPPORT) +static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); +#endif + +static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + const unsigned int max_len); +static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_ier_ctrl +* DESCRIPTION +* BTIF Rx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if rx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_ier_ctrl +* DESCRIPTION +* BTIF Tx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +#ifndef MTK_BTIF_MARK_UNUSED_API +static int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* _btif_receive_data +* DESCRIPTION +* receive data from btif module in FIFO polling mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +static int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len); +static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count); +#endif + +static int btif_dump_array(char *string, char *p_buf, int len) +{ + unsigned int idx = 0; + unsigned char str[30]; + unsigned char *p_str; + + pr_debug("========dump %s start ========\n", string, len); + p_str = &str[0]; + for (idx = 0; idx < len; idx++, p_buf++) { + sprintf(p_str, "%02x ", *p_buf); + p_str += 3; + if (7 == (idx % 8)) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + p_str = &str[0]; + } + } + if (len % 8) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + } + pr_debug("========dump %s end========\n", string); + return 0; +} + +#if NEW_TX_HANDLING_SUPPORT +static int _btif_tx_fifo_init(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = -1; + + spin_lock_init(&(p_btif_info->tx_fifo_spinlock)); + + if (p_btif_info->p_tx_fifo == NULL) { + p_btif_info->p_tx_fifo = kzalloc(sizeof(struct kfifo), + GFP_ATOMIC); + if (p_btif_info->p_tx_fifo == NULL) { + i_ret = -ENOMEM; + BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); + goto ret; + } + + i_ret = kfifo_alloc(p_btif_info->p_tx_fifo, + BTIF_HAL_TX_FIFO_SIZE, GFP_ATOMIC); + if (i_ret != 0) { + BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); + i_ret = -ENOMEM; + goto ret; + } + i_ret = 0; + } else { + BTIF_WARN_FUNC + ("p_btif_info->p_tx_fifo is already init p_btif_info->p_tx_fifo(0x%p)\n", + p_btif_info->p_tx_fifo); + i_ret = 0; + } +ret: + return i_ret; +} + +static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = 0; + unsigned long flag = 0; + + spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag); + if (p_btif_info->p_tx_fifo == NULL) + i_ret = 0; + else + i_ret = kfifo_avail(p_btif_info->p_tx_fifo); + spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("tx kfifo:0x%p, available room:%d\n", p_btif_info->p_tx_fifo, i_ret); + return i_ret; +} + +static int _btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = 0; + + if (p_btif_info->p_tx_fifo != NULL) + kfifo_reset(p_btif_info->p_tx_fifo); + return i_ret; +} + +#endif + +#ifdef CONFIG_OF +static void _btif_set_default_setting(void) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = {0, 0, 0}; + unsigned int phy_base; + + node = of_find_compatible_node(NULL, NULL, "mediatek,btif"); + if (node) { + mtk_btif.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get btif irq(%d),register base(0x%lx)\n", + mtk_btif.p_irq->irq_id, mtk_btif.base); + } else { + BTIF_ERR_FUNC("get btif device node fail\n"); + } + + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", mtk_btif.p_irq->irq_flags); + } + + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) + BTIF_ERR_FUNC("get register phy base from DTS fail\n"); + else + BTIF_INFO_FUNC("get register phy base(0x%x)\n", (unsigned int)phy_base); +} +#endif + +/***************************************************************************** +* FUNCTION +* hal_btif_info_get +* DESCRIPTION +* get btif's information included base address , irq related information +* PARAMETERS +* RETURNS +* BTIF's information +*****************************************************************************/ +P_MTK_BTIF_INFO_STR hal_btif_info_get(void) +{ +#if NEW_TX_HANDLING_SUPPORT + int i_ret = 0; +/*tx fifo and fifo lock init*/ + i_ret = _btif_tx_fifo_init(&mtk_btif); + if (i_ret == 0) + BTIF_INFO_FUNC("_btif_tx_fifo_init succeed\n"); + else + BTIF_ERR_FUNC("_btif_tx_fifo_init failed, i_ret:%d\n", i_ret); + +#endif + +#ifdef CONFIG_OF + _btif_set_default_setting(); +#endif + + spin_lock_init(&g_clk_cg_spinlock); + + return &mtk_btif; +} +/***************************************************************************** +* FUNCTION +* hal_btif_clk_get_and_prepare +* DESCRIPTION +* get clock from device tree and prepare for enable/disable control +* PARAMETERS +* pdev device pointer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +#if !defined(CONFIG_MTK_CLKMGR) +int hal_btif_clk_get_and_prepare(struct platform_device *pdev) +{ + int i_ret = -1; + + clk_btif = devm_clk_get(&pdev->dev, "btifc"); + if (IS_ERR(clk_btif)) { + BTIF_ERR_FUNC("[CCF]cannot get clk_btif clock.\n"); + return PTR_ERR(clk_btif); + } + BTIF_ERR_FUNC("[CCF]clk_btif=%p\n", clk_btif); + clk_btif_apdma = devm_clk_get(&pdev->dev, "apdmac"); + if (IS_ERR(clk_btif_apdma)) { + BTIF_ERR_FUNC("[CCF]cannot get clk_btif_apdma clock.\n"); + return PTR_ERR(clk_btif_apdma); + } + BTIF_ERR_FUNC("[CCF]clk_btif_apdma=%p\n", clk_btif_apdma); + + i_ret = clk_prepare(clk_btif); + if (i_ret != 0) { + BTIF_ERR_FUNC("clk_prepare clk_btif failed! ret:%d\n", i_ret); + return i_ret; + } + + i_ret = clk_prepare(clk_btif_apdma); + if (i_ret != 0) { + BTIF_ERR_FUNC("clk_prepare clk_btif_apdma failed! ret:%d\n", i_ret); + return i_ret; + } + return i_ret; +} +/***************************************************************************** +* FUNCTION +* hal_btif_clk_unprepare +* DESCRIPTION +* unprepare btif clock and apdma clock +* PARAMETERS +* none +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_unprepare(void) +{ + clk_unprepare(clk_btif); + clk_unprepare(clk_btif_apdma); + return 0; +} +#endif +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of BTIF module +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag) +{ +/*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/ +/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ + int i_ret = 0; + unsigned long irq_flag = 0; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + static atomic_t s_clk_ref = ATOMIC_INIT(0); +#else + static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; +#endif + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_CTL + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + + if (flag == CLK_OUT_ENABLE) { + if (atomic_inc_return(&s_clk_ref) == 1) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); + i_ret = clk_enable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } + } + } else if (flag == CLK_OUT_DISABLE) { + if (atomic_dec_return(&s_clk_ref) == 0) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); + clk_disable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + +#else + + if (status == flag) { + i_ret = 0; + BTIF_DBG_FUNC("btif clock already %s\n", + CLK_OUT_ENABLE == + status ? "enabled" : "disabled"); + } else { + if (flag == CLK_OUT_ENABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); + i_ret = clk_enable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } + } else if (flag == CLK_OUT_DISABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); + clk_disable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + } +#endif + +#else + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + +#else + + status = flag; +#endif + + i_ret = 0; +#endif + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + if (i_ret == 0) { + BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#else + + if (i_ret == 0) { + BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#endif +#if defined(CONFIG_MTK_CLKMGR) + BTIF_DBG_FUNC("BTIF's clock is %s\n", (clock_is_on(MTK_BTIF_CG_BIT) == 0) ? "off" : "on"); +#endif + return i_ret; +} + +static int btif_new_handshake_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool enable) +{ + unsigned long base = p_btif->base; + + if (enable == true) + BTIF_SET_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); + else + BTIF_CLR_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); + return true; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_hw_init +* DESCRIPTION +* BTIF hardware init +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned long base = p_btif->base; + +#if NEW_TX_HANDLING_SUPPORT + _btif_tx_fifo_reset(p_btif); +#endif + +/*set to normal mode*/ + btif_reg_sync_writel(BTIF_FAKELCR_NORMAL_MODE, BTIF_FAKELCR(base)); +/*set to newhandshake mode*/ + btif_new_handshake_ctrl(p_btif, true); +/*No need to access: enable sleep mode*/ +/*No need to access: set Rx timeout count*/ +/*set Tx threshold*/ +/*set Rx threshold*/ +/*disable internal loopback test*/ + +/*set Rx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); +/*clear Rx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); +/*set Tx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); +/*clear Tx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + + btif_reg_sync_writel(BTIF_TRI_LVL_TX(p_btif->tx_tri_lvl) + | BTIF_TRI_LVL_RX(p_btif->rx_tri_lvl) + | BTIF_TRI_LOOP_DIS, BTIF_TRI_LVL(base)); + hal_btif_loopback_ctrl(p_btif, false); +/*disable BTIF Tx DMA mode*/ + hal_btif_tx_mode_ctrl(p_btif, false); +/*disable BTIF Rx DMA mode*/ + hal_btif_rx_mode_ctrl(p_btif, false); +/*auto reset*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_AUTORST_EN); +/*disable Tx IER*/ + hal_btif_tx_ier_ctrl(p_btif, false); +/*enable Rx IER by default*/ + hal_btif_rx_ier_ctrl(p_btif, true); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_ier_ctrl +* DESCRIPTION +* BTIF Rx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if rx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_RXFEN); + else + BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_RXFEN); + +/*TODO:do we need to read back ? Answer: no*/ + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_ier_ctrl +* DESCRIPTION +* BTIF Tx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_TXEEN); + else + BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_TXEEN); + +/*TODO:do we need to read back ? Answer: no*/ + i_ret = 0; + + return i_ret; +} + +#ifndef MTK_BTIF_MARK_UNUSED_API + +/***************************************************************************** +* FUNCTION +* _btif_receive_data +* DESCRIPTION +* receive data from btif module in FIFO polling mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + +/*check parameter valid or not*/ + if ((p_buf == NULL) || (max_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } + i_ret = btif_rx_irq_handler(p_btif, p_buf, max_len); + + return i_ret; +} + +int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); + else + BTIF_SET_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + unsigned int value = 0; + +/*read BTIF_TRI_LVL*/ + value = BTIF_READ32(BTIF_TRI_LVL(base)); +/*clear Tx threshold bits*/ + value &= (~BTIF_TRI_LVL_TX_MASK); +/*set tx threshold bits*/ + value |= BTIF_TRI_LVL_TX(BTIF_TX_FIFO_THRE); +/*write back to BTIF_TRI_LVL*/ + btif_reg_sync_writel(value, BTIF_TRI_LVL(base)); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_rx_fifo_reset +* DESCRIPTION +* reset BTIF's rx fifo +* PARAMETERS +* p_base [IN] BTIF module's base address +* ec [IN] control if loopback mode is enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_rx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned long base = p_btif->base; + +/*set Rx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); + +/*clear Rx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_tx_fifo_reset +* DESCRIPTION +* reset BTIF's tx fifo +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + +/*set Tx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + +/*clear Tx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +#endif + +/***************************************************************************** +* FUNCTION +* hal_btif_loopback_ctrl +* DESCRIPTION +* BTIF Tx/Rx loopback mode set, this operation can only be done after set BTIF to normal mode +* PARAMETERS +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); + else + BTIF_SET_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_handler +* DESCRIPTION +* lower level interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success; negative means fail; positive means rx data length +*****************************************************************************/ +int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned int iir = 0; + unsigned int rx_len = 0; + unsigned long base = p_btif->base; + +#if 0 +/*check parameter valid or not*/ + if ((p_buf == NULL) || (max_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } +#endif + unsigned long irq_flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*read interrupt identifier register*/ + iir = BTIF_READ32(BTIF_IIR(base)); + +/*is rx interrupt exist?*/ +#if 0 + while ((iir & BTIF_IIR_RX) && (rx_len < max_len)) { + rx_len += + btif_rx_irq_handler(p_btif, (p_buf + rx_len), + (max_len - rx_len)); + +/*update IIR*/ + iir = BTIF_READ32(BTIF_IIR(base)); + } +#endif + + while (iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) { + rx_len += btif_rx_irq_handler(p_btif, p_buf, max_len); + +/*update IIR*/ + iir = BTIF_READ32(BTIF_IIR(base)); + } + +/*is tx interrupt exist?*/ + if (iir & BTIF_IIR_TX_EMPTY) + i_ret = btif_tx_irq_handler(p_btif); + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + + i_ret = rx_len != 0 ? rx_len : i_ret; + return i_ret; +} + +int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, btif_rx_buf_write rx_cb) +{ + if (p_btif_info->rx_cb != NULL) + BTIF_DBG_FUNC("rx_cb already registered, replace (0x%p) with (0x%p)\n", + p_btif_info->rx_cb, rx_cb); + p_btif_info->rx_cb = rx_cb; + + return 0; +} + +/***************************************************************************** +* FUNCTION +* btif_rx_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* positive means length of rx data , negative means fail +*****************************************************************************/ +static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = 0; + unsigned int iir = 0; + unsigned int rx_len = 0; + unsigned long base = p_btif_info->base; + unsigned char rx_buf[256]; + unsigned int local_buf_len = 256; + btif_rx_buf_write rx_cb = p_btif_info->rx_cb; + unsigned int total_len = 0; + +/*read interrupt identifier register*/ + iir = BTIF_READ32(BTIF_IIR(base)); + while ((iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) && + (rx_len < local_buf_len)) { + rx_buf[rx_len] = BTIF_READ8(base); + rx_len++; +/*need to consult CC Hwang for advice */ +/* + * whether we need to do memory barrier here + * Ans: no + */ +/* + * whether we need to d memory barrier when call BTIF_SET_BIT or BTIF_CLR_BIT + * Ans: no + */ + if (rx_len == local_buf_len) { + if (rx_cb) + (*rx_cb) (p_btif_info, rx_buf, rx_len); + rx_len = 0; + total_len += rx_len; + } + iir = BTIF_READ32(BTIF_IIR(base)); + } + total_len += rx_len; + if (rx_len && rx_cb) + (*rx_cb) (p_btif_info, rx_buf, rx_len); + +/* + * make sure all data write back to memory, mb or dsb? + * need to consult CC Hwang for advice + * Ans: no need here + */ + i_ret = total_len; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_tx_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + +#if NEW_TX_HANDLING_SUPPORT + int how_many = 0; + unsigned int lsr; + unsigned int ava_len = 0; + unsigned long base = p_btif->base; + char local_buf[BTIF_TX_FIFO_SIZE]; + char *p_data = local_buf; + unsigned long flag = 0; + + struct kfifo *p_tx_fifo = p_btif->p_tx_fifo; + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (lsr & BTIF_LSR_TEMT_BIT) + /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE; + else if (lsr & BTIF_LSR_THRE_BIT) + /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; + else { + /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ + ava_len = 0; + goto ret; + } + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); + how_many = kfifo_out(p_tx_fifo, local_buf, ava_len); + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, + kfifo_avail(p_tx_fifo)); + while (how_many--) + btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); +/*clear Tx enable flag if necessary*/ + if (kfifo_is_empty(p_tx_fifo)) { + hal_btif_tx_ier_ctrl(p_btif, false); + BTIF_DBG_FUNC("BTIF tx FIFO is empty\n"); + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); +ret: +#else +/*clear Tx enable flag*/ + hal_btif_tx_ier_ctrl(p_btif, false); +#endif + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_mode_ctrl +* DESCRIPTION +* set BTIF tx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (mode == BTIF_MODE_DMA) + /*set to DMA mode*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); + else + /*set to PIO mode*/ + BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_mode_ctrl +* DESCRIPTION +* set BTIF rx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (mode == BTIF_MODE_DMA) + /*set to DMA mode*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); + else + /*set to PIO mode*/ + BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_send_data +* DESCRIPTION +* send data through btif in FIFO mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* positive means number of data sent; 0 means no data put to FIFO; negative means error happens +*****************************************************************************/ +int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, + const unsigned char *p_buf, const unsigned int buf_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + + unsigned int ava_len = 0; + unsigned int sent_len = 0; + +#if !(NEW_TX_HANDLING_SUPPORT) + unsigned long base = p_btif->base; + unsigned int lsr = 0; + unsigned int left_len = 0; + unsigned char *p_data = (unsigned char *)p_buf; +#endif + +/*check parameter valid or not*/ + if ((p_buf == NULL) || (buf_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } +#if NEW_TX_HANDLING_SUPPORT + ava_len = _get_btif_tx_fifo_room(p_btif); + sent_len = buf_len <= ava_len ? buf_len : ava_len; + if (sent_len > 0) { + int enqueue_len = 0; + unsigned long flag = 0; + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); + enqueue_len = kfifo_in(p_btif->p_tx_fifo, + (unsigned char *)p_buf, sent_len); + if (sent_len != enqueue_len) { + BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n", + sent_len, enqueue_len); + } + i_ret = enqueue_len; + mb(); +/*enable BTIF Tx IRQ*/ + hal_btif_tx_ier_ctrl(p_btif, true); + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len); + } else { + i_ret = 0; + } +#else + while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) { + /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (lsr & BTIF_LSR_TEMT_BIT) + /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE; + else if (lsr & BTIF_LSR_THRE_BIT) + /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; + else { + /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ + ava_len = 0; + break; + } + + left_len = buf_len - sent_len; +/*ava_len will be real length will write to BTIF THR*/ + ava_len = ava_len > left_len ? left_len : ava_len; +/*update sent length valud after this operation*/ + sent_len += ava_len; +/* + * whether we need memory barrier here? + * Ans: No, no memory ordering issue exist, + * CPU will make sure logically right + */ + while (ava_len--) + btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); + + } +/* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */ + + i_ret = sent_len; + +/*enable BTIF Tx IRQ*/ + hal_btif_tx_ier_ctrl(p_btif, true); +#endif + return i_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_btif_raise_wak_sig +* DESCRIPTION +* raise wakeup signal to counterpart +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + unsigned long base = p_btif->base; +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + BTIF_ERR_FUNC("%s: clock is off before send wakeup signal!!!\n", + __FILE__); + return i_ret; + } +#endif +/*write 0 to BTIF_WAK to pull ap_wakeup_consyss low */ + BTIF_CLR_BIT(BTIF_WAK(base), BTIF_WAK_BIT); + +/*wait for a period for longer than 1/32k period, here we use 40us*/ + set_current_state(TASK_UNINTERRUPTIBLE); + usleep_range(128, 160); +/* + * according to linux/documentation/timers/timers-how-to, we choose usleep_range + * SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): * Use usleep_range + */ +/*write 1 to pull ap_wakeup_consyss high*/ + BTIF_SET_BIT(BTIF_WAK(base), BTIF_WAK_BIT); + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_base [IN] BTIF module's base address +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + int idx = 0; + /*unsigned long irq_flag = 0;*/ + unsigned long base = p_btif->base; + unsigned char reg_map[0xE0 / 4] = { 0 }; + unsigned int lsr = 0x0; + unsigned int dma_en = 0; + + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + lsr = BTIF_READ32(BTIF_LSR(base)); + dma_en = BTIF_READ32(BTIF_DMA_EN(base)); + /* + * here we omit 1st register which is THR/RBR register to avoid + * Rx data read by this debug information accidently + */ + for (idx = 1; idx < sizeof(reg_map); idx++) + reg_map[idx] = BTIF_READ8(p_btif->base + (4 * idx)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_INFO_FUNC("BTIF's clock is on\n"); + BTIF_INFO_FUNC("base address: 0x%lx\n", base); + switch (flag) { + case REG_BTIF_ALL: +#if 0 + BTIF_INFO_FUNC("BTIF_IER:0x%x\n", BTIF_READ32(BTIF_IER(base))); + BTIF_INFO_FUNC("BTIF_IIR:0x%x\n", BTIF_READ32(BTIF_IIR(base))); + BTIF_INFO_FUNC("BTIF_FAKELCR:0x%x\n", + BTIF_READ32(BTIF_FAKELCR(base))); + BTIF_INFO_FUNC("BTIF_LSR:0x%x\n", BTIF_READ32(BTIF_LSR(base))); + BTIF_INFO_FUNC("BTIF_SLEEP_EN:0x%x\n", + BTIF_READ32(BTIF_SLEEP_EN(base))); + BTIF_INFO_FUNC("BTIF_DMA_EN:0x%x\n", + BTIF_READ32(BTIF_DMA_EN(base))); + BTIF_INFO_FUNC("BTIF_RTOCNT:0x%x\n", + BTIF_READ32(BTIF_RTOCNT(base))); + BTIF_INFO_FUNC("BTIF_TRI_LVL:0x%x\n", + BTIF_READ32(BTIF_TRI_LVL(base))); + BTIF_INFO_FUNC("BTIF_WAT_TIME:0x%x\n", + BTIF_READ32(BTIF_WAT_TIME(base))); + BTIF_INFO_FUNC("BTIF_HANDSHAKE:0x%x\n", + BTIF_READ32(BTIF_HANDSHAKE(base))); +#endif + btif_dump_array("BTIF register", reg_map, sizeof(reg_map)); + break; + default: + break; + } + + BTIF_INFO_FUNC("Tx DMA %s\n", + (dma_en & BTIF_DMA_EN_TX) ? "enabled" : "disabled"); + BTIF_INFO_FUNC("Rx DMA %s\n", + (dma_en & BTIF_DMA_EN_RX) ? "enabled" : "disabled"); + + BTIF_INFO_FUNC("Rx data is %s\n", + (lsr & BTIF_LSR_DR_BIT) ? "not empty" : "empty"); + BTIF_INFO_FUNC("Tx data is %s\n", + (lsr & BTIF_LSR_TEMT_BIT) ? "empty" : "not empty"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + bool b_ret = false; + unsigned int lsr = 0; + unsigned long flags = 0; + unsigned long base = p_btif->base; + unsigned int tx_empty = 0; + unsigned int rx_dr = 0; + unsigned int tx_irq_disable = 0; + +/* + * 3 conditions allow clock to be disable + * 1. if TEMT is set or not + * 2. if DR is set or not + * 3. Tx IRQ is disabled or not + */ + lsr = BTIF_READ32(BTIF_LSR(base)); + tx_empty = lsr & BTIF_LSR_TEMT_BIT; + rx_dr = lsr & BTIF_LSR_DR_BIT; + tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN; + + b_ret = + (tx_empty && (tx_irq_disable == 0) && (rx_dr == 0)) ? true : false; + if (!b_ret) { + BTIF_DBG_FUNC + ("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", + tx_empty, rx_dr, tx_irq_disable); + } +#if NEW_TX_HANDLING_SUPPORT + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); +/*clear Tx enable flag if necessary*/ + if (!(kfifo_is_empty(p_btif->p_tx_fifo))) { + BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n"); + b_ret = false; + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); +#endif + return b_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_allow +* DESCRIPTION +* whether tx is allowed +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) +{ +#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) +#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) + +/*Chaozhong: To be implement*/ + bool b_ret = false; + +#if NEW_TX_HANDLING_SUPPORT + unsigned long flags = 0; + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); +/*clear Tx enable flag if necessary*/ + if (kfifo_is_full(p_btif->p_tx_fifo)) { + BTIF_WARN_FUNC("BTIF tx FIFO is full\n"); + b_ret = false; + } else { + b_ret = true; + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); +#else + unsigned int lsr = 0; + unsigned long base = p_btif->base; + unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB; /*only ava length */ + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT))) { + BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us); +/* usleep_range(wait_us, 3 * 10 * wait_us); */ + usleep_range(wait_us, 3 * wait_us); + } + lsr = BTIF_READ32(BTIF_LSR(base)); + b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; + if (!b_ret) + BTIF_DBG_FUNC(" tx is not allowed for the moment\n"); + else + BTIF_DBG_FUNC(" tx is allowed\n"); +#endif + return b_ret; +} + +#if !(NEW_TX_HANDLING_SUPPORT) + +static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + bool b_ret = false; + unsigned long base = p_btif->base; + unsigned int lsr = 0; + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; + return b_ret; +} +#endif + +int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid) +{ + int i_ret = -1; + + BTIF_DBG_FUNC("op id: %d\n", opid); + switch (opid) { + case BTIF_PM_DPIDLE_EN: + i_ret = 0; + break; + case BTIF_PM_DPIDLE_DIS: + i_ret = 0; + break; + case BTIF_PM_SUSPEND: + i_ret = 0; + break; + case BTIF_PM_RESUME: + i_ret = 0; + break; + case BTIF_PM_RESTORE_NOIRQ:{ + unsigned int flag = 0; + P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + else + flag = IRQF_TRIGGER_FALLING; /*make this as default type */ + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + default: + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + } +#endif +/* irq_set_irq_type(p_irq->irq_id, flag); */ + i_ret = 0; + } + break; + default: + i_ret = ERR_INVALID_PAR; + break; + } + + return i_ret; +} +void mtk_btif_read_cpu_sw_rst_debug_plat(void) +{ +#define CONSYS_AP2CONN_WAKEUP_OFFSET 0x00000064 + BTIF_WARN_FUNC("+CONSYS_AP2CONN_WAKEUP_OFFSET(0x%x)\n", + BTIF_READ32(mtk_btif.base + CONSYS_AP2CONN_WAKEUP_OFFSET)); +} + diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h new file mode 100644 index 0000000000000..5e2f5a9857d91 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BTIF_H_ +#define __MTK_BTIF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* gettimeofday */ +#include + +#include "btif_pub.h" +#include "btif_dma_pub.h" +#include "mtk_btif_exp.h" + +#define BTIF_PORT_NR 1 +#define BTIF_USER_NAME_MAX_LEN 32 + +/*-------------Register Defination Start ---------------*/ +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define BTIF_RX_BUFFER_SIZE (1024 * 32) +#else +#define BTIF_RX_BUFFER_SIZE (1024 * 64) +#endif +#define BTIF_TX_FIFO_SIZE (1024 * 4) + +/*------------Register Defination End ----------------*/ + +/*------------BTIF Module Clock and Power Control Defination---------------*/ +typedef enum _ENUM_BTIF_RX_TYPE_ { + BTIF_IRQ_CTX = 0, + BTIF_TASKLET_CTX = BTIF_IRQ_CTX + 1, + BTIF_THREAD_CTX = BTIF_TASKLET_CTX + 1, + BTIF_WQ_CTX = BTIF_THREAD_CTX + 1, + BTIF_RX_TYPE_MAX, +} ENUM_BTIF_RX_TYPE; + +typedef enum _ENUM_BTIF_TX_TYPE_ { + BTIF_TX_USER_CTX = 0, + BTIF_TX_SINGLE_CTX = BTIF_TX_USER_CTX + 1, + BTIF_TX_TYPE_MAX, +} ENUM_BTIF_TX_TYPE; + +typedef enum _ENUM_BTIF_STATE_ { + B_S_OFF = 0, + B_S_SUSPEND = B_S_OFF + 1, + B_S_DPIDLE = B_S_SUSPEND + 1, + B_S_ON = B_S_DPIDLE + 1, + B_S_MAX, +} ENUM_BTIF_STATE; + +#define ENABLE_BTIF_RX_DMA 1 +#define ENABLE_BTIF_TX_DMA 1 + +#if ENABLE_BTIF_TX_DMA +#define BTIF_TX_MODE BTIF_MODE_DMA +#else +#define BTIF_TX_MODE BTIF_MODE_PIO +#endif + +#if ENABLE_BTIF_RX_DMA +#define BTIF_RX_MODE BTIF_MODE_DMA +#else +#define BTIF_RX_MODE BTIF_MODE_PIO +#endif + +#define BTIF_RX_BTM_CTX BTIF_THREAD_CTX/*BTIF_WQ_CTX*//* BTIF_TASKLET_CTX */ +/* + * -- cannot be used because , + * mtk_wcn_stp_parser data will call *(stp_if_tx) to send ack, + * in which context sleepable lock or usleep operation may be used, + * these operation is not allowed in tasklet, may cause schedule_bug + */ + +#define BTIF_TX_CTX BTIF_TX_USER_CTX /* BTIF_TX_SINGLE_CTX */ + +#define ENABLE_BTIF_RX_THREAD_RT_SCHED 0 +#define MAX_BTIF_RXD_TIME_REC 3 + +/*Structure Defination*/ + +/*-----------------BTIF setting--------------*/ +typedef struct _mtk_btif_setting_ { + ENUM_BTIF_MODE tx_mode; /*BTIF Tx Mode Setting */ + ENUM_BTIF_MODE rx_mode; /*BTIF Tx Mode Setting */ + ENUM_BTIF_RX_TYPE rx_type; /*rx handle type */ + ENUM_BTIF_TX_TYPE tx_type; /*tx type */ +} mtk_btif_setting, *p_mtk_btif_setting; +/*---------------------------------------------------------------------------*/ + +#if 0 +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_register_ { + unsigned int iir; /*Interrupt Identification Register */ + unsigned int lsr; /*Line Status Register */ + unsigned int fake_lcr; /*Fake Lcr Regiseter */ + unsigned int fifo_ctrl; /*FIFO Control Register */ + unsigned int ier; /*Interrupt Enable Register */ + unsigned int sleep_en; /*Sleep Enable Register */ + unsigned int rto_counter; /*Rx Timeout Counter Register */ + unsigned int dma_en; /*DMA Enalbe Register */ + unsigned int tri_lvl; /*Tx/Rx Trigger Level Register */ + unsigned int wat_time; /*Async Wait Time Register */ + unsigned int handshake; /*New HandShake Mode Register */ + unsigned int sleep_wak; /*Sleep Wakeup Reigster */ +} mtk_btif_register, *p_mtk_btif_register; +/*---------------------------------------------------------------------------*/ + +#endif + +typedef struct _btif_buf_str_ { + unsigned int size; + unsigned char *p_buf; + /* + * For Tx: next Tx data pointer to FIFO; + * For Rx: next read data pointer from BTIF user + */ + unsigned int rd_idx; + /* + * For Tx: next Tx data pointer from BTIF user; + * For Rx: next write data(from FIFO) pointer + */ + unsigned int wr_idx; +} btif_buf_str, *p_btif_buf_str; + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_dma_ { + /*p_mtk_btif*/ void *p_btif; + /*BTIF pointer to which DMA belongs */ + +#if 0 + unsigned int channel; /*DMA's channel */ +#endif + + ENUM_BTIF_DIR dir; /*DMA's direction: */ + bool enable; /*DMA enable or disable flag */ + + P_MTK_DMA_INFO_STR p_dma_info; /*DMA's IRQ information */ + +#if 0 + mtk_dma_register register; /*DMA's register */ +#endif + + spinlock_t iolock; /*io lock for DMA channel */ + atomic_t entry; /* entry count */ +} mtk_btif_dma, *p_mtk_btif_dma; + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define BTIF_LOG_ENTRY_NUM 10 +#else +#define BTIF_LOG_ENTRY_NUM 30 +#endif + +#define BTIF_LOG_SZ 1536 + +typedef void (*MTK_BTIF_RX_NOTIFY) (void); + +typedef struct _btif_log_buf_t_ { + unsigned int len; + struct timeval timer; + unsigned char buffer[BTIF_LOG_SZ]; +} BTIF_LOG_BUF_T, *P_BTIF_LOG_BUF_T; + +typedef struct _btif_log_queue_t_ { + ENUM_BTIF_DIR dir; + bool enable; + bool output_flag; + unsigned int in; + unsigned int out; + unsigned int size; + spinlock_t lock; + P_BTIF_LOG_BUF_T p_queue[BTIF_LOG_ENTRY_NUM]; +} BTIF_LOG_QUEUE_T, *P_BTIF_LOG_QUEUE_T; + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_ { + unsigned int open_counter; /*open counter */ + bool enable; /*BTIF module enable flag */ + bool lpbk_flag; /*BTIF module enable flag */ +#if 0 + unsigned long base; /* BTIF controller base address */ +#endif + + ENUM_BTIF_STATE state; /*BTIF state mechanism */ + struct mutex state_mtx; /*lock to BTIF state mechanism's state change */ + struct mutex ops_mtx; /*lock to BTIF's open and close */ + +#if 0 + mtk_btif_register register; /*BTIF registers */ +#endif + + ENUM_BTIF_MODE tx_mode; /* BTIF Tx channel mode */ + ENUM_BTIF_MODE rx_mode; /* BTIF Rx channel mode */ + struct mutex tx_mtx; /*lock to BTIF's tx process */ +/*rx handling */ + ENUM_BTIF_RX_TYPE btm_type; /*BTIF Rx bottom half context */ +/*tx handling*/ + ENUM_BTIF_TX_TYPE tx_ctx; /*BTIF tx context */ +/* unsigned char rx_buf[BTIF_RX_BUFFER_SIZE]; */ + btif_buf_str btif_buf; + spinlock_t rx_irq_spinlock; /*lock for rx irq handling */ + +/*rx workqueue information*/ + /*lock to BTIF's rx bottom half when kernel thread is used */ + struct mutex rx_mtx; + struct workqueue_struct *p_rx_wq; + struct work_struct rx_work; + + struct workqueue_struct *p_tx_wq; + struct work_struct tx_work; + struct kfifo *p_tx_fifo; + +/*rx tasklet information*/ + struct tasklet_struct rx_tasklet; + /*lock to BTIF's rx bottom half when tasklet is used */ + spinlock_t rx_tasklet_spinlock; + +/*rx thread information*/ + struct task_struct *p_task; + struct completion rx_comp; + + mtk_btif_setting *setting; /*BTIF setting */ + + p_mtk_btif_dma p_tx_dma; /*BTIF Tx channel DMA */ + p_mtk_btif_dma p_rx_dma; /*BTIF Rx channel DMA */ + + MTK_WCN_BTIF_RX_CB rx_cb; /*Rx callback function */ + MTK_BTIF_RX_NOTIFY rx_notify; + + P_MTK_BTIF_INFO_STR p_btif_info; /*BTIF's information */ + +/*Log Tx data to buffer*/ + BTIF_LOG_QUEUE_T tx_log; + +/*Log Rx data to buffer*/ + BTIF_LOG_QUEUE_T rx_log; + +/* struct list_head *p_user_list; */ + struct list_head user_list; +/* get btif dev pointer*/ + void *private_data; +} mtk_btif, *p_mtk_btif; +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +#if 0 +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_dma_register_ { + unsigned int int_flag; /*Tx offset:0x0 Rx offset:0x0 */ + unsigned int int_enable; /*Tx offset:0x4 Rx offset:0x4 */ + unsigned int dma_enable; /*Tx offset:0x8 Rx offset:0x8 */ + unsigned int dma_reset; /*Tx offset:0xc Rx offset:0xc */ + unsigned int dma_stop; /*Tx offset:0x10 Rx offset:0x10 */ + unsigned int dma_flush; /*Tx offset:0x14 Rx offset:0x14 */ + unsigned int vff_addr; /*Tx offset:0x1c Rx offset:0x1c */ + unsigned int vff_len; /*Tx offset:0x24 Rx offset:0x24 */ + unsigned int vff_thr; /*Tx offset:0x28 Rx offset:0x28 */ + unsigned int vff_wpt; /*Tx offset:0x2c Rx offset:0x2c */ + unsigned int vff_rpt; /*Tx offset:0x30 Rx offset:0x30 */ + unsigned int rx_fc_thr; /*Tx:No this register Rx offset:0x34 */ + unsigned int int_buf_size; /*Tx offset:0x38 Rx offset:0x38 */ + unsigned int vff_valid_size; /*Tx offset:0x3c Rx offset:0x3c */ + unsigned int vff_left_size; /*Tx offset:0x40 Rx offset:0x40 */ + unsigned int debug_status; /*Tx offset:0x50 Rx offset:0x50 */ +} mtk_dma_register, *p_mtk_dma_register; +/*---------------------------------------------------------------------------*/ +#endif + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_user_ { + bool enable; /*register its state */ + struct list_head entry; /*btif_user's bi-direction list table */ + /*BTIF's user, static allocation */ + char u_name[BTIF_USER_NAME_MAX_LEN]; + unsigned long u_id; + p_mtk_btif p_btif; +} mtk_btif_user, *p_mtk_btif_user; + +/*---------------------------------------------------------------------------*/ +#define BBS_PTR(ptr, idx) ((ptr->p_buf) + idx) + +#define BBS_SIZE(ptr) ((ptr)->size) +#define BBS_MASK(ptr) (BBS_SIZE(ptr) - 1) +#define BBS_COUNT(ptr) ((ptr)->wr_idx >= (ptr)->rd_idx ? (ptr)->wr_idx - \ +(ptr)->rd_idx : BBS_SIZE(ptr) - \ +((ptr)->rd_idx - (ptr)->wr_idx)) +#define BBS_COUNT_CUR(ptr, wr_idx) (wr_idx >= (ptr)->rd_idx ? wr_idx - \ +(ptr)->rd_idx : BBS_SIZE(ptr) - \ +((ptr)->rd_idx - wr_idx)) + +#define BBS_LEFT(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) + +#define BBS_AVL_SIZE(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) +#define BBS_FULL(ptr) (BBS_COUNT(ptr) - BBS_SIZE(ptr)) +#define BBS_EMPTY(ptr) ((ptr)->wr_idx == (ptr)->rd_idx) +#define BBS_WRITE_MOVE_NEXT(ptr) ((ptr)->wr_idx = \ +((ptr)->wr_idx + 1) & BBS_MASK(ptr)) +#define BBS_READ_MOVE_NEXT(ptr) ((ptr)->rd_idx = \ +((ptr)->rd_idx + 1) & BBS_MASK(ptr)) + +#define BBS_INIT(ptr) \ +{ \ +(ptr)->rd_idx = (ptr)->wr_idx = 0; \ +(ptr)->size = BTIF_RX_BUFFER_SIZE; \ +} + + +#define BTIF_MUTEX_UNLOCK(x) mutex_unlock(x) + +extern mtk_btif g_btif[]; + +int btif_open(p_mtk_btif p_btif); +int btif_close(p_mtk_btif p_btif); +int btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); +int btif_enter_dpidle(p_mtk_btif p_btif); +int btif_exit_dpidle(p_mtk_btif p_btif); +int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb); + +/*for test purpose*/ +int _btif_suspend(p_mtk_btif p_btif); +int _btif_resume(p_mtk_btif p_btif); +int _btif_restore_noirq(p_mtk_btif p_btif); + +int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); +int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, + int len); +int btif_dump_data(char *p_buf, int len); +int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_init(p_mtk_btif p_btif); +int btif_dump_reg(p_mtk_btif p_btif); +int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify); +int btif_raise_wak_signal(p_mtk_btif p_btif); +int btif_clock_ctrl(p_mtk_btif p_btif, int en); +bool btif_parser_wmt_evt(p_mtk_btif p_btif, + const char *sub_str, + unsigned int sub_len); +void mtk_btif_read_cpu_sw_rst_debug(void); + +#endif /*__MTK_BTIF_H_*/ diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h new file mode 100644 index 0000000000000..3752644fe0aae --- /dev/null +++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_BTIF_EXP_H_ +#define _MTK_BTIF_EXP_H_ + +/*--------------marco defination---------------*/ +#define BTIF_MAX_LEN_PER_PKT 2048 +#define BTIF_RXD_BE_BLOCKED_DETECT 1 +/*--------------Enum Defination---------------*/ +typedef enum _ENUM_BTIF_DPIDLE_ { + BTIF_DPIDLE_DISABLE = 0, + BTIF_DPIDLE_ENABLE = BTIF_DPIDLE_DISABLE + 1, + BTIF_DPIDLE_MAX, +} ENUM_BTIF_DPIDLE_CTRL; + +typedef enum _ENUM_BTIF_LPBK_MODE_ { + BTIF_LPBK_DISABLE = 0, + BTIF_LPBK_ENABLE = BTIF_LPBK_DISABLE + 1, + BTIF_LPBK_MAX, +} ENUM_BTIF_LPBK_MODE; + +typedef enum _ENUM_BTIF_DBG_ID_ { + BTIF_DISABLE_LOGGER = 0, + BTIF_ENABLE_LOGGER = BTIF_DISABLE_LOGGER + 1, + BTIF_DUMP_LOG = BTIF_ENABLE_LOGGER + 1, + BTIF_CLR_LOG = BTIF_DUMP_LOG + 1, + BTIF_DUMP_BTIF_REG = BTIF_CLR_LOG + 1, + BTIF_ENABLE_RT_LOG = BTIF_DUMP_BTIF_REG + 1, + BTIF_DISABLE_RT_LOG = BTIF_ENABLE_RT_LOG + 1, + BTIF_DBG_MAX, +} ENUM_BTIF_DBG_ID; + +typedef enum _ENUM_BTIF_OP_ERROR_CODE_ { + E_BTIF_AGAIN = 0, + E_BTIF_FAIL = -1, + E_BTIF_BAD_POINTER = -2, + E_BTIF_NO_SPACE = -3, + E_BTIF_INTR = -4, + E_BTIF_INVAL_PARAM = -5, + E_BTIF_ALREADY_OPEN = -6, + E_BTIF_NOT_OPEN = -7, + E_BTIF_INVAL_STATE = -8, +} ENUM_BTIF_OP_ERROR_CODE; + +/*--------------End of Enum Defination---------------*/ + +/*--------------Type Definition---------------*/ + +typedef int (*MTK_WCN_BTIF_RX_CB) (const unsigned char *p_buf, + unsigned int len); + +/*--------------End of Type Definition---------------*/ + +/*--------------Normal Mode API declearation---------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_open +* DESCRIPTION +* open BTIF interface, will do BTIF module HW and SW initialization +* PARAMETERS +* p_owner [IN] pointer to owner who call this API, +* currently there are 2 owner ("stp" or "btif_tester") +* may use this module +* user's id string must be less than 32 bytes +* for "stp", BTIF will call rx callback function to route rx data to STP module +* for "stp_tester", BTIF will save rx data +* and wait for native process to access +* p_id [IN] BTIF's user id will be put to this address +* RETURNS +* int 0 = succeed; others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +* if open success, value p_id will be the only identifier for +* user to access BTIF's other operations +* including read/write/dpidle_ctrl/rx_cb_retister +* this user id is only an identifier used for owner identification +*****************************************************************************/ +int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id); +//EXPORT_SYMBOL(mtk_wcn_btif_open) +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_close +* DESCRIPTION +* close BTIF interface, will do BTIF module HW and SW de-initialization +* once this API is called, p_btif should never be used by BTIF's user again +* PARAMETERS +* u_id [IN] BTIF's user id +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_close(unsigned long u_id); +//EXPORT_SYMBOL(mtk_wcn_btif_close) +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_write +* DESCRIPTION +* send data throuth BTIF module +* there's no internal buffer to cache STP data in BTIF driver, +* if in DMA mode +* btif driver will check if there's enough space +* in vFIFO for data to send in DMA mode +* if yes, put data to vFIFO and return corresponding data length to caller +* if no, corresponding error code will be returned to called +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN] pointer to target data to send +* len [IN] data length (should be less than 2014 bytes per STP package) +* +* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller +* if btif driver detected that no space is available in Tx FIFO, +* will return E_BTIF_NO_SPACE, +* mostly something is wrong with BTIF or consys when this +* return value is returned +* RETURNS +* int positive: data length send through BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +* E_BTIF_AGAIN (0) will be returned to caller if btif does not have +* enough vFIFO to send data, when caller get 0, +* he should wait for a moment (5~10ms maybe) and +* try a few times (maybe 10~20) +* if still get E_BTIF_AGAIN, should call BTIF's debug API and +* dump BTIF driver and BTIF/DMA register information to kernel log +* for debug +* E_BTIF_BAD_POINTER will be returned to caller if btif is not +* opened successfully before call this API +* E_BTIF_INVAL_PARAM will be returned if parameter is not valid + +*****************************************************************************/ +int mtk_wcn_btif_write(unsigned long u_id, + const unsigned char *p_buf, unsigned int len); +//EXPORT_SYMBOL(mtk_wcn_btif_write) +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_read +* DESCRIPTION +* read data from BTIF module +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN/OUT] pointer to buffer where rx data will be put +* max_len [IN] max buffer length +* RETURNS +* int positive: data length read from BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_read(unsigned long u_id, + unsigned char *p_buf, unsigned int max_len); +//EXPORT_SYMBOL(mtk_wcn_btif_read) +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_dpidle_ctrl +* DESCRIPTION +* control if BTIF module allow system enter deepidle state or not +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL +* RETURNS +* int always return 0 +*****************************************************************************/ +int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_rx_cb_register +* DESCRIPTION +* register rx callback function to BTIF module by btif user +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* rx_cb [IN] pointer to stp rx handler callback function, +* should be comply with MTK_WCN_BTIF_RX_CB +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_wakeup_consys +* DESCRIPTION +* once sleep command is sent to con sys, +* should call this API before send wakeup command to +* make con sys aware host want to send data to consys +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_wakeup_consys(unsigned long u_id); + +/*--------------End of Normal Mode API declearation----------------*/ + +/*--------------Debug Purpose API declearation----------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_loopback_ctrl +* DESCRIPTION +* enable/disable BTIF internal loopback function, +* when this function is enabled, +* data send to btif will be received by btif itself +* only for debug purpose, should never use this function in normal mode +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* enable [IN] loopback mode control flag, enable or disable, +* shou be one of ENUM_BTIF_LPBK_MODE +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable); +//EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl) +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_logger_ctrl +* DESCRIPTION +* control BTIF logger function's behavior +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* flag [IN] should be one of ENUM_BTIF_DBG_ID +* BTIF_DISABLE_LOGGER - disable btif logger +* BTIF_ENABLE_LOGGER - enable btif logger +* BTIF_DUMP_LOG - dump log logged by btif +* BTIF_CLR_LOG - clear btif log buffer +* BTIF_DUMP_BTIF_REG - dump btif controller's register +* BTIF_DUMP_DMA_REG - dump DMA controller's register +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag); +//EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); +/*-----------End of Debug Purpose API declearation------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_parser_wmt_evt +* DESCRIPTION +* parser wmt sleep/wakeup evt in btif bbs buffer for debug +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* sub_str [IN] the str to be parsered +* str_len [IN] the length of sub_str +* RETURNS +* bool true = succeed; +* false = fail; +*****************************************************************************/ +bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, + const char *sub_str, unsigned int str_len); + +int mtk_btif_exp_open_test(void); +int mtk_btif_exp_close_test(void); +int mtk_btif_exp_write_test(void); +int mtk_btif_exp_suspend_test(void); +int mtk_btif_exp_resume_test(void); +int mtk_btif_exp_enter_dpidle_test(void); +int mtk_btif_exp_exit_dpidle_test(void); +int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int loop); +int mtk_btif_exp_log_debug_test(int flag); +int mtk_btif_exp_restore_noirq_test(void); +int btif_wakeup_consys_no_id(void); +int mtk_btif_exp_clock_ctrl(int en); +#if BTIF_RXD_BE_BLOCKED_DETECT +int mtk_btif_rxd_be_blocked_flag_get(void); +#endif +void mtk_btif_read_cpu_sw_rst_debug_exp(void); +#endif /*_MTK_BTIF_EXP_H_*/ diff --git a/drivers/misc/mediatek/btif/common/mtk_btif.c b/drivers/misc/mediatek/btif/common/mtk_btif.c new file mode 100644 index 0000000000000..5deb64ef3e56f --- /dev/null +++ b/drivers/misc/mediatek/btif/common/mtk_btif.c @@ -0,0 +1,3472 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*-----------linux system header files----------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/*#include */ +/*-----------driver own header files----------------*/ +#ifdef CONFIG_COMPAT +#include +#endif +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF" + +#define BTIF_CDEV_SUPPORT 1 + +#include "btif_pub.h" +#include "btif_dma_pub.h" +#include "mtk_btif_exp.h" +#include "mtk_btif.h" + +/*-----------static function declearation----------------*/ +static int mtk_btif_probe(struct platform_device *pdev); +static int mtk_btif_remove(struct platform_device *pdev); +static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state); +static int mtk_btif_resume(struct platform_device *pdev); +static int mtk_btif_drv_resume(struct device *dev); +static int mtk_btif_drv_suspend(struct device *pdev); + +static int mtk_btif_restore_noirq(struct device *device); +static int btif_file_open(struct inode *pinode, struct file *pfile); +static int btif_file_release(struct inode *pinode, struct file *pfile); +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops); +static unsigned int btif_poll(struct file *filp, poll_table *wait); +static int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, + mtk_btif_irq_handler irq_handler, void *data); +static int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data); +static int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en); +static int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en); +static irqreturn_t btif_irq_handler(int irq, void *data); +static unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + unsigned int buf_len); + +static irqreturn_t btif_tx_dma_irq_handler(int irq, void *data); +static irqreturn_t btif_rx_dma_irq_handler(int irq, void *data); + +static unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + unsigned int buf_len); +static int _btif_controller_tx_setup(p_mtk_btif p_btif); +static int _btif_controller_tx_free(p_mtk_btif p_btif); +static int _btif_controller_rx_setup(p_mtk_btif p_btif); +static int _btif_controller_rx_free(p_mtk_btif p_btif); +static int _btif_tx_pio_setup(p_mtk_btif p_btif); +static int _btif_rx_pio_setup(p_mtk_btif p_btif); +static int _btif_rx_dma_setup(p_mtk_btif p_btif); +static int _btif_rx_dma_free(p_mtk_btif p_btif); +static int _btif_tx_dma_setup(p_mtk_btif p_btif); +static int _btif_tx_dma_free(p_mtk_btif p_btif); +static int _btif_controller_setup(p_mtk_btif p_btif); +static int _btif_controller_free(p_mtk_btif p_btif); + +static int _btif_pio_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); +static int _btif_dma_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); + +static unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static unsigned int btif_bbs_read(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static unsigned int btif_bbs_write(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs); +static int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len); +static int _btif_rx_btm_deinit(p_mtk_btif p_btif); +static int _btif_rx_btm_sched(p_mtk_btif p_btif); +static int _btif_rx_btm_init(p_mtk_btif p_btif); +static void btif_rx_tasklet(unsigned long func_data); +static void btif_rx_worker(struct work_struct *p_work); +static int btif_rx_thread(void *p_data); +static int btif_rx_data_consummer(p_mtk_btif p_btif); + +static int _btif_tx_ctx_init(p_mtk_btif p_btif); +static int _btif_tx_ctx_deinit(p_mtk_btif p_btif); +static void btif_tx_worker(struct work_struct *p_work); + +static int _btif_state_deinit(p_mtk_btif p_btif); +static int _btif_state_release(p_mtk_btif p_btif); +static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif); +static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state); +static int _btif_state_hold(p_mtk_btif p_btif); +static int _btif_state_init(p_mtk_btif p_btif); + +static int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, + ENUM_BTIF_DPIDLE_CTRL en_flag); +static int _btif_enter_dpidle(p_mtk_btif p_btif); +static int _btif_exit_dpidle(p_mtk_btif p_btif); +static int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif); +static int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif); +static int _btif_enter_dpidle_from_on(p_mtk_btif p_btif); +static int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif); + +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma); +static int _btif_vfifo_init(p_mtk_btif_dma p_dma); +#endif + +static bool _btif_is_tx_complete(p_mtk_btif p_btif); +static int _btif_init(p_mtk_btif p_btif); +static int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); +static int btif_rx_dma_mode_set(int en); +static int btif_tx_dma_mode_set(int en); + +static int _btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); + +/*-----------end of static function declearation----------------*/ + +static const char *g_state[B_S_MAX] = { + "OFF", + "SUSPEND", + "DPIDLE", + "ON", +}; + +/*-----------BTIF setting--------------*/ +mtk_btif_setting g_btif_setting[BTIF_PORT_NR] = { + { + .tx_mode = BTIF_TX_MODE, + .rx_mode = BTIF_RX_MODE, + .rx_type = BTIF_RX_BTM_CTX, + .tx_type = BTIF_TX_CTX, + }, +}; + +mtk_btif g_btif[BTIF_PORT_NR] = { + { + .open_counter = 0, + .state = B_S_OFF, + .setting = &g_btif_setting[0], + .p_tx_dma = NULL, + .p_rx_dma = NULL, + .rx_cb = NULL, + .p_btif_info = NULL, + }, +}; + +mtk_btif_dma g_dma[BTIF_PORT_NR][BTIF_DIR_MAX] = { + { + { + .p_btif = NULL, + .dir = BTIF_TX, + .p_dma_info = NULL, + .entry = ATOMIC_INIT(0), + }, + { + .p_btif = NULL, + .dir = BTIF_RX, + .p_dma_info = NULL, + .entry = ATOMIC_INIT(0), + }, + }, +}; + +#define G_MAX_PKG_LEN (7 * 1024) +static int g_max_pkg_len = G_MAX_PKG_LEN; /*DMA vFIFO is set to 8 * 1024, we set this to 7/8 * vFIFO size*/ +static int g_max_pding_data_size = BTIF_RX_BUFFER_SIZE * 3 / 4; + + +static int mtk_btif_dbg_lvl = BTIF_LOG_ERR; + +#if BTIF_RXD_BE_BLOCKED_DETECT +static struct timeval btif_rxd_time_stamp[MAX_BTIF_RXD_TIME_REC]; +#endif +/*-----------Platform bus related structures----------------*/ +#define DRV_NAME "mtk_btif" + +#ifdef CONFIG_OF +const struct of_device_id apbtif_of_ids[] = { + { .compatible = "mediatek,btif", }, + {} +}; +#endif + +const struct dev_pm_ops mtk_btif_drv_pm_ops = { + .restore_noirq = mtk_btif_restore_noirq, + .suspend = mtk_btif_drv_suspend, + .resume = mtk_btif_drv_resume, +}; + +struct platform_driver mtk_btif_dev_drv = { + .probe = mtk_btif_probe, + .remove = mtk_btif_remove, +#ifdef CONFIG_PM + .suspend = mtk_btif_suspend, + .resume = mtk_btif_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &mtk_btif_drv_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = apbtif_of_ids, +#endif + } +}; + +#define BTIF_STATE_RELEASE(x) _btif_state_release(x) + +/*-----------End of Platform bus related structures----------------*/ + +/*-----------platform bus related operation APIs----------------*/ + +static int mtk_btif_probe(struct platform_device *pdev) +{ +/*Chaozhong: ToDo: to be implement*/ +/*register IRQ for BTIF and Tx Rx DMA and disable them by default*/ + BTIF_INFO_FUNC("DO BTIF PROBE\n"); + platform_set_drvdata(pdev, &g_btif[0]); + g_btif[0].private_data = (struct device *)&pdev->dev; + +#if !defined(CONFIG_MTK_CLKMGR) + hal_btif_clk_get_and_prepare(pdev); +#endif + + return 0; +} + +static int mtk_btif_remove(struct platform_device *pdev) +{ +/*Chaozhong: ToDo: to be implement*/ + BTIF_INFO_FUNC("DO BTIF REMOVE\n"); + platform_set_drvdata(pdev, NULL); + g_btif[0].private_data = NULL; + return 0; +} + +int _btif_suspend(p_mtk_btif p_btif) +{ + int i_ret; + + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif != NULL) { + if (!(p_btif->enable)) + i_ret = 0; + else { + if (_btif_state_get(p_btif) == B_S_ON) { + BTIF_ERR_FUNC("BTIF in ON state,", + "there are data need to be send or recev,suspend fail\n"); + i_ret = -1; + } else { + /* + * before disable BTIF controller and DMA controller + * we need to set BTIF to ON state + */ + i_ret = _btif_exit_dpidle(p_btif); + if (i_ret == 0) { + i_ret += _btif_controller_free(p_btif); + i_ret = _btif_controller_tx_free(p_btif); + i_ret += _btif_controller_rx_free(p_btif); + } + if (i_ret != 0) { + BTIF_INFO_FUNC("failed\n"); + /*Chaozhong: what if failed*/ + } else { + BTIF_INFO_FUNC("succeed\n"); + i_ret = _btif_state_set(p_btif, B_S_SUSPEND); + if (i_ret && _btif_init(p_btif)) { + /*Chaozhong:BTIF re-init failed? what to do*/ + i_ret = _btif_state_set(p_btif, B_S_OFF); + } + } + } + } + } else + i_ret = -1; + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + + +static int mtk_btif_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + pm_message_t state = PMSG_SUSPEND; + + return mtk_btif_suspend(pdev, state); +} + +static int mtk_btif_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return mtk_btif_resume(pdev); +} + +static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state) +{ + int i_ret = 0; + p_mtk_btif p_btif = NULL; + +/*Chaozhong: ToDo: to be implement*/ + BTIF_DBG_FUNC("++\n"); + p_btif = platform_get_drvdata(pdev); + i_ret = _btif_suspend(p_btif); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +int _btif_restore_noirq(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*BTIF IRQ restore no irq*/ + i_ret = hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF HW IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC("BTIF HW IRQ restore failed, i_ret:%d\n", i_ret); + return i_ret; + } +/*BTIF DMA restore no irq*/ + if (p_btif->tx_mode & BTIF_MODE_DMA) { + i_ret = hal_dma_pm_ops(p_btif->p_tx_dma->p_dma_info, + BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF Tx DMA IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC + ("BTIF Tx DMA IRQ restore failed, i_ret:%d\n", + i_ret); + return i_ret; + } + } + if (p_btif->rx_mode & BTIF_MODE_DMA) { + i_ret = hal_dma_pm_ops(p_btif->p_rx_dma->p_dma_info, + BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF Rx DMA IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC + ("BTIF Rx DMA IRQ restore failed, i_ret:%d\n", + i_ret); + return i_ret; + } + } + return i_ret; +} + +static int mtk_btif_restore_noirq(struct device *dev) +{ + int i_ret = 0; + struct platform_device *pdev = to_platform_device(dev); + p_mtk_btif p_btif = platform_get_drvdata(pdev); + + BTIF_INFO_FUNC("++\n"); + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif->enable) + BTIF_ERR_FUNC("!!!-----------------!BTIF is not closed before IPOH shutdown!!!---------------!\n"); + WARN_ON(p_btif->enable); + + i_ret = _btif_restore_noirq(p_btif); + BTIF_STATE_RELEASE(p_btif); + BTIF_INFO_FUNC("--\n"); + return 0; +} + +int _btif_resume(p_mtk_btif p_btif) +{ + int i_ret = 0; + ENUM_BTIF_STATE state = B_S_MAX; + + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif != NULL) { + state = _btif_state_get(p_btif); + if (!(p_btif->enable)) + i_ret = 0; + else if (state == B_S_SUSPEND) + i_ret = _btif_enter_dpidle(p_btif); + else + BTIF_INFO_FUNC + ("BTIF state: %s before resume, do nothing\n", g_state[state]); + } else + i_ret = -1; + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + +static int mtk_btif_resume(struct platform_device *pdev) +{ + int i_ret = 0; + p_mtk_btif p_btif = NULL; +/*Chaozhong: ToDo: to be implement*/ + BTIF_DBG_FUNC("++\n"); + p_btif = platform_get_drvdata(pdev); + i_ret = _btif_resume(p_btif); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return 0; +} + +/*-----------device node----------------*/ +#if BTIF_CDEV_SUPPORT + +dev_t btif_dev; +struct class *p_btif_class; +struct device *p_btif_dev; +const char *p_btif_dev_name = "btif"; +static struct semaphore wr_mtx; +static struct semaphore rd_mtx; +unsigned char wr_buf[2048]; +unsigned char rd_buf[2048]; +static int rx_notify_flag; +static DECLARE_WAIT_QUEUE_HEAD(btif_wq); +static int btif_file_open(struct inode *pinode, struct file *pfile); +static int btif_file_release(struct inode *pinode, struct file *pfile); +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops); + +static ssize_t btif_file_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos); +static long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); +#ifdef CONFIG_COMPAT +static long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static struct cdev btif_dev_c; +static wait_queue_head_t btif_read_inq; /* read queues */ + +const struct file_operations mtk_btif_fops = { + .owner = THIS_MODULE, + .open = btif_file_open, + .release = btif_file_release, + .read = btif_file_read, + .write = btif_file_write, + .unlocked_ioctl = btif_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = btif_compat_ioctl, +#endif + .poll = btif_poll, +}; + +static int btif_chrdev_init(void) +{ + int i_ret; + + int i_err; + + /* alloc device number dynamically */ + i_ret = alloc_chrdev_region(&btif_dev, 0, 1, p_btif_dev_name); + if (i_ret) { + BTIF_ERR_FUNC("devuce number allocation failed, i_ret:%d\n", + i_ret); + } else { + BTIF_INFO_FUNC("devuce number allocation succeed\n"); + } + cdev_init(&btif_dev_c, &mtk_btif_fops); + btif_dev_c.owner = THIS_MODULE; + i_err = cdev_add(&btif_dev_c, btif_dev, 1); + if (i_err) { + BTIF_ERR_FUNC("error add btif dev to kernel, error code:%d\n", + i_err); + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -1; + } + BTIF_INFO_FUNC("add btif dev to kernel succeed\n"); + + p_btif_class = class_create(THIS_MODULE, p_btif_dev_name); + if (IS_ERR(p_btif_class)) { + BTIF_ERR_FUNC("error happened when doing class_create\n"); + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -2; + } + BTIF_INFO_FUNC("create class for btif succeed\n"); + + p_btif_dev = device_create(p_btif_class, + NULL, btif_dev, 0, p_btif_dev_name); + if (IS_ERR(p_btif_dev)) { + BTIF_ERR_FUNC("error happened when doing device_create\n"); + class_destroy(p_btif_class); + p_btif_class = NULL; + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -3; + } + BTIF_INFO_FUNC("create device for btif succeed\n"); + + return 0; +} + +void btif_rx_notify_cb(void) +{ + BTIF_DBG_FUNC("++\n"); + rx_notify_flag = 1; + wake_up(&btif_wq); + wake_up_interruptible(&btif_read_inq); + BTIF_DBG_FUNC("--\n"); +} + +unsigned int btif_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; + unsigned int ava_len = 0; +/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ + unsigned int wr_idx = g_btif[0].btif_buf.wr_idx; + +/* BTIF_Rx_IRQ_Disable(); */ + ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); + BTIF_INFO_FUNC("++\n"); + if (ava_len == 0) { + poll_wait(filp, &btif_read_inq, wait); + wr_idx = g_btif[0].btif_buf.wr_idx; + ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); +/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ + if (ava_len) + mask |= POLLIN | POLLRDNORM; /* readable */ + } else { + mask |= POLLIN | POLLRDNORM; /* readable */ + } +/*make for writable*/ + mask |= POLLOUT | POLLWRNORM; /* writable */ + BTIF_INFO_FUNC("--, mask:%d\n", mask); + return mask; +} + +static int _btif_file_open(void) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_INFO_FUNC("++\n"); + +/*Chaozhong: ToDo: to be implement*/ + i_ret = btif_open(p_btif); + if ((i_ret != 0) && (i_ret != E_BTIF_ALREADY_OPEN)) { + BTIF_ERR_FUNC("btif_open failed, error code:%d\n", i_ret); + } else { + BTIF_INFO_FUNC("btif_open succeed\n"); + i_ret = 0; + } +/*semaphore for read and write operation init*/ + sema_init(&wr_mtx, 1); + sema_init(&rd_mtx, 1); + +/*buffer for read and write init*/ + memset(wr_buf, 0, sizeof(wr_buf)); + memset(rd_buf, 0, sizeof(rd_buf)); + init_waitqueue_head(&(btif_read_inq)); + btif_rx_notify_reg(p_btif, btif_rx_notify_cb); + BTIF_INFO_FUNC("--\n"); + return i_ret; +} + +static int _btif_file_close(void) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("++\n"); +/*Chaozhong: ToDo: to be implement*/ + i_ret = btif_close(&g_btif[0]); + if (i_ret != 0) + BTIF_ERR_FUNC("btif_close failed, error code:%d\n", i_ret); + else + BTIF_INFO_FUNC("btif_close succeed\n"); + + BTIF_INFO_FUNC("--\n"); + return i_ret; +} + +static int btif_file_open(struct inode *pinode, struct file *pfile) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("pid:%d\n", current->pid); + i_ret = 0; + return i_ret; +} + +static int btif_file_release(struct inode *pinode, struct file *pfile) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("pid:%d\n", current->pid); + i_ret = 0; + return i_ret; +} + +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops) +{ + int i_ret = 0; + int rd_len = 0; + + BTIF_INFO_FUNC("++\n"); + down(&rd_mtx); + rd_len = btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); + while (rd_len == 0) { + if (pfile->f_flags & O_NONBLOCK) + break; + + wait_event(btif_wq, rx_notify_flag != 0); + rx_notify_flag = 0; + rd_len = + btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, + sizeof(rd_buf)); + } + + if (rd_len == 0) + i_ret = 0; + else if ((rd_len > 0) && (copy_to_user(buf, rd_buf, rd_len) == 0)) + i_ret = rd_len; + else + i_ret = -EFAULT; + + up(&rd_mtx); + BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +ssize_t btif_file_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos) +{ + int i_ret = 0; + int copy_size = 0; + + copy_size = count > sizeof(wr_buf) ? sizeof(wr_buf) : count; + + BTIF_INFO_FUNC("++\n"); + down(&wr_mtx); + if (copy_from_user(&wr_buf[0], &buf[0], copy_size)) + i_ret = -EFAULT; + else + i_ret = btif_send_data(&g_btif[0], wr_buf, copy_size); + + up(&wr_mtx); + BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); + + return i_ret; +} +#ifdef CONFIG_COMPAT +long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + BTIF_INFO_FUNC("cmd[0x%x]\n", cmd); + ret = btif_unlocked_ioctl(filp, cmd, arg); + return ret; +} +#endif +long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ +#define BTIF_IOC_MAGIC 0xb0 +#define BTIF_IOCTL_OPEN _IOW(BTIF_IOC_MAGIC, 1, int) +#define BTIF_IOCTL_CLOSE _IOW(BTIF_IOC_MAGIC, 2, int) +#define BTIF_IOCTL_LPBK_CTRL _IOWR(BTIF_IOC_MAGIC, 3, int) +#define BTIF_IOCTL_LOG_FUNC_CTRL _IOWR(BTIF_IOC_MAGIC, 4, int) +#define BTIF_IOCTL_RT_LOG_CTRL _IOWR(BTIF_IOC_MAGIC, 5, int) +#define BTIF_IOCTL_LOG_DUMP _IOWR(BTIF_IOC_MAGIC, 6, int) +#define BTIF_IOCTL_REG_DUMP _IOWR(BTIF_IOC_MAGIC, 7, int) +#define BTIF_IOCTL_DMA_CTRL _IOWR(BTIF_IOC_MAGIC, 8, int) + + long ret = 0; +/* unsigned char p_buf[NAME_MAX + 1]; */ + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_INFO_FUNC("++\n"); + BTIF_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); + + switch (cmd) { + case BTIF_IOCTL_OPEN: + ret = _btif_file_open(); + break; + case BTIF_IOCTL_CLOSE: + ret = _btif_file_close(); + break; + case BTIF_IOCTL_LPBK_CTRL: + ret = btif_lpbk_ctrl(p_btif, arg == 0 ? 0 : 1); + break; + case BTIF_IOCTL_LOG_FUNC_CTRL: + if (arg == 0) { + ret += btif_log_buf_disable(&p_btif->tx_log); + ret += btif_log_buf_disable(&p_btif->rx_log); + } else { + ret += btif_log_buf_enable(&p_btif->tx_log); + ret += btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_IOCTL_RT_LOG_CTRL: + if (arg == 0) { + ret += btif_log_output_disable(&p_btif->tx_log); + ret += btif_log_output_disable(&p_btif->rx_log); + } else { + ret += btif_log_output_enable(&p_btif->tx_log); + ret += btif_log_output_enable(&p_btif->rx_log); + } + break; + case BTIF_IOCTL_LOG_DUMP: + + ret += btif_log_buf_dmp_out(&p_btif->tx_log); + ret += btif_log_buf_dmp_out(&p_btif->rx_log); + break; + case BTIF_IOCTL_REG_DUMP: + ret += btif_dump_reg(p_btif); + break; + case BTIF_IOCTL_DMA_CTRL: + if (arg == 0) { + ret += btif_tx_dma_mode_set(0); + ret += btif_rx_dma_mode_set(0); + } else { + ret += btif_tx_dma_mode_set(1); + ret += btif_rx_dma_mode_set(1); + } + break; + default: + BTIF_INFO_FUNC("unknown cmd(%d)\n", cmd); + ret = -2; + break; + } + BTIF_INFO_FUNC("--\n"); + return ret; +} + +#endif + +/*-----------device property----------------*/ +//static ssize_t driver_flag_read(struct device_driver *drv, char *buf) +static ssize_t flag_show(struct device_driver *drv, char *buf) +{ + return sprintf(buf, "btif driver debug level:%d\n", mtk_btif_dbg_lvl); +} + +//static ssize_t driver_flag_set(struct device_driver *drv, +static ssize_t flag_store(struct device_driver *drv, + const char *buffer, size_t count) +{ + char buf[256]; + char *p_buf; + unsigned long len = count; + long x = 0; + long y = 0; + long z = 0; + int result = 0; + char *p_token = NULL; + char *p_delimiter = " \t"; + + BTIF_INFO_FUNC("buffer = %s, count = %zd\n", buffer, count); + if (len >= sizeof(buf)) { + BTIF_ERR_FUNC("input handling fail!\n"); + len = sizeof(buf) - 1; + return -1; + } + + memcpy(buf, buffer, sizeof(buf)); + p_buf = buf; + + p_token = strsep(&p_buf, p_delimiter); + if (p_token != NULL) { + result = kstrtol(p_token, 16, &x); + BTIF_INFO_FUNC("x = 0x%08x\n\r", x); + } else + x = 0; +/* x = (NULL != p_token) ? kstrtol(p_token, 16, NULL) : 0;*/ + + p_token = strsep(&p_buf, "\t\n "); + if (p_token != NULL) { + result = kstrtol(p_token, 16, &y); + BTIF_INFO_FUNC("y = 0x%08x\n\r", y); + } else + y = 0; + + p_token = strsep(&p_buf, "\t\n "); + if (p_token != NULL) + result = kstrtol(p_token, 16, &z); + else + z = 0; + + BTIF_INFO_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); + + switch (x) { + case 1: + mtk_btif_exp_open_test(); + break; + case 2: + mtk_btif_exp_close_test(); + break; + case 3: + mtk_btif_exp_write_test(); + break; + case 4: + mtk_btif_exp_enter_dpidle_test(); + break; + case 5: + mtk_btif_exp_exit_dpidle_test(); + break; + case 6: + mtk_btif_exp_suspend_test(); + break; + case 7: + mtk_btif_exp_resume_test(); + break; + case 8: + if (y > BTIF_LOG_LOUD) + mtk_btif_dbg_lvl = BTIF_LOG_LOUD; + else if (y < BTIF_LOG_ERR) + mtk_btif_dbg_lvl = BTIF_LOG_WARN; + else + mtk_btif_dbg_lvl = y; + BTIF_ERR_FUNC("mtk_btif_dbg_lvl set to %d\n", mtk_btif_dbg_lvl); + break; + case 9: + mtk_btif_exp_open_test(); + mtk_btif_exp_write_test(); + mtk_btif_exp_close_test(); + break; + case 0xa: + mtk_btif_exp_log_debug_test(y); + break; + case 0xb: + btif_tx_dma_mode_set(1); + btif_rx_dma_mode_set(1); + break; + case 0xc: + btif_tx_dma_mode_set(0); + btif_rx_dma_mode_set(0); + break; + case 0xd: + mtk_btif_exp_restore_noirq_test(); + break; + case 0xe: + btif_wakeup_consys_no_id(); + break; + case 0xf: + mtk_btif_exp_clock_ctrl(y); + break; + case 0x10: + y = y > G_MAX_PKG_LEN ? G_MAX_PKG_LEN : y; + y = y < 1024 ? 1024 : y; + BTIF_INFO_FUNC("g_max_pkg_len is set to %d\n", y); + g_max_pkg_len = y; + break; + case 0x11: + y = y > BTIF_RX_BUFFER_SIZE ? BTIF_RX_BUFFER_SIZE : y; + y = y < 1024 ? 1024 : y; + BTIF_INFO_FUNC("g_max_pding_data_size is set to %d\n", y); + g_max_pding_data_size = y; + break; + default: + mtk_btif_exp_open_test(); + mtk_btif_exp_write_stress_test(3030, 1); + mtk_btif_exp_close_test(); + BTIF_WARN_FUNC("not supported.\n"); + break; + } + + return count; +} + +//FWU: driver_ATTR dropped in 4.14 +//static DRIVER_ATTR(flag, S_IRUGO | S_IWUSR, driver_flag_read, driver_flag_set); +static DRIVER_ATTR_RW(flag); + +/*-----------End of platform bus related operation APIs------------*/ + +/*-----------------------platform driver ----------------*/ + +int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, + mtk_btif_irq_handler irq_handler, void *data) +{ + int i_ret = -1; + unsigned int irq_id; + unsigned int flag; + + if ((p_irq == NULL) || (irq_handler == NULL)) + return E_BTIF_INVAL_PARAM; + + if (!(p_irq->is_irq_sup)) { + BTIF_WARN_FUNC("%s is not supported\n", p_irq->name); + return 0; + } + + irq_id = p_irq->irq_id; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + else + /*make this as default type */ + flag = IRQF_TRIGGER_FALLING; + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + /*make this as default type */ + flag = IRQF_TRIGGER_LOW; + break; + default: + /*make this as default type */ + flag = IRQF_TRIGGER_LOW; + break; + } +#endif + + p_irq->p_irq_handler = irq_handler; + i_ret = request_irq(irq_id, + (irq_handler_t) irq_handler, + flag, p_irq->name, data); + if (i_ret) + return i_ret; + + p_irq->reg_flag = true; + return 0; +} + +int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data) +{ + int i_ret = 0; + unsigned int eint_num = p_irq->irq_id; + + if ((p_irq->is_irq_sup) && (p_irq->reg_flag)) { + _btif_irq_ctrl(p_irq, false); + free_irq(eint_num, data); + p_irq->reg_flag = false; + } +/*do nothing for this operation*/ + return i_ret; +} + +int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en) +{ + unsigned int eint_num = p_irq->irq_id; + + if (en) + enable_irq(eint_num); + else + disable_irq_nosync(eint_num); + + return 0; +} + +int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en) +{ + unsigned int eint_num = p_irq->irq_id; + + if (en) + enable_irq(eint_num); + else + disable_irq(eint_num); + + return 0; +} + + +irqreturn_t btif_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ +/*Chaozhong: do we need lock here?*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + + _btif_irq_ctrl(p_btif->p_btif_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); +#endif + + hal_btif_irq_handler(p_btif->p_btif_info, NULL, 0); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +#endif + + _btif_irq_ctrl(p_btif->p_btif_info->p_irq, true); + _btif_rx_btm_sched(p_btif); + + BTIF_DBG_FUNC("--\n"); + return IRQ_HANDLED; +} + +irqreturn_t btif_tx_dma_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + p_mtk_btif_dma p_tx_dma = p_btif->p_tx_dma; + P_MTK_DMA_INFO_STR p_dma_info = p_tx_dma->p_dma_info; + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + _btif_irq_ctrl(p_dma_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); +#endif + + hal_tx_dma_irq_handler(p_dma_info); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +#endif + _btif_irq_ctrl(p_dma_info->p_irq, true); + BTIF_DBG_FUNC("--\n"); + return IRQ_HANDLED; +} + +irqreturn_t btif_rx_dma_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + p_mtk_btif_dma p_rx_dma = p_btif->p_rx_dma; + P_MTK_DMA_INFO_STR p_rx_dma_info = p_rx_dma->p_dma_info; + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + + _btif_irq_ctrl(p_rx_dma_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); + hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_ENABLE); +#endif + + hal_rx_dma_irq_handler(p_rx_dma_info, NULL, 0); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_DISABLE); + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +#endif + + _btif_irq_ctrl(p_rx_dma_info->p_irq, true); + + _btif_rx_btm_sched(p_btif); + + BTIF_DBG_FUNC("--\n"); + + return IRQ_HANDLED; +} + +unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + unsigned int buf_len) +{ + unsigned int index = 0; + p_mtk_btif p_btif = &(g_btif[index]); + +#if 0 + _btif_dump_memory("", p_buf, buf_len); +#endif + + btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); +/*save DMA Rx packet here*/ + if (buf_len > 0) + btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); + + return 0; +} + +unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + unsigned int buf_len) +{ + unsigned int index = 0; + p_mtk_btif p_btif = &(g_btif[index]); + +#if 0 + _btif_dump_memory("", p_buf, buf_len); +#endif + btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); + +/*save PIO Rx packet here*/ + if (buf_len > 0) + btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); + + return 0; +} + +bool btif_parser_wmt_evt(p_mtk_btif p_btif, + const char *sub_str, + unsigned int str_len) +{ + unsigned int data_cnt = 0; + unsigned int copy_cnt = 0; + char *local_buf = NULL; + bool b_ret = false; + p_btif_buf_str p_bbs = &(p_btif->btif_buf); + unsigned int wr_idx = p_bbs->wr_idx; + unsigned int rd_idx = p_bbs->rd_idx; + + data_cnt = copy_cnt = BBS_COUNT(p_bbs); + + if (data_cnt < str_len) { + BTIF_WARN_FUNC("there is not enough data for parser,need(%d),have(%d)\n", str_len, data_cnt); + return false; + } + BTIF_INFO_FUNC("data count in bbs buffer:%d,wr_idx(%d),rd_idx(%d)\n", data_cnt, wr_idx, rd_idx); + local_buf = vmalloc((data_cnt + 3) & ~0x3UL); + if (!local_buf) { + BTIF_WARN_FUNC("vmalloc memory fail\n"); + return false; + } + + if (wr_idx >= rd_idx) { + memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), copy_cnt); + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - rd_idx; + + BTIF_INFO_FUNC("tail_Len(%d)\n", tail_len); + memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), tail_len); + memcpy(local_buf + tail_len, BBS_PTR(p_bbs, 0), copy_cnt - tail_len); + } + + do { + int i = 0; + int j = 0; + int k = 0; + int d = 0; + + BTIF_INFO_FUNC("sub_str_len:%d\n", str_len); + for (i = 0; i < copy_cnt; i++) { + BTIF_DBG_FUNC("i:%d\n", i); + k = i; + while (1) { + if ((j >= str_len) || (k >= copy_cnt) || (sub_str[j++] != local_buf[k++])) + break; + } + + if (j == str_len) { + for (d = i; d < (str_len + i); d++) + BTIF_INFO_FUNC("0x%2x", local_buf[d]); + BTIF_INFO_FUNC("find sub str index:%d\n", i); + b_ret = true; + break; + } + if (j < str_len) + j = 0; + } + + } while (0); + + vfree(local_buf); + return b_ret; +} +int _btif_controller_tx_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->tx_mode == BTIF_MODE_DMA) { + i_ret = _btif_tx_dma_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_setup failed,i_ret(%d),", + "set tx to PIO mode\n", i_ret); + i_ret = _btif_tx_pio_setup(p_btif); + } + } else +/*enable Tx PIO mode*/ + i_ret = _btif_tx_pio_setup(p_btif); + + return i_ret; +} + +int _btif_controller_tx_free(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->tx_mode == BTIF_MODE_DMA) { + i_ret = _btif_tx_dma_free(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_free failed, i_ret(%d)\n", + i_ret); + } + } else { +/*do nothing for Tx PIO mode*/ + } + return i_ret; +} + +int _btif_controller_rx_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->rx_mode == BTIF_MODE_DMA) { + i_ret = _btif_rx_dma_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_setup failed, i_ret(%d),", + "set tx to PIO mode\n", i_ret); + i_ret = _btif_rx_pio_setup(p_btif); + } + } else { +/*enable Tx PIO mode*/ + i_ret = _btif_rx_pio_setup(p_btif); + } + return i_ret; +} + +int _btif_controller_rx_free(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->rx_mode == BTIF_MODE_DMA) { + i_ret = _btif_rx_dma_free(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_rx_dma_free failed, i_ret(%d)\n", + i_ret); + } + } else { +/*do nothing for Rx PIO mode*/ + } + return i_ret; +} + +int _btif_tx_pio_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + +/*set Tx to PIO mode*/ + p_btif->tx_mode = BTIF_MODE_PIO; +/*enable Tx PIO mode*/ + i_ret = hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); + return i_ret; +} + +int _btif_rx_pio_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; + + p_btif->rx_mode = BTIF_MODE_PIO; +/*Enable Rx IRQ*/ + _btif_irq_ctrl(p_btif_irq, true); +/*enable Rx PIO mode*/ + i_ret = hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); + return i_ret; +} + +int _btif_rx_dma_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = NULL; + P_MTK_BTIF_IRQ_STR p_btif_irq = NULL; + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; + + p_btif_info = p_btif->p_btif_info; + p_btif_irq = p_dma_info->p_irq; + +/*vFIFO reset*/ + hal_btif_vfifo_reset(p_dma_info); + + i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d),", + "set rx to pio mode\n", i_ret); +/*DMA control failed set Rx to PIO mode*/ + return _btif_rx_pio_setup(p_btif); + } +/*hardware init*/ + hal_btif_dma_hw_init(p_dma_info); + + hal_btif_dma_rx_cb_reg(p_dma_info, + (dma_rx_buf_write) btif_dma_rx_data_receiver); + +/*DMA controller enable*/ + i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", + "set rx to pio mode\n", i_ret); + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +/*DMA control failed set Rx to PIO mode*/ + i_ret = _btif_rx_pio_setup(p_btif); + } else { +/*enable Rx DMA mode*/ + hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); + +/*DMA Rx IRQ register*/ + _btif_irq_reg(p_btif_irq, btif_rx_dma_irq_handler, p_btif); +#if 0 +/*Enable DMA Rx IRQ*/ + _btif_irq_ctrl(p_btif_irq, true); +#endif + BTIF_DBG_FUNC("succeed\n"); + } + return i_ret; +} + +int _btif_rx_dma_free(p_mtk_btif p_btif) +{ + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_rx_dma->p_dma_info->p_irq; + + hal_btif_dma_rx_cb_reg(p_dma_info, (dma_rx_buf_write) NULL); + _btif_irq_free(p_irq, p_btif); +/*disable BTIF Rx DMA channel*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); +/*disable clock output*/ + return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +} + +int _btif_tx_dma_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_dma_info->p_irq; + +/*vFIFO reset*/ + hal_btif_vfifo_reset(p_dma_info); + + i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d)\n", + i_ret); + return i_ret; + } +/*DMA controller setup*/ + hal_btif_dma_hw_init(p_dma_info); + +/*DMA HW Enable*/ + i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", + "set tx to pio mode\n", i_ret); + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +#endif + + _btif_tx_pio_setup(p_btif); + } else { + hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); +/*DMA Tx IRQ register*/ + _btif_irq_reg(p_btif_irq, btif_tx_dma_irq_handler, p_btif); +#if 0 +/*disable DMA Tx IRQ*/ + _btif_irq_ctrl(p_btif_irq, false); +#endif + + BTIF_DBG_FUNC("succeed\n"); + } + return i_ret; +} + +int _btif_tx_dma_free(p_mtk_btif p_btif) +{ + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_tx_dma->p_dma_info->p_irq; + + _btif_irq_free(p_irq, p_btif); +/*disable BTIF Tx DMA channel*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); +/*disable clock output*/ + return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +} + +int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) +{ + int i_ret = -1; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +#if 0 + state = _btif_state_get(p_btif); + if (p_btif->enable && B_S_ON == state) + i_ret = _btif_lpbk_ctrl(p_btif, flag); + else + i_ret = E_BTIF_INVAL_STATE; +#endif + i_ret = _btif_exit_dpidle(p_btif); + if (i_ret == 0) + i_ret = _btif_lpbk_ctrl(p_btif, flag); + else + i_ret = E_BTIF_INVAL_STATE; + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) +{ + int i_ret = -1; + + if (flag) { + i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, true); + BTIF_DBG_FUNC("loopback function enabled\n"); + } else { + i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, false); + BTIF_DBG_FUNC("loopback function disabled\n"); + } + if (i_ret == 0) + p_btif->lpbk_flag = flag; + + return i_ret; +} + +int btif_clock_ctrl(p_mtk_btif p_btif, int en) +{ + int i_ret = 0; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + ENUM_CLOCK_CTRL ctrl_flag = en == 0 ? CLK_OUT_DISABLE : CLK_OUT_ENABLE; + + i_ret = hal_btif_clk_ctrl(p_btif_info, ctrl_flag); + + if (p_btif->rx_mode == BTIF_MODE_DMA) + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ctrl_flag); + + if (p_btif->tx_mode == BTIF_MODE_DMA) + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ctrl_flag); + + return i_ret; +} + +int _btif_controller_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; + +/*BTIF rx buffer init*/ +/* memset(p_btif->rx_buf, 0, BTIF_RX_BUFFER_SIZE); */ + BBS_INIT(&(p_btif->btif_buf)); +/************************************************/ + hal_btif_rx_cb_reg(p_btif_info, + (btif_rx_buf_write) btif_pio_rx_data_receiver); + + i_ret = hal_btif_clk_ctrl(p_btif_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_clk_ctrl failed, i_ret(%d)\n", i_ret); + return i_ret; + } +/*BTIF controller init*/ + i_ret = hal_btif_hw_init(p_btif_info); + if (i_ret) { + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); + BTIF_ERR_FUNC("hal_btif_hw_init failed, i_ret(%d)\n", i_ret); + return i_ret; + } + _btif_lpbk_ctrl(p_btif, p_btif->lpbk_flag); +/*BTIF IRQ register*/ + i_ret = _btif_irq_reg(p_btif_irq, btif_irq_handler, p_btif); + if (i_ret) { + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); + + BTIF_ERR_FUNC("_btif_irq_reg failed, i_ret(%d)\n", i_ret); + return i_ret; + } + +/*disable IRQ*/ + _btif_irq_ctrl(p_btif_irq, false); + i_ret = 0; + BTIF_DBG_FUNC("succeed\n"); + return i_ret; +} + +int _btif_controller_free(p_mtk_btif p_btif) +{ +/*No need to set BTIF to PIO mode, only enable BTIF CG*/ + hal_btif_rx_cb_reg(p_btif->p_btif_info, (btif_rx_buf_write) NULL); + _btif_irq_free(p_btif->p_btif_info->p_irq, p_btif); + return hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +} + +int _btif_init(p_mtk_btif p_btif) +{ + int i_ret = 0; + + i_ret = _btif_controller_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_init failed, i_ret(%d)\n", + i_ret); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + + i_ret = _btif_controller_tx_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", + i_ret); + _btif_controller_free(p_btif); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + + i_ret = _btif_controller_rx_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", + i_ret); + _btif_controller_tx_free(p_btif); + _btif_controller_free(p_btif); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + return i_ret; +} + +int btif_open(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->enable) + return E_BTIF_ALREADY_OPEN; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +/*disable deepidle*/ + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); + + i_ret = _btif_init(p_btif); + if (i_ret == 0) { + /*set BTIF's enable flag*/ + p_btif->enable = true; + _btif_state_set(p_btif, B_S_ON); + } else { + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + } + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + + BTIF_STATE_RELEASE(p_btif); + + BTIF_DBG_FUNC("BTIF's Tx Mode:%d, Rx Mode(%d)\n", + p_btif->tx_mode, p_btif->rx_mode); + return i_ret; +} + +int btif_close(p_mtk_btif p_btif) +{ + int i_ret = 0; + + if (!(p_btif->enable)) + return E_BTIF_NOT_OPEN; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +/*always set state back to B_S_ON before do close operation*/ + _btif_exit_dpidle(p_btif); +/*set BTIF's state to disable state*/ + p_btif->enable = false; + + _btif_controller_free(p_btif); + _btif_controller_tx_free(p_btif); + _btif_controller_rx_free(p_btif); + +/*reset BTIF's rx_cb function*/ + p_btif->rx_cb = NULL; + p_btif->rx_notify = NULL; + p_btif->lpbk_flag = false; + +/*set state mechine to B_S_OFF*/ + _btif_state_set(p_btif, B_S_OFF); + + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + +int _btif_exit_dpidle(p_mtk_btif p_btif) +{ + int i_ret = -1; + ENUM_BTIF_STATE state = B_S_MAX; + + state = _btif_state_get(p_btif); + switch (state) { + case B_S_DPIDLE: + i_ret = _btif_exit_dpidle_from_dpidle(p_btif); + break; + case B_S_SUSPEND: +/*in suspend state, need to do reinit of btif*/ + i_ret = _btif_exit_dpidle_from_sus(p_btif); + break; + case B_S_OFF: + i_ret = _btif_init(p_btif); + break; + case B_S_ON: + i_ret = 0; /* for btif_close case */ + break; + default: + i_ret = E_BTIF_INVAL_PARAM; + BTIF_INFO_FUNC("invalid state change:%d->\n", state, B_S_ON); + break; + } + + if (i_ret == 0) + i_ret = _btif_state_set(p_btif, B_S_ON); + return i_ret; +} + +int btif_exit_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + i_ret = _btif_exit_dpidle(p_btif); + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_enter_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + ENUM_BTIF_STATE state = B_S_MAX; + + state = _btif_state_get(p_btif); + if (state == B_S_ON) { + i_ret = _btif_enter_dpidle_from_on(p_btif); + } else if (state == B_S_SUSPEND) { + /*do reinit and enter deepidle*/ + i_ret = _btif_enter_dpidle_from_sus(p_btif); + } else if (state == B_S_DPIDLE) { + /*do nothing*/ + i_ret = 0; + } else { + BTIF_WARN_FUNC("operation is not allowed, current state:%d\n", + state); + i_ret = E_BTIF_INVAL_STATE; + } +/*anyway, set to B_S_DPIDLE state*/ + if (i_ret == 0) + i_ret = _btif_state_set(p_btif, B_S_DPIDLE); + return i_ret; +} + +int btif_enter_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + i_ret = _btif_enter_dpidle(p_btif); + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*in dpidle state, only need to open related clock*/ + if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*enable BTIF Tx DMA's clock*/ + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, + CLK_OUT_ENABLE); + } + if (p_btif->rx_mode == BTIF_MODE_DMA) { + /*enable BTIF Rx DMA's clock*/ + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, + CLK_OUT_ENABLE); + } +/*enable BTIF's clock*/ + i_ret += hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); + + if (i_ret != 0) + BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); + return i_ret; +} + +int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif) +{ +/*in suspend state, need to do driver re-init*/ + + int i_ret = _btif_init(p_btif); + + return i_ret; +} + +int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif) +{ +/*do driiver reinit*/ + int i_ret = _btif_init(p_btif); + + if (i_ret == 0) + i_ret = _btif_enter_dpidle_from_on(p_btif); + return i_ret; +} + +int _btif_enter_dpidle_from_on(p_mtk_btif p_btif) +{ +#define MAX_WAIT_TIME_MS 5000 +/* + * this max wait time cannot exceed 12s, + * because dpm will monitor each device's + * resume/suspend process by start up a watch dog timer of 12s + * incase of one driver's suspend/resume process block other device's suspend/resume + */ + int i_ret = 0; + unsigned int retry = 0; + unsigned int wait_period = 1; + unsigned int max_retry = MAX_WAIT_TIME_MS / wait_period; + struct timeval timer_start; + struct timeval timer_now; + + do_gettimeofday(&timer_start); + + while ((!_btif_is_tx_complete(p_btif)) && (retry < max_retry)) { + do_gettimeofday(&timer_now); + if ((MAX_WAIT_TIME_MS/1000) <= (timer_now.tv_sec - timer_start.tv_sec)) { + BTIF_WARN_FUNC("max retry timer expired, timer_start.tv_sec:%d, timer_now.tv_sec:%d,", + "retry:%d\n", timer_start.tv_sec, timer_now.tv_sec, retry); + break; + } + msleep(wait_period); + retry++; + } + + if (retry < max_retry) { + if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*disable BTIF Tx DMA's clock*/ + i_ret += + hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, + CLK_OUT_DISABLE); + } + if (p_btif->rx_mode == BTIF_MODE_DMA) { + /*disable BTIF Rx DMA's clock*/ + i_ret += + hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, + CLK_OUT_DISABLE); + } +/*disable BTIF's clock*/ + i_ret += + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); + + if (i_ret) + BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); + } else + i_ret = -1; + + return i_ret; +} + +int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ENUM_BTIF_DPIDLE_CTRL en_flag) +{ +/*call WCP's API to control deepidle's enable/disable*/ + if (en_flag == BTIF_DPIDLE_DISABLE) + hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_DIS); + else + hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_EN); + + return 0; +} + +int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb) +{ + if (p_btif->rx_cb) { + BTIF_WARN_FUNC + ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", + p_btif->rx_cb, rx_cb); + } + p_btif->rx_cb = rx_cb; + + return 0; +} + +int btif_raise_wak_signal(p_mtk_btif p_btif) +{ + int i_ret = 0; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); +#endif + + i_ret = hal_btif_raise_wak_sig(p_btif_info); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); +#endif + return i_ret; +} + +bool _btif_is_tx_complete(p_mtk_btif p_btif) +{ + bool b_ret = false; + ENUM_BTIF_MODE tx_mode = p_btif->tx_mode; + +/* + * make sure BTIF tx finished in PIO mode + * make sure BTIF tx finished and DMA tx finished in DMA mode + */ + if (tx_mode == BTIF_MODE_DMA) { + b_ret = hal_dma_is_tx_complete(p_btif->p_tx_dma->p_dma_info); + if (b_ret == false) { + BTIF_DBG_FUNC("Tx DMA is not finished\n"); + return b_ret; + } + } + + b_ret = hal_btif_is_tx_complete(p_btif->p_btif_info); + if (b_ret == false) { + BTIF_DBG_FUNC("BTIF Tx is not finished\n"); + return b_ret; + } + b_ret = true; + return b_ret; +} + +/*--------------------------------Functions-------------------------------------------*/ + +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_init(p_mtk_btif_dma p_dma) +{ + P_DMA_VFIFO p_vfifo = NULL; + struct device *dev = NULL; + p_mtk_btif p_btif = NULL; + + if (p_dma == NULL) { + BTIF_ERR_FUNC("p_dma is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + p_btif = (p_mtk_btif)p_dma->p_btif; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); + return E_BTIF_INVAL_PARAM; + } + + dev = (struct device *)p_btif->private_data; + if (dev == NULL) + BTIF_WARN_FUNC("Null dev pointer!!!!\n"); + + p_vfifo = p_dma->p_dma_info->p_vfifo; + if (p_vfifo->p_vir_addr != NULL) { + BTIF_ERR_FUNC + ("BTIF vFIFO memory already allocated, do nothing\n"); + return E_BTIF_BAD_POINTER; + } + +/*vFIFO memory allocation*/ + p_vfifo->p_vir_addr = dma_zalloc_coherent(dev, + p_vfifo->vfifo_size, + &p_vfifo->phy_addr, GFP_DMA | GFP_DMA32); + if (p_vfifo->p_vir_addr == NULL) { + BTIF_ERR_FUNC("alloc vFIFO memory for BTIF failed\n"); + return E_BTIF_FAIL; + } + + if (sizeof(dma_addr_t) == sizeof(unsigned long long)) + BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch64,vir addr:0x%p,", + "phy addr:0x%llx\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); + else + BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch32,vir addr:0x%p,", + "phy addr:0x%08x\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); + + return 0; +} +#endif +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma) +{ + P_DMA_VFIFO p_vfifo = NULL; + struct device *dev = NULL; + p_mtk_btif p_btif = NULL; + + if (p_dma == NULL) { + BTIF_ERR_FUNC("p_dma is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + + p_btif = (p_mtk_btif)p_dma->p_btif; + if (p_btif == NULL) { + BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); + return E_BTIF_INVAL_PARAM; + } + + dev = (struct device *)p_btif->private_data; + if (dev == NULL) + BTIF_WARN_FUNC("Null dev pointer!!!!\n"); + + p_vfifo = p_dma->p_dma_info->p_vfifo; + +/*free DMA memory if allocated successfully before*/ + if (p_vfifo->p_vir_addr != NULL) { + dma_free_coherent(dev, + p_vfifo->vfifo_size, + p_vfifo->p_vir_addr, p_vfifo->phy_addr); + p_vfifo->p_vir_addr = NULL; + } + + return 0; +} +#endif + +static int _btif_state_init(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + p_btif->state = B_S_OFF; + mutex_init(&(p_btif->state_mtx)); + + return 0; +} + +static int _btif_state_hold(p_mtk_btif p_btif) +{ + return mutex_lock_killable(&(p_btif->state_mtx)); +} + +static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state) +{ +/*chaozhong: To do: need to finished state mechine here*/ + int i_ret = 0; + int ori_state = p_btif->state; + + if (ori_state == state) { + BTIF_INFO_FUNC("already in %s state\n", g_state[state]); + return i_ret; + } + if ((state >= B_S_OFF) && (state < B_S_MAX)) { + BTIF_DBG_FUNC("%s->%s request\n", g_state[ori_state], + g_state[state]); + if (state == B_S_ON) + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); + switch (ori_state) { + case B_S_ON: +/*B_S_ON can only be switched to B_S_OFF, B_S_SUSPEND and B_S_DPIDLE*/ +/*B_S_ON->B_S_OFF : do nothing here*/ +/* + * B_S_ON->B_S_DPLE : disable clock backup + * BTIF and DMA controller's register if necessary + */ + if (state == B_S_DPIDLE) { + /*clock controlled id done in _btif_enter_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_OFF) { + /*clock controlled is done in btif_close*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_SUSPEND) { + /*clock controlled is done in btif_close*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + case B_S_DPIDLE: +/*B_S_DPIDLE can only be switched to B_S_ON and B_S_SUSPEND*/ +/*B_S_DPIDLE-> B_S_ON: do nothing for this moment*/ +/* + * B_S_DPIDLE-> B_S_SUSPEND: + * disable clock backup BTIF and DMA controller's register if necessary + */ + if (state == B_S_ON) { + /*clock controlled id done in _btif_exit_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_SUSPEND) { + /*clock controlled is done in _btif_exit_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + + case B_S_SUSPEND: +/*B_S_SUSPEND can be switched to B_S_IDLE and B_S_ON*/ +/*reinit BTIF controller and DMA controller*/ + if (state == B_S_DPIDLE) { + /* + * system call resume API, do resume operation, + * change to deepidle state + */ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_ON) { + /* + * when stp want to send data before + * system do resume operation + */ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + + case B_S_OFF:{ +/*B_S_OFF can only be switched to B_S_ON*/ + if (state == B_S_ON) { + /*clock controlled is done in btif_open*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + } + break; + default: +/*no this possibility*/ + BTIF_ERR_FUNC + ("state change request is not allowed, this should never happen\n"); + break; + } + + if (state != B_S_ON) + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + + } else { + i_ret = E_BTIF_INVAL_PARAM; + BTIF_ERR_FUNC("invalid state:%d, do nothing\n", state); + } + return i_ret; +} + +static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif) +{ + return p_btif->state; +} + +static int _btif_state_release(p_mtk_btif p_btif) +{ + int i_ret = 0; + + BTIF_MUTEX_UNLOCK(&(p_btif->state_mtx)); + return i_ret; +} + +static int _btif_state_deinit(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + p_btif->state = B_S_OFF; + mutex_destroy(&(p_btif->state_mtx)); + + return 0; +} + +static int btif_rx_data_consummer(p_mtk_btif p_btif) +{ + unsigned int length = 0; + unsigned char *p_buf = NULL; +/*get BTIF rx buffer's information*/ + p_btif_buf_str p_bbs = &(p_btif->btif_buf); +/* + * wr_idx of btif_buf may be modified in IRQ handler, + * in order not to be effected by case in which irq interrupt this operation, + * we record wr_idx here + */ + unsigned int wr_idx = p_bbs->wr_idx; + + length = BBS_COUNT_CUR(p_bbs, wr_idx); + +/*make sure length of rx buffer data > 0*/ + do { + if (length > 0) { + /* + * check if rx_cb empty or not, if registered , + * call user's rx callback to handle these data + */ + if (p_btif->rx_cb) { + if (p_bbs->rd_idx <= wr_idx) { + p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); + /* p_buf = &(p_bbs->buf[p_bbs->rd_idx]); */ + /* length = BBS_COUNT(p_bbs); */ + length = (wr_idx >= (p_bbs)->rd_idx) ? + (wr_idx - (p_bbs)->rd_idx) : + BBS_SIZE(p_bbs) - + ((p_bbs)->rd_idx - wr_idx); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, length); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + /*update rx data read index*/ + p_bbs->rd_idx = wr_idx; + } else { + unsigned int len_tail = + BBS_SIZE(p_bbs) - (p_bbs)->rd_idx; + /*p_buf = &(p_bbs->buf[p_bbs->->rd_idx]);*/ + p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, len_tail); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + length = BBS_COUNT_CUR(p_bbs, wr_idx); + length -= len_tail; + /*p_buf = &(p_bbs->buf[0]);*/ + p_buf = BBS_PTR(p_bbs, 0); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, length); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + /*update rx data read index*/ + p_bbs->rd_idx = wr_idx; + } + } else if (p_btif->rx_notify != NULL) { + (*p_btif->rx_notify) (); + } else { + BTIF_WARN_FUNC + ("p_btif:0x%p, both rx_notify and rx_cb are NULL\n", + p_btif); + break; + } + } else { + BTIF_DBG_FUNC("length:%d\n", length); + break; + } + wr_idx = p_bbs->wr_idx; + length = BBS_COUNT_CUR(p_bbs, wr_idx); + } while (1); + return length; +} + +#if BTIF_RXD_BE_BLOCKED_DETECT +static int mtk_btif_rxd_be_blocked_by_timer(void) +{ + int ret = 0; + int counter = 0; + unsigned int i; + struct timeval now; + int time_gap[MAX_BTIF_RXD_TIME_REC]; + + do_gettimeofday(&now); + + for (i = 0; i < MAX_BTIF_RXD_TIME_REC; i++) { + BTIF_INFO_FUNC("btif_rxd_time_stamp[%d]=%d.%d\n", i, + btif_rxd_time_stamp[i].tv_sec, btif_rxd_time_stamp[i].tv_usec); + if (now.tv_sec >= btif_rxd_time_stamp[i].tv_sec) { + time_gap[i] = now.tv_sec - btif_rxd_time_stamp[i].tv_sec; + time_gap[i] *= 1000000; /*second*/ + if (now.tv_usec >= btif_rxd_time_stamp[i].tv_usec) + time_gap[i] += now.tv_usec - btif_rxd_time_stamp[i].tv_usec; + else + time_gap[i] += 1000000 - now.tv_usec + btif_rxd_time_stamp[i].tv_usec; + + if (time_gap[i] > 1000000) + counter++; + BTIF_INFO_FUNC("time_gap[%d]=%d,counter:%d\n", i, time_gap[i], counter); + } else { + time_gap[i] = 0; + BTIF_ERR_FUNC("abnormal case now:%d < time_stamp[%d]:%d\n", now.tv_sec, + i, btif_rxd_time_stamp[i].tv_usec); + } + } + if (counter > (MAX_BTIF_RXD_TIME_REC - 2)) + ret = 1; + return ret; +} +static int mtk_btif_rxd_be_blocked_by_data(void) +{ + unsigned int out_index = 0; + unsigned int in_index = 0; + unsigned int dump_size = 0; + unsigned int len = 0; + unsigned long flags; + unsigned int sync_pkt_n = 0; + P_BTIF_LOG_BUF_T p_log_buf = NULL; + P_BTIF_LOG_QUEUE_T p_log_que = NULL; + p_mtk_btif p_btif = &(g_btif[0]); + + p_log_que = &p_btif->rx_log; + spin_lock_irqsave(&p_log_que->lock, flags); + in_index = p_log_que->in; + dump_size = p_log_que->size; + out_index = p_log_que->size >= + BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - + p_log_que->size + + in_index) % BTIF_LOG_ENTRY_NUM; + if (dump_size != 0) { + while (dump_size--) { + p_log_buf = p_log_que->p_queue[0] + out_index; + len = p_log_buf->len; + if (len > BTIF_LOG_SZ) + len = BTIF_LOG_SZ; + if ((0x7f == *(p_log_buf->buffer)) && (0x7f == *(p_log_buf->buffer + 1))) { + sync_pkt_n++; + BTIF_INFO_FUNC("tx pkt_count:%d is sync pkt\n", out_index); + } + out_index++; + out_index %= BTIF_LOG_ENTRY_NUM; + } + } + if (sync_pkt_n == 0) + BTIF_ERR_FUNC("there is no sync pkt in BTIF buffer\n"); + else + BTIF_ERR_FUNC("there are %d sync pkt in BTIF buffer\n", sync_pkt_n); + spin_unlock_irqrestore(&p_log_que->lock, flags); + return sync_pkt_n; +} + +int mtk_btif_rxd_be_blocked_flag_get(void) +{ + int ret = 0; + int condition1 = 0, condition2 = 0; + + condition1 = mtk_btif_rxd_be_blocked_by_timer(); + condition2 = mtk_btif_rxd_be_blocked_by_data(); + if (condition1 && condition2) { + BTIF_ERR_FUNC("btif_rxd thread be blocked too long!\n"); + ret = 1; + } + return ret; +} +#endif +static int btif_rx_thread(void *p_data) +{ +#if BTIF_RXD_BE_BLOCKED_DETECT + unsigned int i = 0; +#endif + p_mtk_btif p_btif = (p_mtk_btif)p_data; + + + while (1) { + wait_for_completion_interruptible(&p_btif->rx_comp); + + if (kthread_should_stop()) { + BTIF_WARN_FUNC("btif rx thread stoping ...\n"); + break; + } +#ifdef BTIF_RXD_BE_BLOCKED_DETECT + do_gettimeofday(&btif_rxd_time_stamp[i]); + i++; + if (i >= MAX_BTIF_RXD_TIME_REC) + i = 0; +#endif + btif_rx_data_consummer(p_btif); + } + return 0; +} + +static void btif_rx_worker(struct work_struct *p_work) +{ +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = container_of(p_work, mtk_btif, rx_work); + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); +/*lock rx_mutex*/ + + if (mutex_lock_killable(&(p_btif->rx_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return; + } + btif_rx_data_consummer(p_btif); + BTIF_MUTEX_UNLOCK(&(p_btif->rx_mtx)); +} + +static void btif_tx_worker(struct work_struct *p_work) +{ + int i_ret = 0; + int leng_sent = 0; +/*tx fifo out*/ + int how_much_get = 0; + unsigned char local_buf[384]; + +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = container_of(p_work, mtk_btif, tx_work); + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); + + if (mutex_lock_killable(&(p_btif->tx_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return; + } + how_much_get = + kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); + do { + while (leng_sent < how_much_get) { + i_ret = _btif_send_data(p_btif, + local_buf + leng_sent, + how_much_get - leng_sent); + if (i_ret > 0) { + leng_sent += i_ret; + } else if (i_ret == 0) { + BTIF_WARN_FUNC + ("_btif_send_data return 0, retry\n"); + } else { + BTIF_WARN_FUNC + ("btif send data fail,reset tx fifo, i_ret(%d)\n", + i_ret); + kfifo_reset(p_btif->p_tx_fifo); + break; + } + } + how_much_get = + kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); + leng_sent = 0; + } while (how_much_get > 0); + BTIF_MUTEX_UNLOCK(&(p_btif->tx_mtx)); +} + +static void btif_rx_tasklet(unsigned long func_data) +{ + unsigned long flags; +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = (p_mtk_btif) func_data; + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); +/*lock rx_spinlock*/ + spin_lock_irqsave(&p_btif->rx_tasklet_spinlock, flags); + btif_rx_data_consummer(p_btif); + spin_unlock_irqrestore(&p_btif->rx_tasklet_spinlock, flags); +} + +static int _btif_tx_ctx_init(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + p_btif->p_tx_wq = create_singlethread_workqueue("btif_txd"); + + if (!(p_btif->p_tx_wq)) { + BTIF_ERR_FUNC + ("create_singlethread_workqueue for tx thread fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + mutex_init(&(p_btif->tx_mtx)); +/* init btif tx work */ + INIT_WORK(&(p_btif->tx_work), btif_tx_worker); + BTIF_INFO_FUNC("btif_tx_worker init succeed\n"); + + p_btif->p_tx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (p_btif->p_tx_fifo == NULL) { + i_ret = -ENOMEM; + BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); + goto btm_init_err; + } + + i_ret = kfifo_alloc(p_btif->p_tx_fifo, + BTIF_TX_FIFO_SIZE, GFP_ATOMIC); + if (i_ret != 0) { + BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); + i_ret = -ENOMEM; + goto btm_init_err; + } + } else if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { + BTIF_INFO_FUNC + ("nothing is done when btif tx in user's thread\n"); + } else { + BTIF_ERR_FUNC("unsupported tx context type:%d\n", + p_btif->tx_ctx); + goto btm_init_err; + } + + BTIF_INFO_FUNC("succeed\n"); + + i_ret = 0; + return i_ret; +btm_init_err: + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + if (p_btif->p_tx_wq) { + destroy_workqueue(p_btif->p_tx_wq); + p_btif->p_tx_wq = NULL; + BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); + } + kfree(p_btif->p_tx_fifo); + } + return i_ret; +} + +static int _btif_tx_ctx_deinit(p_mtk_btif p_btif) +{ + int i_ret = 0; + + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + if (p_btif->p_tx_wq) { + destroy_workqueue(p_btif->p_tx_wq); + p_btif->p_tx_wq = NULL; + BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); + } + if (p_btif->p_tx_fifo) { + kfifo_free(p_btif->p_tx_fifo); + kfree(p_btif->p_tx_fifo); + p_btif->p_tx_fifo = NULL; + } + } + return i_ret; +} + +static int _btif_rx_btm_init(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->btm_type == BTIF_THREAD_CTX) { + init_completion(&p_btif->rx_comp); + + /*create kernel thread for later rx data handle*/ + p_btif->p_task = kthread_create(btif_rx_thread, p_btif, "btif_rxd"); + if (p_btif->p_task == NULL) { + BTIF_ERR_FUNC("kthread_create fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + +#if ENABLE_BTIF_RX_THREAD_RT_SCHED + { + int i_ret = -1; + int policy = SCHED_FIFO; + struct sched_param param; + + param.sched_priority = MAX_RT_PRIO - 20; + i_ret = sched_setscheduler(p_btif->p_task, policy, ¶m); + if (i_ret != 0) + BTIF_WARN_FUNC("set RT to btif_rxd workqueue failed\n"); + else + BTIF_INFO_FUNC("set RT to btif_rxd workqueue succeed\n"); + } +#endif + + wake_up_process(p_btif->p_task); + BTIF_INFO_FUNC("btif_rxd start to work!\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + p_btif->p_rx_wq = create_singlethread_workqueue("btif_rxwq"); + if (!(p_btif->p_rx_wq)) { + BTIF_ERR_FUNC("create_singlethread_workqueue fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + mutex_init(&(p_btif->rx_mtx)); + /* init btif rx work */ + INIT_WORK(&(p_btif->rx_work), btif_rx_worker); + BTIF_INFO_FUNC("btif_rx_worker init succeed\n"); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + /*init rx tasklet*/ + tasklet_init(&(p_btif->rx_tasklet), btif_rx_tasklet, + (unsigned long)p_btif); + spin_lock_init(&(p_btif->rx_tasklet_spinlock)); + BTIF_INFO_FUNC("btif_rx_tasklet init succeed\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + +/*spinlock init*/ + spin_lock_init(&(p_btif->rx_irq_spinlock)); + BTIF_INFO_FUNC("rx_spin_lock init succeed\n"); + + i_ret = 0; + return i_ret; +btm_init_err: + if (p_btif->btm_type == BTIF_THREAD_CTX) { + /*do nothing*/ + BTIF_INFO_FUNC("failed\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + if (p_btif->p_rx_wq) { + destroy_workqueue(p_btif->p_rx_wq); + p_btif->p_rx_wq = NULL; + BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); + } + } + return i_ret; +} + +static int _btif_rx_btm_sched(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->btm_type == BTIF_THREAD_CTX) { + complete(&p_btif->rx_comp); + BTIF_DBG_FUNC("schedule btif_rx_thread\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + queue_work(p_btif->p_rx_wq, &(p_btif->rx_work)); + BTIF_DBG_FUNC("schedule btif_rx_worker\n"); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + /*schedule it!*/ + tasklet_schedule(&(p_btif->rx_tasklet)); + BTIF_DBG_FUNC("schedule btif_rx_tasklet\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + + return 0; +} + +static int _btif_rx_btm_deinit(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + if (p_btif->btm_type == BTIF_THREAD_CTX) { + if (p_btif->p_task != NULL) { + BTIF_INFO_FUNC("signaling btif rx thread to stop ...\n"); + kthread_stop(p_btif->p_task); + } + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + if (p_btif->p_rx_wq) { + cancel_work_sync(&(p_btif->rx_work)); + BTIF_INFO_FUNC("btif_rx_worker cancelled\n"); + destroy_workqueue(p_btif->p_rx_wq); + p_btif->p_rx_wq = NULL; + BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); + } + mutex_destroy(&(p_btif->rx_mtx)); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + tasklet_kill(&(p_btif->rx_tasklet)); + BTIF_INFO_FUNC("rx_tasklet killed\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + + spin_lock_init(&(p_btif->rx_irq_spinlock)); + + return 0; +} + + +void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs) +{ + BTIF_INFO_FUNC + ("%s UBS:0x%p\n Size:0x%p\n read:0x%08x\n write:0x%08x\n", + p_str, p_bbs, p_bbs->size, p_bbs->rd_idx, p_bbs->wr_idx); +} + +unsigned int btif_bbs_write(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ +/*in IRQ context, so read operation won't interrupt this operation*/ + + unsigned int wr_len = 0; + + unsigned int emp_len = BBS_LEFT(p_bbs); + unsigned int ava_len = emp_len - 1; + p_mtk_btif p_btif = container_of(p_bbs, mtk_btif, btif_buf); + + if (ava_len <= 0) { + BTIF_ERR_FUNC + ("no empty space left for write, (%d)ava_len, (%d)to write\n", + ava_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + return 0; + } + + if (ava_len < buf_len) { + BTIF_ERR_FUNC("BTIF overrun, (%d)empty, (%d)needed\n", + emp_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + } + + if (buf_len >= g_max_pkg_len) { + BTIF_WARN_FUNC("buf_len too long, (%d)ava_len, (%d)to write\n", + ava_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + } + + wr_len = min(buf_len, ava_len); + btif_bbs_wr_direct(p_bbs, p_buf, wr_len); + + if (BBS_COUNT(p_bbs) >= g_max_pding_data_size) { + BTIF_WARN_FUNC("Rx buf_len too long, size(%d)\n", + BBS_COUNT(p_bbs)); + btif_dump_bbs_str("Rx buffer tooo long", p_bbs); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + BBS_INIT(p_bbs); + } + + return wr_len; +} + +unsigned int btif_bbs_read(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int rd_len = 0; + unsigned int ava_len = 0; + unsigned int wr_idx = p_bbs->wr_idx; + + ava_len = BBS_COUNT_CUR(p_bbs, wr_idx); + if (ava_len >= 4096) { + BTIF_WARN_FUNC("ava_len too long, size(%d)\n", ava_len); + btif_dump_bbs_str("Rx buffer tooo long", p_bbs); + } + if (ava_len != 0) { + if (buf_len >= ava_len) { + rd_len = ava_len; + if (wr_idx >= (p_bbs)->rd_idx) { + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + ava_len); + (p_bbs)->rd_idx = wr_idx; + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - + (p_bbs)->rd_idx; + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + tail_len); + memcpy(p_buf + tail_len, BBS_PTR(p_bbs, + 0), ava_len - tail_len); + (p_bbs)->rd_idx = wr_idx; + } + } else { + rd_len = buf_len; + if (wr_idx >= (p_bbs)->rd_idx) { + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + rd_len); + (p_bbs)->rd_idx = (p_bbs)->rd_idx + rd_len; + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - + (p_bbs)->rd_idx; + if (tail_len >= rd_len) { + memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), + rd_len); + (p_bbs)->rd_idx = + ((p_bbs)->rd_idx + rd_len) & (BBS_MASK(p_bbs)); + } else { + memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), tail_len); + memcpy(p_buf + tail_len, + (p_bbs)->p_buf, rd_len - tail_len); + (p_bbs)->rd_idx = rd_len - tail_len; + } + } + } + } + mb(); + return rd_len; +} + +unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int tail_len = 0; + unsigned int l = 0; + unsigned int tmp_wr_idx = p_bbs->wr_idx; + + tail_len = BBS_SIZE(p_bbs) - (tmp_wr_idx & BBS_MASK(p_bbs)); + + l = min(tail_len, buf_len); + + memcpy((p_bbs->p_buf) + (tmp_wr_idx & BBS_MASK(p_bbs)), p_buf, l); + memcpy(p_bbs->p_buf, p_buf + l, buf_len - l); + + mb(); + + tmp_wr_idx += buf_len; + tmp_wr_idx &= BBS_MASK(p_bbs); + p_bbs->wr_idx = tmp_wr_idx; + + mb(); + return buf_len; +} + +int _btif_dma_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int i_ret = 0; + unsigned int retry = 0; + unsigned int max_tx_retry = 10; + + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + + _btif_irq_ctrl_sync(p_dma_info->p_irq, false); + do { + /*wait until tx is allowed*/ + while (!hal_dma_is_tx_allow(p_dma_info) && + (retry < max_tx_retry)) { + retry++; + if (retry >= max_tx_retry) { + BTIF_ERR_FUNC("wait for tx allowed timeout\n"); + break; + } + } + if (retry >= max_tx_retry) + break; + + if (buf_len <= hal_dma_get_ava_room(p_dma_info)) + i_ret = hal_dma_send_data(p_dma_info, p_buf, buf_len); + else + i_ret = 0; + } while (0); + _btif_irq_ctrl_sync(p_dma_info->p_irq, true); + return i_ret; +} + +int _btif_pio_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int i_ret = 0; + unsigned int sent_len = 0; + unsigned int retry = 0; + unsigned int max_tx_retry = 10; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + + while ((sent_len < buf_len)) { + if (hal_btif_is_tx_allow(p_btif_info)) { + i_ret = hal_btif_send_data(p_btif_info, + p_buf + sent_len, + buf_len - sent_len); + if (i_ret > 0) { + sent_len += i_ret; + BTIF_DBG_FUNC("lent sent:%d, total sent:%d\n", + i_ret, sent_len); + retry = 0; + } + } + if ((++retry > max_tx_retry) || (i_ret < 0)) { + BTIF_INFO_FUNC("exceed retry times limit :%d\n", retry); + break; + } + } + i_ret = sent_len; + return i_ret; +} + +int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int idx = 0; + + pr_debug("%s:, length:%d\n", str, buf_len); + for (idx = 0; idx < buf_len;) { + pr_debug("%02x ", p_buf[idx]); + idx++; + if (idx % 8 == 0) + pr_debug("\n"); + } + return 0; +} + +int btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + int i_ret = 0; + + if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { + i_ret = _btif_send_data(p_btif, p_buf, buf_len); + } else if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + int length = 0; +/*tx fifo in*/ + length = kfifo_in(p_btif->p_tx_fifo, + (unsigned char *)p_buf, buf_len); + if (length == buf_len) { + queue_work(p_btif->p_tx_wq, &(p_btif->tx_work)); + BTIF_DBG_FUNC("schedule btif_tx_worker\n"); + i_ret = length; + } else { + i_ret = 0; + BTIF_ERR_FUNC("fifo in failed, target len(%d),in len(%d),", + "don't schedule btif_tx_worker\n", buf_len, length); + } + } else { + BTIF_ERR_FUNC("invalid btif tx context:%d\n", p_btif->tx_ctx); + i_ret = 0; + } + + return i_ret; +} + +int _btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + int i_ret = 0; + unsigned int state = 0; + +/*make sure BTIF in ON state before doing tx operation*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + state = _btif_state_get(p_btif); + + if (state != B_S_ON) + i_ret = _btif_exit_dpidle(p_btif); + + if (i_ret != 0) { + i_ret = E_BTIF_INVAL_STATE; + } else if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ + i_ret = _btif_dma_write(p_btif, p_buf, buf_len); + } else if (p_btif->tx_mode == BTIF_MODE_PIO) { + /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ + i_ret = _btif_pio_write(p_btif, p_buf, buf_len); + } else { + BTIF_ERR_FUNC("invalid tx mode:%d\n", p_btif->tx_mode); + i_ret = 0; + } + +/*save Tx packet here*/ + if (i_ret > 0) + btif_log_buf_dmp_in(&p_btif->tx_log, p_buf, i_ret); + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int btif_dump_reg(p_mtk_btif p_btif) +{ + int i_ret = 0; + unsigned int ori_state = 0; + +/*make sure BTIF in ON state before doing tx operation*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + ori_state = _btif_state_get(p_btif); + + if (ori_state == B_S_OFF) { + i_ret = E_BTIF_INVAL_STATE; + BTIF_ERR_FUNC + ("BTIF in OFF state, ", + "should no need to dump register, ", + "please check wmt's operation is okay or not.\n"); + goto dmp_reg_err; + } + + if ((ori_state != B_S_ON) && (ori_state < B_S_MAX)) { + BTIF_ERR_FUNC("BTIF's original state is %s, not B_S_ON\n", g_state[ori_state]); + BTIF_ERR_FUNC("!!!!---<<>>---!!!"); + i_ret = _btif_exit_dpidle(p_btif); + } + + if (i_ret != 0) { + i_ret = E_BTIF_INVAL_STATE; + BTIF_ERR_FUNC("switch to B_S_ON failed\n"); + goto dmp_reg_err; + } + +/*dump BTIF register*/ + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + +/*dump BTIF Tx DMA channel register if in DMA mode*/ + if (p_btif->tx_mode == BTIF_MODE_DMA) + hal_dma_dump_reg(p_btif->p_tx_dma->p_dma_info, REG_TX_DMA_ALL); + else + BTIF_INFO_FUNC("BTIF Tx in PIO mode,no need to dump Tx DMA's register\n"); + +/*dump BTIF Rx DMA channel register if in DMA mode*/ + if (p_btif->rx_mode == BTIF_MODE_DMA) + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + else + BTIF_INFO_FUNC("BTIF Rx in PIO mode,no need to dump Rx DMA's register\n"); + + switch (ori_state) { + case B_S_SUSPEND: +/*return to dpidle state*/ +/* break; */ + case B_S_DPIDLE: +/*return to dpidle state*/ + _btif_enter_dpidle(p_btif); + break; + case B_S_ON: +/*nothing needs to be done*/ + break; + default: + break; + } + +dmp_reg_err: + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify) +{ + if (p_btif->rx_notify) { + BTIF_WARN_FUNC + ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", + p_btif->rx_notify, rx_notify); + } + p_btif->rx_notify = rx_notify; + + return 0; +} + +int btif_dump_data(char *p_buf, int len) +{ + unsigned int idx = 0; + unsigned char str[30]; + unsigned char *p_str; + + p_str = &str[0]; + for (idx = 0; idx < len; idx++, p_buf++) { + sprintf(p_str, "%02x ", *p_buf); + p_str += 3; + if (7 == (idx % 8)) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + p_str = &str[0]; + } + } + if (len % 8) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + } + return 0; +} + +int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, + int len) +{ + P_BTIF_LOG_BUF_T p_log_buf = NULL; + char *dir = NULL; + struct timeval *p_timer = NULL; + unsigned long flags; + bool output_flag = false; + + BTIF_DBG_FUNC("++\n"); + + if ((p_log_que == NULL) || (p_buf == NULL) || (len == 0)) { + BTIF_ERR_FUNC("invalid parameter, p_log_que(0x%x), buf(0x%x), ", + "len(%d)\n", p_log_que, p_buf, len); + return 0; + } + if (!(p_log_que->enable)) + return 0; + + dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; + output_flag = p_log_que->output_flag; + + spin_lock_irqsave(&(p_log_que->lock), flags); + +/*get next log buffer for record usage*/ + p_log_buf = p_log_que->p_queue[0] + p_log_que->in; + p_timer = &p_log_buf->timer; + +/*log time stamp*/ + do_gettimeofday(p_timer); + +/*record data information including length and content*/ + p_log_buf->len = len; + memcpy(p_log_buf->buffer, p_buf, len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len); + +/*update log queue size information*/ + p_log_que->size++; + p_log_que->size = p_log_que->size > + BTIF_LOG_ENTRY_NUM ? BTIF_LOG_ENTRY_NUM : p_log_que->size; + +/*update log queue index information*/ + p_log_que->in++; + p_log_que->in %= BTIF_LOG_ENTRY_NUM; + + spin_unlock_irqrestore(&p_log_que->lock, flags); + +/*check if log dynamic output function is enabled or not*/ + if (output_flag) { + pr_debug("BTIF-DBG, dir:%s, %d.%ds len:%d\n", + dir, (int)p_timer->tv_sec, (int)p_timer->tv_usec, len); +/*output buffer content*/ + btif_dump_data((char *)p_buf, len); + } + BTIF_DBG_FUNC("--\n"); + + return 0; +} + +int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que) +{ + P_BTIF_LOG_BUF_T p_log_buf = NULL; + unsigned int out_index = 0; + unsigned int in_index = 0; + unsigned int dump_size = 0; + unsigned char *p_buf = NULL; + unsigned int len = 0; + unsigned int pkt_count = 0; + unsigned char *p_dir = NULL; + struct timeval *p_timer = NULL; + unsigned long flags; + +#if 0 /* no matter enable or not, we allowed output */ + if (!(p_log_que->enable)) + return; +#endif + BTIF_DBG_FUNC("++\n"); + + spin_lock_irqsave(&p_log_que->lock, flags); + in_index = p_log_que->in; + dump_size = p_log_que->size; + out_index = p_log_que->size >= + BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - + p_log_que->size + + in_index) % BTIF_LOG_ENTRY_NUM; + p_dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; + + BTIF_INFO_FUNC("btif %s log buffer size:%d\n", p_dir, dump_size); + + if (dump_size != 0) { + while (dump_size--) { + p_log_buf = p_log_que->p_queue[0] + out_index; + + len = p_log_buf->len; + p_buf = p_log_buf->buffer; + p_timer = &p_log_buf->timer; + + len = len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len; + + BTIF_INFO_FUNC("dir:%s, pkt_count:%d, %d.%ds len:%d\n", + p_dir, + pkt_count++, + (int)p_timer->tv_sec, + (int)p_timer->tv_usec, len); +/*output buffer content*/ + btif_dump_data(p_log_buf->buffer, len); + out_index++; + out_index %= BTIF_LOG_ENTRY_NUM; + } + } + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_DBG_FUNC("--\n"); + + return 0; +} + +int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->enable = true; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("enable %s log function\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->enable = false; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("disable %s log function\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->output_flag = true; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("%s log rt output enabled\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->output_flag = false; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("%s log rt output disabled\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + +/*tx log buffer init*/ + p_log_que->in = 0; + p_log_que->out = 0; + p_log_que->size = 0; + p_log_que->enable = true; + memset((p_log_que->p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_DBG_FUNC("reset %s log buffer\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_init(p_mtk_btif p_btif) +{ +/*tx log buffer init*/ + p_btif->tx_log.dir = BTIF_TX; + p_btif->tx_log.in = 0; + p_btif->tx_log.out = 0; + p_btif->tx_log.size = 0; + p_btif->tx_log.output_flag = false; + p_btif->tx_log.enable = true; + spin_lock_init(&(p_btif->tx_log.lock)); + BTIF_DBG_FUNC("tx_log.p_queue:0x%p\n", p_btif->tx_log.p_queue[0]); + memset((p_btif->tx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + +/*rx log buffer init*/ + p_btif->rx_log.dir = BTIF_RX; + p_btif->rx_log.in = 0; + p_btif->rx_log.out = 0; + p_btif->rx_log.size = 0; + p_btif->rx_log.output_flag = false; + p_btif->rx_log.enable = true; + spin_lock_init(&(p_btif->rx_log.lock)); + BTIF_DBG_FUNC("rx_log.p_queue:0x%p\n", p_btif->rx_log.p_queue[0]); + memset((p_btif->rx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + + return 0; +} + +int btif_tx_dma_mode_set(int en) +{ + int index = 0; + ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; + + for (index = 0; index < BTIF_PORT_NR; index++) + g_btif[index].tx_mode = mode; + + return 0; +} + +int btif_rx_dma_mode_set(int en) +{ + int index = 0; + ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; + + for (index = 0; index < BTIF_PORT_NR; index++) + g_btif[index].rx_mode = mode; + + return 0; +} + +static int BTIF_init(void) +{ + int i_ret = -1; + int index = 0; + p_mtk_btif_dma p_tx_dma = NULL; + p_mtk_btif_dma p_rx_dma = NULL; + unsigned char *p_btif_buffer = NULL; + unsigned char *p_tx_queue = NULL; + unsigned char *p_rx_queue = NULL; + + BTIF_DBG_FUNC("++\n"); + +/*Platform Driver initialization*/ + i_ret = platform_driver_register(&mtk_btif_dev_drv); + if (i_ret) { + BTIF_ERR_FUNC("BTIF platform driver registered failed, ret(%d)\n", i_ret); + goto err_exit1; + } + + i_ret = driver_create_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); + if (i_ret) + BTIF_ERR_FUNC("BTIF pdriver_create_file failed, ret(%d)\n", i_ret); + +/*SW init*/ + for (index = 0; index < BTIF_PORT_NR; index++) { + p_btif_buffer = kmalloc(BTIF_RX_BUFFER_SIZE, GFP_ATOMIC); + if (!p_btif_buffer) { + BTIF_ERR_FUNC("p_btif_buffer kmalloc memory fail\n"); + return -1; + } + BTIF_INFO_FUNC("p_btif_buffer get memory 0x%p\n", p_btif_buffer); + p_tx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); + if (!p_tx_queue) { + BTIF_ERR_FUNC("p_tx_queue kmalloc memory fail\n"); + kfree(p_btif_buffer); + return -1; + } + BTIF_INFO_FUNC("p_tx_queue get memory 0x%p\n", p_tx_queue); + p_rx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); + if (!p_rx_queue) { + BTIF_ERR_FUNC("p_rx_queue kmalloc memory fail\n"); + kfree(p_btif_buffer); + kfree(p_tx_queue); + return -1; + } + BTIF_INFO_FUNC("p_rx_queue get memory 0x%p\n", p_rx_queue); + + INIT_LIST_HEAD(&(g_btif[index].user_list)); + BBS_INIT(&(g_btif[index].btif_buf)); + g_btif[index].enable = false; + g_btif[index].open_counter = 0; + g_btif[index].setting = &g_btif_setting[index]; + g_btif[index].p_btif_info = hal_btif_info_get(); + g_btif[index].tx_mode = g_btif_setting[index].tx_mode; + g_btif[index].rx_mode = g_btif_setting[index].rx_mode; + g_btif[index].btm_type = g_btif_setting[index].rx_type; + g_btif[index].tx_ctx = g_btif_setting[index].tx_type; + g_btif[index].lpbk_flag = false; + g_btif[index].rx_cb = NULL; + g_btif[index].rx_notify = NULL; + g_btif[index].btif_buf.p_buf = p_btif_buffer; + g_btif[index].tx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_tx_queue; + g_btif[index].rx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_rx_queue; + btif_log_buf_init(&g_btif[index]); + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF clock gating by default*/ + i_ret = hal_btif_clk_ctrl(g_btif[index].p_btif_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF controller CG failed\n"); + goto err_exit2; + } +#endif + +/* + * viftual FIFO memory must be physical continious, + * because DMA will access it directly without MMU + */ +#if ENABLE_BTIF_TX_DMA + p_tx_dma = &g_dma[index][BTIF_TX]; + g_btif[index].p_tx_dma = p_tx_dma; + p_tx_dma->dir = BTIF_TX; + p_tx_dma->p_btif = &(g_btif[index]); + +/*DMA Tx vFIFO initialization*/ + p_tx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_TX); +/*spinlock init*/ + spin_lock_init(&(p_tx_dma->iolock)); +/*entry setup*/ + atomic_set(&(p_tx_dma->entry), 0); +/*vFIFO initialization*/ + i_ret = _btif_vfifo_init(p_tx_dma); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx vFIFO allocation failed\n"); + goto err_exit2; + } + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF Tx DMA channel's clock gating by default*/ + i_ret = hal_btif_dma_clk_ctrl(p_tx_dma->p_dma_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx DMA's CG failed\n"); + goto err_exit2; + } +#endif + +#else + g_btif[index].p_tx_dma = NULL; +/*force tx mode to DMA no matter what it is in default setting*/ + g_btif[index].tx_mode = BTIF_MODE_PIO; +#endif + +#if ENABLE_BTIF_RX_DMA + p_rx_dma = &g_dma[index][BTIF_RX]; + g_btif[index].p_rx_dma = p_rx_dma; + p_rx_dma->p_btif = &(g_btif[index]); + p_rx_dma->dir = BTIF_RX; + +/*DMA Tx vFIFO initialization*/ + p_rx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_RX); +/*spinlock init*/ + spin_lock_init(&(p_rx_dma->iolock)); +/*entry setup*/ + atomic_set(&(p_rx_dma->entry), 0); +/*vFIFO initialization*/ + i_ret = _btif_vfifo_init(p_rx_dma); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx vFIFO allocation failed\n"); + goto err_exit2; + } + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF Tx DMA channel's clock gating by default*/ + i_ret = hal_btif_dma_clk_ctrl(p_rx_dma->p_dma_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx DMA's CG failed\n"); + goto err_exit2; + } +#endif + +#else + g_btif[index].p_rx_dma = NULL; +/*force rx mode to DMA no matter what it is in default setting*/ + g_btif[index].rx_mode = BTIF_MODE_PIO; + +#endif +/*PM state mechine initialization*/ + i_ret = _btif_state_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF state mechanism init failed\n"); + goto err_exit2; + } + +/*Rx bottom half initialization*/ + i_ret = _btif_rx_btm_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx btm init failed\n"); + goto err_exit3; + } + i_ret = _btif_tx_ctx_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx context init failed\n"); + goto err_exit4; + } +/*Character Device initialization*/ +/*Chaozhong: ToDo: to be initialized*/ + + mutex_init(&g_btif[index].ops_mtx); + } + +/*Debug purpose initialization*/ + +#if BTIF_CDEV_SUPPORT + btif_chrdev_init(); +#endif + + return 0; + +err_exit4: + for (index = 0; index < BTIF_PORT_NR; index++) + _btif_tx_ctx_deinit(&(g_btif[index])); + +err_exit3: + for (index = 0; index < BTIF_PORT_NR; index++) { + _btif_rx_btm_deinit(&(g_btif[index])); + + _btif_state_deinit(&(g_btif[index])); + } + +err_exit2: + for (index = 0; index < BTIF_PORT_NR; index++) { + p_tx_dma = &g_dma[index][BTIF_TX]; + p_rx_dma = &g_dma[index][BTIF_RX]; +#if ENABLE_BTIF_TX_DMA + _btif_vfifo_deinit(p_tx_dma); +#endif + +#if ENABLE_BTIF_RX_DMA + _btif_vfifo_deinit(p_rx_dma); +#endif + g_btif[index].open_counter = 0; + g_btif[index].enable = false; + } + driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); + platform_driver_unregister(&mtk_btif_dev_drv); + +err_exit1: + i_ret = -1; + BTIF_DBG_FUNC("--\n"); + return i_ret; +} + +static void BTIF_exit(void) +{ + unsigned int index = 0; + p_mtk_btif_dma p_tx_dma = NULL; + p_mtk_btif_dma p_rx_dma = NULL; + + BTIF_DBG_FUNC("++\n"); + + for (index = 0; index < BTIF_PORT_NR; index++) { + g_btif[index].open_counter = 0; + g_btif[index].enable = false; + p_tx_dma = &g_dma[index][BTIF_TX]; + p_rx_dma = &g_dma[index][BTIF_RX]; +#if ENABLE_BTIF_TX_DMA + _btif_vfifo_deinit(p_tx_dma); +#endif + +#if ENABLE_BTIF_RX_DMA + _btif_vfifo_deinit(p_rx_dma); +#endif + _btif_state_deinit(&(g_btif[index])); + + _btif_rx_btm_deinit(&(g_btif[index])); + + mutex_destroy(&g_btif[index].ops_mtx); + } + +#if !defined(CONFIG_MTK_CLKMGR) + hal_btif_clk_unprepare(); +#endif + + driver_remove_file(&mtk_btif_dev_drv.driver, &driver_attr_flag); + platform_driver_unregister(&mtk_btif_dev_drv); + BTIF_DBG_FUNC("--\n"); +} + +int mtk_btif_hal_get_log_lvl(void) +{ + return mtk_btif_dbg_lvl; +} + +void mtk_btif_read_cpu_sw_rst_debug(void) +{ + mtk_btif_read_cpu_sw_rst_debug_plat(); +} + +/*---------------------------------------------------------------------------*/ + +module_init(BTIF_init); +module_exit(BTIF_exit); + +/*---------------------------------------------------------------------------*/ + +MODULE_AUTHOR("MBJ/WCN/SE/SS1/Chaozhong.Liang"); +MODULE_DESCRIPTION("MTK BTIF Driver$1.0$"); +MODULE_LICENSE("GPL"); + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/misc/mediatek/btif/common/mtk_btif_exp.c b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c new file mode 100644 index 0000000000000..c0df44558357b --- /dev/null +++ b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c @@ -0,0 +1,786 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF-EXP" + +/*#include "mtk_btif_exp.h"*/ +#include "mtk_btif.h" + +/*---------------------------------Function----------------------------------*/ + +p_mtk_btif btif_exp_srh_id(unsigned long u_id) +{ + int index = 0; + p_mtk_btif p_btif = NULL; + struct list_head *p_list = NULL; + struct list_head *tmp = NULL; + p_mtk_btif_user p_user = NULL; + + for (index = 0; (index < BTIF_PORT_NR) && (p_btif == NULL); index++) { + p_list = &(g_btif[index].user_list); + list_for_each(tmp, p_list) { + p_user = container_of(tmp, mtk_btif_user, entry); + if (u_id == p_user->u_id) { + p_btif = p_user->p_btif; + BTIF_DBG_FUNC + ("BTIF's user id(0x%p), p_btif(0x%p)\n", + p_user->u_id, p_btif); + break; + } + } + } + if (p_btif == NULL) { + BTIF_INFO_FUNC + ("no btif structure found for BTIF's user id(0x%lx)\n", + u_id); + } + return p_btif; +} + +/*-----Normal Mode API declearation-------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_open +* DESCRIPTION +* open BTIF interface, will do BTIF module HW and SW initialization +* PARAMETERS +* p_owner [IN] pointer to owner who call this API, +* currently there are 2 owner ("stp" or "btif_tester") +* may use this module +* for "stp", BTIF will call rx callback function to route rx data to STP module +* for "stp_tester", BTIF will save rx data and wait for native process to access +* p_id [IN] BTIF's user id will be put to this address +* RETURNS +* int 0 = BTIF module initialization fail; negative = BTIF module initialization success +* if open success, value p_id will be the only identifier +* for user to access BTIF's other operations +* including read/write/dpidle_ctrl/rx_cb_retister +* this user id is only an identifier used for owner identification +*****************************************************************************/ +int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id) +{ + int i_ret = -1; + unsigned int index = 0; + p_mtk_btif_user p_new_user = NULL; + p_mtk_btif p_btif = &g_btif[index]; + struct list_head *p_user_list = &(p_btif->user_list); + + BTIF_DBG_FUNC("++"); + BTIF_DBG_FUNC("p_btif(0x%p)\n", p_btif); + + if (mutex_lock_killable(&(p_btif->ops_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return E_BTIF_INTR; + } + if ((p_owner == NULL) || (p_id == NULL)) { + if (p_id) + *p_id = 0; + BTIF_ERR_FUNC("parameter invalid, p_owner(0x%p), p_id(0x%p)\n", + p_owner, p_id); + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + return E_BTIF_INVAL_PARAM; + } + +/*check if btif is already opened or not, if yes, just return fail*/ + if (!list_empty(p_user_list)) { + struct list_head *pos; + p_mtk_btif_user p_user; + + BTIF_ERR_FUNC("BTIF's user list is not empty\n"); + list_for_each(pos, p_user_list) { + p_user = container_of(pos, mtk_btif_user, entry); + BTIF_INFO_FUNC("BTIF's user id(0x%lx), name(%s)\n", + p_user->u_id, p_user->u_name); + } +/*leave p_id alone*/ + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + return E_BTIF_ALREADY_OPEN; + } + p_new_user = vmalloc(sizeof(mtk_btif_user)); + + if (p_new_user != NULL) { + INIT_LIST_HEAD(&(p_new_user->entry)); + p_new_user->enable = false; + p_new_user->p_btif = p_btif; + p_new_user->u_id = (unsigned long)p_new_user; + strncpy(p_new_user->u_name, p_owner, sizeof(p_new_user->u_name) - 1); + p_new_user->u_name[sizeof(p_new_user->u_name) - 1] = '\0'; + BTIF_DBG_FUNC("owner name:%s, recorded name:%s\n", + p_owner, p_new_user->u_name); + + i_ret = btif_open(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); + *p_id = 0; +/*free btif new user's structure*/ + vfree(p_new_user); + p_new_user = NULL; + } else { + BTIF_INFO_FUNC("btif_open succeed\n"); + *p_id = p_new_user->u_id; +/*mark enable flag to true*/ + p_new_user->enable = true; +/*add to uer lsit*/ + list_add_tail(&(p_new_user->entry), p_user_list); + } + } else { + *p_id = 0; + i_ret = -ENOMEM; + BTIF_ERR_FUNC("allocate memory for mtk_btif_user failed\n"); + } + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + BTIF_DBG_FUNC("--"); + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_open); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_close +* DESCRIPTION +* close BTIF interface, will do BTIF module HW and SW de-initialization +* once this API is called, p_btif should never be used by BTIF's user again +* PARAMETERS +* u_id [IN] BTIF's user id +* RETURNS +* int 0 = succeed; +* others = fail, +* for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_close(unsigned long u_id) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + struct list_head *pos = NULL; + struct list_head *p_user_list = NULL; + + BTIF_DBG_FUNC("++"); + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + if (mutex_lock_killable(&(p_btif->ops_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return E_BTIF_INTR; + } + p_user_list = &(p_btif->user_list); + list_for_each(pos, p_user_list) { + p_mtk_btif_user p_user = + container_of(pos, mtk_btif_user, entry); + + if (p_user->u_id == u_id) { + BTIF_INFO_FUNC + ("user who's id is 0x%lx deleted from user list\n", + u_id); + list_del(pos); + vfree(p_user); + i_ret = btif_close(p_btif); + if (i_ret) + BTIF_WARN_FUNC("BTIF close failed"); + break; + } + } + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + BTIF_DBG_FUNC("--"); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_btif_close); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_write +* DESCRIPTION +* send data throuth BTIF module +* there's no internal buffer to cache STP data in BTIF driver, +* if in DMA mode +* btif driver will check if there's enough space in vFIFO for data to send in DMA mode +* if yes, put data to vFIFO and return corresponding data length to caller +* if no, corresponding error code will be returned to called +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN] pointer to target data to send +* len [IN] data length (should be less than 2014 bytes per STP package) +* +* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller +* if btif driver detected that no space is available in Tx FIFO, +* will return E_BTIF_NO_SPACE, mostly something is wrong with BTIF or +* consys when this return value is returned +* RETURNS +* int positive: data length send through BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +* E_BTIF_AGAIN (0) will be returned to caller +* if btif does not have enough vFIFO to send data, +* when caller get 0, he should wait for a moment +* (5~10ms maybe) and try a few times (maybe 10~20) +* if still get E_BTIF_AGAIN, +* should call BTIF's debug API and dump BTIF driver +* and BTIF/DMA register information to kernel log for debug +* E_BTIF_BAD_POINTER will be returned to caller +* if btif is not opened successfully before call this API +* E_BTIF_INVAL_PARAM will be returned if parameter is not valid + +*****************************************************************************/ +int mtk_wcn_btif_write(unsigned long u_id, + const unsigned char *p_buf, unsigned int len) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + BTIF_DBG_FUNC("++"); + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + if (p_buf == NULL) { + BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); + return E_BTIF_INVAL_PARAM; + } + if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { + BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); + return E_BTIF_INVAL_PARAM; + } + + i_ret = btif_send_data(p_btif, p_buf, len); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_write); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_read +* DESCRIPTION +* read data from BTIF module +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN/OUT] pointer to buffer where rx data will be put +* max_len [IN] max buffer length +* RETURNS +* int positive: data length read from BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_read(unsigned long u_id, + unsigned char *p_buf, unsigned int max_len) +{ + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_dpidle_ctrl +* DESCRIPTION +* control if BTIF module allow system enter deepidle state or not +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL +* RETURNS +* int always return 0 +*****************************************************************************/ +int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + if (en_flag == BTIF_DPIDLE_DISABLE) + i_ret = btif_exit_dpidle(p_btif); + else + i_ret = btif_enter_dpidle(p_btif); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_dpidle_ctrl); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_rx_cb_register +* DESCRIPTION +* register rx callback function to BTIF module by btif user +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* rx_cb [IN] pointer to stp rx handler callback function, +* should be comply with MTK_WCN_BTIF_RX_CB +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + i_ret = btif_rx_cb_reg(p_btif, rx_cb); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_rx_cb_register); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_wakeup_consys +* DESCRIPTION +* once sleep command is sent to con sys, +* should call this API before send wakeup command +* to make con sys aware host want to send data to consys +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* RETURNS +* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_wakeup_consys(unsigned long u_id) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + +/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ + i_ret = btif_raise_wak_signal(p_btif); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_wakeup_consys); + + +/***************End of Normal Mode API declearation**********/ + +/***************Debug Purpose API declearation**********/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_loopback_ctrl +* DESCRIPTION +* enable/disable BTIF internal loopback function, +* when this function is enabled data send to btif +* will be received by btif itself +* only for debug purpose, should never use this function in normal mode +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* enable [IN] loopback mode control flag, enable or disable, +* shou be one of ENUM_BTIF_LPBK_MODE +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + i_ret = + btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_logger_ctrl +* DESCRIPTION +* control BTIF logger function's behavior +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* flag [IN] should be one of ENUM_BTIF_DBG_ID +* BTIF_DISABLE_LOGGER - disable btif logger +* BTIF_ENABLE_LOGGER - enable btif logger +* BTIF_DUMP_LOG - dump log logged by btif +* BTIF_CLR_LOG - clear btif log buffer +* BTIF_DUMP_BTIF_REG - dump btif controller's register +* BTIF_DUMP_DMA_REG - dump DMA controller's register +* RETURNS +* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + i_ret = 0; + switch (flag) { + case BTIF_DISABLE_LOGGER:{ + BTIF_INFO_FUNC + ("disable btif log function for both Tx and Rx\n"); + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + } + break; + case BTIF_ENABLE_LOGGER:{ + BTIF_INFO_FUNC + ("enable btif log function for both Tx and Rx\n"); + btif_log_buf_enable(&p_btif->tx_log); + btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_DUMP_LOG:{ + BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); + btif_log_buf_dmp_out(&p_btif->tx_log); + btif_log_buf_dmp_out(&p_btif->rx_log); + } + break; + + case BTIF_CLR_LOG:{ + BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + } + break; + case BTIF_DUMP_BTIF_REG: + /*TBD*/ btif_dump_reg(p_btif); + break; + case BTIF_ENABLE_RT_LOG: + BTIF_INFO_FUNC + ("enable btif real time log for both Tx and Rx\n"); + btif_log_output_enable(&p_btif->tx_log); + btif_log_output_enable(&p_btif->rx_log); + break; + case BTIF_DISABLE_RT_LOG: + BTIF_INFO_FUNC + ("disable btif real time log for both Tx and Rx\n"); + btif_log_output_disable(&p_btif->tx_log); + btif_log_output_disable(&p_btif->rx_log); + break; + default: + BTIF_INFO_FUNC("not supported flag:%d\n", flag); + i_ret = -2; + break; + } + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); + +bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, + const char *sub_str, unsigned int str_len) +{ + bool b_ret = false; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + b_ret = btif_parser_wmt_evt(p_btif, sub_str, str_len); + BTIF_INFO_FUNC("parser wmt evt %s\n", b_ret ? "ok" : "fail"); + + return b_ret; +} + +/**********End of Debug Purpose API declearation**********/ + +int btif_open_no_id(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_open(p_btif); + + if (i_ret) + BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); + else + BTIF_INFO_FUNC("btif_open succeed\n"); + + return i_ret; +} + +int btif_close_no_id(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_close(p_btif); + + if (i_ret) + BTIF_ERR_FUNC("btif_close failed, i_ret(%d)\n", i_ret); + else + BTIF_INFO_FUNC("btif_close succeed\n"); + return i_ret; +} + +int btif_write_no_id(const unsigned char *p_buf, unsigned int len) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_DBG_FUNC("++"); + + if (p_buf == NULL) { + BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); + return E_BTIF_INVAL_PARAM; + } + if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { + BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); + return E_BTIF_INVAL_PARAM; + } + + i_ret = btif_send_data(p_btif, p_buf, len); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +int btif_dpidle_ctrl_no_id(ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + if (en_flag == BTIF_DPIDLE_DISABLE) + i_ret = btif_exit_dpidle(p_btif); + else + i_ret = btif_enter_dpidle(p_btif); + + return i_ret; +} + +int btif_wakeup_consys_no_id(void) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + +/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ + i_ret = btif_raise_wak_signal(p_btif); + + return i_ret; +} + +int btif_loopback_ctrl_no_id(ENUM_BTIF_LPBK_MODE enable) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = + btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); + + return i_ret; +} + +int btif_dbg_ctrl_no_id(ENUM_BTIF_DBG_ID flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = 0; + switch (flag) { + case BTIF_DISABLE_LOGGER:{ + BTIF_INFO_FUNC + ("disable btif log function for both Tx and Rx\n"); + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + } + break; + case BTIF_ENABLE_LOGGER:{ + BTIF_INFO_FUNC + ("enable btif log function for both Tx and Rx\n"); + btif_log_buf_enable(&p_btif->tx_log); + btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_DUMP_LOG:{ + BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); + btif_log_buf_dmp_out(&p_btif->tx_log); + btif_log_buf_dmp_out(&p_btif->rx_log); + } + break; + + case BTIF_CLR_LOG:{ + BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + } + break; + case BTIF_DUMP_BTIF_REG: + /*TBD*/ btif_dump_reg(p_btif); + break; + case BTIF_ENABLE_RT_LOG: + BTIF_INFO_FUNC + ("enable btif real time log for both Tx and Rx\n"); + btif_log_output_enable(&p_btif->tx_log); + btif_log_output_enable(&p_btif->rx_log); + break; + case BTIF_DISABLE_RT_LOG: + BTIF_INFO_FUNC + ("disable btif real time log for both Tx and Rx\n"); + btif_log_output_disable(&p_btif->tx_log); + btif_log_output_disable(&p_btif->rx_log); + break; + default: + BTIF_INFO_FUNC("not supported flag:%d\n", flag); + i_ret = -2; + break; + } + + return i_ret; +} + +int mtk_btif_exp_open_test(void) +{ + int i_ret = 0; + + i_ret = btif_open_no_id(); + if (i_ret < 0) { + BTIF_INFO_FUNC("mtk_wcn_btif_open failed\n"); + return -1; + } + + BTIF_INFO_FUNC("mtk_wcn_btif_open succeed\n"); + + return i_ret; +} + +int mtk_btif_exp_close_test(void) +{ + int i_ret = 0; + + i_ret = btif_close_no_id(); + if (i_ret < 0) { + BTIF_INFO_FUNC("mtk_wcn_btif_close failed\n"); + return -1; + } + + BTIF_INFO_FUNC("mtk_wcn_btif_close succeed\n"); + + return i_ret; +} + +int mtk_btif_exp_write_test(void) +{ + return mtk_btif_exp_write_stress_test(100, 10); +} + +int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int max_loop) +{ +#define BUF_LEN 1024 + int i_ret = 0; + int idx = 0; + int buf_len = length > BUF_LEN ? BUF_LEN : length; + int loop = max_loop > 1000000 ? 1000000 : max_loop; + unsigned char *buffer; + + buffer = kmalloc(BUF_LEN, GFP_KERNEL); + if (!buffer) { + BTIF_ERR_FUNC("btif tester kmalloc failed\n"); + return -1; + } + + for (idx = 0; idx < buf_len; idx++) + /* btif_stress_test_buf[idx] = BUF_LEN -idx; */ + *(buffer + idx) = idx % 255; + i_ret = btif_loopback_ctrl_no_id(BTIF_LPBK_ENABLE); + BTIF_INFO_FUNC("mtk_wcn_btif_loopback_ctrl returned %d\n", i_ret); + while (loop--) { + i_ret = btif_write_no_id(buffer, buf_len); + BTIF_INFO_FUNC("mtk_wcn_btif_write left loop:%d, i_ret:%d\n", + loop, i_ret); + if (i_ret != buf_len) { + BTIF_INFO_FUNC + ("mtk_wcn_btif_write failed, target len %d, sent len: %d\n", + buf_len, i_ret); + break; + } + buf_len--; + if (buf_len <= 0) + buf_len = length > BUF_LEN ? BUF_LEN : length; + } + kfree(buffer); + return i_ret; +} + +int mtk_btif_exp_suspend_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_suspend(p_btif); + return i_ret; +} + +int mtk_btif_exp_restore_noirq_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_restore_noirq(p_btif); + return i_ret; +} + +int mtk_btif_exp_clock_ctrl(int en) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_clock_ctrl(p_btif, en); + return i_ret; +} + +int mtk_btif_exp_resume_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_resume(p_btif); + return i_ret; +} + +int mtk_btif_exp_enter_dpidle_test(void) +{ + return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_ENABLE); +} + +int mtk_btif_exp_exit_dpidle_test(void) +{ + return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_DISABLE); +} + +int mtk_btif_exp_log_debug_test(int flag) +{ + int i_ret = 0; + + i_ret = btif_dbg_ctrl_no_id(flag); + return i_ret; +} + +void mtk_btif_read_cpu_sw_rst_debug_exp(void) +{ + mtk_btif_read_cpu_sw_rst_debug(); +} + +/************End of Function**********/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h new file mode 100644 index 0000000000000..97756f684ab40 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_DMA_H_ +#define __HAL_BTIF_DMA_H_ + +#include +#include "btif_dma_pub.h" + +#if defined(CONFIG_MTK_CLKMGR) +#if defined(CONFIG_ARCH_MT6580) +#define MTK_BTIF_APDMA_CLK_CG MT_CG_APDMA_SW_CG +#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) +#define MTK_BTIF_APDMA_CLK_CG MT_CG_PERI_APDMA +#endif +#else +extern struct clk *clk_btif_apdma; /*btif apdma clock*/ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + +#define TX_DMA_VFF_SIZE (1024 * 8) /*Tx vFIFO Len must be 8 Byte allignment */ +#define RX_DMA_VFF_SIZE (1024 * 8) /*Rx vFIFO Len must be 8 Byte allignment */ + +#define DMA_TX_THRE(n) (n - 7) /*Tx Trigger Level */ +#define DMA_RX_THRE(n) ((n) * 3 / 4) /*Rx Trigger Level */ + +/**********************************Hardware related defination**************************/ +#ifndef CONFIG_OF +/*DMA channel's offset refer to AP_DMA's base address*/ +#define BTIF_TX_DMA_OFFSET 0x880 +#define BTIF_RX_DMA_OFFSET 0x900 +#endif + +/*Register Address Mapping*/ +#define DMA_INT_FLAG_OFFSET 0x00 +#define DMA_INT_EN_OFFSET 0x04 +#define DMA_EN_OFFSET 0x08 +#define DMA_RST_OFFSET 0x0C +#define DMA_STOP_OFFSET 0x10 +#define DMA_FLUSH_OFFSET 0x14 + +#define DMA_BASE_OFFSET 0x1C +#define DMA_LEN_OFFSET 0x24 + +#define DMA_THRE_OFFSET 0x28 +#define DMA_WPT_OFFSET 0x2C +#define DMA_RPT_OFFSET 0x30 +#define DMA_VALID_OFFSET 0x3C +#define DMA_LEFT_OFFSET 0x40 +#define DMA_VFF_BIT29_OFFSET 0x01 + +#define TX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Tx Virtual FIFO Interrupt Flag Register */ +#define TX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Tx Virtual FIFO Interrupt Enable Register */ +#define TX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET)/*BTIF Tx Virtual FIFO Enable Register */ +#define TX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET)/*BTIF Tx Virtual FIFO Reset Register */ +#define TX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET)/*BTIF Tx Virtual FIFO STOP Register */ +#define TX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET)/*BTIF Tx Virtual FIFO Flush Register */ +#define TX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Tx Virtual FIFO Base Address Register */ +#define TX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Tx Virtual FIFO Length Register */ +#define TX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Tx Virtual FIFO Threshold Register */ +#define TX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Tx Virtual FIFO Write Pointer Register */ +#define TX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Tx Virtual FIFO Read Pointer Register */ +#define TX_DMA_W_INT_BUF_SIZE(base) (unsigned long)(base + 0x34) +/*BTIF Tx Virtual FIFO Internal Tx Write Buffer Size Register */ +#define TX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) +/*BTIF Tx Virtual FIFO Internal Tx Buffer Size Register */ + +#define TX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Tx Virtual FIFO Valid Size Register */ +#define TX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Tx Virtual FIFO Left Size Register */ +#define TX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Tx Virtual FIFO Debug Status Register */ +#define TX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Tx Virtual FIFO Base High Address Register */ + +/*Rx Register Address Mapping*/ +#define RX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Rx Virtual FIFO Interrupt Flag Register */ +#define RX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Rx Virtual FIFO Interrupt Enable Register */ +#define RX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET) /*BTIF Rx Virtual FIFO Enable Register */ +#define RX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET) /*BTIF Rx Virtual FIFO Reset Register */ +#define RX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET) /*BTIF Rx Virtual FIFO Stop Register */ +#define RX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET) /*BTIF Rx Virtual FIFO Flush Register */ +#define RX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Rx Virtual FIFO Base Address Register */ +#define RX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Rx Virtual FIFO Length Register */ +#define RX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Rx Virtual FIFO Threshold Register */ +#define RX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Rx Virtual FIFO Write Pointer Register */ +#define RX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Rx Virtual FIFO Read Pointer Register */ +#define RX_DMA_FLOW_CTRL_THRE(base) (unsigned long)(base + 0x34) /*BTIF Rx Virtual FIFO Flow Control Register */ +#define RX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) /*BTIF Rx Virtual FIFO Internal Buffer Register */ +#define RX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Rx Virtual FIFO Valid Size Register */ +#define RX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Rx Virtual FIFO Left Size Register */ +#define RX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Rx Virtual FIFO Debug Status Register */ +#define RX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Rx Virtual FIFO Base High Address Register */ + +#define DMA_EN_BIT (0x1) +#define DMA_STOP_BIT (0x1) +#define DMA_RST_BIT (0x1) +#define DMA_FLUSH_BIT (0x1) + +#define DMA_WARM_RST (0x1 << 0) +#define DMA_HARD_RST (0x1 << 1) + +#define DMA_WPT_MASK (0x0000FFFF) +#define DMA_WPT_WRAP (0x00010000) + +#define DMA_RPT_MASK (0x0000FFFF) +#define DMA_RPT_WRAP (0x00010000) + +/*APDMA BTIF Tx Reg Ctrl Bit*/ +#define TX_DMA_INT_FLAG_MASK (0x1) + +#define TX_DMA_INTEN_BIT (0x1) + +#define TX_DMA_ADDR_MASK (0xFFFFFFF8) +#define TX_DMA_LEN_MASK (0x0000FFF8) + +#define TX_DMA_THRE_MASK (0x0000FFFF) + +#define TX_DMA_W_INT_BUF_MASK (0x000000FF) + +#define TX_DMA_VFF_VALID_MASK (0x0000FFFF) +#define TX_DMA_VFF_LEFT_MASK (0x0000FFFF) + +/*APDMA BTIF Rx Reg Ctrl Bit*/ +#define RX_DMA_INT_THRE (0x1 << 0) +#define RX_DMA_INT_DONE (0x1 << 1) + +#define RX_DMA_INT_THRE_EN (0x1 << 0) +#define RX_DMA_INT_DONE_EN (0x1 << 1) + +#define RX_DMA_ADDR_MASK (0xFFFFFFF8) +#define RX_DMA_LEN_MASK (0x0000FFF8) + +#define RX_DMA_THRE_MASK (0x0000FFFF) + +#define RX_DMA_FLOW_CTRL_THRE_MASK (0x000000FF) + +#define RX_DMA_INT_BUF_SIZE_MASK (0x0000001F) + +#define RX_DMA_VFF_VALID_MASK (0x0000001F) + +#define RX_DMA_VFF_LEFT_MASK (0x0000FFFF) + +typedef struct _MTK_BTIF_DMA_VFIFO_ { + DMA_VFIFO vfifo; + unsigned int wpt; /*DMA's write pointer, which is maintained by SW for Tx DMA and HW for Rx DMA */ + unsigned int last_wpt_wrap; /*last wrap bit for wpt */ + unsigned int rpt; /*DMA's read pointer, which is maintained by HW for Tx DMA and SW for Rx DMA */ + unsigned int last_rpt_wrap; /*last wrap bit for rpt */ +} MTK_BTIF_DMA_VFIFO, *P_MTK_BTIF_DMA_VFIFO; + +/*for DMA debug purpose*/ +typedef struct _MTK_BTIF_DMA_REG_DMP_DBG_ { + unsigned long reg_addr; + unsigned int reg_val; +} MTK_BTIF_DMA_REG_DMP_DBG, *P_MTK_BTIF_DMA_REG_DMP_DBG; + +#endif /*__HAL_BTIF_DMA_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h new file mode 100644 index 0000000000000..0773f2ce387ac --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIFD_DMA_PUB_H_ +#define __HAL_BTIFD_DMA_PUB_H_ + +#include + +#include "plat_common.h" + +typedef enum _ENUM_DMA_CTRL_ { + DMA_CTRL_DISABLE = 0, + DMA_CTRL_ENABLE = DMA_CTRL_DISABLE + 1, + DMA_CTRL_BOTH, +} ENUM_DMA_CTRL; + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_info_get +* DESCRIPTION +* get btif tx dma channel's information +* PARAMETERS +* dma_dir [IN] DMA's direction +* RETURNS +* pointer to btif dma's information structure +*****************************************************************************/ +P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir); + +/***************************************************************************** +* FUNCTION +* hal_btif_dma_hw_init +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ctrl +* DESCRIPTION +* enable/disable Tx DMA channel +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* ctrl_id [IN] enable/disable ID +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id); + +/***************************************************************************** +* FUNCTION +* hal_btif_dma_rx_cb_reg +* DESCRIPTION +* register rx callback function to dma module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* rx_cb [IN] function pointer to btif +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, + dma_rx_buf_write rx_cb); + +/***************************************************************************** +* FUNCTION +* hal_tx_vfifo_reset +* DESCRIPTION +* reset tx virtual fifo information, except memory information +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_send_data +* DESCRIPTION +* send data through btif in DMA mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, + const unsigned char *p_buf, const unsigned int buf_len); + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_get_ava_room +* DESCRIPTION +* get tx available room +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* available room size +*****************************************************************************/ +int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_allow +* DESCRIPTION +* is tx operation allowed by DMA +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_rx_dma_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len); + +/***************************************************************************** +* FUNCTION +* hal_dma_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag); + +int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid); + +#endif /*__HAL_BTIFD_DMA_PUB_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h new file mode 100644 index 0000000000000..51fe58a82b49c --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_H_ +#define __HAL_BTIF_H_ + +#ifndef CONFIG_OF +#define MTK_BTIF_REG_BASE BTIF_BASE +#endif + +#if defined(CONFIG_MTK_CLKMGR) +#if defined(CONFIG_ARCH_MT6580) +#define MTK_BTIF_CG_BIT MT_CG_BTIF_SW_CG +#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) +#define MTK_BTIF_CG_BIT MT_CG_PERI_BTIF +#endif +#else +struct clk *clk_btif_apdma; /*btif apdma clock*/ +struct clk *clk_btif; /*btif clock*/ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + +#define BTIF_RBR(base) (unsigned long)(base + 0x0) /*RX Buffer Register: read only */ +#define BTIF_THR(base) (unsigned long)(base + 0x0) /*Rx Holding Register: write only */ +#define BTIF_IER(base) (unsigned long)(base + 0x4) /*Interrupt Enable Register: read/write */ +#define BTIF_IIR(base) (unsigned long)(base + 0x8) /*Interrupt Identification Register: read only */ +#define BTIF_FIFOCTRL(base) (unsigned long)(base + 0x8) /*FIFO Control Register: write only */ +#define BTIF_FAKELCR(base) (unsigned long)(base + 0xC) /*FAKE LCR Register: read/write */ +#define BTIF_LSR(base) (unsigned long)(base + 0x14) /*Line Status Register: read only */ +#define BTIF_SLEEP_EN(base) (unsigned long)(base + 0x48) /*Sleep Enable Register: read/write */ +#define BTIF_DMA_EN(base) (unsigned long)(base + 0x4C) /*DMA Enable Register: read/write */ +#define BTIF_RTOCNT(base) (unsigned long)(base + 0x54) /*Rx Timeout Count Register: read/write */ +#define BTIF_TRI_LVL(base) (unsigned long)(base + 0x60) /*Tx/Rx Trigger Level Control Register: read/write */ +#define BTIF_WAK(base) (unsigned long)(base + 0x64) /*BTIF module wakeup Register: write only */ +#define BTIF_WAT_TIME(base) (unsigned long)(base + 0x68) /*BTIF ASYNC Wait Time Control Register: read/write */ +#define BTIF_HANDSHAKE(base) (unsigned long)(base + 0x6C) /*BTIF New Handshake Control Register: read/write */ + +/*BTIF_IER bits*/ +#define BTIF_IER_TXEEN (0x1 << 1) /*1: Tx holding register is empty */ +#define BTIF_IER_RXFEN (0x1 << 0) /*1: Rx buffer contains data */ + +/*BTIF_IIR bits*/ +#define BTIF_IIR_NINT (0x1 << 0) /*No INT Pending */ +#define BTIF_IIR_TX_EMPTY (0x1 << 1) /*Tx Holding Register empty */ +#define BTIF_IIR_RX (0x1 << 2) /*Rx data received */ +#define BTIF_IIR_RX_TIMEOUT (0x11 << 2) /*Rx data received */ + +/*BTIF_LSR bits*/ +#define BTIF_LSR_DR_BIT (0x1 << 0) +#define BTIF_LSR_THRE_BIT (0x1 << 5) +#define BTIF_LSR_TEMT_BIT (0x1 << 6) + +/*BTIF_FIFOCTRL bits*/ +#define BTIF_FIFOCTRL_CLR_TX (0x1 << 2) /*Clear Tx FIRO */ +#define BTIF_FIFOCTRL_CLR_RX (0x1 << 1) /*Clear Rx FIRO */ + +/*BTIF_FAKELCR bits*/ +#define BTIF_FAKELCR_NORMAL_MODE 0x0 + +/*BTIF_SLEEP_EN bits*/ +#define BTIF_SLEEP_EN_BIT (0x1 << 0) /*enable Sleep mode */ +#define BTIF_SLEEP_DIS_BIT (0x0) /*disable sleep mode */ + +/*BTIF_DMA_EN bits*/ +#define BTIF_DMA_EN_RX (0x1 << 0) /*Enable Rx DMA */ +#define BTIF_DMA_EN_TX (0x1 << 1) /*Enable Tx DMA */ +#define BTIF_DMA_EN_AUTORST_EN (0x1 << 2) /*1: timeout counter will be auto reset */ +#define BTIF_DMA_EN_AUTORST_DIS (0x0 << 2) /* + * 0: after Rx timeout happens, + * SW shall reset the interrupt by reading BTIF 0x4C + */ + +/*BTIF_TRI_LVL bits*/ +#define BTIF_TRI_LVL_TX_MASK ((0xf) << 0) +#define BTIF_TRI_LVL_RX_MASK ((0x7) << 4) + +#define BTIF_TRI_LVL_TX(x) ((x & 0xf) << 0) +#define BTIF_TRI_LVL_RX(x) ((x & 0x7) << 4) + +#define BTIF_TRI_LOOP_EN (0x1 << 7) +#define BTIF_TRI_LOOP_DIS (0x0 << 7) + +/*BTIF_WAK bits*/ +#define BTIF_WAK_BIT (0x1 << 0) + +/*BTIF_HANDSHAKE bits*/ +#define BTIF_HANDSHAKE_EN_HANDSHAKE 1 +#define BTIF_HANDSHAKE_DIS_HANDSHAKE 0 + +#define BTIF_TX_FIFO_SIZE 16 +#define BTIF_RX_FIFO_SIZE 8 + +#define BTIF_TX_FIFO_THRE (BTIF_TX_FIFO_SIZE / 2) +#define BTIF_RX_FIFO_THRE 0x1 /* 0x5 */ + +#endif /*__HAL_BTIF_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h new file mode 100644 index 0000000000000..1555d5a50c384 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_PUB_H_ +#define __HAL_BTIF_PUB_H_ + +#include "plat_common.h" + +/*Enum Defination*/ +/*BTIF Mode Enum */ +typedef enum _ENUM_BTIF_MODE_ { + BTIF_MODE_PIO = 0, + BTIF_MODE_DMA = BTIF_MODE_PIO + 1, + BTIF_MODE_MAX, +} ENUM_BTIF_MODE; + +/***************************************************************************** +* FUNCTION +* hal_btif_info_get +* DESCRIPTION +* get btif's information included base address , irq related information +* PARAMETERS +* RETURNS +* BTIF's information +*****************************************************************************/ +P_MTK_BTIF_INFO_STR hal_btif_info_get(void); + +#if 0 /*included in hal_btif_info_get */ +/***************************************************************************** +* FUNCTION +* hal_btif_get_irq +* DESCRIPTION +* get BTIF module's IRQ information +* PARAMETERS +* RETURNS +* pointer to BTIF's irq structure +*****************************************************************************/ +P_MTK_BTIF_IRQ_STR hal_btif_get_irq(void); +#endif + +#if !defined(CONFIG_MTK_CLKMGR) +/***************************************************************************** +* FUNCTION +* hal_btif_clk_get_and_prepare +* DESCRIPTION +* get clock from device tree and prepare for enable/disable control +* PARAMETERS +* pdev device pointer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_get_and_prepare(struct platform_device *pdev); +/***************************************************************************** +* FUNCTION +* hal_btif_clk_unprepare +* DESCRIPTION +* unprepare btif clock and apdma clock +* PARAMETERS +* none +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_unprepare(void); +#endif +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of BTIF module +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag); + +/***************************************************************************** +* FUNCTION +* hal_btif_hw_init +* DESCRIPTION +* BTIF module init, after this step, BTIF should enable to do tx/rx with PIO +* mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_cb_reg +* DESCRIPTION +* BTIF rx callback register API +* PARAMETERS +* p_btif_info [IN] pointer to BTIF's information +* rx_cb [IN] rx callback function +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, + btif_rx_buf_write rx_cb); + +/***************************************************************************** +* FUNCTION +* hal_btif_loopback_ctrl +* DESCRIPTION +* BTIF Tx/Rx loopback mode set, this operation can only be done +* after set BTIF to normal mode +* PARAMETERS +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_handler +* DESCRIPTION +* lower level interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success; negative means fail; positive means rx data length +*****************************************************************************/ +int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len); + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_mode_ctrl +* DESCRIPTION +* set BTIF tx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_mode_ctrl +* DESCRIPTION +* set BTIF rx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); + +/***************************************************************************** +* FUNCTION +* hal_btif_send_data +* DESCRIPTION +* send data through btif in FIFO mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* positive means number of data sent; +* 0 means no data put to FIFO; +* negative means error happens +*****************************************************************************/ +int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, + const unsigned char *p_buf, const unsigned int buf_len); + +/***************************************************************************** +* FUNCTION +* hal_btif_raise_wak_sig +* DESCRIPTION +* raise wakeup signal to counterpart +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_base [IN] BTIF module's base address +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag); + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_allow +* DESCRIPTION +* whether tx is allowed +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); + +int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif, MTK_BTIF_PM_OPID opid); + +void mtk_btif_read_cpu_sw_rst_debug_plat(void); + +#endif /*__HAL_BTIF_PUB_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h new file mode 100644 index 0000000000000..2a1462cb32ff4 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_PUB_H_ +#define __HAL_PUB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF +#include +#include +#include +#else +#include +#include +#endif +#if defined(CONFIG_MTK_CLKMGR) +#include +#else +#include +#include +#endif /* defined(CONFIG_MTK_CLKMGR) */ +#include + +extern int mtk_btif_hal_get_log_lvl(void); + +#define MTK_BTIF_MARK_UNUSED_API + +typedef irq_handler_t mtk_btif_irq_handler; + +#define MTK_BTIF_ENABLE_CLK_CTL 1 +#define MTK_BTIF_ENABLE_CLK_REF_COUNTER 1 + +#define DBG_LOG_STR_SIZE 256 + +/*Log defination*/ +static int hal_log_print(const char *str, ...) +{ + va_list args; + char temp_sring[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(temp_sring, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_err("%s", temp_sring); + + return 0; +} + +#define BTIF_LOG_LOUD 4 +#define BTIF_LOG_DBG 3 +#define BTIF_LOG_INFO 2 +#define BTIF_LOG_WARN 1 +#define BTIF_LOG_ERR 0 + +#ifndef DFT_TAG +#define DFT_TAG "[BTIF-DFT]" +#endif + +#define BTIF_LOUD_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_LOUD) \ + hal_log_print(DFT_TAG "[L]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_INFO_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_INFO)\ + hal_log_print(DFT_TAG "[I]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_WARN_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_WARN)\ + hal_log_print(DFT_TAG "[W]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_ERR_FUNC(fmt, arg ...)\ +do {\ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_ERR)\ + hal_log_print(DFT_TAG "[E]%s(%d):" fmt,\ + __func__, __LINE__, ## arg);\ +} while (0) + +#define BTIF_DBG_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ + hal_log_print(DFT_TAG "[D]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_TRC_FUNC(f) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ + hal_log_print(DFT_TAG "<%s> <%d>\n", \ + __func__, __LINE__); \ +} while (0) + +/*-----------------------------------Enum Defination--------------------------------*/ +/*IRQ sensetive type */ +typedef enum _ENUM_IRQ_SENS_TYPE_ { + IRQ_SENS_EDGE = 0, + IRQ_SENS_LVL = IRQ_SENS_EDGE + 1, + IRQ_SENS_TYPE_MAX +} ENUM_IRQ_SENS_TYPE; + +/*IRQ level trigger type */ +typedef enum _ENUM_IRQ_LVL_TYPE_ { + IRQ_LVL_LOW = 0, + IRQ_LVL_HIGH = IRQ_LVL_LOW + 1, + IRQ_LVL_MAX +} ENUM_IRQ_LVL; + +/*IRQ edge trigger type */ +typedef enum _ENUM_IRQ_EDGE_TYPE_ { + IRQ_EDGE_FALL = 0, + IRQ_EDGE_RAISE = IRQ_EDGE_FALL + 1, + IRQ_EDGE_BOTH = IRQ_EDGE_RAISE + 1, + IRQ_EDGE_MAX +} ENUM_IRQ_EDGE; + +typedef enum _ENUM_CLOCK_CTRL_ { + CLK_OUT_DISABLE = 0, + CLK_OUT_ENABLE = CLK_OUT_DISABLE + 1, + CLK_OUT_MAX +} ENUM_CLOCK_CTRL; + +/*Error No. table */ +typedef enum _ENUM_ERROR_CODE_ { + ERR_NO_ERROR = 0, + ERR_INVALID_PAR = ERR_NO_ERROR - 1, + ERR_MAX = ERR_INVALID_PAR - 1, +} ENUM_ERROR_CODE; + +typedef enum _ENUM_BTIF_DIR_ { + BTIF_TX = 0, + BTIF_RX = BTIF_TX + 1, + BTIF_DIR_MAX, +} ENUM_BTIF_DIR; + +typedef enum _ENUM_DMA_DIR_ { + DMA_DIR_RX = 0, + DMA_DIR_TX = DMA_DIR_RX + 1, + DMA_DIR_BOTH, +} ENUM_DMA_DIR; + +typedef enum _ENUM_BTIF_REG_ID_ { + REG_IIR = 0, /*Interrupt Identification Register */ + REG_LSR = 1, /*Line Status Register */ + REG_FAKE_LCR = 2, /*Fake Lcr Regiseter */ + REG_FIFO_CTRL = 3, /*FIFO Control Register */ + REG_IER = 4, /*Interrupt Enable Register */ + REG_SLEEP_EN = 5, /*Sleep Enable Register */ + REG_RTO_COUNTER = 6, /*Rx Timeout Counter Register */ + REG_DMA_EN = 7, /*DMA Enalbe Register */ + REG_TRIG_LVL = 8, /*Tx/Rx Trigger Level Register */ + REG_WAT_TIME = 9, /*Async Wait Time Register */ + REG_HANDSHAKE = 10, /*New HandShake Mode Register */ + REG_SLP_WAK = 11, /*Sleep Wakeup Reigster */ + REG_BTIF_ALL = 12, /*all btif controller's registers */ + REG_TX_DMA_ALL = 13, + REG_RX_DMA_ALL = 14, + REG_MAX +} ENUM_BTIF_REG_ID; + +typedef enum _MTK_BTIF_PM_OPID_ { + BTIF_PM_DPIDLE_EN, + BTIF_PM_DPIDLE_DIS, + BTIF_PM_SUSPEND, + BTIF_PM_RESUME, + BTIF_PM_RESTORE_NOIRQ, +} MTK_BTIF_PM_OPID; + +#define BTIF_HAL_TX_FIFO_SIZE (1024 * 4) + +/*-----------------------------------Enum Defination End--------------------------------*/ + +/*****************************structure definition***************************/ +/*IRQ related information*/ +typedef struct _MTK_BTIF_IRQ_STR_ { + const char *name; + bool is_irq_sup; + unsigned int irq_id; +#ifdef CONFIG_OF + unsigned int irq_flags; +#else + ENUM_IRQ_SENS_TYPE sens_type; + union { + ENUM_IRQ_LVL lvl_type; + ENUM_IRQ_EDGE edge_type; + }; +#endif + bool reg_flag; + irq_handler_t p_irq_handler; +} MTK_BTIF_IRQ_STR, *P_MTK_BTIF_IRQ_STR; + +typedef struct _DMA_VFIFO_ { + /*[Driver Access] vFIFO memory'svirtual address */ + unsigned char *p_vir_addr; + /*[HW Access] dma handle , physically address, set to DMA's HW Register */ + dma_addr_t phy_addr; + /*DMA's vFIFO size */ + unsigned int vfifo_size; + /*DMA's threshold value */ + unsigned int thre; +} DMA_VFIFO, *P_DMA_VFIFO; + +typedef unsigned int (*dma_rx_buf_write) (void *p_dma_info, + unsigned char *p_buf, + unsigned int buf_len); +typedef unsigned int (*btif_rx_buf_write) (void *p_btif_info, + unsigned char *p_buf, + unsigned int buf_len); + +/*DMA related information*/ +typedef struct _MTK_DMA_INFO_STR_ { + unsigned long base; + ENUM_DMA_DIR dir; + P_MTK_BTIF_IRQ_STR p_irq; + dma_rx_buf_write rx_cb; + P_DMA_VFIFO p_vfifo; +} MTK_DMA_INFO_STR, *P_MTK_DMA_INFO_STR; + +/*DMA related information*/ +typedef struct _MTK_BTIF_INFO_STR_ { + unsigned long base; /*base address */ + P_MTK_BTIF_IRQ_STR p_irq; /*irq related information */ + + unsigned int tx_fifo_size; /*BTIF tx FIFO size */ + unsigned int rx_fifo_size; /*BTIF rx FIFO size */ + + unsigned int tx_tri_lvl; /*BTIFtx trigger level in FIFO mode */ + unsigned int rx_tri_lvl; /*BTIFrx trigger level in FIFO mode */ + + unsigned int clk_gat_addr; /*clock gating address */ + unsigned int set_bit; /*enable clock gating bit */ + unsigned int clr_bit; /*clear clock gating bit */ + + unsigned int rx_data_len; /*rx data length */ + + btif_rx_buf_write rx_cb; + + struct kfifo *p_tx_fifo; /*tx fifo */ + spinlock_t tx_fifo_spinlock; /*tx fifo spinlock */ +} MTK_BTIF_INFO_STR, *P_MTK_BTIF_INFO_STR; + +/**********End of Structure Definition***********/ + +/***********register operation***********/ +#ifdef __KERNEL__ +/*byte write <1 byte> */ +#define btif_reg_sync_writeb(v, a) mt_reg_sync_writeb(v, a) +/*word write <2 byte> */ +#define btif_reg_sync_writew(v, a) mt_reg_sync_writew(v, a) +/*long write <4 byte> */ +#define btif_reg_sync_writel(v, a) mt_reg_sync_writel(v, a) +#else +/*byte write <1 byte> */ +#define btif_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) +/*word write <2 byte> */ +#define btif_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) +/*long write <4 byte> */ +#define btif_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) +#endif +#define BTIF_READ8(REG) __raw_readb((unsigned char *)(REG)) +#define BTIF_READ16(REG) __raw_readw((unsigned short *)(REG)) +#define BTIF_READ32(REG) __raw_readl((unsigned int *)(REG)) + +#define BTIF_SET_BIT(REG, BITVAL) do { \ +*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL)); \ +mb(); /**/ \ +} \ +while (0) +#define BTIF_CLR_BIT(REG, BITVAL) do { \ +(*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL)); \ +mb(); /**/\ +} \ +while (0) + +/***********end of register operation *********/ + +#endif /*__HAL_PUB_H_*/ diff --git a/drivers/misc/mediatek/connectivity/Kconfig b/drivers/misc/mediatek/connectivity/Kconfig new file mode 100644 index 0000000000000..4a944b1f0ebe5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/Kconfig @@ -0,0 +1,299 @@ +config MTK_COMBO + tristate "MediaTek Connectivity Combo Chip Support" + help + MTK connectivity combo chip driver for MT66xx + +# +# MTK Combo Chip Selection +# + +choice + prompt "Select Chip" + depends on MTK_COMBO + +config MTK_COMBO_CHIP_MT6620 + bool "MT6620" + help + this config is used to decided combo chip version + in current platform + is + MT6620 + +config MTK_COMBO_CHIP_MT6628 + bool "MT6628" + help + this config is used to decided combo chip version + in current platform + is + MT6628 + +config MTK_COMBO_CHIP_MT6630 + bool "MT6630" + help + this config is used to decided combo chip version + in current platform + is + MT6630 + +config MTK_COMBO_CHIP_CONSYS_6572 + bool "CONSYS_6572" + help + this config is used to decided SOC consys version + in current platform + is + MT6572 + +config MTK_COMBO_CHIP_CONSYS_6582 + bool "CONSYS_6582" + help + this config is used to decided SOC consys version + in current platform + is + MT6582 + +config MTK_COMBO_CHIP_CONSYS_8127 + bool "CONSYS_8127" + help + this config is used to decided SOC consys version + in current platform + is + MT6572 + +config MTK_COMBO_CHIP_CONSYS_7623 + bool "CONSYS_7623" + #select MTK_PLATFORM::="mt7623" + help + this config is used to decide SOC consys version + in current platform is MT7623 and prepare proper + system services like radio power on/off and firmware + download for the Bluetotoh and Wifi. + + +config MTK_COMBO_CHIP_CONSYS_6752 + bool "CONSYS_6752" + help + this config is used to decided SOC consys version + in current platform + is + MT6752 + +config MTK_COMBO_CHIP_CONSYS_6592 + bool "CONSYS_6592" + help + this config is used to decided SOC consys version + in current platform + is + MT6592 + +config MTK_COMBO_CHIP_CONSYS_8163 + bool "CONSYS_8163" + help + this config is used to decided SOC consys version + in current platform + is + MT8163 + +config MTK_COMBO_CHIP_CONSYS_6735 + bool "CONSYS_6735" + help + this config is used to decided SOC consys version + in current platform + is + MT6735 + +config MTK_COMBO_CHIP_CONSYS_6755 + bool "CONSYS_6755" + help + this config is used to decided SOC consys version + in current platform + is + MT6755 + +config MTK_COMBO_CHIP_CONSYS_6580 + bool "CONSYS_6580" + help + this config is used to decided SOC consys version + in current platform + is + MT6580 + +config MTK_COMBO_CHIP_CONSYS_6797 + bool "CONSYS_6797" + help + this config is used to decided SOC consys version + in current platform + is + MT6797 +endchoice + +config MTK_COMBO_CHIP + string + default "MT6620" if MTK_COMBO_CHIP_MT6620 + default "MT6628" if MTK_COMBO_CHIP_MT6628 + default "MT6630" if MTK_COMBO_CHIP_MT6630 + default "CONSYS_6572" if MTK_COMBO_CHIP_CONSYS_6572 + default "CONSYS_6582" if MTK_COMBO_CHIP_CONSYS_6582 + default "CONSYS_8127" if MTK_COMBO_CHIP_CONSYS_8127 + default "CONSYS_7623" if MTK_COMBO_CHIP_CONSYS_7623 + default "CONSYS_6752" if MTK_COMBO_CHIP_CONSYS_6752 + default "CONSYS_6755" if MTK_COMBO_CHIP_CONSYS_6755 + default "CONSYS_6592" if MTK_COMBO_CHIP_CONSYS_6592 + default "CONSYS_8163" if MTK_COMBO_CHIP_CONSYS_8163 + default "CONSYS_6735" if MTK_COMBO_CHIP_CONSYS_6735 + default "CONSYS_6580" if MTK_COMBO_CHIP_CONSYS_6580 + default "CONSYS_6797" if MTK_COMBO_CHIP_CONSYS_6797 + help + this feature is used to identify combo chip version or SOC chip + consys version. + +# +# Target Platform Selection +# +config MTK_COMBO_PLAT_PATH + string "Platform folder name" + depends on MTK_COMBO + default "sample" if MTK_COMBO_PLAT_SAMPLE + help + Specify platform folder under common driver platform folder: + mtk_wcn_combo/common/platform/* + +# +# MTK COMBO Chip Configuration +# +config MTK_COMBO_COMM + depends on MTK_COMBO + tristate "MediaTek Combo Chip Common part driver" + help + MediaTek combo chip common part driver + +#config MTK_COMBO_COMM_PS +# depends on MTK_COMBO_COMM +# bool "Enable PS support" +# default n +# help +# Enable PS support of common UART interface + +config MTK_COMBO_COMM_UART + depends on MTK_COMBO_COMM + tristate "Common interface UART" + help + Use UART for common part interface type + +config MTK_COMBO_COMM_SDIO + depends on MTK_COMBO_COMM + tristate "Common interface SDIO" + help + Use SDIO for common part interface type + +config MTK_COMBO_COMM_NPWR + depends on MTK_COMBO_COMM + bool "Enable NPWR support" + default n + help + Enable NPWR support of new power on swquence + +config MTK_COMBO_COMM_APO + depends on MTK_COMBO_COMM + bool "Enable always power on support" + #default y + help + Enable chip will always power on + +config MTK_COMBO_BT + tristate "MediaTek Combo Chip BT driver" + depends on BT && MTK_COMBO + select MTK_BTIF + help + MTK BT /dev/stpbt driver for Bluedroid + +config MTK_COMBO_BT_HCI + tristate "MediaTek Combo Chip BlueZ driver" + depends on BT && MTK_COMBO + select MTK_BTIF + help + MTK BT driver for BlueZ + +config MTK_COMBO_WIFI + tristate "MediaTek combo chip Wi-Fi support" + depends on MTK_COMBO + select MTK_BTIF + select WIRELESS_EXT + select WEXT_PRIV + +config MTK_WAPI_SUPPORT + bool "MTK_WAPI_SUPPORT" + depends on MTK_COMBO_WIFI + #default y + help + if it is set to TRUE: Support WAPI (WLAN Authentication and + Privacy Infrastructure) + +config MTK_PASSPOINT_R1_SUPPORT + bool "MTK_PASSPOINT_R1_SUPPORT" + depends on MTK_COMBO_WIFI + help + Support Passpoint R1 (Hotspot 2.0 R1) + +config MTK_PASSPOINT_R2_SUPPORT + bool "MTK_PASSPOINT_R2_SUPPORT" + depends on MTK_COMBO_WIFI + help + Support Passpoint R2 + +config MTK_WIFI_MCC_SUPPORT + bool "MTK_WIFI_MCC_SUPPORT" + depends on MTK_COMBO_WIFI + #default y + help + if it is set to TRUE, wlan will support Multi-Channel Concurrency, + otherwise, only support Single Channel Concurrency + +config MTK_DHCPV6C_WIFI + bool "MTK_DHCPV6C_WIFI" + help + no: disable this feature + +config MTK_CONN_LTE_IDC_SUPPORT + bool "MediaTek CONN LTE IDC support" + select MTK_CONN_MD + #default y + help + This option enables CONN LTE IDC support + +menuconfig GPS + tristate "GPS drivers" + #default y + ---help--- + Say Y here for supporting GPS. + +if GPS +config MTK_GPS + tristate "MediaTek GPS driver" + #default y + ---help--- + MTK GPS driver + To switch gps nmea port driver. + Set "yes" to turn on. + Set "no" to turn off. +endif # GPS + +config MTK_GPS_SUPPORT + tristate "MediaTek GPS driver" + select MTK_GPS + help + to switch GPS feature on the platform. + Set "yes" to turn on and set "no" + (with MTK_AGPS_APP=no at the same time) + to turn off. + +config MTK_GPS_REGISTER_SETTING + tristate "MediaTek GPS Register Setting" + depends on MTK_COMBO_GPS + help + GPS register settings. + +config MTK_GPS_EMI + tristate "MediaTek GPS EMI Driver" + depends on MTK_COMBO_GPS + help + GPS EMI driver is for MNL OFFLOAD feature. diff --git a/drivers/misc/mediatek/connectivity/Makefile b/drivers/misc/mediatek/connectivity/Makefile new file mode 100644 index 0000000000000..0947788d189a8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# Connectivity combo driver +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) +subdir-ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE +ifeq ($(CONFIG_ARM64), y) +subdir-ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + subdir-ccflags-y += -D WMT_IDC_SUPPORT=1 +else + subdir-ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + + obj-y += common/ + obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/ + obj-n := dummy.o + +# Otherwise we were called directly from the command line; +# invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +endif diff --git a/drivers/misc/mediatek/connectivity/common/Makefile b/drivers/misc/mediatek/connectivity/common/Makefile new file mode 100644 index 0000000000000..622b74430e132 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/Makefile @@ -0,0 +1,23 @@ +subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include +subdir-ccflags-y += -Werror -I$(srctree)/drivers/misc/mediatek/include/mt-plat + +#ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) +# obj-y += combo/ +#endif +#ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) +# subdir-ccflags-y += -D MT6628 +# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT +# obj-y += combo/ +#endif +#ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) +# subdir-ccflags-y += -D MT6630 +#ifneq ($(CONFIG_ARCH_MT2601),y) +# subdir-ccflags-y += -D MERGE_INTERFACE_SUPPORT +#endif +# obj-y += combo/ +#endif +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + obj-y += conn_soc/ +endif + +obj-y += common_detect/ diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile new file mode 100644 index 0000000000000..8d7dc690affd2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/Makefile @@ -0,0 +1,47 @@ +subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/$(ARCH_MTK_PROJECT)/dct/dct +subdir-ccflags-y += -DWMT_PLAT_ALPS=1 + +COMBO_CHIP_SUPPORT := false +ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifeq ($(COMBO_CHIP_SUPPORT), true) + subdir-ccflags-y += -D MTK_WCN_COMBO_CHIP_SUPPORT + ccflags-y += -I$(src)/../combo/linux/include +endif + +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + subdir-ccflags-y += -D MTK_WCN_SOC_CHIP_SUPPORT + ccflags-y += -I$(src)/../conn_soc/linux/include +endif + + +ifeq ($(CONFIG_MTK_COMBO),y) + ccflags-y += -I$(src)/drv_init/inc + obj-y += mtk_wcn_stub_alps.o + obj-y += wmt_stp_exp.o + obj-y += wmt_gpio.o + + obj-y += wmt_detect.o + obj-y += sdio_detect.o + obj-y += wmt_detect_pwr.o + + obj-y += drv_init/ +endif + +ifeq ($(CONFIG_MTK_COMBO),m) + obj-y += mtk_wcn_stub_alps.o + obj-y += wmt_stp_exp.o + obj-y += wmt_gpio.o + + obj-$(CONFIG_MTK_COMBO) += mtk_wmt_detect.o + mtk_wmt_detect-objs := wmt_detect.o + mtk_wmt_detect-objs += sdio_detect.o + mtk_wmt_detect-objs += wmt_detect_pwr.o +endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile new file mode 100644 index 0000000000000..bb84384b9a24f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/Makefile @@ -0,0 +1,22 @@ +ifeq ($(CONFIG_MTK_COMBO),y) + ccflags-y += -I$(src)/inc/ + ccflags-y += -I$(src)/../ + +ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN3 +endif +ifneq ($(filter "CONSYS_6797",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN3 +else ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN2 +endif + + obj-y += conn_drv_init.o + obj-y += common_drv_init.o + obj-y += bluetooth_drv_init.o + obj-y += gps_drv_init.o + obj-y += fm_drv_init.o + obj-y += wlan_drv_init.o + obj-($(CONFIG_MTK_COMBO_ANT)) += ant_drv_init.o + +endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c new file mode 100644 index 0000000000000..aa453f9397a47 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/ant_drv_init.c @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[ANT-MOD-INIT]" + +#include "wmt_detect.h" +#include "ant_drv_init.h" + +int do_ant_drv_init(int chip_id) +{ + int i_ret = -1; + + WMT_DETECT_INFO_FUNC("start to do ANT driver init\n"); + switch (chip_id) { + case 0x6630: + case 0x6797: + i_ret = mtk_wcn_stpant_drv_init(); + WMT_DETECT_INFO_FUNC("finish ANT driver init, i_ret:%d\n", i_ret); + break; + default: + WMT_DETECT_ERR_FUNC("chipid is not 6630,ANT is not supported!\n"); + } + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c new file mode 100644 index 0000000000000..47b0554334433 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c @@ -0,0 +1,35 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[BT-MOD-INIT]" + +#include "wmt_detect.h" +#include "bluetooth_drv_init.h" + +int do_bluetooth_drv_init(int chip_id) +{ + int i_ret = -1; + +#if defined(CONFIG_MTK_COMBO_BT) || defined(CONFIG_MTK_COMBO_BT_HCI) + WMT_DETECT_INFO_FUNC("start to do bluetooth driver init\n"); + i_ret = mtk_wcn_stpbt_drv_init(); + WMT_DETECT_INFO_FUNC("finish bluetooth driver init, i_ret:%d\n", i_ret); +#else + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_BT is not defined\n"); +#endif + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c new file mode 100644 index 0000000000000..f9c332ea266b9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c @@ -0,0 +1,103 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-MOD-INIT]" + +#include "wmt_detect.h" +#include "common_drv_init.h" + +static int do_combo_common_drv_init(int chip_id) +{ + int i_ret = 0; + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + int i_ret_tmp = 0; + + WMT_DETECT_DBG_FUNC("start to do combo driver init, chipid:0x%08x\n", chip_id); + + /* HIF-SDIO driver init */ + i_ret_tmp = mtk_wcn_hif_sdio_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_DBG_FUNC("HIF-SDIO driver init, i_ret:%d\n", i_ret); + + /* WMT driver init */ + i_ret_tmp = mtk_wcn_combo_common_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); + + /* STP-UART driver init */ + i_ret_tmp = mtk_wcn_stp_uart_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_DBG_FUNC("STP-UART driver init, i_ret:%d\n", i_ret); + + /* STP-SDIO driver init */ + i_ret_tmp = mtk_wcn_stp_sdio_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_DBG_FUNC("STP-SDIO driver init, i_ret:%d\n", i_ret); + +#else + i_ret = -1; + WMT_DETECT_ERR_FUNC("COMBO chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); +#endif + WMT_DETECT_DBG_FUNC("finish combo driver init\n"); + return i_ret; +} + +static int do_soc_common_drv_init(int chip_id) +{ + int i_ret = 0; + +#ifdef MTK_WCN_SOC_CHIP_SUPPORT + int i_ret_tmp = 0; + + WMT_DETECT_DBG_FUNC("start to do soc common driver init, chipid:0x%08x\n", chip_id); + + /* WMT driver init */ + i_ret_tmp = mtk_wcn_soc_common_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_DBG_FUNC("COMBO COMMON driver init, i_ret:%d\n", i_ret); + +#else + i_ret = -1; + WMT_DETECT_ERR_FUNC("SOC chip is not supported, please check CONFIG_MTK_COMBO_CHIP in kernel config\n"); +#endif + + WMT_DETECT_DBG_FUNC("TBD........\n"); + return i_ret; +} + +int do_common_drv_init(int chip_id) +{ + int i_ret = 0; + + WMT_DETECT_INFO_FUNC("start to do common driver init, chipid:0x%08x\n", chip_id); + + switch (chip_id) { + case 0x6620: + case 0x6628: + case 0x6630: + i_ret = do_combo_common_drv_init(chip_id); + break; + default: + i_ret = do_soc_common_drv_init(chip_id); + break; + } + + WMT_DETECT_INFO_FUNC("finish common driver init\n"); + + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c new file mode 100644 index 0000000000000..8112d2a1d95e2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c @@ -0,0 +1,80 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WCN-MOD-INIT]" + +#include "wmt_detect.h" +#include "conn_drv_init.h" +#include "common_drv_init.h" +#include "fm_drv_init.h" +#include "wlan_drv_init.h" +#include "bluetooth_drv_init.h" +#include "gps_drv_init.h" +#include "ant_drv_init.h" + +int __weak do_wlan_drv_init(int chip_id) +{ + WMT_DETECT_ERR_FUNC("Can not find wlan module for chip: %d !\n", chip_id); + return 0; +} + +int __weak do_ant_drv_init(int chip_id) +{ + WMT_DETECT_DBG_FUNC("Chip: %d can not support ANT !\n", chip_id); + return 0; +} + +int do_connectivity_driver_init(int chip_id) +{ + int i_ret = 0; + int tmp_ret = 0; + + tmp_ret = do_common_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) { + WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); + WMT_DETECT_ERR_FUNC("abort connectivity driver init, because common part is not ready\n"); + return i_ret; + } + + tmp_ret = do_bluetooth_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_gps_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_ERR_FUNC("do common driver init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_fm_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_ERR_FUNC("do fm module init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_wlan_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_ERR_FUNC("do wlan module init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_ant_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_ERR_FUNC("do ANT module init failed, ret:%d\n", tmp_ret); + + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c new file mode 100644 index 0000000000000..069c1cf13bbaf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[FM-MOD-INIT]" + +#include "wmt_detect.h" +#include "fm_drv_init.h" + +int do_fm_drv_init(int chip_id) +{ + WMT_DETECT_INFO_FUNC("start to do fm module init\n"); + +#ifdef CONFIG_MTK_FMRADIO + mtk_wcn_fm_init(); +#endif + + WMT_DETECT_INFO_FUNC("finish fm module init\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c new file mode 100644 index 0000000000000..6da1d70a3ca65 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c @@ -0,0 +1,35 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[GPS-MOD-INIT]" + +#include "wmt_detect.h" +#include "gps_drv_init.h" + +int do_gps_drv_init(int chip_id) +{ + int i_ret = -1; +#ifdef CONFIG_MTK_COMBO_GPS + WMT_DETECT_INFO_FUNC("start to do gps driver init\n"); + i_ret = mtk_wcn_stpgps_drv_init(); + WMT_DETECT_INFO_FUNC("finish gps driver init, i_ret:%d\n", i_ret); +#else + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_GPS is not defined\n"); +#endif + return i_ret; + +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h new file mode 100644 index 0000000000000..4a436a2362900 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/ant_drv_init.h @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _ANT_DRIVER_INIT_H_ +#define _ANT_DRIVER_INIT_H_ + +extern int do_ant_drv_init(int chip_id); +extern int mtk_wcn_stpant_drv_init(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h new file mode 100644 index 0000000000000..8a847d361fc8c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _BLUETOOTH_DRIVER_INIT_H_ +#define _BLUETOOTH_DRIVER_INIT_H_ + +extern int do_bluetooth_drv_init(int chip_id); +extern int mtk_wcn_stpbt_drv_init(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h new file mode 100644 index 0000000000000..ea01bd633c3c4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h @@ -0,0 +1,31 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _COMMON_DRV_INIT_H_ +#define _COMMON_DRV_INIT_H_ +extern int do_common_drv_init(int chip_id); + +/*defined in common part driver*/ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +extern int mtk_wcn_combo_common_drv_init(void); +extern int mtk_wcn_hif_sdio_drv_init(void); +extern int mtk_wcn_stp_uart_drv_init(void); +extern int mtk_wcn_stp_sdio_drv_init(void); +#endif + +#ifdef MTK_WCN_SOC_CHIP_SUPPORT +extern int mtk_wcn_soc_common_drv_init(void); +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h new file mode 100644 index 0000000000000..971193eade9e9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h @@ -0,0 +1,18 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _CONNECTIVITY_DRV_INIT_H_ +#define _CONNECTIVITY_DRV_INIT_H_ +extern int do_connectivity_driver_init(int chip_id); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h new file mode 100644 index 0000000000000..f6ea30addc5da --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _FM_DRV_INIT_H_ +#define _FM_DRV_INIT_H_ +extern int do_fm_drv_init(int chip_id); +extern int mtk_wcn_fm_init(void); +extern void mtk_wcn_fm_exit(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h new file mode 100644 index 0000000000000..006ce072c53b6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h @@ -0,0 +1,19 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _GPS_DRIVER_INIT_H_ +#define _GPS_DRIVER_INIT_H_ +extern int do_gps_drv_init(int chip_id); +extern int mtk_wcn_stpgps_drv_init(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h new file mode 100644 index 0000000000000..cb71b50bf950d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h @@ -0,0 +1,30 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WLAN_DRV_INIT_H_ +#define _WLAN_DRV_INIT_H_ + + +extern int do_wlan_drv_init(int chip_id); + +extern int mtk_wcn_wmt_wifi_init(void); + +#ifdef MTK_WCN_WLAN_GEN2 +extern int mtk_wcn_wlan_gen2_init(void); +#endif +#ifdef MTK_WCN_WLAN_GEN3 +extern int mtk_wcn_wlan_gen3_init(void); +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c new file mode 100644 index 0000000000000..5b0d039a4a425 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WLAN-MOD-INIT]" + +#include "wmt_detect.h" +#include "wlan_drv_init.h" + + +int do_wlan_drv_init(int chip_id) +{ + int i_ret = 0; + +#ifdef CONFIG_MTK_COMBO_WIFI + int ret = 0; + + WMT_DETECT_INFO_FUNC("start to do wlan module init 0x%x\n", chip_id); + + /* WMT-WIFI char dev init */ + ret = mtk_wcn_wmt_wifi_init(); + WMT_DETECT_INFO_FUNC("WMT-WIFI char dev init, ret:%d\n", ret); + i_ret += ret; + + switch (chip_id) { + case 0x6630: + case 0x6797: +#ifdef MTK_WCN_WLAN_GEN3 + /* WLAN driver init */ + ret = mtk_wcn_wlan_gen3_init(); + WMT_DETECT_INFO_FUNC("WLAN-GEN3 driver init, ret:%d\n", ret); + i_ret += ret; +#else + WMT_DETECT_ERR_FUNC("WLAN-GEN3 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); + i_ret = -1; +#endif + break; + + default: +#ifdef MTK_WCN_WLAN_GEN2 + /* WLAN driver init */ + ret = mtk_wcn_wlan_gen2_init(); + WMT_DETECT_INFO_FUNC("WLAN-GEN2 driver init, ret:%d\n", ret); + i_ret += ret; +#else + WMT_DETECT_ERR_FUNC("WLAN-GEN2 driver is not supported, please check CONFIG_MTK_COMBO_CHIP\n"); + i_ret = -1; +#endif + break; + } + + WMT_DETECT_INFO_FUNC("finish wlan module init\n"); + +#else + + WMT_DETECT_INFO_FUNC("CONFIG_MTK_COMBO_WIFI is not defined\n"); + +#endif + + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c new file mode 100644 index 0000000000000..fa8d437686f2d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c @@ -0,0 +1,605 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CMB_STUB_DBG_LOG 3 +#define CMB_STUB_INFO_LOG 2 +#define CMB_STUB_WARN_LOG 1 + +int gCmbStubLogLevel = CMB_STUB_INFO_LOG; + +#define CMB_STUB_LOG_INFO(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_INFO_LOG) \ + pr_warn(fmt, ##arg); \ +} while (0) +#define CMB_STUB_LOG_WARN(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_WARN_LOG) \ + pr_warn(fmt, ##arg); \ +} while (0) +#define CMB_STUB_LOG_DBG(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_DBG_LOG) \ + pr_debug(fmt, ##arg); \ +} while (0) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmt_detect.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 +#endif + +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +struct work_struct *g_sdio_1v_autok_wk = NULL; +#endif +int gConnectivityChipId = -1; + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +/* +* current used uart port name, default is "ttyMT2", +* will be changed when wmt driver init +*/ +char *wmt_uart_port_desc = "ttyMT2"; +EXPORT_SYMBOL(wmt_uart_port_desc); +#endif + +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data); +static void mtk_wcn_cmb_sdio_enable_eirq(void); +static void mtk_wcn_cmb_sdio_disable_eirq(void); +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data); + +struct sdio_ops mt_sdio_ops[4] = { + {NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm} +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb; +static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb; +static wmt_thermal_query_cb cmb_stub_thermal_ctrl_cb; +static CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0; +static wmt_deep_idle_ctrl_cb cmb_stub_deep_idle_ctrl_cb; +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +static wmt_get_drv_status cmb_stub_drv_status_ctrl_cb; +#endif +static wmt_func_do_reset cmb_stub_do_reset_cb; +/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X. + * This is used for ALPS backward compatible ONLY!!! Remove this table, related + * functions, and type definition after modifying other kernel built-in modules, + * such as AUDIO. [FixMe][GeorgeKuo] + */ +#if 0 +static CMB_STUB_AIF_X audio2aif[] = { + [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0, + [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1, + [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2, + [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3, +}; +#endif +static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler; +static atomic_t sdio_claim_irq_enable_flag; +static atomic_t irq_enable_flag; +static pm_callback_t mtk_wcn_cmb_sdio_pm_cb; +static void *mtk_wcn_cmb_sdio_pm_data; +static void *mtk_wcn_cmb_sdio_eirq_data; + +static u32 wifi_irq = 0xffffffff; +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +static void mtk_wcn_cmb_stub_1v_autok_work(struct work_struct *work) +{ + CMB_STUB_LOG_WARN("++enter++\n"); + mtk_wcn_cmb_stub_func_ctrl(11, 1); + mtk_wcn_cmb_stub_func_ctrl(11, 0); + CMB_STUB_LOG_WARN("--exit--\n"); +} + +/*! + * \brief A function for Getting current driver status:on/off + * + * \param driver type:0/bt,1/fm,2/gps,3/wifi,11/autok->run wmt turn on/off wifi flow + * + * \retval 0/off,2/on,-1/null pointer + */ +static int mtk_wcn_cmb_stub_drv_status(unsigned int type) +{ + int ret = -1; + + if (cmb_stub_drv_status_ctrl_cb) + ret = (*cmb_stub_drv_status_ctrl_cb) (type); + else + CMB_STUB_LOG_WARN("cmb_stub_drv_status_ctrl_cb is NULL\n"); + return ret; +} + +/*! + * \brief A 1v AutoK function for kernel DVFS driver calling when screen off + * + * \param void + * + * \retval int,mt6630 state:0/off,1/power on,2/func on, -1/null + */ +int mtk_wcn_cmb_stub_1vautok_for_dvfs(void) +{ + int wmt_status; + + CMB_STUB_LOG_WARN("DVFS driver call sdio 1v autok\n"); + + wmt_status = mtk_wcn_cmb_stub_drv_status(4); + CMB_STUB_LOG_WARN("current mt6630 status is %d\n", wmt_status); + if (0 == wmt_status) { + if (g_sdio_1v_autok_wk) + schedule_work(g_sdio_1v_autok_wk); + else + CMB_STUB_LOG_WARN("g_sdio_1v_autok_wk is NULL\n"); + } else if ((2 == wmt_status) || (1 == wmt_status)) { + CMB_STUB_LOG_WARN("mt6630 is on state,skip AUTOK\n"); + } else { + CMB_STUB_LOG_WARN("mt6630 is unknown state(%d)\n", wmt_status); + } + + return wmt_status; + +} +#endif +/*! + * \brief A registration function for WMT-PLAT to register itself to CMB-STUB. + * + * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register + * itself and related callback functions when driver being loaded into kernel. + * + * \param p_stub_cb a pointer carrying CMB_STUB_CB information + * + * \retval 0 operation success + * \retval -1 invalid parameters + */ +int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb) +{ + if ((!p_stub_cb) + || (p_stub_cb->size != sizeof(CMB_STUB_CB))) { + CMB_STUB_LOG_WARN("[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n", + p_stub_cb, (p_stub_cb) ? p_stub_cb->size : 0); + return -1; + } + + CMB_STUB_LOG_DBG("[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n", p_stub_cb, p_stub_cb->size); + + cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb; + cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb; + cmb_stub_thermal_ctrl_cb = p_stub_cb->thermal_query_cb; + cmb_stub_deep_idle_ctrl_cb = p_stub_cb->deep_idle_ctrl_cb; + cmb_stub_do_reset_cb = p_stub_cb->wmt_do_reset_cb; +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + cmb_stub_drv_status_ctrl_cb = p_stub_cb->get_drv_status_cb; + g_sdio_1v_autok_wk = vmalloc(sizeof(struct work_struct)); + if (!g_sdio_1v_autok_wk) + CMB_STUB_LOG_WARN("vmalloc work_struct(%zd) fail\n", sizeof(struct work_struct)); + else + INIT_WORK(g_sdio_1v_autok_wk, mtk_wcn_cmb_stub_1v_autok_work); + +#endif + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg); +/*! + * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB. + * + * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to + * unregister itself and clear callback function references. + * + * \retval 0 operation success + */ +int mtk_wcn_cmb_stub_unreg(void) +{ + cmb_stub_aif_ctrl_cb = NULL; + cmb_stub_func_ctrl_cb = NULL; + cmb_stub_thermal_ctrl_cb = NULL; + cmb_stub_deep_idle_ctrl_cb = NULL; + cmb_stub_do_reset_cb = NULL; + CMB_STUB_LOG_INFO("[cmb_stub] unregistered\n"); /* KERN_DEBUG */ + +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + if (g_sdio_1v_autok_wk) { + vfree(g_sdio_1v_autok_wk); + g_sdio_1v_autok_wk = NULL; + } +#endif + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg); + +/* stub functions for kernel to control audio path pin mux */ +int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + int ret; + + if ((CMB_STUB_AIF_MAX <= state) + || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { + + CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n", state, ctrl); + return -1; + } + + /* avoid the early interrupt before we register the eirq_handler */ + if (cmb_stub_aif_ctrl_cb) { + ret = (*cmb_stub_aif_ctrl_cb) (state, ctrl); + CMB_STUB_LOG_INFO("[cmb_stub] aif_ctrl_cb state(%d->%d) ctrl(%d) ret(%d)\n", + cmb_stub_aif_stat, state, ctrl, ret); /* KERN_DEBUG */ + + cmb_stub_aif_stat = state; + } else { + CMB_STUB_LOG_WARN("[cmb_stub] aif_ctrl_cb null\n"); + ret = -2; + } + return ret; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl); + +/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X + * for ALPS backward compatible ONLY!!! Remove this table, related functions, + * and type definition after modifying other kernel built-in modules, such as + * AUDIO. [FixMe][GeorgeKuo] + */ + +void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on) +{ + if (cmb_stub_func_ctrl_cb) + (*cmb_stub_func_ctrl_cb) (type, on); + else + CMB_STUB_LOG_WARN("[cmb_stub] func_ctrl_cb null\n"); +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl); + +int mtk_wcn_cmb_stub_query_ctrl(void) +{ + signed long temp = 0; + + if (cmb_stub_thermal_ctrl_cb) + temp = (*cmb_stub_thermal_ctrl_cb) (); + else + CMB_STUB_LOG_WARN("[cmb_stub] thermal_ctrl_cb null\n"); + + return temp; +} + +/*platform-related APIs*/ +/* void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); */ +/* void set_device_working_ability(UINT32 clockId, MT6573_STATE state); */ + +static int _mt_combo_plt_do_deep_idle(COMBO_IF src, int enter) +{ + int ret = -1; + +#if 0 + if (src != COMBO_IF_UART && src != COMBO_IF_MSDC && src != COMBO_IF_BTIF) { + CMB_STUB_LOG_WARN("src = %d is error\n", src); + return ret; + } + if (src >= 0 && src < COMBO_IF_MAX) + CMB_STUB_LOG_INFO("src = %s, to enter deep idle? %d\n", combo_if_name[src], enter); +#endif + /*TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI + to decide if the msdc will enter deep idle safely */ + + switch (src) { + case COMBO_IF_UART: + if (enter == 0) { + /* clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ + /* disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +#if 0 + ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 0); + if (ret < 0) + CMB_STUB_LOG_WARN("[CMB] %s exit deep idle failed\n", wmt_uart_port_desc); +#endif +#endif + } else { + /* set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ + /* enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +#if 0 + ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 1); + if (ret < 0) + CMB_STUB_LOG_WARN("[CMB] %s enter deep idle failed\n", wmt_uart_port_desc); +#endif +#endif + } + ret = 0; + break; + + case COMBO_IF_MSDC: + if (enter == 0) { + /* for common sdio hif */ + /* clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ + } else { + /* for common sdio hif */ + /* set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ + } + ret = 0; + break; + + case COMBO_IF_BTIF: + if (cmb_stub_deep_idle_ctrl_cb) + ret = (*cmb_stub_deep_idle_ctrl_cb) (enter); + else + CMB_STUB_LOG_WARN("NULL function pointer\n"); + + if (ret) + CMB_STUB_LOG_WARN("%s deep idle fail(%d)\n", enter == 1 ? "enter" : "exit", ret); + else + CMB_STUB_LOG_DBG("%s deep idle ok(%d)\n", enter == 1 ? "enter" : "exit", ret); + break; + default: + break; + } + + return ret; +} + +int mt_combo_plt_enter_deep_idle(COMBO_IF src) +{ + /* return 0; */ + /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ + return _mt_combo_plt_do_deep_idle(src, 1); +} +EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle); + +int mt_combo_plt_exit_deep_idle(COMBO_IF src) +{ + /* return 0; */ + /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ + return _mt_combo_plt_do_deep_idle(src, 0); +} +EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle); + +int mtk_wcn_wmt_chipid_query(void) +{ + return gConnectivityChipId; +} +EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query); + +void mtk_wcn_wmt_set_chipid(int chipid) +{ + CMB_STUB_LOG_INFO("set current consys chipid (0x%x)\n", chipid); + gConnectivityChipId = chipid; +} +EXPORT_SYMBOL(mtk_wcn_wmt_set_chipid); + +int mtk_wcn_cmb_stub_do_reset(unsigned int type) +{ + if (cmb_stub_do_reset_cb) + return (*cmb_stub_do_reset_cb) (type); + else + return -1; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_do_reset); + +static void mtk_wcn_cmb_sdio_enable_eirq(void) +{ + if (atomic_read(&irq_enable_flag)) + CMB_STUB_LOG_DBG("wifi eint has been enabled\n"); + else { + atomic_set(&irq_enable_flag, 1); + if (wifi_irq != 0xfffffff) { + enable_irq(wifi_irq); + CMB_STUB_LOG_DBG(" enable WIFI EINT irq %d !!\n", wifi_irq); + } + } +} + +static void mtk_wcn_cmb_sdio_disable_eirq(void) +{ + if (!atomic_read(&irq_enable_flag)) + CMB_STUB_LOG_DBG("wifi eint has been disabled!\n"); + else { + if (wifi_irq != 0xfffffff) { + disable_irq_nosync(wifi_irq); + CMB_STUB_LOG_DBG("disable WIFI EINT irq %d !!\n", wifi_irq); + } + atomic_set(&irq_enable_flag, 0); + } +} + +irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data) +{ + if ((NULL != mtk_wcn_cmb_sdio_eirq_handler)&&(0 != atomic_read(&sdio_claim_irq_enable_flag))) + mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data); + return IRQ_HANDLED; +} + +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data) +{ + struct device_node *node; + int ret = -EINVAL; +#if 0 + unsigned int gpio_wifi_eint_pin; +#endif + + CMB_STUB_LOG_INFO("enter %s\n", __func__); + mtk_wcn_sdio_irq_flag_set(0); + atomic_set(&irq_enable_flag, 0); + mtk_wcn_cmb_sdio_eirq_data = data; + mtk_wcn_cmb_sdio_eirq_handler = irq_handler; + + node = (struct device_node *)of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); + if (node) { +#if 0 + gpio_wifi_eint_pin = of_get_gpio(node, 5); + CMB_STUB_LOG_INFO("WIFI EINT pin %d !!\n", gpio_wifi_eint_pin); + wifi_irq = gpio_to_irq(gpio_wifi_eint_pin); +#else + wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */ +#endif +#if 1 + ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW, + "WIFI-eint", NULL); + CMB_STUB_LOG_DBG("WIFI EINT irq %d !!\n", wifi_irq); +#endif + + if (ret) + CMB_STUB_LOG_WARN("WIFI EINT IRQ LINE NOT AVAILABLE!!\n"); + else + mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/ + } else + CMB_STUB_LOG_WARN("[%s] can't find connectivity compatible node\n", __func__); + + CMB_STUB_LOG_INFO("exit %s\n", __func__); +} + +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data) +{ + CMB_STUB_LOG_DBG("mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data); + /* register pm change callback */ + mtk_wcn_cmb_sdio_pm_cb = pm_cb; + mtk_wcn_cmb_sdio_pm_data = data; +} + +static void mtk_wcn_cmb_sdio_on(int sdio_port_num) +{ + pm_message_t state = {.event = PM_EVENT_USER_RESUME }; + + CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_on (%d)\n", sdio_port_num); + + /* 1. disable sdio eirq */ + mtk_wcn_cmb_sdio_disable_eirq(); + + /* 2. call sd callback */ + if (mtk_wcn_cmb_sdio_pm_cb) { + /* pr_warn("mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p)\n", + * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ + mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); + } else + CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_on no sd callback!!\n"); +} + +static void mtk_wcn_cmb_sdio_off(int sdio_port_num) +{ + pm_message_t state = {.event = PM_EVENT_USER_SUSPEND }; + + CMB_STUB_LOG_INFO("mtk_wcn_cmb_sdio_off (%d)\n", sdio_port_num); + + /* 1. call sd callback */ + if (mtk_wcn_cmb_sdio_pm_cb) { + /* pr_warn("mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p)\n", + * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); */ + mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); + } else + CMB_STUB_LOG_WARN("mtk_wcn_cmb_sdio_off no sd callback!!\n"); + + /* 2. disable sdio eirq */ + mtk_wcn_cmb_sdio_disable_eirq(); +} + +int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on) +{ + CMB_STUB_LOG_DBG("mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", sdio_port_num, on); + if (on) { +#if 1 + CMB_STUB_LOG_DBG("board_sdio_ctrl force off before on\n"); + mtk_wcn_cmb_sdio_off(sdio_port_num); +#else + CMB_STUB_LOG_WARN("skip sdio off before on\n"); +#endif + /* off -> on */ + mtk_wcn_cmb_sdio_on(sdio_port_num); + if (wifi_irq != 0xfffffff) + irq_set_irq_wake(wifi_irq, 1); + else + CMB_STUB_LOG_WARN("wifi_irq is not available\n"); + } else { + if (wifi_irq != 0xfffffff) + irq_set_irq_wake(wifi_irq, 0); + else + CMB_STUB_LOG_WARN("wifi_irq is not available\n"); + /* on -> off */ + mtk_wcn_cmb_sdio_off(sdio_port_num); + } + + return 0; +} +EXPORT_SYMBOL(board_sdio_ctrl); + +int mtk_wcn_sdio_irq_flag_set(int flag) +{ + if (0 != flag) + atomic_set(&sdio_claim_irq_enable_flag, 1); + else + atomic_set(&sdio_claim_irq_enable_flag, 0); + + CMB_STUB_LOG_DBG("sdio_claim_irq_enable_flag:%d\n", atomic_read(&sdio_claim_irq_enable_flag)); + + return atomic_read(&sdio_claim_irq_enable_flag); +} +EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set); diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c new file mode 100644 index 0000000000000..7ac5ac73ef5d8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c @@ -0,0 +1,269 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[SDIO-DETECT]" + +#include "wmt_detect.h" + +#if MTK_HIF_SDIO_AUTOK_ENABLED +#include +#endif + +unsigned int gComboChipId = -1; +struct sdio_func *g_func = NULL; + +MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = { + /* MT6620 *//* Not an SDIO standard class device */ + {{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620}, /* SDIO1:FUNC1:WIFI */ + {{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620}, /* SDIO2:FUNC1:BT+FM+GPS */ + {{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628}, + + /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630}, + +}; + +/* Supported SDIO device table */ +static const struct sdio_device_id mtk_sdio_id_tbl[] = { + /* MT6618 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */ + {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */ + {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ + + /* MT6619 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */ + + /* MT6620 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */ + {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */ + {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT5921 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x5921)}, + + /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6628)}, + + /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6630)}, + { /* end: all zeroes */ }, +}; + +static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id); + +static void sdio_detect_remove(struct sdio_func *func); + +static struct sdio_driver mtk_sdio_client_drv = { + .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ + .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ + .probe = sdio_detect_probe, + .remove = sdio_detect_remove, +}; + +static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id); + +int hif_sdio_is_chipid_valid(int chipId) +{ + int index = -1; + + int left = 0; + int middle = 0; + int right = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]) - 1; + + if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId)) + return index; + + middle = (left + right) / 2; + + while (left <= right) { + if (chipId > gChipInfoArray[middle].chipId) { + left = middle + 1; + } else if (chipId < gChipInfoArray[middle].chipId) { + right = middle - 1; + } else { + index = middle; + break; + } + middle = (left + right) / 2; + } + + if (0 > index) + WMT_DETECT_ERR_FUNC("no supported chipid found\n"); + else + WMT_DETECT_INFO_FUNC("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId); + + return index; +} + +int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id) +{ + int maxIndex = sizeof(gChipInfoArray) / sizeof(gChipInfoArray[0]); + int index = 0; + struct sdio_device_id *localId = NULL; + int chipId = -1; + + for (index = 0; index < maxIndex; index++) { + localId = &(gChipInfoArray[index].deviceId); + if ((localId->vendor == id->vendor) && (localId->device == id->device)) { + chipId = gChipInfoArray[index].chipId; + WMT_DETECT_INFO_FUNC + ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index, + localId->vendor, localId->device, chipId); + gComboChipId = chipId; + mtk_wcn_wmt_set_chipid(gComboChipId); + break; + } + } + if (0 > chipId) { + WMT_DETECT_ERR_FUNC("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, + id->device); + } + + return chipId; +} + +int sdio_detect_query_chipid(int waitFlag) +{ + unsigned int timeSlotMs = 200; + unsigned int maxTimeSlot = 15; + unsigned int counter = 0; + /* gComboChipId = 0x6628; */ + if (0 == waitFlag) + return gComboChipId; + if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) + return gComboChipId; + + while (counter < maxTimeSlot) { + if (0 <= hif_sdio_is_chipid_valid(gComboChipId)) + break; + msleep(timeSlotMs); + counter++; + } + + return gComboChipId; +} + +int sdio_detect_do_autok(int chipId) +{ + int i_ret = 0; + +#if MTK_HIF_SDIO_AUTOK_ENABLED +#if 0 + BOOTMODE boot_mode; + + boot_mode = get_boot_mode(); + + if (boot_mode == META_BOOT) { + WMT_DETECT_INFO_FUNC("omit autok in meta mode\n"); + return 0; + } +#endif + if (0x6630 == chipId) { +#ifdef CONFIG_SDIOAUTOK_SUPPORT + if (NULL != g_func) { + WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready++\n"); + i_ret = wait_sdio_autok_ready(g_func->card->host); + WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready--\n"); + if (0 == i_ret) { + WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return success\n"); + } else { + WMT_DETECT_INFO_FUNC("wait_sdio_autok_ready return fail, i_ret:%d\n", i_ret); + gComboChipId = -1; + } + } else { + WMT_DETECT_INFO_FUNC("g_func NULL, omit autok\n"); + } +#else + i_ret = 0; + WMT_DETECT_INFO_FUNC("MTK_SDIOAUTOK_SUPPORT not defined\n"); +#endif + } else { + WMT_DETECT_INFO_FUNC("MT%x does not support SDIO3.0 autoK is not needed\n", chipId); + } +#else + i_ret = 0; + WMT_DETECT_INFO_FUNC("MTK_HIF_SDIO_AUTOK_ENABLED is not defined\n"); +#endif + return i_ret; +} + +/*! + * \brief hif_sdio probe function + * + * hif_sdio probe function called by mmc driver when any matched SDIO function + * is detected by it. + * + * \param func + * \param id + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int chipId = 0; + + WMT_DETECT_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); + chipId = hif_sdio_match_chipid_by_dev_id(id); + + if ((0x6630 == chipId) && (1 == func->num)) { + int ret = 0; + + g_func = func; + WMT_DETECT_INFO_FUNC("autok function detected, func:0x%p\n", g_func); + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + if (ret) + WMT_DETECT_ERR_FUNC("sdio_enable_func failed!\n"); + } + + return 0; +} + +static void sdio_detect_remove(struct sdio_func *func) +{ + if (g_func == func) { + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + g_func = NULL; + } + WMT_DETECT_INFO_FUNC("do sdio remove\n"); +} + +int sdio_detect_init(void) +{ + int ret = -1; + /* register to mmc driver */ + ret = sdio_register_driver(&mtk_sdio_client_drv); + WMT_DETECT_INFO_FUNC("sdio_register_driver() ret=%d\n", ret); + return 0; +} + +int sdio_detect_exit(void) +{ + g_func = NULL; + /* register to mmc driver */ + sdio_unregister_driver(&mtk_sdio_client_drv); + WMT_DETECT_INFO_FUNC("sdio_unregister_driver\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h new file mode 100644 index 0000000000000..3a0bff9def1b1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _SDIO_DETECT_H_ +#define _SDIO_DETECT_H_ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SDIOAUTOK_SUPPORT +#define MTK_HIF_SDIO_AUTOK_ENABLED 1 +extern int wait_sdio_autok_ready(void *); +#else +#define MTK_HIF_SDIO_AUTOK_ENABLED 0 +#endif + +typedef struct _MTK_WCN_HIF_SDIO_CHIP_INFO_ { + struct sdio_device_id deviceId; + unsigned int chipId; +} MTK_WCN_HIF_SDIO_CHIP_INFO, *P_MTK_WCN_HIF_SDIO_CHIP_INFO; + +extern int sdio_detect_exit(void); +extern int sdio_detect_init(void); +extern int sdio_detect_query_chipid(int waitFlag); +extern int hif_sdio_is_chipid_valid(int chipId); + +extern int sdio_detect_do_autok(int chipId); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c new file mode 100644 index 0000000000000..487852df8f20f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c @@ -0,0 +1,380 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include +#include + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DETECT]" + +#include "wmt_detect.h" +#include "wmt_gpio.h" + +#if MTK_WCN_REMOVE_KO +#include "conn_drv_init.h" +#endif +#ifdef CONFIG_COMPAT +#include +#endif + +#define WMT_DETECT_MAJOR 154 +#define WMT_DETECT_DEV_NUM 1 +#define WMT_DETECT_DRVIER_NAME "mtk_wcn_detect" +#define WMT_DETECT_DEVICE_NAME "wmtdetect" + +struct class *pDetectClass = NULL; +struct device *pDetectDev = NULL; +static int gWmtDetectMajor = WMT_DETECT_MAJOR; +static struct cdev gWmtDetectCdev; +unsigned int gWmtDetectDbgLvl = WMT_DETECT_LOG_INFO; + + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +inline unsigned int wmt_plat_get_soc_chipid(void) +{ + WMT_DETECT_INFO_FUNC("no soc chip supported, due to MTK_WCN_SOC_CHIP_SUPPORT is not set.\n"); + return -1; +} +#endif + +static int wmt_detect_open(struct inode *inode, struct file *file) +{ + WMT_DETECT_INFO_FUNC("open major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static int wmt_detect_close(struct inode *inode, struct file *file) +{ + WMT_DETECT_INFO_FUNC("close major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static ssize_t wmt_detect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + WMT_DETECT_INFO_FUNC(" ++\n"); + WMT_DETECT_INFO_FUNC(" --\n"); + + return 0; +} + +ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + WMT_DETECT_INFO_FUNC(" ++\n"); + WMT_DETECT_INFO_FUNC(" --\n"); + + return 0; +} + +static long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + WMT_DETECT_INFO_FUNC("cmd (%d),arg(%ld)\n", cmd, arg); + + switch (cmd) { + case COMBO_IOCTL_GET_CHIP_ID: + /*just get chipid from sdio-detect module */ + /*check if external combo chip exists or not */ + /*if yes, just return combo chip id */ + /*if no, get soc chipid */ + retval = mtk_wcn_wmt_chipid_query(); + break; + + case COMBO_IOCTL_SET_CHIP_ID: + mtk_wcn_wmt_set_chipid(arg); + + break; + + case COMBO_IOCTL_EXT_CHIP_PWR_ON: + retval = wmt_detect_ext_chip_pwr_on(); + break; + + case COMBO_IOCTL_EXT_CHIP_DETECT: + retval = wmt_detect_ext_chip_detect(); + break; + + case COMBO_IOCTL_EXT_CHIP_PWR_OFF: + retval = wmt_detect_ext_chip_pwr_off(); + break; + + case COMBO_IOCTL_DO_SDIO_AUDOK: + retval = sdio_detect_do_autok(arg); + break; + + case COMBO_IOCTL_GET_SOC_CHIP_ID: + retval = wmt_plat_get_soc_chipid(); + /*get soc chipid by HAL interface */ + break; + + case COMBO_IOCTL_MODULE_CLEANUP: +#if (MTK_WCN_REMOVE_KO) + /*deinit SDIO-DETECT module */ + retval = sdio_detect_exit(); +#else + WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); +#endif + break; + + case COMBO_IOCTL_DO_MODULE_INIT: +#if (MTK_WCN_REMOVE_KO) + /*deinit SDIO-DETECT module */ + retval = do_connectivity_driver_init(arg); +#else + WMT_DETECT_INFO_FUNC("no MTK_WCN_REMOVE_KO defined\n"); +#endif + break; + + default: + WMT_DETECT_WARN_FUNC("unknown cmd (%d)\n", cmd); + retval = 0; + break; + } + return retval; +} +#ifdef CONFIG_COMPAT +static long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + WMT_DETECT_INFO_FUNC("cmd (%d)\n", cmd); + ret = wmt_detect_unlocked_ioctl(filp, cmd, arg); + return ret; +} +#endif +const struct file_operations gWmtDetectFops = { + .open = wmt_detect_open, + .release = wmt_detect_close, + .read = wmt_detect_read, + .write = wmt_detect_write, + .unlocked_ioctl = wmt_detect_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = WMT_compat_detect_ioctl, +#endif +}; + +int wmt_detect_ext_chip_pwr_on(void) +{ + /*pre power on external chip */ + /* wmt_plat_pwr_ctrl(FUNC_ON); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + WMT_DETECT_INFO_FUNC("++\n"); + if (0 != wmt_detect_chip_pwr_ctrl(1)) + return -1; + if (0 != wmt_detect_sdio_pwr_ctrl(1)) + return -2; + return 0; +#else + WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); + return -1; +#endif +} + +int wmt_detect_ext_chip_pwr_off(void) +{ + /*pre power off external chip */ + /* wmt_plat_pwr_ctrl(FUNC_OFF); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + WMT_DETECT_INFO_FUNC("--\n"); + wmt_detect_sdio_pwr_ctrl(0); + return wmt_detect_chip_pwr_ctrl(0); +#else + WMT_DETECT_INFO_FUNC("combo chip is not supported\n"); + return 0; +#endif +} + +int wmt_detect_ext_chip_detect(void) +{ + int iRet = -1; + unsigned int chipId = -1; + /*if there is no external combo chip, return -1 */ + int bgfEintStatus = -1; + + WMT_DETECT_INFO_FUNC("++\n"); + /*wait for a stable time */ + msleep(20); + + /*read BGF_EINT_PIN status */ + bgfEintStatus = wmt_detect_read_ext_cmb_status(); + + if (0 == bgfEintStatus) { + /*external chip does not exist */ + WMT_DETECT_INFO_FUNC("external combo chip not detected\n"); + } else if (1 == bgfEintStatus) { + /*combo chip exists */ + WMT_DETECT_INFO_FUNC("external combo chip detected\n"); + + /*detect chipid by sdio_detect module */ + chipId = sdio_detect_query_chipid(1); + if (0 <= hif_sdio_is_chipid_valid(chipId)) + WMT_DETECT_INFO_FUNC("valid external combo chip id (0x%x)\n", chipId); + else + WMT_DETECT_INFO_FUNC("invalid external combo chip id (0x%x)\n", chipId); + iRet = 0; + } else { + /*Error exists */ + WMT_DETECT_ERR_FUNC("error happens when detecting combo chip\n"); + } + WMT_DETECT_INFO_FUNC("--\n"); + /*return 0 */ + return iRet; + /*todo: if there is external combo chip, power on chip return 0 */ +} + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +static int wmt_detect_probe(struct platform_device *pdev) +{ + int ret = 0; + + WMT_DETECT_ERR_FUNC("platform name: %s\n", pdev->name); + ret = wmt_gpio_init(pdev); + if (-1 == ret) + WMT_DETECT_ERR_FUNC("gpio init fail ret:%d\n", ret); + return ret; +} + +static int wmt_detect_remove(struct platform_device *pdev) +{ + wmt_gpio_deinit(); + return 0; +} +#endif + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +static struct of_device_id wmt_detect_match[] = { + { .compatible = "mediatek,connectivity-combo", }, + {} +}; +MODULE_DEVICE_TABLE(of, wmt_detect_match); + +static struct platform_driver wmt_detect_driver = { + .probe = wmt_detect_probe, + .remove = wmt_detect_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mediatek,connectivity-combo", + .of_match_table = wmt_detect_match, + }, +}; +#endif + +/*module_platform_driver(wmt_detect_driver);*/ +static int wmt_detect_driver_init(void) +{ + dev_t devID = MKDEV(gWmtDetectMajor, 0); + int cdevErr = -1; + int ret = -1; + + ret = register_chrdev_region(devID, WMT_DETECT_DEV_NUM, WMT_DETECT_DRVIER_NAME); + if (ret) { + WMT_DETECT_ERR_FUNC("fail to register chrdev\n"); + return ret; + } + + cdev_init(&gWmtDetectCdev, &gWmtDetectFops); + gWmtDetectCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gWmtDetectCdev, devID, WMT_DETECT_DEV_NUM); + if (cdevErr) { + WMT_DETECT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); + goto err1; + } + + pDetectClass = class_create(THIS_MODULE, WMT_DETECT_DEVICE_NAME); + if (IS_ERR(pDetectClass)) { + WMT_DETECT_ERR_FUNC("class create fail, error code(%ld)\n", PTR_ERR(pDetectClass)); + goto err1; + } + + pDetectDev = device_create(pDetectClass, NULL, devID, NULL, WMT_DETECT_DEVICE_NAME); + if (IS_ERR(pDetectDev)) { + WMT_DETECT_ERR_FUNC("device create fail, error code(%ld)\n", PTR_ERR(pDetectDev)); + goto err2; + } + + WMT_DETECT_INFO_FUNC("driver(major %d) installed success\n", gWmtDetectMajor); + + /*init SDIO-DETECT module */ + sdio_detect_init(); + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + ret = platform_driver_register(&wmt_detect_driver); + if (ret) + WMT_DETECT_ERR_FUNC("platform driver register fail ret:%d\n", ret); +#endif + + return 0; + +err2: + + if (pDetectClass) { + class_destroy(pDetectClass); + pDetectClass = NULL; + } + +err1: + + if (cdevErr == 0) + cdev_del(&gWmtDetectCdev); + + if (ret == 0) { + unregister_chrdev_region(devID, WMT_DETECT_DEV_NUM); + gWmtDetectMajor = -1; + } + + WMT_DETECT_ERR_FUNC("fail\n"); + + return -1; +} + +static void wmt_detect_driver_exit(void) +{ + dev_t dev = MKDEV(gWmtDetectMajor, 0); + + if (pDetectDev) { + device_destroy(pDetectClass, dev); + pDetectDev = NULL; + } + + if (pDetectClass) { + class_destroy(pDetectClass); + pDetectClass = NULL; + } + + cdev_del(&gWmtDetectCdev); + unregister_chrdev_region(dev, WMT_DETECT_DEV_NUM); + +#if !(MTK_WCN_REMOVE_KO) +/*deinit SDIO-DETECT module*/ + sdio_detect_exit(); +#endif + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + platform_driver_unregister(&wmt_detect_driver); +#endif + + WMT_DETECT_INFO_FUNC("done\n"); +} + +module_init(wmt_detect_driver_init); +module_exit(wmt_detect_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhiguo.Niu & Chaozhong.Liang @ MBJ/WCNSE/SS1"); + +module_param(gWmtDetectMajor, uint, 0); diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h new file mode 100644 index 0000000000000..7e152bfd39ec9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h @@ -0,0 +1,114 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WMT_DETECT_H_ +#define _WMT_DETECT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +#define MTK_WCN_REMOVE_KO 1 +#else +#define MTK_WCN_REMOVE_KO 0 +#endif + +#include "sdio_detect.h" +#include "wmt_detect_pwr.h" +#include + +#define WMT_DETECT_LOG_LOUD 4 +#define WMT_DETECT_LOG_DBG 3 +#define WMT_DETECT_LOG_INFO 2 +#define WMT_DETECT_LOG_WARN 1 +#define WMT_DETECT_LOG_ERR 0 + +extern unsigned int gWmtDetectDbgLvl; + +#define WMT_DETECT_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_LOUD) \ + pr_debug(DFT_TAG"[L]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_DETECT_DBG_FUNC(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_DBG) \ + pr_debug(DFT_TAG"[D]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_DETECT_INFO_FUNC(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_INFO) \ + pr_err(DFT_TAG"[I]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_DETECT_WARN_FUNC(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_WARN) \ + pr_warn(DFT_TAG"[W]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ +} while (0) +#define WMT_DETECT_ERR_FUNC(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_ERR) \ + pr_err(DFT_TAG"[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ +} while (0) + +#define WMT_IOC_MAGIC 'w' +#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_IOC_MAGIC, 1, int) +#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_IOC_MAGIC, 2, int) +#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_IOC_MAGIC, 3, int) +#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_IOC_MAGIC, 4, int) +#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_IOC_MAGIC, 5, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_IOC_MAGIC, 6, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_IOC_MAGIC, 7, int) +#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_IOC_MAGIC, 8, int) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +********************************************************************************/ +extern int wmt_detect_ext_chip_detect(void); +extern int wmt_detect_ext_chip_pwr_on(void); +extern int wmt_detect_ext_chip_pwr_off(void); + +#ifdef MTK_WCN_SOC_CHIP_SUPPORT +extern unsigned int wmt_plat_get_soc_chipid(void); +#endif + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver + * + * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" + * @ enable - "1", enable deep idle; "0", disable deep idle + * + * Return 0 if success, else -1 + */ +extern unsigned int mtk_uart_pdn_enable(char *port, int enable); +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c new file mode 100644 index 0000000000000..1dcb7ed358bcf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c @@ -0,0 +1,232 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DETECT]" + +#include "wmt_detect.h" +#include "wmt_gpio.h" + +#define INVALID_PIN_ID (0xFFFFFFFF) + +/*copied form WMT module*/ +static int wmt_detect_dump_pin_conf(void) +{ + WMT_DETECT_DBG_FUNC("[WMT-DETECT]=>dump wmt pin configuration start<=\n"); + + WMT_DETECT_INFO_FUNC("LDO(GPIO%d), PMU(GPIO%d), PMUV28(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num); + + WMT_DETECT_INFO_FUNC("RST(GPIO%d), BGF_EINT(GPIO%d), BGF_EINT_NUM(%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num, + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num)); + + WMT_DETECT_INFO_FUNC("WIFI_EINT(GPIO%d), WIFI_EINT_NUM(%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num, + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)); + + WMT_DETECT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration ends<=\n"); + + return 0; +} + +int _wmt_detect_output_low(unsigned int id) +{ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 0); + WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); + } + + return 0; +} + +int _wmt_detect_output_high(unsigned int id) +{ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 1); + WMT_DETECT_DBG_FUNC("WMT-DETECT: set GPIO%d to output %d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); + } + + return 0; +} + +int _wmt_detect_read_gpio_input(unsigned int id) +{ + int retval = 0; + + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[id].gpio_num) { + retval = gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num); + WMT_DETECT_DBG_FUNC("WMT-DETECT: get GPIO%d val%d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, retval); + } + + return retval; +} + +/*This power on sequence must support all combo chip's basic power on sequence + * 1. LDO control is a must, if external LDO exist + * 2. PMU control is a must + * 3. RST control is a must + * 4. WIFI_EINT pin control is a must, used for GPIO mode for EINT status checkup + * 5. RTC32k clock control is a must + * */ +static int wmt_detect_chip_pwr_on(void) +{ + int retval = -1; + /*setting validiation check*/ + if ((INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) || + (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) || + (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)) { + WMT_DETECT_ERR_FUNC("WMT-DETECT: either PMU(%d) or RST(%d) or WIFI_EINT(%d) is not set\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num); + + return retval; + } + /*set LDO/PMU/RST to output 0, no pull*/ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) + _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); + } else + WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DETECT_INFO_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); + } else + WMT_DETECT_ERR_FUNC("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + _wmt_detect_output_low(GPIO_COMBO_RST_PIN); + +#if 0 + _wmt_detect_output_high(GPIO_WIFI_EINT_PIN); +#endif + + /*pull high LDO*/ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) + _wmt_detect_output_high(GPIO_COMBO_LDO_EN_PIN); + /*sleep for LDO stable time*/ + msleep(MAX_LDO_STABLE_TIME); + + /*export RTC clock, sleep for RTC stable time*/ + rtc_gpio_enable_32k(RTC_GPIO_USER_GPS); + msleep(MAX_RTC_STABLE_TIME); + /*PMU output low, RST output low, to make chip power off completely*/ + /*always done*/ + /*sleep for power off stable time*/ + msleep(MAX_OFF_STABLE_TIME); + /*PMU output high, and sleep for reset stable time*/ + _wmt_detect_output_high(GPIO_COMBO_PMU_EN_PIN); +#ifdef CONFIG_MTK_COMBO_COMM_NPWR + if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != INVALID_PIN_ID) && + (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != INVALID_PIN_ID)) { + msleep(20); + _wmt_detect_output_high(GPIO_PCM_DAISYNC_PIN); + + msleep(20); + _wmt_detect_output_high(GPIO_COMBO_I2S_DAT_PIN); + + msleep(20); + _wmt_detect_output_low(GPIO_COMBO_I2S_DAT_PIN); + + msleep(20); + _wmt_detect_output_low(GPIO_PCM_DAISYNC_PIN); + + msleep(20); + } +#endif + msleep(MAX_RST_STABLE_TIME); + /*RST output high, and sleep for power on stable time */ + _wmt_detect_output_high(GPIO_COMBO_RST_PIN); + msleep(MAX_ON_STABLE_TIME); + + retval = 0; + return retval; +} + +static int wmt_detect_chip_pwr_off(void) +{ + + /*set RST pin to input low status*/ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num) + _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); + /*set RST pin to input low status*/ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) + _wmt_detect_output_low(GPIO_COMBO_RST_PIN); + /*set PMU pin to input low status*/ + if (INVALID_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) + _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); + return 0; +} + +int wmt_detect_read_ext_cmb_status(void) +{ + int retval = 0; + /*read WIFI_EINT pin status*/ + if (INVALID_PIN_ID == gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num) { + retval = 0; + WMT_DETECT_ERR_FUNC("WMT-DETECT: no WIFI_EINT pin set\n"); + } else { + retval = _wmt_detect_read_gpio_input(GPIO_WIFI_EINT_PIN); + WMT_DETECT_ERR_FUNC("WMT-DETECT: WIFI_EINT input status:%d\n", retval); + } + return retval; +} + +int wmt_detect_chip_pwr_ctrl(int on) +{ + int retval = -1; + + if (0 == on) { + /*power off combo chip */ + retval = wmt_detect_chip_pwr_off(); + } else { + wmt_detect_dump_pin_conf(); + /*power on combo chip */ + retval = wmt_detect_chip_pwr_on(); + } + return retval; +} + +int wmt_detect_sdio_pwr_ctrl(int on) +{ + int retval = -1; +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + if (0 == on) { + /*power off SDIO slot */ + retval = board_sdio_ctrl(1, 0); + } else { + /*power on SDIO slot */ + retval = board_sdio_ctrl(1, 1); + } +#else + WMT_DETECT_WARN_FUNC("WMT-DETECT: MTK_WCN_COMBO_CHIP_SUPPORT is not set\n"); +#endif + return retval; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h new file mode 100644 index 0000000000000..32e661520fd0d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef __WMT_DETECT_PWR_H_ +#define __WMT_DETECT_PWR_H_ + +#define MAX_RTC_STABLE_TIME 100 +#define MAX_LDO_STABLE_TIME 100 +#define MAX_RST_STABLE_TIME 30 +#define MAX_OFF_STABLE_TIME 10 +#define MAX_ON_STABLE_TIME 30 + +extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); +extern int wmt_detect_chip_pwr_ctrl(int on); +extern int wmt_detect_sdio_pwr_ctrl(int on); +extern int wmt_detect_read_ext_cmb_status(void); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c new file mode 100644 index 0000000000000..3a79e1e9d15a9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c @@ -0,0 +1,371 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include "wmt_gpio.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX] = {{"gpio_ldo_en_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_ldo_en_in_pulldown", + ""}, + {"gpio_pmuv28_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_pmuv28_in_pulldown", + ""}, + {"gpio_pmu_en_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_pmu_en_in_pulldown", + ""}, + {"gpio_rst_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"", + "", + "", + "", + "", + "", + "", + "", + "gpio_bgf_eint_in_pulldown", + "gpio_bgf_eint_in_pullup"}, + {"", + "", + "", + "", + "", + "", + "", + "gpio_wifi_eint_in_pull_dis", + "", + "gpio_wifi_eint_in_pullup"}, + {"", + "", + "", + "", + "", + "", + "", + "", + "gpio_all_eint_in_pulldown", + "gpio_all_eint_in_pullup"}, + {"gpio_urxd_uart_pull_dis", + "", + "", + "", + "", + "", + "", + "gpio_urxd_gpio_in_pull_dis", + "", + "gpio_urxd_gpio_in_pullup"}, + {"gpio_utxd_uart_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daiclk_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daipcmin_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daipcmout_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daisync_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_ck_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_ws_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_dat_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_gps_sync_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_gps_lna_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""} +}; + +const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX] = {"gpio_combo_ldo_en_pin", + "gpio_combo_pmuv28_en_pin", + "gpio_combo_pmu_en_pin", + "gpio_combo_rst_pin", + "gpio_combo_bgf_eint_pin", + "gpio_wifi_eint_pin", + "gpio_all_eint_pin", + "gpio_combo_urxd_pin", + "gpio_combo_utxd_pin", + "gpio_pcm_daiclk_pin", + "gpio_pcm_daipcmin_pin", + "gpio_pcm_daipcmout_pin", + "gpio_pcm_daisync_pin", + "gpio_combo_i2s_ck_pin", + "gpio_combo_i2s_ws_pin", + "gpio_combo_i2s_dat_pin", + "gpio_gps_sync_pin", + "gpio_gps_lna_pin"}; + +GPIO_CTRL_INFO gpio_ctrl_info; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_gpio_init(struct platform_device *pdev) +{ + INT32 iret = 0; + UINT32 i, j; + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); + if (!node) { + for (i = 0; i < GPIO_PIN_ID_MAX; i++) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + pr_err("wmt_gpio:can't find device tree node!\n"); + iret = -1; + goto err; + } + + gpio_ctrl_info.pinctrl_info = devm_pinctrl_get(&pdev->dev); + if (gpio_ctrl_info.pinctrl_info) { + for (i = 0; i < GPIO_PIN_ID_MAX; i++) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = of_get_named_gpio(node, + gpio_pin_name[i], 0); + if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num < 0) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { + for (j = 0; j < GPIO_STATE_MAX; j++) { + if (0 != strlen(gpio_state_name[i][j])) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = + pinctrl_lookup_state(gpio_ctrl_info.pinctrl_info, + gpio_state_name[i][j]); + } else + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; + } + } + } + + pr_err("wmt_gpio: gpio init start!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN]. + gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + 0); + pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN out to 0: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, + 0); + pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN out to 0: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); + pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP done!\n"); + } else + pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN]. + gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN]. + gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN]. + gpio_state[GPIO_PULL_DIS]); + pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS done!\n"); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + pr_err("wmt_gpio: gpio init done!\n"); + } else { + pr_err("wmt_gpio:can't find pinctrl dev!\n"); + iret = -1; + } +err: + return iret; +} + +INT32 wmt_gpio_deinit(VOID) +{ + INT32 iret = 0; + UINT32 i; + UINT32 j; + + for (i = 0; i < GPIO_PIN_ID_MAX; i++) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + if (DEFAULT_PIN_ID != gpio_ctrl_info.gpio_ctrl_state[i].gpio_num) { + for (j = 0; j < GPIO_STATE_MAX; j++) { + if (0 != strlen(gpio_state_name[i][j])) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; + } + } + } + if (gpio_ctrl_info.pinctrl_info) { + devm_pinctrl_put(gpio_ctrl_info.pinctrl_info); + gpio_ctrl_info.pinctrl_info = NULL; + } + + return iret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h new file mode 100644 index 0000000000000..cd935bfddd994 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h @@ -0,0 +1,103 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WMT_GPIO_H_ +#define _WMT_GPIO_H_ + +#include +#include +#include +#include +#include +#include +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define DEFAULT_PIN_ID (0xffffffff) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_GPIO_PIN_ID { + GPIO_COMBO_LDO_EN_PIN = 0, + GPIO_COMBO_PMUV28_EN_PIN, + GPIO_COMBO_PMU_EN_PIN, + GPIO_COMBO_RST_PIN, + GPIO_COMBO_BGF_EINT_PIN, + GPIO_WIFI_EINT_PIN, + GPIO_COMBO_ALL_EINT_PIN, + GPIO_COMBO_URXD_PIN, + GPIO_COMBO_UTXD_PIN, + GPIO_PCM_DAICLK_PIN, + GPIO_PCM_DAIPCMIN_PIN, + GPIO_PCM_DAIPCMOUT_PIN, + GPIO_PCM_DAISYNC_PIN, + GPIO_COMBO_I2S_CK_PIN, + GPIO_COMBO_I2S_WS_PIN, + GPIO_COMBO_I2S_DAT_PIN, + GPIO_GPS_SYNC_PIN, + GPIO_GPS_LNA_PIN, + GPIO_PIN_ID_MAX +} ENUM_GPIO_PIN_ID, *P_ENUM_GPIO_PIN_ID; + +typedef enum _ENUM_GPIO_STATE_ID { + GPIO_PULL_DIS = 0, + GPIO_PULL_DOWN, + GPIO_PULL_UP, + GPIO_OUT_LOW, + GPIO_OUT_HIGH, + GPIO_IN_DIS, + GPIO_IN_EN, + GPIO_IN_PULL_DIS, + GPIO_IN_PULLDOWN, + GPIO_IN_PULLUP, + GPIO_STATE_MAX, +} ENUM_GPIO_STATE_ID, *P_ENUM_GPIO_STATE_ID; + +typedef struct _GPIO_CTRL_STATE { + INT32 gpio_num; + struct pinctrl_state *gpio_state[GPIO_STATE_MAX]; +} GPIO_CTRL_STATE, *P_GPIO_CTRL_STATE; + +typedef struct _GPIO_CTRL_INFO { + struct pinctrl *pinctrl_info; + GPIO_CTRL_STATE gpio_ctrl_state[GPIO_PIN_ID_MAX]; +} GPIO_CTRL_INFO, *P_GPIO_CTRL_INFO; + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX]; +extern const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX]; +extern GPIO_CTRL_INFO gpio_ctrl_info; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +INT32 wmt_gpio_init(struct platform_device *pdev); + +INT32 wmt_gpio_deinit(VOID); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c new file mode 100644 index 0000000000000..4fc3144b3ba6c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c @@ -0,0 +1,480 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +#include "osal_typedef.h" +#include "wmt_stp_exp.h" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-STP-EXP]" + +#define WMT_STP_EXP_INFO_FUNC(fmt, arg...) pr_debug(DFT_TAG "[I]%s: " fmt, __func__ , ##arg) +#define WMT_STP_EXP_WARN_FUNC(fmt, arg...) pr_warn(DFT_TAG "[W]%s: " fmt, __func__ , ##arg) +#define WMT_STP_EXP_ERR_FUNC(fmt, arg...) pr_err(DFT_TAG "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +/*STP exp*/ +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_f = NULL; +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_raw_f = NULL; +MTK_WCN_STP_PARSER_DATA mtk_wcn_stp_parser_data_f = NULL; +MTK_WCN_STP_RECV_DATA mtk_wcn_stp_receive_data_f = NULL; +MTK_WCN_STP_IS_RXQ_EMPTY mtk_wcn_stp_is_rxqueue_empty_f = NULL; +MTK_WCN_STP_IS_RDY mtk_wcn_stp_is_ready_f = NULL; +MTK_WCN_STP_SET_BLUEZ mtk_wcn_stp_set_bluez_f = NULL; +MTK_WCN_STP_REG_IF_TX mtk_wcn_stp_if_tx_f = NULL; +MTK_WCN_STP_REG_IF_RX mtk_wcn_stp_if_rx_f = NULL; +MTK_WCN_STP_REG_EVENT_CB mtk_wcn_stp_reg_event_cb_f = NULL; +MTK_WCN_STP_RGE_TX_EVENT_CB mtk_wcn_stp_reg_tx_event_cb_f = NULL; +MTK_WCN_STP_COREDUMP_START_GET mtk_wcn_stp_coredump_start_get_f = NULL; + +/*WMT exp*/ +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_on_f = NULL; +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_off_f = NULL; +MTK_WCN_WMT_THERM_CTRL mtk_wcn_wmt_therm_ctrl_f = NULL; +MTK_WCN_WMT_HWVER_GET mtk_wcn_wmt_hwver_get_f = NULL; +MTK_WCN_WMT_DSNS_CTRL mtk_wcn_wmt_dsns_ctrl_f = NULL; +MTK_WCN_WMT_MSGCB_REG mtk_wcn_wmt_msgcb_reg_f = NULL; +MTK_WCN_WMT_MSGCB_UNREG mtk_wcn_wmt_msgcb_unreg_f = NULL; +MTK_WCN_WMT_SDIO_OP_REG mtk_wcn_wmt_sdio_op_reg_f = NULL; +MTK_WCN_WMT_SDIO_HOST_AWAKE mtk_wcn_wmt_sdio_host_awake_f = NULL; +MTK_WCN_WMT_ASSERT mtk_wcn_wmt_assert_f = NULL; +MTK_WCN_WMT_ASSERT_TIMEOUT mtk_wcn_wmt_assert_timeout_f = NULL; +MTK_WCN_WMT_IC_INFO_GET mtk_wcn_wmt_ic_info_get_f = NULL; +MTK_WCN_WMT_PSM_CTRL mtk_wcn_wmt_psm_ctrl_f = NULL; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb reg\n"); + + mtk_wcn_stp_send_data_f = pStpExpCb->stp_send_data_cb; + mtk_wcn_stp_send_data_raw_f = pStpExpCb->stp_send_data_raw_cb; + mtk_wcn_stp_parser_data_f = pStpExpCb->stp_parser_data_cb; + mtk_wcn_stp_receive_data_f = pStpExpCb->stp_receive_data_cb; + mtk_wcn_stp_is_rxqueue_empty_f = pStpExpCb->stp_is_rxqueue_empty_cb; + mtk_wcn_stp_is_ready_f = pStpExpCb->stp_is_ready_cb; + mtk_wcn_stp_set_bluez_f = pStpExpCb->stp_set_bluez_cb; + mtk_wcn_stp_if_tx_f = pStpExpCb->stp_if_tx_cb; + mtk_wcn_stp_if_rx_f = pStpExpCb->stp_if_rx_cb; + mtk_wcn_stp_reg_event_cb_f = pStpExpCb->stp_reg_event_cb; + mtk_wcn_stp_reg_tx_event_cb_f = pStpExpCb->stp_reg_tx_event_cb; + mtk_wcn_stp_coredump_start_get_f = pStpExpCb->stp_coredump_start_get_cb; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_reg); + +UINT32 mtk_wcn_stp_exp_cb_unreg(VOID) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb unreg\n"); + + mtk_wcn_stp_send_data_f = NULL; + mtk_wcn_stp_send_data_raw_f = NULL; + mtk_wcn_stp_parser_data_f = NULL; + mtk_wcn_stp_receive_data_f = NULL; + mtk_wcn_stp_is_rxqueue_empty_f = NULL; + mtk_wcn_stp_is_ready_f = NULL; + mtk_wcn_stp_set_bluez_f = NULL; + mtk_wcn_stp_if_tx_f = NULL; + mtk_wcn_stp_if_rx_f = NULL; + mtk_wcn_stp_reg_event_cb_f = NULL; + mtk_wcn_stp_reg_tx_event_cb_f = NULL; + mtk_wcn_stp_coredump_start_get_f = NULL; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_unreg); + +INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_send_data_f) { + ret = (*mtk_wcn_stp_send_data_f) (buffer, length, type); + /* WMT_STP_EXP_INFO_FUNC("mtk_wcn_stp_send_data_f send data(%d)\n",ret); */ + } else { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_f cb is null\n"); + } + + return ret; + +} +EXPORT_SYMBOL(mtk_wcn_stp_send_data); + +INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_send_data_raw_f) + ret = (*mtk_wcn_stp_send_data_raw_f) (buffer, length, type); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_raw_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); + +INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_parser_data_f) + ret = (*mtk_wcn_stp_parser_data_f) (buffer, length); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_parser_data_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_parser_data); + +INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_receive_data_f) + ret = (*mtk_wcn_stp_receive_data_f) (buffer, length, type); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_receive_data_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_receive_data); + +MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_stp_is_rxqueue_empty_f) + ret = (*mtk_wcn_stp_is_rxqueue_empty_f) (type); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_rxqueue_empty_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); + +MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_stp_is_ready_f) + ret = (*mtk_wcn_stp_is_ready_f) (); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_ready_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_is_ready); + +void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags) +{ + + if (mtk_wcn_stp_set_bluez_f) + (*mtk_wcn_stp_set_bluez_f) (flags); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_set_bluez_f cb is null\n"); + +} +EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); + +INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_if_tx_f) + ret = (*mtk_wcn_stp_if_tx_f) (stp_if, func); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_tx_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); + +INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_if_rx_f) + ret = (*mtk_wcn_stp_if_rx_f) (func); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_rx_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); + +INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_reg_event_cb_f) + ret = (*mtk_wcn_stp_reg_event_cb_f) (type, func); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_event_cb_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); + +INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_reg_tx_event_cb_f) + ret = (*mtk_wcn_stp_reg_tx_event_cb_f) (type, func); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_tx_event_cb_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); + +INT32 mtk_wcn_stp_coredump_start_get(VOID) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_coredump_start_get_f) + ret = (*mtk_wcn_stp_coredump_start_get_f) (); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_coredump_start_get_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get); + +UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb) +{ + WMT_STP_EXP_INFO_FUNC("call wmt exp cb reg\n"); + + mtk_wcn_wmt_func_on_f = pWmtExpCb->wmt_func_on_cb; + mtk_wcn_wmt_func_off_f = pWmtExpCb->wmt_func_off_cb; + mtk_wcn_wmt_therm_ctrl_f = pWmtExpCb->wmt_therm_ctrl_cb; + mtk_wcn_wmt_hwver_get_f = pWmtExpCb->wmt_hwver_get_cb; + mtk_wcn_wmt_dsns_ctrl_f = pWmtExpCb->wmt_dsns_ctrl_cb; + mtk_wcn_wmt_msgcb_reg_f = pWmtExpCb->wmt_msgcb_reg_cb; + mtk_wcn_wmt_msgcb_unreg_f = pWmtExpCb->wmt_msgcb_unreg_cb; + mtk_wcn_wmt_sdio_op_reg_f = pWmtExpCb->wmt_sdio_op_reg_cb; + mtk_wcn_wmt_sdio_host_awake_f = pWmtExpCb->wmt_sdio_host_awake_cb; + mtk_wcn_wmt_assert_f = pWmtExpCb->wmt_assert_cb; + mtk_wcn_wmt_assert_timeout_f = pWmtExpCb->wmt_assert_timeout_cb; + mtk_wcn_wmt_ic_info_get_f = pWmtExpCb->wmt_ic_info_get_cb; + mtk_wcn_wmt_psm_ctrl_f = pWmtExpCb->wmt_psm_ctrl_cb; + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_reg); + +UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID) +{ + WMT_STP_EXP_INFO_FUNC("call wmt exp cb unreg\n"); + + mtk_wcn_wmt_func_on_f = NULL; + mtk_wcn_wmt_func_off_f = NULL; + mtk_wcn_wmt_therm_ctrl_f = NULL; + mtk_wcn_wmt_hwver_get_f = NULL; + mtk_wcn_wmt_dsns_ctrl_f = NULL; + mtk_wcn_wmt_msgcb_reg_f = NULL; + mtk_wcn_wmt_msgcb_unreg_f = NULL; + mtk_wcn_wmt_sdio_op_reg_f = NULL; + mtk_wcn_wmt_sdio_host_awake_f = NULL; + mtk_wcn_wmt_assert_f = NULL; + mtk_wcn_wmt_assert_timeout_f = NULL; + mtk_wcn_wmt_ic_info_get_f = NULL; + mtk_wcn_wmt_psm_ctrl_f = NULL; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_unreg); + +MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_wmt_func_off_f) + ret = (*mtk_wcn_wmt_func_off_f) (type); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_off_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_off); + +MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_wmt_func_on_f) { + ret = (*mtk_wcn_wmt_func_on_f) (type); + WMT_STP_EXP_INFO_FUNC("mtk_wcn_wmt_func_on_f type(%d)\n", type); + } else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_on_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_on); + +INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) +{ + INT32 ret = -1; + + if (mtk_wcn_wmt_therm_ctrl_f) + ret = (*mtk_wcn_wmt_therm_ctrl_f) (eType); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_therm_ctrl_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); + +ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) +{ + ENUM_WMTHWVER_TYPE_T ret = WMTHWVER_INVALID; + + if (mtk_wcn_wmt_hwver_get_f) + ret = (*mtk_wcn_wmt_hwver_get_f) (); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_hwver_get_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); + +MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_wmt_dsns_ctrl_f) + ret = (*mtk_wcn_wmt_dsns_ctrl_f) (eType); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_dsns_ctrl_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); + +INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +{ + INT32 ret = 0; + + if (mtk_wcn_wmt_msgcb_reg_f) + ret = (*mtk_wcn_wmt_msgcb_reg_f) (eType, pCb); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_reg_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); + +INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +{ + INT32 ret = 0; + + if (mtk_wcn_wmt_msgcb_unreg_f) + ret = (*mtk_wcn_wmt_msgcb_unreg_f) (eType); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_unreg_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); + +INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) +{ + INT32 ret = -1; + + if (mtk_wcn_wmt_sdio_op_reg_f) + ret = (*mtk_wcn_wmt_sdio_op_reg_f) (own_cb); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_op_reg_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); + +INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) +{ + INT32 ret = -1; + + if (mtk_wcn_wmt_sdio_host_awake_f) + ret = (*mtk_wcn_wmt_sdio_host_awake_f) (); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_host_awake_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); + +MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_wmt_assert_f) + ret = (*mtk_wcn_wmt_assert_f) (type, reason); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_assert); + +MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (mtk_wcn_wmt_assert_timeout_f) + ret = (*mtk_wcn_wmt_assert_timeout_f)(type, reason, timeout); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_timeout_f cb is null\n"); + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_assert_timeout); + +UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type) +{ + UINT32 ret = 0; + + if (mtk_wcn_wmt_ic_info_get_f) + ret = (*mtk_wcn_wmt_ic_info_get_f) (type); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_ic_info_get_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get); + +INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag) +{ + UINT32 ret = 0; + + if (mtk_wcn_wmt_psm_ctrl_f) + ret = (*mtk_wcn_wmt_psm_ctrl_f)(flag); + else + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_psm_ctrl_f cb is null\n"); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h new file mode 100644 index 0000000000000..1c3dc89652981 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h @@ -0,0 +1,610 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WMT_STP_EXP_H_ +#define _WMT_STP_EXP_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "osal_typedef.h" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 +#endif + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +#if (WMT_IDC_SUPPORT) +#define CFG_WMT_LTE_COEX_HANDLING 1 +#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0 +#else +#define CFG_WMT_LTE_COEX_HANDLING 0 +#endif + +/*from stp_exp.h*/ +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define ANT_TASK_INDX (7) +#if CFG_WMT_LTE_COEX_HANDLING +#define COEX_TASK_INDX (8) +#define MTKSTP_MAX_TASK_NUM (9) +#else +#define MTKSTP_MAX_TASK_NUM (8) +#endif + +#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ +/*end from stp_exp.h*/ + +/******************************************************************************* +* D A T A T Y P E S +********************************************************************************/ + +/*moved from stp_exp.h*/ +typedef void (*MTK_WCN_STP_EVENT_CB) (void); +typedef INT32(*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); +/* export for HIF driver */ +typedef void (*MTK_WCN_STP_IF_RX) (const PUINT8 data, INT32 size); + +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX = 1, + STP_BTIF_IF_TX = 2, + STP_MAX_IF_TX +} ENUM_STP_TX_IF_TYPE; + +/*end moved from stp_exp.h*/ + +typedef INT32(*MTK_WCN_STP_SEND_DATA) (const PUINT8 buffer, const UINT32 length, const UINT8 type); +typedef INT32(*MTK_WCN_STP_PARSER_DATA) (PUINT8 buffer, UINT32 length); +typedef INT32(*MTK_WCN_STP_RECV_DATA) (PUINT8 buffer, UINT32 length, UINT8 type); +typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RXQ_EMPTY) (UINT8 type); +typedef MTK_WCN_BOOL(*MTK_WCN_STP_IS_RDY) (VOID); +typedef VOID(*MTK_WCN_STP_SET_BLUEZ) (MTK_WCN_BOOL flags); +typedef INT32(*MTK_WCN_STP_REG_IF_TX) (ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); +typedef INT32(*MTK_WCN_STP_REG_IF_RX) (MTK_WCN_STP_IF_RX func); +typedef INT32(*MTK_WCN_STP_REG_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); +typedef INT32(*MTK_WCN_STP_RGE_TX_EVENT_CB) (INT32 type, MTK_WCN_STP_EVENT_CB func); +typedef INT32(*MTK_WCN_STP_COREDUMP_START_GET)(VOID); + +typedef struct _MTK_WCN_STP_EXP_CB_INFO_ { + MTK_WCN_STP_SEND_DATA stp_send_data_cb; + MTK_WCN_STP_SEND_DATA stp_send_data_raw_cb; + MTK_WCN_STP_PARSER_DATA stp_parser_data_cb; + MTK_WCN_STP_RECV_DATA stp_receive_data_cb; + MTK_WCN_STP_IS_RXQ_EMPTY stp_is_rxqueue_empty_cb; + MTK_WCN_STP_IS_RDY stp_is_ready_cb; + MTK_WCN_STP_SET_BLUEZ stp_set_bluez_cb; + MTK_WCN_STP_REG_IF_TX stp_if_tx_cb; + MTK_WCN_STP_REG_IF_RX stp_if_rx_cb; + MTK_WCN_STP_REG_EVENT_CB stp_reg_event_cb; + MTK_WCN_STP_RGE_TX_EVENT_CB stp_reg_tx_event_cb; + MTK_WCN_STP_COREDUMP_START_GET stp_coredump_start_get_cb; +} MTK_WCN_STP_EXP_CB_INFO, *P_MTK_WCN_STP_EXP_CB_INFO; + +/*moved from wmt_exp.h*/ + +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_ANT = 5, + WMTDRV_TYPE_STP = 6, + WMTDRV_TYPE_SDIO1 = 7, + WMTDRV_TYPE_SDIO2 = 8, + WMTDRV_TYPE_LPBK = 9, + WMTDRV_TYPE_COREDUMP = 10, +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + WMTDRV_TYPE_AUTOK = 11, +#endif + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +typedef enum _ENUM_WMTDSNS_TYPE_T { + WMTDSNS_FM_DISABLE = 0, + WMTDSNS_FM_ENABLE = 1, + WMTDSNS_FM_GPS_DISABLE = 2, + WMTDSNS_FM_GPS_ENABLE = 3, + WMTDSNS_MAX +} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; + +typedef enum _ENUM_WMTHWVER_TYPE_T { + WMTHWVER_E1 = 0x0, + WMTHWVER_E2 = 0x1, + WMTHWVER_E3 = 0x2, + WMTHWVER_E4 = 0x3, + WMTHWVER_E5 = 0x4, + WMTHWVER_E6 = 0x5, + WMTHWVER_E7 = 0x6, + WMTHWVER_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +typedef enum _ENUM_WMTTHERM_TYPE_T { + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY = 3, + WMTMSG_TYPE_HW_FUNC_ON = 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client + can't touch this buffer after this function return. */ + UINT32 /* Buffer size in unit of byte */ +); + +typedef enum _SDIO_PS_OP { + OWN_SET = 0, + OWN_CLR = 1, + OWN_STATE = 2, +} SDIO_PS_OP; + +typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); + +typedef enum _ENUM_WMTCHIN_TYPE_T { + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_MAX, + +} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; + +/*end moved from wmt_exp.h*/ + +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_FUNC_CTRL) (ENUM_WMTDRV_TYPE_T type); +typedef INT8(*MTK_WCN_WMT_THERM_CTRL) (ENUM_WMTTHERM_TYPE_T eType); +typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET) (VOID); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_DSNS_CTRL) (ENUM_WMTDSNS_TYPE_T eType); +typedef INT32(*MTK_WCN_WMT_MSGCB_REG) (ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); +typedef INT32(*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType); +typedef INT32(*MTK_WCN_WMT_SDIO_OP_REG) (PF_WMT_SDIO_PSOP own_cb); +typedef INT32(*MTK_WCN_WMT_SDIO_HOST_AWAKE) (VOID); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT) (ENUM_WMTDRV_TYPE_T type, UINT32 reason); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT_TIMEOUT)(ENUM_WMTDRV_TYPE_T type, + UINT32 reason, INT32 timeout); +typedef UINT32(*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type); +typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag); + +typedef struct _MTK_WCN_WMT_EXP_CB_INFO_ { + MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb; + MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb; + MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb; + MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb; + MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb; + MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb; + MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb; + MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb; + MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb; + MTK_WCN_WMT_ASSERT wmt_assert_cb; + MTK_WCN_WMT_ASSERT_TIMEOUT wmt_assert_timeout_cb; + MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb; + MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb; +} MTK_WCN_WMT_EXP_CB_INFO, *P_MTK_WCN_WMT_EXP_CB_INFO; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*exp for WMT/STP register callback*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_exp_cb_reg +* DESCRIPTION +* stp driver reigster exp symbols +* PARAMETERS +* pStpExpCb [IN] stp callback structure pointer +* RETURNS +* UINT32 = 0: OK +*****************************************************************************/ +UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_exp_cb_unreg +* DESCRIPTION +* stp driver unreigster exp symbols +* PARAMETERS +* VOID +* RETURNS +* UINT32 = 0: OK +*****************************************************************************/ +UINT32 mtk_wcn_stp_exp_cb_unreg(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_exp_cb_reg +* DESCRIPTION +* WMT driver reigster exp symbols +* PARAMETERS +* pStpExpCb [IN] wmt callback structure pointer +* RETURNS +* UINT32 = 0: OK +*****************************************************************************/ +UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_exp_cb_unreg +* DESCRIPTION +* wmt driver unreigster exp symbols +* PARAMETERS +* VOID +* RETURNS +* UINT32 = 0: OK +*****************************************************************************/ +UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID); + +/*stp exp symbols*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data_raw +* DESCRIPTION +* subfunction send data through STP without seq/ack +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* Is STP ready? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:ready, FALSE:not ready +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); + +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_tx +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_rx +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_event_cb +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* func +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_tx_event_cb +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* func +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get coredump flag is set or not +* PARAMETERS +* VOID +* RETURNS +* INT32: 0:coredump flag is not set , 1: coredump flag is set +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_get(VOID); + +/*wmt exp symbols*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_func_off +* DESCRIPTION +* wmt turn off subsystem +* PARAMETERS +* type [IN] subsystem type +* RETURNS +* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_func_on +* DESCRIPTION +* wmt turn on subsystem +* PARAMETERS +* type [IN] subsystem type +* RETURNS +* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_therm_ctrl +* DESCRIPTION +* query chip temperature by WMT CMD +* PARAMETERS +* eType [IN] thermal ctrl type +* RETURNS +* >=0: chip temperature; 0xff:error +*****************************************************************************/ +extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_hwver_get +* DESCRIPTION +* get chip hardware version +* PARAMETERS +* VOID +* RETURNS +* >=0: chip hw version; 0xff:error +*****************************************************************************/ +extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_ic_info_get +* DESCRIPTION +* get chip hardware version or f/w version +* PARAMETERS +* type : which kind of information is needed +* RETURNS +* f/w version or hw version information +*****************************************************************************/ +extern UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_dsns_ctrl +* DESCRIPTION +* fm dsns cmd ctrl +* PARAMETERS +* eType [IN] fm dsns ctrl type +* RETURNS +* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_msgcb_reg +* DESCRIPTION +* used for subsystem register chip reset callback for received wmt reset msg. +* PARAMETERS +* eType [IN] subsystem type +* pCb [IN] rst callback +* RETURNS +* 1: OK; 0:error +*****************************************************************************/ +extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_msgcb_unreg +* DESCRIPTION +* used for subsystem unregister chip reset callback for received wmt reset msg. +* PARAMETERS +* eType [IN] subsystem type +* RETURNS +* 1: OK; 0:error +*****************************************************************************/ +extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_wmt_sdio_op_reg +* DESCRIPTION +* used to register callback for set sdio ownership. +* PARAMETERS +* own_cb [IN] set owner ship callback +* RETURNS +* always return 0; +*****************************************************************************/ +extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_wmt_sdio_host_awake +* DESCRIPTION +* handing host awake when link is stp sdio? +* PARAMETERS +* VOID +* RETURNS +* always return 0; +*****************************************************************************/ +extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_assert +* DESCRIPTION +* host trigger firmware assert +* PARAMETERS +* type [IN] subsystem driver type +* reason [IN] trigger assert reason +* RETURNS +* MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); + +/***************************************************************************** + * * FUNCTION + * * mtk_wcn_wmt_assert_timeout + * * DESCRIPTION + * * host trigger firmware assert + * * PARAMETERS + * * type [IN] subsystem driver type + * * reason [IN] trigger assert reason + * * timeout [IN] trigger assert timeout data + * * RETURNS + * * MTK_WCN_BOOL_TRUE: OK; MTK_WCN_BOOL_FALSE:error + * *****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, + UINT32 reason, INT32 timeout); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmt_psm_ctrl +* DESCRIPTION +* disable/enable psm +* PARAMETERS +* flag [IN] disable:0, enable:1 +* RETURNS +* always return 0; +*****************************************************************************/ +extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag); + +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile new file mode 100644 index 0000000000000..286bfd4bfed36 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/Makefile @@ -0,0 +1,65 @@ +subdir-ccflags-y += \ + -I$(src)/linux/include \ + -I$(src)/linux/pri/include \ + -I$(src)/core/include \ + -I$(src)/include \ + -I$(src)/../common_detect \ + -I$(srctree)/drivers/misc/mediatek/btif/common/inc + +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/ +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM) +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs/ +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include + +EXT_FLAG=_soc +COMMON_SRC_PATH := $(src) +COMMON_OBJ_PATH := $(src) + +ifeq ($(CONFIG_ARCH_MT6580), y) +subdir-ccflags-y += -D CFG_WMT_READ_EFUSE_VCN33 +endif + +ifeq ($(CONFIG_MTK_COMBO), m) +# WMT DRIVER +obj-$(CONFIG_MTK_COMBO) += mtk_stp_wmt$(EXT_FLAG).o +# WMT DRIVER-core part +mtk_stp_wmt$(EXT_FLAG)-objs := core/wmt_core.o core/wmt_ctrl.o core/wmt_func.o core/wmt_ic_soc.o core/wmt_lib.o core/wmt_conf.o + + +# WMT DRIVER-linux private part +mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/wmt_dev.o linux/pri/wmt_exp.o +mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_btif.o + + +# WMT DRIVER-OSAL +mtk_stp_wmt$(EXT_FLAG)-objs += linux/pub/osal.o linux/pub/bgw_desense.o +# WMT DRIVER-platform implementation +# ccflags-y += -D WMT_PLAT_ALPS +# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/wmt_plat_alps.o + +# mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/mtk_wcn_consys_hw.o + + +mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_exp.o core/stp_core.o core/psm_core.o core/btm_core.o linux/pri/stp_dbg.o + +# WMT stub part (built-in kernel image) +# obj-y += platform/alps/mtk_wcn_consys_stub_alps.o + + + +obj-$(CONFIG_MTK_COMBO_BT) += mtk_stp_bt$(EXT_FLAG).o +mtk_stp_bt$(EXT_FLAG)-objs := linux/pub/stp_chrdev_bt.o + + +obj-$(CONFIG_MTK_COMBO_WIFI) += mtk_wmt_wifi$(EXT_FLAG).o +mtk_wmt_wifi$(EXT_FLAG)-objs := linux/pub/wmt_chrdev_wifi.o + +endif + +ifeq ($(CONFIG_MTK_COMBO), y) +# subdir-ccflags-y += -D WMT_PLAT_ALPS +obj-y += core/ +obj-y += linux/ +#obj-y += $(subst ",,$(CONFIG_MTK_PLATFORM))/ +obj-y += mt7623/ +endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile new file mode 100644 index 0000000000000..9df71b9e163ea --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/Makefile @@ -0,0 +1,22 @@ +ifeq ($(CONFIG_MTK_COMBO), y) + +ccflags-y += \ + -I$(src)/../linux/include \ + -I$(src)/../linux/pri/include \ + -I$(src)/../core/include \ + -I$(src)/../include \ + -I$(src)/../../common_detect \ + -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ + +obj-y += wmt_core.o \ + wmt_ctrl.o \ + wmt_func.o \ + wmt_ic_soc.o \ + wmt_lib.o \ + wmt_conf.o \ + btm_core.o \ + dbg_core.o \ + psm_core.o \ + stp_core.o + +endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c new file mode 100644 index 0000000000000..4946b682d8266 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/btm_core.c @@ -0,0 +1,1376 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +#include + +#include "osal_typedef.h" +#include "osal.h" +#include "stp_dbg.h" +#include "stp_core.h" +#include "btm_core.h" +#include "wmt_plat.h" + +#define PFX_BTM "[STP-BTM] " +#define STP_BTM_LOG_LOUD 4 +#define STP_BTM_LOG_DBG 3 +#define STP_BTM_LOG_INFO 2 +#define STP_BTM_LOG_WARN 1 +#define STP_BTM_LOG_ERR 0 + +INT32 gBtmDbgLevel = STP_BTM_LOG_INFO; + +#define STP_BTM_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_LOUD) \ + pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_BTM_DBG_FUNC(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ + pr_debug(PFX_BTM "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_BTM_INFO_FUNC(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_INFO) \ + pr_debug(PFX_BTM "[I]%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_BTM_WARN_FUNC(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_WARN) \ + pr_warn(PFX_BTM "[W]%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_BTM_ERR_FUNC(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_ERR) \ + pr_err(PFX_BTM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ +} while (0) +#define STP_BTM_TRC_FUNC(f) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ + pr_debug(PFX_BTM "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +#define ASSERT(expr) + +MTKSTP_BTM_T stp_btm_i; +MTKSTP_BTM_T *stp_btm = &stp_btm_i; + +const char *g_btm_op_name[] = { + "STP_OPID_BTM_RETRY", + "STP_OPID_BTM_RST", + "STP_OPID_BTM_DBG_DUMP", + "STP_OPID_BTM_DUMP_TIMEOUT", + "STP_OPID_BTM_POLL_CPUPCR", + "STP_OPID_BTM_PAGED_DUMP", + "STP_OPID_BTM_FULL_DUMP", + "STP_OPID_BTM_PAGED_TRACE", + "STP_OPID_BTM_FORCE_FW_ASSERT", +#if CFG_WMT_LTE_COEX_HANDLING + "STP_OPID_BTM_WMT_LTE_COEX", +#endif + "STP_OPID_BTM_EXIT" +}; + +#if 0 +static char *_stp_pkt_type(int type) +{ + + static char s[10]; + + switch (type) { + case WMT_TASK_INDX: + osal_memcpy(s, "WMT", strlen("WMT") + 1); + break; + case BT_TASK_INDX: + osal_memcpy(s, "BT", strlen("BT") + 1); + break; + case GPS_TASK_INDX: + osal_memcpy(s, "GPS", strlen("GPS") + 1); + break; + case FM_TASK_INDX: + osal_memcpy(s, "FM", strlen("FM") + 1); + break; + default: + osal_memcpy(s, "UNKNOWN", strlen("UNKNOWN") + 1); + break; + } + + return s; +} +#endif + +static INT32 _stp_btm_put_dump_to_nl(void) +{ +#define NUM_FETCH_ENTRY 8 + + static UINT8 buf[2048]; + static UINT8 tmp[2048]; + + UINT32 buf_len; + STP_PACKET_T *pkt; + STP_DBG_HDR_T *hdr; + INT32 len; + INT32 remain = 0, index = 0; + INT32 retry = 0, rc = 0, nl_retry = 0; + + STP_BTM_INFO_FUNC("Enter..\n"); + + index = 0; + tmp[index++] = '['; + tmp[index++] = 'M'; + tmp[index++] = ']'; + + do { + index = 3; + remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); + if (buf_len > 0) { + pkt = (STP_PACKET_T *) buf; + hdr = &pkt->hdr; + len = pkt->hdr.len; + osal_memcpy(&tmp[index], &len, 2); + index += 2; + if (hdr->dbg_type == STP_DBG_FW_DMP) { + osal_memcpy(&tmp[index], pkt->raw, len); + + if (len <= 1500) { + /* pr_warn("\n%s\n+++\n", tmp); */ + /* pr_warn("send coredump len:%d\n", len); */ + /* pr_warn("send coredump:%s\n", tmp); */ + rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); + + while (rc) { + nl_retry++; + if (nl_retry > 1000) + break; + STP_BTM_WARN_FUNC + ("**dump send fails, and retry again.**\n"); + osal_sleep_ms(3); + rc = stp_dbg_nl_send((PINT8)&tmp, 2, len+5); + if (!rc) + STP_BTM_WARN_FUNC("****retry again ok!**\n"); + } + /* schedule(); */ + } else { + STP_BTM_INFO_FUNC("dump entry length is over long\n"); + BUG_ON(0); + } + retry = 0; + } + } else { + retry++; + osal_sleep_ms(100); + } + } while ((remain > 0) || (retry < 2)); + + STP_BTM_INFO_FUNC("Exit..\n"); + return 0; +} + +#define SUB_PKT_SIZE 1024 +#define SUB_PKT_HEADER 5 /*'[M]',3Bytes; len,2Bytes*/ + +INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len) +{ + static UINT8 tmp[SUB_PKT_SIZE + SUB_PKT_HEADER]; + + INT32 remain = dump_len, index = 0; + INT32 rc = 0, nl_retry = 0; + INT32 len; + INT32 offset = 0; + + STP_BTM_INFO_FUNC("Enter..\n"); + + if (dump_len > 0) { + index = 0; + tmp[index++] = '['; + tmp[index++] = 'M'; + tmp[index++] = ']'; + + do { + index = 3; + if (remain >= SUB_PKT_SIZE) + len = SUB_PKT_SIZE; + else + len = remain; + remain -= len; + + osal_memcpy(&tmp[index], &len, 2); + index += 2; + osal_memcpy(&tmp[index], data_buf + offset, len); + offset += len; + STP_BTM_DBG_FUNC + ("send %d remain %d\n", len, remain); + + rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); + while (rc) { + nl_retry++; + if (nl_retry > 1000) + break; + STP_BTM_WARN_FUNC + ("**dump send fails, and retry again.**\n"); + osal_sleep_ms(3); + rc = stp_dbg_nl_send((PINT8)&tmp, 2, len + SUB_PKT_HEADER); + if (!rc) { + STP_BTM_WARN_FUNC + ("****retry again ok!**\n"); + } + } + /* schedule(); */ + } while (remain > 0); + } else + STP_BTM_INFO_FUNC("dump entry length is 0\n"); + + STP_BTM_INFO_FUNC("Exit..\n"); + return 0; +} + +static INT32 _stp_btm_put_dump_to_aee(void) +{ + static UINT8 buf[2048]; + static UINT8 tmp[2048]; + + UINT32 buf_len; + STP_PACKET_T *pkt; + STP_DBG_HDR_T *hdr; + INT32 remain = 0; + INT32 retry = 0; + INT32 ret = 0; + + STP_BTM_INFO_FUNC("Enter..\n"); + + do { + remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); + if (buf_len > 0) { + pkt = (STP_PACKET_T *) buf; + hdr = &pkt->hdr; + if (hdr->dbg_type == STP_DBG_FW_DMP) { + memcpy(&tmp[0], pkt->raw, pkt->hdr.len); + + if (pkt->hdr.len <= 1500) { + tmp[pkt->hdr.len] = '\n'; + tmp[pkt->hdr.len + 1] = '\0'; + + ret = stp_dbg_aee_send(tmp, pkt->hdr.len, 0); + } else { + STP_BTM_INFO_FUNC("dump entry length is over long\n"); + BUG_ON(0); + } + retry = 0; + } + } else { + retry++; + msleep(100); + } + } while ((remain > 0) || (retry < 2)); + + STP_BTM_INFO_FUNC("Exit..\n"); + return ret; +} + +#if 0 +INT32 _stp_trigger_firmware_assert_via_emi(VOID) +{ + PUINT8 p_virtual_addr = NULL; + INT32 status = -1; + INT32 i = 0, j = 0; + + do { + STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); + if (!p_virtual_addr) { + STP_BTM_ERR_FUNC("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); + STP_BTM_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); +#if 1 + /* wait for firmware assert */ + osal_sleep_ms(50); + /* if firmware is not assert self, host driver helps it. */ + do { + if (0 != mtk_wcn_stp_coredump_start_get()) { + status = 0; + break; + } + + mtk_wcn_stp_wakeup_consys(); + STP_BTM_INFO_FUNC("[Force Assert] wakeup consys (%d)\n", i); + stp_dbg_poll_cpupcr(5, 1, 1); + osal_sleep_ms(5); + + i++; + if (i > 20) { + i = 0; + break; + } + } while (1); +#endif + + if (0 != mtk_wcn_stp_coredump_start_get()) { + status = 0; + break; + } + + j++; + if (j > 8) { + j = 0; + break; + } + } while (1); + + return status; +} +#else +INT32 _stp_trigger_firmware_assert_via_emi(VOID) +{ + INT32 status = -1; + INT32 j = 0; + + wmt_plat_force_trigger_assert(STP_FORCE_TRG_ASSERT_DEBUG_PIN); + + do { + if (0 != mtk_wcn_stp_coredump_start_get()) { + status = 0; + break; + } + + stp_dbg_poll_cpupcr(5, 1, 1); + stp_dbg_poll_dmaregs(5, 1); + j++; + STP_BTM_INFO_FUNC("Wait for assert message (%d)\n", j); + osal_sleep_ms(20); + if (j > 49) { /* wait for 1 second */ + stp_dbg_set_fw_info("host trigger fw assert timeout", + osal_strlen("host trigger fw assert timeout"), + STP_HOST_TRIGGER_ASSERT_TIMEOUT); + wcn_core_dump_timeout(); /* trigger collect SYS_FTRACE */ + break; + } + } while (1); + + return status; +} +#endif + +#define COMBO_DUMP2AEE +#if 1 +#define STP_DBG_PAGED_DUMP_BUFFER_SIZE (32*1024*sizeof(char)) +UINT8 g_paged_dump_buffer[STP_DBG_PAGED_DUMP_BUFFER_SIZE] = { 0 }; + +#define STP_DBG_PAGED_TRACE_SIZE (2048*sizeof(char)) +UINT8 g_paged_trace_buffer[STP_DBG_PAGED_TRACE_SIZE] = { 0 }; + +UINT32 g_paged_dump_len = 0; +UINT32 g_paged_trace_len = 0; +VOID _stp_dump_emi_dump_buffer(UINT8 *buffer, UINT32 len) +{ + UINT32 i = 0; + + if (len > 16) + len = 16; + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i != 0) + pr_cont("\n "); + + if (buffer[i] == ']' || buffer[i] == '[' || buffer[i] == ',') + pr_cont("%c", buffer[i]); + else + pr_cont("0x%02x ", buffer[i]); + } +} +#endif +static INT32 _stp_btm_handler(MTKSTP_BTM_T *stp_btm, P_STP_BTM_OP pStpOp) +{ + INT32 ret = -1; + INT32 dump_sink = 1; /* core dump target, 0: aee; 1: netlink */ + INT32 Ret = 0; + static UINT32 counter; + UINT32 full_dump_left = STP_FULL_DUMP_TIME; + UINT32 page_counter = 0; + UINT32 packet_num = STP_PAGED_DUMP_TIME_LIMIT/100; + UINT32 dump_num = 0; + ENUM_STP_FW_ISSUE_TYPE issue_type; + P_CONSYS_EMI_ADDR_INFO p_ecsi; + + p_ecsi = wmt_plat_get_emi_phy_add(); + osal_assert(p_ecsi); + if (NULL == pStpOp) + return -1; + + switch (pStpOp->opId) { + case STP_OPID_BTM_EXIT: + /* TODO: clean all up? */ + ret = 0; + break; + + /*tx timeout retry */ + case STP_OPID_BTM_RETRY: + stp_do_tx_timeout(); + ret = 0; + + break; + + /*whole chip reset */ + case STP_OPID_BTM_RST: + STP_BTM_INFO_FUNC("whole chip reset start!\n"); + STP_BTM_INFO_FUNC("....+\n"); + if (stp_btm->wmt_notify) { + stp_btm->wmt_notify(BTM_RST_OP); + ret = 0; + } else { + STP_BTM_ERR_FUNC("stp_btm->wmt_notify is NULL."); + ret = -1; + } + + STP_BTM_INFO_FUNC("whole chip reset end!\n"); + + break; + + case STP_OPID_BTM_DBG_DUMP: + /*Notify the wmt to get dump data */ + STP_BTM_DBG_FUNC("wmt dmp notification\n"); + dump_sink = ((stp_btm->wmt_notify(BTM_GET_AEE_SUPPORT_FLAG) == MTK_WCN_BOOL_TRUE) ? 0 : 1); + + if (dump_sink == 0) + _stp_btm_put_dump_to_aee(); + else if (dump_sink == 1) + _stp_btm_put_dump_to_nl(); + else + STP_BTM_ERR_FUNC("unknown sink %d\n", dump_sink); + + break; + + case STP_OPID_BTM_DUMP_TIMEOUT: + /* Flush dump data, and reset compressor */ + STP_BTM_INFO_FUNC("Flush dump data\n"); + wcn_core_dump_flush(0, MTK_WCN_BOOL_TRUE); + break; + + case STP_OPID_BTM_POLL_CPUPCR: + do { + UINT32 times; + UINT32 sleep; + + times = pStpOp->au4OpData[0]; + sleep = pStpOp->au4OpData[1]; + + ret = stp_dbg_poll_cpupcr(times, sleep, 0); + ret += stp_dbg_poll_dmaregs(times, sleep); + } while (0); + break; + + case STP_OPID_BTM_PAGED_DUMP: + g_paged_dump_len = 0; + issue_type = STP_FW_ASSERT_ISSUE; + /*packet number depend on dump_num get from register:0xf0080044 ,support jade*/ + wcn_core_dump_deinit_gcoredump(); + dump_num = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_page_dump_num); + if (dump_num != 0) { + packet_num = dump_num; + STP_BTM_WARN_FUNC("get consys dump num packet_num(%d)\n", packet_num); + } else { + STP_BTM_ERR_FUNC("can not get consys dump num and default num is 35\n"); + } + Ret = wcn_core_dump_init_gcoredump(packet_num, STP_CORE_DUMP_TIMEOUT); + if (Ret) { + STP_BTM_ERR_FUNC("core dump init fail\n"); + break; + } + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + page_counter = 0; + do { + UINT32 loop_cnt1 = 0; + UINT32 loop_cnt2 = 0; + ENUM_HOST_DUMP_STATE host_state; + ENUM_CHIP_DUMP_STATE chip_state; + UINT32 dump_phy_addr = 0; + UINT8 *dump_vir_addr = NULL; + UINT32 dump_len = 0; + UINT32 isEnd = 0; + + host_state = (ENUM_HOST_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_state); + if (STP_HOST_DUMP_NOT_START == host_state) { + counter++; + STP_BTM_INFO_FUNC("counter(%d)\n", counter); + osal_sleep_ms(100); + } else { + counter = 0; + } + while (1) { + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (STP_CHIP_DUMP_PUT_DONE == chip_state) { + STP_BTM_INFO_FUNC("chip put done\n"); + break; + } + STP_BTM_INFO_FUNC("waiting chip put done\n"); + STP_BTM_INFO_FUNC("chip_state: %d\n", chip_state); + loop_cnt1++; + osal_sleep_ms(5); + + if (loop_cnt1 > 10) + goto paged_dump_end; + + } + + wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); + + dump_phy_addr = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); + + if (!dump_phy_addr) { + STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); + ret = -1; + break; + } + + dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); + if (!dump_vir_addr) { + STP_BTM_ERR_FUNC("get paged dump phy address fail\n"); + ret = -2; + break; + } + dump_len = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); + STP_BTM_INFO_FUNC("dump_phy_ddr(%08x),dump_vir_add(0x%p),dump_len(%d)\n", + dump_phy_addr, dump_vir_addr, dump_len); + + /*move dump info according to dump_addr & dump_len */ +#if 1 + osal_memcpy(&g_paged_dump_buffer[0], dump_vir_addr, dump_len); + _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], dump_len); + + if (0 == page_counter) { /* do fw assert infor paser in first paged dump */ + if (1 == stp_dbg_get_host_trigger_assert()) + issue_type = STP_HOST_TRIGGER_FW_ASSERT; + + ret = stp_dbg_set_fw_info(&g_paged_dump_buffer[0], 512, issue_type); + if (ret) { + STP_BTM_ERR_FUNC("set fw issue infor fail(%d),maybe fw warm reset...\n", ret); + stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"), + STP_FW_WARM_RST_ISSUE); + } + } + + if (dump_len <= 32 * 1024) { + pr_err("g_coredump_mode: %d!\n", g_coredump_mode); + if (1 == g_coredump_mode) + ret = stp_dbg_aee_send(&g_paged_dump_buffer[0], dump_len, 0); + else if (2 == g_coredump_mode) + ret = _stp_btm_put_emi_dump_to_nl(&g_paged_dump_buffer[0], dump_len); + else{ + STP_BTM_INFO_FUNC("coredump is disabled!\n"); + return 0; + } + if (ret == 0) + STP_BTM_INFO_FUNC("aee send ok!\n"); + else if (ret == 1) + STP_BTM_INFO_FUNC("aee send fisish!\n"); + else + STP_BTM_ERR_FUNC("aee send error!\n"); + } else + STP_BTM_ERR_FUNC("dump len is over than 32K(%d)\n", dump_len); + + g_paged_dump_len += dump_len; + STP_BTM_INFO_FUNC("dump len update(%d)\n", g_paged_dump_len); +#endif + wmt_plat_update_host_sync_num(); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); + + STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", + wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), + wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); + + page_counter++; + STP_BTM_INFO_FUNC("\n\n++ paged dump counter(%d) ++\n\n\n", page_counter); + + while (1) { + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (STP_CHIP_DUMP_END == chip_state) { + STP_BTM_INFO_FUNC("chip put end\n"); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); + break; + } + STP_BTM_INFO_FUNC("waiting chip put end\n"); + + loop_cnt2++; + osal_sleep_ms(10); + + if (loop_cnt2 > 10) + goto paged_dump_end; + } + +paged_dump_end: + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + + if (counter > packet_num) { + isEnd = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_paded_dump_end); + + if (isEnd) { + STP_BTM_INFO_FUNC("paged dump end\n"); + + STP_BTM_INFO_FUNC("\n\n paged dump print ++\n\n"); + _stp_dump_emi_dump_buffer(&g_paged_dump_buffer[0], g_paged_dump_len); + STP_BTM_INFO_FUNC("\n\n paged dump print --\n\n"); + STP_BTM_INFO_FUNC("\n\n paged dump size = %d, paged dump page number = %d\n\n", + g_paged_dump_len, page_counter); + counter = 0; + ret = 0; + } else { + STP_BTM_ERR_FUNC("paged dump fail\n"); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + stp_dbg_poll_cpupcr(5, 5, 0); + stp_dbg_poll_dmaregs(5, 1); + counter = 0; + ret = -1; + } + break; + } + + } while (1); + + break; + + case STP_OPID_BTM_FULL_DUMP: + + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + do { + UINT32 loop_cnt1 = 0; + UINT32 loop_cnt2 = 0; + ENUM_CHIP_DUMP_STATE chip_state; + UINT32 dump_phy_addr = 0; + UINT8 *dump_vir_addr = NULL; + UINT32 dump_len = 0; + UINT32 isFail = 0; + + while (1) { + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (STP_CHIP_DUMP_PUT_DONE == chip_state) + break; + + loop_cnt1++; + osal_sleep_ms(10); + + if (loop_cnt1 > 10) { + isFail = 1; + goto full_dump_end; + } + } + + wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET); + + dump_phy_addr = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); + if (!dump_phy_addr) { + STP_BTM_ERR_FUNC("get phy dump address fail\n"); + ret = -1; + break; + } + + dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); + if (!dump_vir_addr) { + STP_BTM_ERR_FUNC("get vir dump address fail\n"); + ret = -2; + break; + } + dump_len = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); + /*move dump info according to dump_addr & dump_len */ + wmt_plat_update_host_sync_num(); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); + + STP_BTM_INFO_FUNC("host sync num(%d),chip sync num(%d)\n", + wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), + wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); + + while (1) { + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (STP_CHIP_DUMP_END == chip_state) { + wmt_plat_set_host_dump_state(STP_HOST_DUMP_END); + break; + } + loop_cnt2++; + osal_sleep_ms(10); + + if (loop_cnt2 > 10) { + isFail = 1; + goto full_dump_end; + } + } + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); +full_dump_end: + if (isFail) { + STP_BTM_ERR_FUNC("full dump fail\n"); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + ret = -1; + break; + } + } while (--full_dump_left > 0); + if (0 == full_dump_left) { + STP_BTM_INFO_FUNC("full dump end\n"); + ret = 0; + } + break; + case STP_OPID_BTM_PAGED_TRACE: + g_paged_trace_len = 0; + do { + UINT32 ctrl_val = 0; + UINT32 loop_cnt1 = 0; + UINT32 buffer_start = 0; + UINT32 buffer_idx = 0; + UINT8 *dump_vir_addr = NULL; + + while (loop_cnt1 < 10) { + ctrl_val = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state); + if (0x8 == ctrl_val) + break; + osal_sleep_ms(10); + loop_cnt1++; + } + + if (loop_cnt1 >= 10) { + STP_BTM_ERR_FUNC("polling CTRL STATE fail\n"); + ret = -1; + break; + } + + buffer_start = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_start); + buffer_idx = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_idx); + /* buffer_len = buffer_idx - buffer_start; */ + g_paged_trace_len = buffer_idx; + STP_BTM_INFO_FUNC("paged trace buffer addr(%08x),buffer_len(%d)\n", buffer_start, buffer_idx); + dump_vir_addr = wmt_plat_get_emi_virt_add(buffer_start - p_ecsi->emi_phy_addr); + if (!dump_vir_addr) { + STP_BTM_ERR_FUNC("get vir dump address fail\n"); + ret = -2; + break; + } + osal_memcpy(&g_paged_trace_buffer[0], dump_vir_addr, + buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE); + /*moving paged trace according to buffer_start & buffer_len */ + do { + int i = 0; + int dump_len = 0; + + dump_len = + buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE; + pr_warn("\n\n -- paged trace hex output --\n\n"); + for (i = 0; i < dump_len; i++) { + if (i % 16 == 0) + pr_cont("\n"); + + pr_cont("%02x ", g_paged_trace_buffer[i]); + } + pr_warn("\n\n -- paged trace ascii output --\n\n"); + for (i = 0; i < dump_len; i++) { + if (i % 64 == 0) + pr_cont("\n"); + pr_cont("%c", g_paged_trace_buffer[i]); + } + } while (0); + /*move parser fw assert infor to paged dump in the one paged dump */ + /* ret = stp_dbg_set_fw_info(&g_paged_trace_buffer[0],g_paged_trace_len,issue_type); */ + ret = 0; + + } while (0); + mtk_wcn_stp_ctx_restore(); + break; + +#if CFG_WMT_LTE_COEX_HANDLING + case STP_OPID_BTM_WMT_LTE_COEX: + ret = wmt_idc_msg_to_lte_handing(); + break; +#endif + default: + ret = -1; + break; + } + + return ret; +} + +static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + /* INT32 ret = 0; */ + + if (!pOpQ) { + STP_BTM_WARN_FUNC("!pOpQ\n"); + return NULL; + } + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* acquire lock success */ + RB_GET(pOpQ, pOp); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + + if (!pOp) + STP_BTM_WARN_FUNC("RB_GET fail\n"); + + return pOp; +} + +static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 ret; + + if (!pOpQ || !pOp) { + STP_BTM_WARN_FUNC("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); + return 0; /* ;MTK_WCN_BOOL_FALSE; */ + } + + ret = 0; + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* acquire lock success */ + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + ret = -1; + + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + + if (ret) { + STP_BTM_WARN_FUNC("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", + pOpQ, + RB_COUNT(pOpQ), + &stp_btm->rFreeOpQ, + &stp_btm->rActiveOpQ); + return 0; + } + /* STP_BTM_WARN_FUNC("RB_COUNT = %d\n",RB_COUNT(pOpQ)); */ + return 1; + +} + +P_OSAL_OP _stp_btm_get_free_op(MTKSTP_BTM_T *stp_btm) +{ + P_OSAL_OP pOp; + + if (stp_btm) { + pOp = _stp_btm_get_op(stp_btm, &stp_btm->rFreeOpQ); + if (pOp) + osal_memset(&pOp->op, 0, sizeof(pOp->op)); + + return pOp; + } else + return NULL; +} + +INT32 _stp_btm_put_act_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp) +{ + INT32 bRet = 0; + INT32 bCleanup = 0; + long wait_ret = -1; + + P_OSAL_SIGNAL pSignal = NULL; + + if (!stp_btm || !pOp) { + STP_BTM_ERR_FUNC("Input NULL pointer\n"); + return bRet; + } + do { + pSignal = &pOp->signal; + + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(&pOp->signal); + } + + /* put to active Q */ + bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp); + if (0 == bRet) { + STP_BTM_WARN_FUNC("put active queue fail\n"); + bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ + break; + } + + /* wake up wmtd */ + osal_trigger_event(&stp_btm->STPd_event); + + if (pSignal->timeoutValue == 0) { + bRet = 1; /* MTK_WCN_BOOL_TRUE; */ + /* clean it in wmtd */ + break; + } + + /* wait result, clean it here */ + bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(&pOp->signal); + + STP_BTM_DBG_FUNC("wait completion:%ld\n", wait_ret); + if (!wait_ret) { + STP_BTM_ERR_FUNC("wait completion timeout\n"); + /* TODO: how to handle it? retry? */ + } else { + if (pOp->result) + STP_BTM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); + + bRet = (pOp->result) ? 0 : 1; + } + } while (0); + + if (bCleanup) { + /* put Op back to freeQ */ + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); + } + bRet = (pOp->result) ? 0 : 1; + return bRet; +} + +static INT32 _stp_btm_wait_for_msg(void *pvData) +{ + MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; + + return (!RB_EMPTY(&stp_btm->rActiveOpQ)) || osal_thread_should_stop(&stp_btm->BTMd); +} + +static INT32 _stp_btm_proc(void *pvData) +{ + MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; + P_OSAL_OP pOp; + INT32 id; + INT32 result; + + if (!stp_btm) { + STP_BTM_WARN_FUNC("!stp_btm\n"); + return -1; + } + + for (;;) { + pOp = NULL; + + osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (void *)stp_btm); + + if (osal_thread_should_stop(&stp_btm->BTMd)) { + STP_BTM_INFO_FUNC("should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeQ */ + pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); + + if (!pOp) { + STP_BTM_WARN_FUNC("get_lxop activeQ fail\n"); + continue; + } + + id = osal_op_get_id(pOp); + + STP_BTM_DBG_FUNC("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", + id, (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), + RB_COUNT(&stp_btm->rActiveOpQ)); + + if (id >= STP_OPID_BTM_NUM) { + STP_BTM_WARN_FUNC("abnormal opid id: 0x%x\n", id); + result = -1; + goto handler_done; + } + + result = _stp_btm_handler(stp_btm, &pOp->op); + +handler_done: + + if (result) { + STP_BTM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, + (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), + result); + } + + if (osal_op_is_wait_for_signal(pOp)) { + osal_op_raise_signal(pOp, result); + } else { + /* put Op back to freeQ */ + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); + } + + if (STP_OPID_BTM_EXIT == id) { + break; + } else if (STP_OPID_BTM_RST == id) { + /* prevent multi reset case */ + stp_btm_reset_btm_wq(stp_btm); + mtk_wcn_stp_coredump_start_ctrl(0); + } + } + + STP_BTM_INFO_FUNC("exits\n"); + + return 0; +}; + +static inline INT32 _stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + STP_BTM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_RST; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + STP_BTM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_RETRY; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + STP_BTM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_DUMP_TIMEOUT; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + STP_BTM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + + pOp->op.opId = opid; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) +{ + + INT32 retval; +#if 0 + UINT32 dump_type; + UINT8 *virtual_addr = NULL; +#endif + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + +#if 1 /* Paged dump */ + STP_BTM_INFO_FUNC("paged dump start++\n"); + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); + if (retval) + STP_BTM_ERR_FUNC("paged dump fail\n"); +#else + virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_CHIP_SYNC_ADDR); + if (!virtual_addr) { + STP_BTM_ERR_FUNC("get dump type virtual addr fail\n"); + return -1; + } + dump_type = CONSYS_REG_READ(virtual_addr); + STP_BTM_INFO_FUNC("dump type:%08x\n", dump_type); + + if ((dump_type & 0xfffff) == (CONSYS_PAGED_DUMP_START_ADDR & 0xfffff)) { + STP_BTM_INFO_FUNC("do paged dump\n"); + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_PAGED_DUMP); + if (retval) { + STP_BTM_ERR_FUNC("paged dump fail,do full dump\n"); + _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); + } + } else if ((dump_type & 0xfffff) == (CONSYS_FULL_DUMP_START_ADDR & 0xfffff)) { + STP_BTM_INFO_FUNC("do full dump\n"); + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_FULL_DUMP); + } else { + STP_BTM_INFO_FUNC("do normal dump\n"); + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DBG_DUMP); + } +#endif + + return retval; +} + +static inline INT32 _stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_POLL_CPUPCR; + pOp->signal.timeoutValue = 0; + pOp->op.au4OpData[0] = times; + pOp->op.au4OpData[1] = sleep; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_PAGED_TRACE; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) +{ + INT32 ret = -1; + + ret = _stp_trigger_firmware_assert_via_emi(); + + return ret; + +} + +INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_wmt_rst_wq(stp_btm); +} + +INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_stp_retry_wq(stp_btm); +} + +INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_coredump_timeout_wq(stp_btm); +} + +INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_wmt_dmp_wq(stp_btm); +} + +INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_wmt_trace_wq(stp_btm); +} + +INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep) +{ + return _stp_notify_btm_poll_cpupcr(stp_btm, times, sleep); +} + +INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en) +{ + return stp_dbg_poll_cuppcr_ctrl(en); +} + +INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) +{ + INT32 ret = -1; +#if BTIF_RXD_BE_BLOCKED_DETECT + if (is_btif_rxd_be_blocked()) + ret = wcn_btif_rxd_blocked_collect_ftrace(); /* trigger collect SYS_FTRACE */ + else +#endif + ret = _stp_btm_do_fw_assert_via_emi(stp_btm); + return ret; +} + +#if CFG_WMT_LTE_COEX_HANDLING + +static inline INT32 _stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + /* STP_BTM_WARN_FUNC("get_free_lxop fail\n"); */ + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_BTM_WMT_LTE_COEX; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) +{ + return _stp_notify_btm_handle_wmt_lte_coex(stp_btm); +} + +#endif +MTKSTP_BTM_T *stp_btm_init(void) +{ + INT32 i = 0x0; + INT32 ret = -1; + + osal_unsleepable_lock_init(&stp_btm->wq_spinlock); + osal_event_init(&stp_btm->STPd_event); + stp_btm->wmt_notify = wmt_lib_btm_cb; + + RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); + RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); + + /* Put all to free Q */ + for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_btm->arQue[i].signal)); + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); + } + + /*Generate PSM thread, to servie STP-CORE for packet retrying and core dump receiving */ + stp_btm->BTMd.pThreadData = (VOID *) stp_btm; + stp_btm->BTMd.pThreadFunc = (VOID *) _stp_btm_proc; + osal_memcpy(stp_btm->BTMd.threadName, BTM_THREAD_NAME, osal_strlen(BTM_THREAD_NAME)); + + ret = osal_thread_create(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_ERR_FUNC("osal_thread_create fail...\n"); + goto ERR_EXIT1; + } + + /* Start STPd thread */ + ret = osal_thread_run(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_ERR_FUNC("osal_thread_run FAILS\n"); + goto ERR_EXIT1; + } + + return stp_btm; + +ERR_EXIT1: + + return NULL; + +} + +INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm) +{ + + INT32 ret = -1; + + STP_BTM_INFO_FUNC("btm deinit\n"); + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + ret = osal_thread_destroy(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_ERR_FUNC("osal_thread_destroy FAILS\n"); + return STP_BTM_OPERATION_FAIL; + } + + return STP_BTM_OPERATION_SUCCESS; +} + +INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm) +{ + UINT32 i = 0; + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); + RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* Put all to free Q */ + for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_btm->arQue[i].signal)); + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c new file mode 100644 index 0000000000000..246448b38b315 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/dbg_core.c @@ -0,0 +1,13 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h new file mode 100644 index 0000000000000..9a429b4af1e30 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/btm_core.h @@ -0,0 +1,133 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _BTM_CORE_H +#define _BTM_CORE_H + +#include "osal_typedef.h" +#include "osal.h" +#include "stp_wmt.h" +#include "wmt_plat.h" +#include "wmt_idc.h" +#include "mtk_btif_exp.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define STP_BTM_OPERATION_FAIL (-1) +#define STP_BTM_OPERATION_SUCCESS (0) + +#define STP_BTM_OP_BUF_SIZE (64) + +#define BTM_THREAD_NAME "mtk_stp_btm" + +#define STP_PAGED_DUMP_TIME_LIMIT 3500 +#define STP_FULL_DUMP_TIME 3 +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_STP_BTM_OPID_T { + STP_OPID_BTM_RETRY = 0x0, + STP_OPID_BTM_RST = 0x1, + STP_OPID_BTM_DBG_DUMP = 0x2, + STP_OPID_BTM_DUMP_TIMEOUT = 0x3, + STP_OPID_BTM_POLL_CPUPCR = 0x4, + STP_OPID_BTM_PAGED_DUMP = 0x5, + STP_OPID_BTM_FULL_DUMP = 0x6, + STP_OPID_BTM_PAGED_TRACE = 0x7, + STP_OPID_BTM_FORCE_FW_ASSERT = 0x8, +#if CFG_WMT_LTE_COEX_HANDLING + STP_OPID_BTM_WMT_LTE_COEX = 0x9, +#endif + STP_OPID_BTM_EXIT, + STP_OPID_BTM_NUM +} ENUM_STP_BTM_OPID_T, *P_ENUM_STP_BTM_OPID_T; + +typedef OSAL_OP_DAT STP_BTM_OP; +typedef P_OSAL_OP_DAT P_STP_BTM_OP; + +typedef struct mtk_stp_btm { + OSAL_THREAD BTMd; /* main thread (wmtd) handle */ + OSAL_EVENT STPd_event; + OSAL_UNSLEEPABLE_LOCK wq_spinlock; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP arQue[STP_BTM_OP_BUF_SIZE]; /* real op instances */ + + /*wmt_notify */ + INT32 (*wmt_notify)(MTKSTP_BTM_WMT_OP_T); +} MTKSTP_BTM_T; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep); +INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en); +INT32 stp_btm_notify_wmt_trace_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm); +INT32 wcn_psm_flag_trigger_collect_ftrace(void); +#if BTIF_RXD_BE_BLOCKED_DETECT +INT32 wcn_btif_rxd_blocked_collect_ftrace(void); +MTK_WCN_BOOL is_btif_rxd_be_blocked(void); +#endif +MTKSTP_BTM_T *stp_btm_init(void); +extern unsigned int g_coredump_mode; +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h new file mode 100644 index 0000000000000..d8c6ebe9c4b06 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/dbg_core.h @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _DBG_CORE_H +#define _DBG_CORE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h new file mode 100644 index 0000000000000..fe92f25e92c18 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/psm_core.h @@ -0,0 +1,251 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PSM_CORE_H +#define _PSM_CORE_H + +#include "osal_typedef.h" +#include "osal.h" +#include "stp_wmt.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define PFX_PSM "[STP-PSM] " +#define STP_PSM_LOG_LOUD 4 +#define STP_PSM_LOG_DBG 3 +#define STP_PSM_LOG_INFO 2 +#define STP_PSM_LOG_WARN 1 +#define STP_PSM_LOG_ERR 0 + +#define ASSERT(expr) +#define STP_PSM_FIFO_SIZE 0x2000 /* 8kbytes */ +#define STP_PSM_TX_SIZE 0x800 /* 2kbytes */ + +#define STP_PSM_OPERATION_FAIL (-1) +#define STP_PSM_OPERATION_SUCCESS (0) + +#define STP_PSM_PACKET_SIZE_MAX (2000) + +#define PSM_HANDLING 127 + +#define STP_PSM_WMT_PS_TASK_HANDLING_TIME 30 /* 20 milli-seconds */ +#define STP_PSM_IDLE_TIME_SLEEP 30 /* temporary for stress testing */ +#define STP_PSM_IDLE_TIME_SLEEP_1000 1000 /* for high speed transmission e.g. BT OPP*/ +#define STP_PSM_SDIO_IDLE_TIME_SLEEP 100 /* temporary for SDIO stress testing */ +#define STP_PSM_WAIT_EVENT_TIMEOUT 6000 +#if 0 +#define STP_PSM_WMT_EVENT_SLEEP_EN (0x1UL << 0) +#define STP_PSM_WMT_EVENT_WAKEUP_EN (0x1UL << 1) +#define STP_PSM_BLOCK_DATA_EN (0x1UL << 2) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (0x1UL << 3) +#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (0x1UL << 4) +#define STP_PSM_RESET_EN (0x1UL << 5) +#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (0x1UL << 6) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (0x1UL << 7) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (0x1UL << 8) +#endif + +#define STP_PSM_WMT_EVENT_SLEEP_EN (0) +#define STP_PSM_WMT_EVENT_WAKEUP_EN (1) +#define STP_PSM_BLOCK_DATA_EN (2) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (3) +#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (4) +#define STP_PSM_RESET_EN (5) +#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (6) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (7) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (8) + +#define STP_PSM_DBG_SIZE (16) + +/* OP command ring buffer : must be power of 2 */ +#define STP_OP_BUF_SIZE (16) + +#define PSM_THREAD_NAME "mtk_stp_psm" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + ACT = 0, + ACT_INACT, + INACT, + INACT_ACT, + STP_PSM_MAX_STATE, +} MTKSTP_PSM_STATE_T; + +typedef enum _ENUM_STP_OPID_T { + STP_OPID_PSM_SLEEP = 0, + STP_OPID_PSM_WAKEUP, + STP_OPID_PSM_HOST_AWAKE, + STP_OPID_PSM_EXIT, + STP_OPID_PSM_NUM, + STP_OPID_PSM_INALID = STP_OPID_PSM_NUM, +} ENUM_STP_OPID_T, *P_ENUM_STP_OPID_T; + +typedef enum { + MON = 0, + UNMON, +} MTKSTP_PSM_MONSTATE_T; + +typedef INT32(*wmt_notify_t) (MTKSTP_PSM_ACTION_T action); +typedef INT32(*stp_tx_cb_t) (unsigned char *buffer, UINT32 length, UINT8 type); + +typedef OSAL_OP_DAT STP_OP; +typedef P_OSAL_OP_DAT P_STP_OP; + +typedef struct mtk_stp_psm { + OSAL_THREAD PSMd; /* main thread (wmtd) handle */ + OSAL_EVENT STPd_event; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP arQue[STP_OP_BUF_SIZE]; /* real op instances */ + + /* OSAL_OP current_active_op; */ + /* P_OSAL_OP current_active_op; */ + UINT32 last_active_opId; + MTKSTP_PSM_STATE_T work_state; /*working state */ + OSAL_BIT_OP_VAR flag; + + /* in normal cases, sleep op is always enabled; + * but in error cases, we can't execute sleep cmd, + * Eg: FW assert, core dump + */ + INT32 sleep_en; + +/* OSAL_UNSLEEPABLE_LOCK flagSpinlock; */ + INT32 idle_time_to_sleep; + OSAL_WAKE_LOCK wake_lock; + OSAL_TIMER psm_timer; /*monitor if active */ + OSAL_EVENT wait_wmt_q; + OSAL_FIFO hold_fifo; + OSAL_SLEEPABLE_LOCK hold_fifo_spinlock_global; + OSAL_UNSLEEPABLE_LOCK wq_spinlock; + OSAL_SLEEPABLE_LOCK stp_psm_lock; + INT32 (*wmt_notify)(MTKSTP_PSM_ACTION_T action); + INT32 (*stp_tx_cb)(unsigned char *buffer, UINT32 length, UINT8 type); + + MTK_WCN_BOOL (*is_wmt_quick_ps_support)(VOID); + UINT8 out_buf[STP_PSM_TX_SIZE]; +} MTKSTP_PSM_T; + +typedef struct { + UINT32 prev_flag; + UINT32 cur_flag; + UINT32 line_num; + UINT32 package_no; + UINT32 sec; + UINT32 usec; + UINT32 pid; +} STP_PSM_ENTRY_T; + +typedef struct stp_psm_record { + STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; + UINT32 in; + UINT32 out; + UINT32 size; + OSAL_UNSLEEPABLE_LOCK lock; +} STP_PSM_RECORD_T; + +typedef struct stp_psm_opid_record { + STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; + UINT32 in; + UINT32 out; + UINT32 size; + OSAL_UNSLEEPABLE_LOCK lock; +} STP_PSM_OPID_RECORD, *P_STP_PSM_OPID_RECORD; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#define PSM_USE_COUNT_PACKAGE 0 + +#if PSM_USE_COUNT_PACKAGE +#define MTK_COMBO_PSM_RX_TH_DEFAULT (1600) +#define MTK_COMBO_PSM_TX_TH_DEFAULT (300) +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir); +#else +#define SAMPLE_DURATION 1 /*1 second */ +#define RTX_SPEED_THRESHOLD 50000 /*50KB/s */ +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length); +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*stp-psm external function*/ +INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); +INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm); + +INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type); +INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep); +struct mtk_stp_psm *stp_psm_init(void); +INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm); +MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel); +INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state); +MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID); + +INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h new file mode 100644 index 0000000000000..eaa5ce773e332 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_core.h @@ -0,0 +1,629 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _STP_CORE_H +#define _STP_CORE_H + +#include "osal_typedef.h" +#include "osal.h" +#include "stp_exp.h" +#include "psm_core.h" +#include "btm_core.h" +#include "stp_btif.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CFG_STP_CORE_CTX_SPIN_LOCK (0) + +#define WMT_LTE_COEX_FLAG (0x16) + +/*configure using SPINLOCK or just mutex for STP-CORE tx*/ +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONFIG_POWER_SAVING_SUPPORT + +#ifdef PFX +#undef PFX +#endif +#define PFX "[STP] " + +#define STP_LOG_DBG 4 +#define STP_LOG_PKHEAD 3 +#define STP_LOG_INFO 2 +#define STP_LOG_WARN 1 +#define STP_LOG_ERR 0 + +extern unsigned int gStpDbgLvl; + +#define STP_DBG_FUNC(fmt, arg...)\ +do { \ + if (gStpDbgLvl >= STP_LOG_DBG) \ + osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_INFO_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgLvl >= STP_LOG_INFO) \ + osal_dbg_print(PFX "%s:[I] " fmt, __func__ , ##arg); \ +} while (0) +#define STP_WARN_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgLvl >= STP_LOG_WARN) \ + osal_warn_print(PFX "%s:[W] " fmt, __func__ , ##arg); \ +} while (0) +#define STP_ERR_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgLvl >= STP_LOG_ERR) \ + osal_err_print(PFX "%s:[E] " fmt, __func__ , ##arg); \ +} while (0) +#define STP_TRC_FUNC(f) \ +do { \ + if (gStpDbgLvl >= STP_LOG_DBG) \ + osal_dbg_print(PFX "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +#define STP_DUMP_PACKET_HEAD(a, b, c) \ +do { \ + if (gStpDbgLvl >= STP_LOG_PKHEAD) \ + stp_dump_data(a, b, c); \ +} while (0) +#define STP_TRACE_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgLvl >= STP_LOG_DBG) \ + osal_dbg_print(PFX "%s: " fmt, __func__ , ##arg); \ +} while (0) + +#define STP_MODE_BIT(x) (0x1UL << x) +#define MTKSTP_UART_FULL_MODE STP_MODE_BIT(0) +#define MTKSTP_UART_MAND_MODE STP_MODE_BIT(1) +#define MTKSTP_BTIF_FULL_MODE STP_MODE_BIT(2) +#define MTKSTP_BTIF_MAND_MODE STP_MODE_BIT(3) +#define MTKSTP_SDIO_MODE STP_MODE_BIT(4) + +#define MTKSTP_BUFFER_SIZE (16384) + +/*To check function driver's status by the the interface*/ +/*Operation definition*/ +#define OP_FUNCTION_ACTIVE 0 + +/*Driver's status*/ +#define STATUS_OP_INVALID 0 +#define STATUS_FUNCTION_INVALID 1 + +#define STATUS_FUNCTION_ACTIVE 31 +#define STATUS_FUNCTION_INACTIVE 32 + +#define MTKSTP_CRC_SIZE (2) +#define MTKSTP_HEADER_SIZE (4) +#define MTKSTP_SEQ_SIZE (8) + +/*#define MTKSTP_WINSIZE (4)*/ +#define MTKSTP_WINSIZE (7) +#define MTKSTP_TX_TIMEOUT (180) /*TODO: Baudrate to decide this */ +#define MTKSTP_RETRY_LIMIT (10) + +#define INDEX_INC(idx) \ +{ \ + idx++; \ + idx &= 0x7; \ +} + +#define INDEX_DEC(idx) \ +{ \ + idx--; \ + idx &= 0x7; \ +} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef INT32(*IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); +/* event/signal */ +typedef INT32(*EVENT_SET) (UINT8 function_type); +typedef INT32(*EVENT_TX_RESUME) (UINT8 winspace); +typedef INT32(*FUNCTION_STATUS) (UINT8 type, UINT8 op); +typedef INT32(*WMT_NOTIFY_FUNC_T) (UINT32 action); +typedef INT32(*BTM_NOTIFY_WMT_FUNC_T) (INT32); + +#if CFG_STP_CORE_CTX_SPIN_LOCK +typedef OSAL_UNSLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; +#else +typedef OSAL_SLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; +#endif + +typedef struct { + /* common interface */ + IF_TX cb_if_tx; + /* event/signal */ + EVENT_SET cb_event_set; + EVENT_TX_RESUME cb_event_tx_resume; + FUNCTION_STATUS cb_check_funciton_status; +} mtkstp_callback; + +typedef enum { + MTKSTP_SYNC = 0, + MTKSTP_SEQ, + MTKSTP_ACK, + MTKSTP_NAK, + MTKSTP_TYPE, + MTKSTP_LENGTH, + MTKSTP_CHECKSUM, + MTKSTP_DATA, + MTKSTP_CRC1, + MTKSTP_CRC2, + MTKSTP_RESYNC1, + MTKSTP_RESYNC2, + MTKSTP_RESYNC3, + MTKSTP_RESYNC4, + MTKSTP_FW_MSG, +} mtkstp_parser_state; + +typedef struct { + mtkstp_parser_state state; + UINT8 seq; + UINT8 ack; + UINT8 nak; + UINT8 type; + UINT16 length; + UINT8 checksum; + UINT16 crc; +#if 1 + UINT8 wmtsubtype; +#endif +} mtkstp_parser_context_struct; + +typedef struct { + UINT8 txseq; /* last tx pkt's seq + 1 */ + UINT8 txack; /* last tx pkt's ack */ + UINT8 rxack; /* last rx pkt's ack */ + UINT8 winspace; /* current sliding window size */ + UINT8 expected_rxseq; /* last rx pkt's seq + 1 */ + UINT8 retry_times; +} mtkstp_sequence_context_struct; + +typedef struct { + /* MTK_WCN_MUTEX mtx; */ + OSAL_UNSLEEPABLE_LOCK mtx; + UINT8 buffer[MTKSTP_BUFFER_SIZE]; + UINT32 read_p; + UINT32 write_p; +} mtkstp_ring_buffer_struct; + +typedef struct { + UINT8 inband_rst_set; + UINT32 rx_counter; /* size of current processing pkt in rx_buf[] */ + UINT8 rx_buf[MTKSTP_BUFFER_SIZE]; /* input buffer of STP, room for current processing pkt */ + UINT32 tx_read; /* read ptr of tx_buf[] */ + UINT32 tx_write; /* write ptr of tx_buf[] */ + UINT8 tx_buf[MTKSTP_BUFFER_SIZE]; /* output buffer of STP */ + UINT32 tx_start_addr[MTKSTP_SEQ_SIZE]; /* ptr of each pkt in tx_buf[] */ + UINT32 tx_length[MTKSTP_SEQ_SIZE]; /* length of each pkt in tx_buf[] */ + mtkstp_ring_buffer_struct ring[MTKSTP_MAX_TASK_NUM]; /* ring buffers for each function driver */ + mtkstp_parser_context_struct parser; /* current rx pkt's content */ + mtkstp_sequence_context_struct sequence; /* state machine's current status */ + /* MTK_WCN_MUTEX stp_mutex; */ + /* OSAL_UNSLEEPABLE_LOCK stp_mutex; */ + STP_CTX_LOCK stp_mutex; + /* MTK_WCN_TIMER tx_timer; // timer for tx timeout handling */ + OSAL_TIMER tx_timer; + + MTKSTP_PSM_T *psm; + MTKSTP_BTM_T *btm; + UINT8 f_enable; /* default disabled */ + UINT8 f_ready; /* default non-ready */ + UINT8 f_pending_type; + UINT8 f_coredump; /*block tx flag, for now, only when f/w assert happens, we will set this bit on */ + UINT8 en_coredump; + /* Flag to identify Blueztooth is Bluez/or MTK Stack */ + MTK_WCN_BOOL f_bluez; + MTK_WCN_BOOL f_dbg_en; + MTK_WCN_BOOL f_autorst_en; + + /* Flag to identify STP by SDIO or UART */ + UINT32 f_mode; + + /* Flag to indicate the last WMT CLOSE */ + UINT32 f_wmt_last_close; + + /* Flag to indicate evt err has triggered assert or not */ + UINT32 f_evt_err_assert; +} mtkstp_context_struct; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_init +* DESCRIPTION +* init STP kernel +* PARAMETERS +* cb_func [IN] function pointers of system APIs +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_deinit +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 mtk_wcn_stp_deinit(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_enable +* DESCRIPTION +* enable/disable STP +* PARAMETERS +* value [IN] 0 = disable, others = enable +* RETURNS +* INT32 0 = success, others = error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_enable(INT32 value); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_ready +* DESCRIPTION +* ready/non-ready STP +* PARAMETERS +* value [IN] 0 = non-ready, others = ready +* RETURNS +* INT32 0 = success, others = error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_ready(INT32 value); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_ctrl +* DESCRIPTION +* set f/w assert flag in STP context +* PARAMETERS +* value [IN] 0=assert end, others=assert begins +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get f/w assert flag in STP context +* PARAMETERS +* VOID +* RETURNS +* INT32 0= f/w assert flag is not set, others=f/w assert flag is set +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_get(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data_raw +* DESCRIPTION +* send raw data to common interface, bypass STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 length transmitted +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_set_sdio_mode +* DESCRIPTION +* Set stp for SDIO mode +* PARAMETERS +* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_mode(UINT32 sdio_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_fullset_mode +* DESCRIPTION +* Is stp use UART Fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:UART Fullset, FALSE:UART Fullset +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_mand_mode +* DESCRIPTION +* Is stp use UART Mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:UART Mandatory, FALSE:UART Mandatory +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void); +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_fullset_mode +* DESCRIPTION +* Is stp use BTIF Fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Fullset, FALSE:BTIF Fullset +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_mand_mode +* DESCRIPTION +* Is stp use BTIF Mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Mandatory, FALSE:BTIF Mandatory +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_sdio_mode +* DESCRIPTION +* Is stp use SDIO mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void); + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To sync to oringnal stp state with f/w stp +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern void mtk_wcn_stp_inband_reset(void); + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To send testing command to chip +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern void mtk_wcn_stp_test_cmd(INT32 no); + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To control STP debugging mechanism +* PARAMETERS +* func_no: function control, func_op: dumpping filer, func_param: dumpping parameter +* RETURNS +* none +*****************************************************************************/ +extern void mtk_wcn_stp_debug_ctrl(INT32 func_no, INT32 func_op, INT32 func_param); +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush +* DESCRIPTION +* flush all stp context +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern void mtk_wcn_stp_flush_context(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_rx_queue +* DESCRIPTION +* flush all stp rx queue +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern void mtk_wcn_stp_flush_rx_queue(UINT32 type); + +/***************************************************************************** +* FUNCTION +* set stp debugging mdoe +* DESCRIPTION +* set stp debugging mdoe +* PARAMETERS +* dbg_mode: switch to dbg mode ? +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode); + +/***************************************************************************** +* FUNCTION +* set stp auto reset mdoe +* DESCRIPTION +* set stp auto reset mdoe +* PARAMETERS +* auto_rst: switch to auto reset mode ? +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst); + +/*stp_psm support*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_notify_stp +* DESCRIPTION +* WMT notification to STP that power saving job is done or not +* PARAMETERS +* +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern int mtk_wcn_stp_psm_notify_stp(const UINT32 action); + +extern int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_enabla +* DESCRIPTION +* enable STP PSM +* PARAMETERS +* int idle_time_to_sleep: IDLE time to sleep +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern int mtk_wcn_stp_psm_enable(int idle_time_to_sleep); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_disable +* DESCRIPTION +* disable STP PSM +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern int mtk_wcn_stp_psm_disable(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_reset +* DESCRIPTION +* reset STP PSM (used on whole chip reset) +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern int mtk_wcn_stp_psm_reset(void); +extern void stp_do_tx_timeout(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_btm_get_dmp +* DESCRIPTION +* get stp dump related information +* PARAMETERS +* buffer: dump placement, len: dump size +* RETURNS +* 0: Success Negative Value: Fail +*****************************************************************************/ +extern int mtk_wcn_stp_btm_get_dmp(char *buf, int *len); + +extern int mtk_wcn_stp_dbg_enable(void); + +extern int mtk_wcn_stp_dbg_disable(void); + +extern void mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type); + +extern int mtk_wcn_sys_if_rx(UINT8 *data, INT32 size); + +extern MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel); + +extern INT32 mtk_wcn_stp_dbg_dump_package(VOID); + +extern int stp_drv_init(void); + +extern void stp_drv_exit(void); + +extern INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on); + +extern INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on); + +extern INT32 mtk_wcn_stp_coredump_flag_get(VOID); +extern INT32 mtk_wcn_stp_notify_sleep_for_thermal(void); + +extern INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value); + +/*stp btif API declared*/ +extern INT32 mtk_wcn_stp_open_btif(VOID); +extern INT32 mtk_wcn_stp_close_btif(VOID); +extern INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb); +extern INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len); +extern INT32 mtk_wcn_stp_wakeup_consys(VOID); +extern INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); +extern INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); +extern INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag); +extern VOID mtk_wcn_stp_ctx_save(VOID); +extern VOID mtk_wcn_stp_ctx_restore(VOID); +extern INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(VOID); +extern VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value); +extern UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(VOID); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _STP_CORE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h new file mode 100644 index 0000000000000..94b3d8a597ac3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/stp_wmt.h @@ -0,0 +1,89 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _STP_WMT_H +#define _STP_WMT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum { + BTM_RST_OP = 0, + BTM_DMP_OP = 1, + BTM_GET_AEE_SUPPORT_FLAG = 2, + BTM_MAX_OP, +} MTKSTP_BTM_WMT_OP_T; + +typedef enum { + SLEEP = 0, + HOST_AWAKE, + WAKEUP, + EIRQ, + ROLL_BACK, + STP_PSM_MAX_ACTION +} MTKSTP_PSM_ACTION_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +extern MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op); + +extern INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action); +extern MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _STP_WMT_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h new file mode 100644 index 0000000000000..4c64b6b5e65bb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_conf.h @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_CONF_H_ +#define _WMT_CONF_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CUST_CFG_WMT "WMT_SOC.cfg" +#define CUST_CFG_WMT_PREFIX "/system/etc/firmware/" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_conf_read_file(VOID); +P_WMT_GEN_CONF wmt_conf_get_cfg(VOID); +INT32 wmt_conf_set_cfg_file(const char *name); + +#endif /* _WMT_CONF_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h new file mode 100644 index 0000000000000..cca52a15cc982 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_core.h @@ -0,0 +1,428 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_CORE_H_ +#define _WMT_CORE_H_ + +#include "osal.h" +#include "wmt_ctrl.h" +#include "wmt_exp.h" +#include "wmt_plat.h" +/* TODO: [GeorgeKuo][FixMe] remove temporarily */ +/* for AIF state definition */ +/* #include "mtk_wcn_cmb_stub.h" */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CFG_CORE_MT6620_SUPPORT 0 /* whether MT6620 is supported or not */ + +#define CFG_CORE_MT6628_SUPPORT 0 /* whether MT6628 is supported or not */ + +#define CFG_CORE_SOC_SUPPORT 1 + +/* TODO:[ChangeFeature][George] move this definition outside so that wmt_dev can remove wmt_core.h inclusion. */ +#define defaultPatchName "mt66xx_patch_hdr.bin" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define BCNT_PATCH_BUF_HEADROOM (8) + +#define DWCNT_HIF_CONF (4) +#define DWCNT_STRAP_CONF (4) +#define DWCNT_RESERVED (8) +#define DWCNT_CTRL_DATA (16) + +#if 0 /* TODO: [obsolete][GeorgeKuo]: remove ubsolete definitions */ +#define WMT_SET (1) +#define WMT_QUERY (0) +#define WMT_PKT_FMT_RAW (1) +#define WMT_PKT_FMT_STP (0) +#endif + +#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE) +#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE) + +#define WMT_HDR_LEN (4) /* header length */ +#define WMT_STS_LEN (1) /* status length */ +#define WMT_FLAG_LEN (1) +#define WMT_HIF_UART_INFO_LEN (4) +#define WMT_FUNC_CTRL_PARAM_LEN (1) + +#define WMT_DEFAULT_BAUD_RATE (115200) + +#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_WMT_FM_T { + WMT_FM_INVALID = 0, + WMT_FM_I2C = 1, + WMT_FM_COMM = 2, + WMT_FM_MAX +} ENUM_WMT_FM_T, *P_ENUM_WMT_FM_T; + +typedef enum _ENUM_WMT_HIF_T { + WMT_HIF_UART = 0, + WMT_HIF_SDIO = 1, + WMT_HIF_BTIF = 2, + WMT_HIF_MAX +} ENUM_WMT_HIF_T, *P_ENUM_WMT_HIF_T; + +#if 0 /* [George] moved to wmt_exp.h for hif_sdio's use */ +typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM; + +typedef enum { + WMT_SDIO_FUNC_STP = 0, + WMT_SDIO_FUNC_WIFI = 1, + WMT_SDIO_FUNC_MAX +} WMT_SDIO_FUNC_TYPE; +#endif + +typedef enum _ENUM_WMT_OPID_T { + WMT_OPID_HIF_CONF = 0, + WMT_OPID_PWR_ON = 1, + WMT_OPID_PWR_OFF = 2, + WMT_OPID_FUNC_ON = 3, + WMT_OPID_FUNC_OFF = 4, + WMT_OPID_REG_RW = 5, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ + WMT_OPID_EXIT = 6, + WMT_OPID_PWR_SV = 7, + WMT_OPID_DSNS = 8, + WMT_OPID_LPBK = 9, + WMT_OPID_CMD_TEST = 10, + WMT_OPID_HW_RST = 11, + WMT_OPID_SW_RST = 12, + WMT_OPID_BAUD_RST = 13, + WMT_OPID_STP_RST = 14, + WMT_OPID_THERM_CTRL = 15, + WMT_OPID_EFUSE_RW = 16, + WMT_OPID_GPIO_CTRL = 17, + WMT_OPID_FW_COREDMP = 18, + WMT_OPID_GPIO_STATE = 19, + WMT_OPID_BGW_DS = 20, + WMT_OPID_SET_MCU_CLK = 21, + WMT_OPID_ADIE_LPBK_TEST = 22, +#if CFG_WMT_LTE_COEX_HANDLING + WMT_OPID_IDC_MSG_HANDLING = 23, +#endif +#ifdef CONFIG_MTK_COMBO_ANT + WMT_OPID_ANT_RAM_DOWN = 24, + WMT_OPID_ANT_RAM_STA_GET = 25, +#endif + WMT_OPID_MAX +} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T; + +typedef OSAL_OP_DAT WMT_OP; +typedef P_OSAL_OP_DAT P_WMT_OP; + +typedef struct _WMT_HIF_CONF { + UINT32 hifType; /* HIF Type */ + UINT32 au4HifConf[DWCNT_HIF_CONF]; /* HIF Config */ + UINT32 au4StrapConf[DWCNT_STRAP_CONF]; /* Strap Config */ +} WMT_HIF_CONF, *P_WMT_HIF_CONF; + +typedef INT32(*WMT_OPID_FUNC) (P_WMT_OP); + +typedef struct _WMT_GEN_CONF { + UINT8 cfgExist; + + UINT8 coex_wmt_ant_mode; + UINT8 coex_wmt_ext_component; + UINT8 coex_wmt_wifi_time_ctl; + UINT8 coex_wmt_ext_pta_dev_on; + /*mt6592 and LTE coex filter mode setting */ + UINT8 coex_wmt_filter_mode; + + UINT8 coex_bt_rssi_upper_limit; + UINT8 coex_bt_rssi_mid_limit; + UINT8 coex_bt_rssi_lower_limit; + UINT8 coex_bt_pwr_high; + UINT8 coex_bt_pwr_mid; + UINT8 coex_bt_pwr_low; + + UINT8 coex_wifi_rssi_upper_limit; + UINT8 coex_wifi_rssi_mid_limit; + UINT8 coex_wifi_rssi_lower_limit; + UINT8 coex_wifi_pwr_high; + UINT8 coex_wifi_pwr_mid; + UINT8 coex_wifi_pwr_low; + + UINT8 coex_ext_pta_hi_tx_tag; + UINT8 coex_ext_pta_hi_rx_tag; + UINT8 coex_ext_pta_lo_tx_tag; + UINT8 coex_ext_pta_lo_rx_tag; + UINT16 coex_ext_pta_sample_t1; + UINT16 coex_ext_pta_sample_t2; + UINT8 coex_ext_pta_wifi_bt_con_trx; + + UINT32 coex_misc_ext_pta_on; + UINT32 coex_misc_ext_feature_set; + /*GPS LNA setting */ + UINT8 wmt_gps_lna_pin; + UINT8 wmt_gps_lna_enable; + /*Power on sequence */ + UINT8 pwr_on_rtc_slot; + UINT8 pwr_on_ldo_slot; + UINT8 pwr_on_rst_slot; + UINT8 pwr_on_off_slot; + UINT8 pwr_on_on_slot; + UINT8 co_clock_flag; + + /* Combo chip side SDIO driving setting */ + UINT32 sdio_driving_cfg; + +} WMT_GEN_CONF, *P_WMT_GEN_CONF; + +typedef enum _ENUM_DRV_STS_ { +#if 0 + DRV_STS_INVALID = 0, + DRV_STS_UNREG = 1, /* Initial State */ +#endif + DRV_STS_POWER_OFF = 0, /* initial state */ + DRV_STS_POWER_ON = 1, /* powered on, only WMT */ + DRV_STS_FUNC_ON = 2, /* FUNC ON */ + DRV_STS_MAX +} ENUM_DRV_STS, *P_ENUM_DRV_STS; + +typedef enum _WMT_IC_PIN_ID_ { + WMT_IC_PIN_AUDIO = 0, + WMT_IC_PIN_EEDI = 1, + WMT_IC_PIN_EEDO = 2, + WMT_IC_PIN_GSYNC = 3, + WMT_IC_PIN_MAX +} WMT_IC_PIN_ID, *P_WMT_IC_PIN_ID; + +typedef enum _WMT_IC_PIN_STATE_ { + WMT_IC_PIN_EN = 0, + WMT_IC_PIN_DIS = 1, + WMT_IC_AIF_0 = 2, /* = CMB_STUB_AIF_0, */ + WMT_IC_AIF_1 = 3, /* = CMB_STUB_AIF_1, */ + WMT_IC_AIF_2 = 4, /* = CMB_STUB_AIF_2, */ + WMT_IC_AIF_3 = 5, /* = CMB_STUB_AIF_3, */ + WMT_IC_PIN_MUX = 6, + WMT_IC_PIN_GPIO = 7, + WMT_IC_PIN_GPIO_HIGH = 8, + WMT_IC_PIN_GPIO_LOW = 9, + WMT_IC_PIN_STATE_MAX +} WMT_IC_PIN_STATE, *P_WMT_IC_PIN_STATE; + +typedef enum _WMT_CO_CLOCK_ { + WMT_CO_CLOCK_DIS = 0, + WMT_CO_CLOCK_EN = 1, + WMT_CO_CLOCK_MAX +} WMT_CO_CLOCK, *P_WMT_CO_CLOCK; + +typedef INT32(*SW_INIT) (P_WMT_HIF_CONF pWmtHifConf); +typedef INT32(*SW_DEINIT) (P_WMT_HIF_CONF pWmtHifConf); +typedef INT32(*IC_PIN_CTRL) (WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); +typedef INT32(*IC_VER_CHECK) (VOID); +typedef INT32(*CO_CLOCK_CTRL) (WMT_CO_CLOCK on); +typedef MTK_WCN_BOOL(*IS_QUICK_SLEEP_SUPPORT) (VOID); +typedef MTK_WCN_BOOL(*IS_AEE_DUMP_SUPPORT) (VOID); + +typedef struct _WMT_IC_OPS_ { + UINT32 icId; + SW_INIT sw_init; + SW_DEINIT sw_deinit; + IC_PIN_CTRL ic_pin_ctrl; + IC_VER_CHECK ic_ver_check; + CO_CLOCK_CTRL co_clock_ctrl; + IS_QUICK_SLEEP_SUPPORT is_quick_sleep; + IS_AEE_DUMP_SUPPORT is_aee_dump_support; +} WMT_IC_OPS, *P_WMT_IC_OPS; + +typedef struct _WMT_CTX_ { + ENUM_DRV_STS eDrvStatus[WMTDRV_TYPE_MAX]; /* Controlled driver status */ + UINT32 wmtInfoBit; /* valid info bit */ + WMT_HIF_CONF wmtHifConf; /* HIF information */ + + /* Pointer to WMT_IC_OPS. Shall be assigned to a correct table in stp_init + * if and only if getting chip id successfully. hwver and fwver are kept in + * WMT-IC module only. + */ + P_WMT_IC_OPS p_ic_ops; +} WMT_CTX, *P_WMT_CTX; + +/* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ +/* Using this struct relies on compiler's implementation and pack() settings */ +typedef struct _WMT_PKT_ { + UINT8 eType; /* PKT_TYPE_* */ + UINT8 eOpCode; /* OPCODE_* */ + UINT16 u2SduLen; /* 2 bytes length, little endian */ + UINT8 aucParam[32]; +} WMT_PKT, *P_WMT_PKT; + +/* WMT Packet Format */ +typedef enum _ENUM_PKT_TYPE { + PKT_TYPE_INVALID = 0, + PKT_TYPE_CMD = 1, + PKT_TYPE_EVENT = 2, + _PKT_TYPE_MAX +} ENUM_PKT_TYPE, *P_ENUM_PKT_TYPE; + +typedef enum _ENUM_OPCODE { + OPCODE_INVALID = 0, + OPCODE_PATCH = 1, + OPCODE_TEST = 2, + OPCODE_WAKEUP = 3, + OPCODE_HIF = 4, + OPCODE_STRAP_CONF = 5, + OPCODE_FUNC_CTRL = 6, + OPCODE_RESET = 7, + OPCODE_INT = 8, + OPCODE_MAX +} ENUM_OPCODE, *P_ENUM_OPCODE; + +typedef enum { + WMT_STP_CONF_EN = 0, + WMT_STP_CONF_RDY = 1, + WMT_STP_CONF_MODE = 2, + WMT_STP_CONF_MAX +} WMT_STP_CONF_TYPE; + +struct init_script { + UINT8 *cmd; + UINT32 cmdSz; + UINT8 *evt; + UINT32 evtSz; + UINT8 *str; +}; + +typedef struct _WMT_PATCH { + UINT8 ucDateTime[16]; + UINT8 ucPLat[4]; + UINT16 u2HwVer; + UINT16 u2SwVer; + UINT32 u4PatchVer; +} WMT_PATCH, *P_WMT_PATCH; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CFG_CORE_MT6620_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6620; +#endif + +#if CFG_CORE_MT6628_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6628; +#endif + +#if CFG_CORE_SOC_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_soc; +#endif +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern INT32 wmt_core_init(VOID); +extern INT32 wmt_core_deinit(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmtd +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 wmt_core_opid(P_WMT_OP pWmtOp); + +extern INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2); + +extern INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn); + +extern INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask); + +extern VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len); + +extern MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer); + +extern INT32 wmt_core_init_script(struct init_script *script, INT32 count); + +extern INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize); + +extern INT32 wmt_core_tx(const PUINT8 pData, UINT32 size, PUINT32 writtenSize, MTK_WCN_BOOL bRawFlag); +extern MTK_WCN_BOOL wmt_core_is_quick_ps_support(void); + +extern MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void); + +#if CFG_CORE_INTERNAL_TXRX +extern INT32 wmt_core_lpbk_do_stp_init(void); +extern INT32 wmt_core_lpbk_do_stp_deinit(void); +#endif + +extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state); +#if CFG_WMT_LTE_COEX_HANDLING +extern VOID wmt_core_set_flag_for_test(UINT32 enable); +extern UINT32 wmt_core_get_flag_for_test(VOID); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static _osal_inline_ MTK_WCN_BOOL wmt_core_ic_ops_check(P_WMT_IC_OPS p_ops) +{ + if (!p_ops) + return MTK_WCN_BOOL_FALSE; + + if ((NULL == p_ops->sw_init) + || (NULL == p_ops->sw_deinit) + || (NULL == p_ops->ic_ver_check) + || (NULL == p_ops->ic_pin_ctrl)) + return MTK_WCN_BOOL_FALSE; + else + return MTK_WCN_BOOL_TRUE; +} + +#endif /* _WMT_CORE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h new file mode 100644 index 0000000000000..0ff3d6058c394 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ctrl.h @@ -0,0 +1,120 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_CTRL_H_ +#define _WMT_CTRL_H_ + +#include "osal.h" +#include "wmt_stp_exp.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define DWCNT_CTRL_DATA (16) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _WMT_CTRL_DATA_ { + SIZE_T ctrlId; + SIZE_T au4CtrlData[DWCNT_CTRL_DATA]; +} WMT_CTRL_DATA, *P_WMT_CTRL_DATA; + +typedef enum _ENUM_WMT_CTRL_T { + WMT_CTRL_HW_PWR_OFF = 0, /* whole chip power off */ + WMT_CTRL_HW_PWR_ON = 1, /* whole chip power on */ + WMT_CTRL_HW_RST = 2, /* whole chip rst */ + WMT_CTRL_STP_CLOSE = 3, + WMT_CTRL_STP_OPEN = 4, + WMT_CTRL_STP_CONF = 5, + WMT_CTRL_FREE_PATCH = 6, + WMT_CTRL_GET_PATCH = 7, + WMT_CTRL_GET_PATCH_NAME = 8, + WMT_CTRL_HWIDVER_SET = 9, /* TODO: rename this and add chip id information in addition to chip version */ + WMT_CTRL_STP_RST = 10, + WMT_CTRL_GET_WMT_CONF = 11, + WMT_CTRL_TX = 12, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ + WMT_CTRL_RX = 13, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ + WMT_CTRL_RX_FLUSH = 14, /* [FixMe][SeanWang]: to be removed by Sean's stp integration */ + WMT_CTRL_GPS_SYNC_SET = 15, + WMT_CTRL_GPS_LNA_SET = 16, + WMT_CTRL_PATCH_SEARCH = 17, + WMT_CTRL_CRYSTAL_TRIMING_GET = 18, + WMT_CTRL_CRYSTAL_TRIMING_PUT = 19, + WMT_CTRL_HW_STATE_DUMP = 20, + WMT_CTRL_GET_PATCH_NUM = 21, + WMT_CTRL_GET_PATCH_INFO = 22, + WMT_CTRL_SOC_PALDO_CTRL = 23, + WMT_CTRL_SOC_WAKEUP_CONSYS = 24, + WMT_CTRL_SET_STP_DBG_INFO = 25, + WMT_CTRL_BGW_DESENSE_CTRL = 26, + WMT_CTRL_EVT_ERR_TRG_ASSERT = 27, +#if CFG_WMT_LTE_COEX_HANDLING + WMT_CTRL_GET_TDM_REQ_ANTSEL = 28, +#endif + WMT_CTRL_EVT_PARSER = 29, + WMT_CTRL_MAX +} ENUM_WMT_CTRL_T, *P_ENUM_WMT_CTRL_T; + +typedef INT32(*WMT_CTRL_FUNC) (P_WMT_CTRL_DATA); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData); + +extern INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_CTRL_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h new file mode 100644 index 0000000000000..d586f442e7ef0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_func.h @@ -0,0 +1,140 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_FUNC_H_ +#define _WMT_FUNC_H_ + +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_core.h" +#include "wmt_plat.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if 1 /* defined(CONFIG_MTK_COMBO_HCI_DRIVER) || defined(CONFIG_MTK_COMBO_BT) */ +#define CFG_FUNC_BT_SUPPORT 1 +#else +#define CFG_FUNC_BT_SUPPORT 0 +#endif + +#if 1 /* defined(CONFIG_MTK_COMBO_FM) */ +#define CFG_FUNC_FM_SUPPORT 1 +#else +#define CFG_FUNC_FM_SUPPORT 0 +#endif + +#if 1 /* defined(CONFIG_MTK_COMBO_GPS) */ +#define CFG_FUNC_GPS_SUPPORT 1 +#else +#define CFG_FUNC_GPS_SUPPORT 0 +#endif + +#if 1 /* defined(CONFIG_MTK_COMBO_WIFI) */ +#define CFG_FUNC_WIFI_SUPPORT 1 +#else +#define CFG_FUNC_WIFI_SUPPORT 0 +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef INT32(*SUBSYS_FUNC_ON) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +typedef INT32(*SUBSYS_FUNC_OFF) (P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +typedef struct _WMT_FUNC_OPS_ { + SUBSYS_FUNC_ON func_on; + SUBSYS_FUNC_OFF func_off; +} WMT_FUNC_OPS, *P_WMT_FUNC_OPS; + +typedef struct _CMB_PIN_CTRL_REG_ { + UINT32 regAddr; + UINT32 regValue; + UINT32 regMask; + +} CMB_PIN_CTRL_REG, *P_CMB_PIN_CTRL_REG; + +typedef struct _CMB_PIN_CTRL_ { + UINT32 pinId; + UINT32 regNum; + P_CMB_PIN_CTRL_REG pFuncOnArray; + P_CMB_PIN_CTRL_REG pFuncOffArray; + +} CMB_PIN_CTRL, *P_CMB_PIN_CTRL; + +typedef enum _ENUM_CMP_PIN_ID_ { + CMB_PIN_EEDI_ID = 0, + CMB_PIN_EEDO_ID = 1, + CMB_PIN_GSYNC_ID = 2, +} ENUM_CMP_PIN_ID, *P_ENUM_CMP_PIN_ID; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CFG_FUNC_BT_SUPPORT +extern WMT_FUNC_OPS wmt_func_bt_ops; +#endif + +#if CFG_FUNC_FM_SUPPORT +extern WMT_FUNC_OPS wmt_func_fm_ops; +#endif + +#if CFG_FUNC_GPS_SUPPORT +extern WMT_FUNC_OPS wmt_func_gps_ops; +#endif + +#if CFG_FUNC_WIFI_SUPPORT +extern WMT_FUNC_OPS wmt_func_wifi_ops; +#endif +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_FUNC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h new file mode 100644 index 0000000000000..901becfdb92f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_ic.h @@ -0,0 +1,122 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_IC_H_ +#define _WMT_IC_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "wmt_core.h" +#include "wmt_exp.h" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define WMT_IC_NAME_MT6620 "MT6620" +#define WMT_IC_NAME_MT6628 "MT6628" +#define WMT_IC_NAME_DEFAULT "SOC_CONSYS" + +#define WMT_IC_VER_E1 "E1" +#define WMT_IC_VER_E2 "E2" +#define WMT_IC_VER_E3 "E3" +#define WMT_IC_VER_E4 "E4" +#define WMT_IC_VER_E5 "E5" +#define WMT_IC_VER_E6 "E6" + +#define WMT_IC_PATCH_DUMMY_EXT "_ex" +#define WMT_IC_PATCH_NO_EXT "" +#define WMT_IC_PATCH_E1_EXT "_e1" +#define WMT_IC_PATCH_E2_EXT "_e2" +#define WMT_IC_PATCH_E3_EXT "_e3" +#define WMT_IC_PATCH_E4_EXT "_e4" +#define WMT_IC_PATCH_E5_EXT "_e5" +#define WMT_IC_PATCH_E6_EXT "_e6" + +#define WMT_IC_PATCH_TAIL "_hdr.bin" + +#define WMT_IC_INVALID_CHIP_ID 0xFFFF + +#define MAJORNUM(x) (x & 0x00F0) +#define MINORNUM(x) (x & 0x000F) + +/******************************************************************************* +* R E G I S T E R M A P +******************************************************************************** +*/ +/* General definition used for ALL/UNKNOWN CHIPS */ +/* Now MT6620 uses these definitions */ +#define GEN_CONFG_BASE (0x80000000UL) +#define GEN_HVR (GEN_CONFG_BASE + 0x0UL) /* HW_VER */ +#define GEN_FVR (GEN_CONFG_BASE + 0x4UL) /* FW_VER */ +#define GEN_VER_MASK (0x0000FFFFUL) /* HW_VER and FW_VER valid bits mask */ +#define GEN_HCR (GEN_CONFG_BASE + 0x8UL) /* HW_CODE, chip id */ +#define GEN_HCR_MASK (0x0000FFFFUL) /* HW_CODE valid bits mask */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _WMT_IC_INFO_S { + UINT32 u4HwVer; /* u4HwId */ + PUINT8 cChipName; + PUINT8 cChipVersion; + PUINT8 cPatchNameExt; + MTK_WCN_BOOL bPsmSupport; + MTK_WCN_BOOL bWorkWithoutPatch; + ENUM_WMTHWVER_TYPE_T eWmtHwVer; +} WMT_IC_INFO_S, *P_WMT_IC_INFO_S; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_IC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h new file mode 100644 index 0000000000000..b0c05cf3a2529 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/include/wmt_lib.h @@ -0,0 +1,300 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_LIB_H_ +#define _WMT_LIB_H_ + +#include "osal.h" +#include "wmt_core.h" +#include "wmt_exp.h" +#include +#include "stp_wmt.h" +#include "wmt_plat.h" +#include "wmt_idc.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define WMT_OP_BUF_SIZE (16) + +typedef enum _ENUM_WMTRSTRET_TYPE_T { + WMTRSTRET_SUCCESS = 0x0, + WMTRSTRET_FAIL = 0x1, + WMTRSTRET_ONGOING = 0x2, + WMTRSTRET_MAX +} ENUM_WMTRSTRET_TYPE_T, *P_ENUM_WMTRSTRET_TYPE_T; + +/* +3(retry times) * 180 (STP retry time out) ++ 10 (firmware process time) + +10 (transmit time) + +10 (uart process -> WMT response pool) + +230 (others) +*/ +#define WMT_LIB_RX_TIMEOUT 20000 /*800-->cover v1.2phone BT function on time (~830ms) */ +/* +open wifi during wifi power on procedure +(because wlan is insert to system after mtk_hif_sdio module, +so wifi card is not registered to hif module +when mtk_wcn_wmt_func_on is called by wifi through rfkill) +*/ +#define MAX_WIFI_ON_TIME 55000 + +#define WMT_PWRON_RTY_DFT 2 +#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT) +#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY WMT_LIB_RX_TIMEOUT /*each WMT command */ +#define MAX_FUNC_ON_TIME \ + (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT + MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3) + +#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ +#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4) + +#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000) /*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ + +#define MAX_GPIO_CTRL_TIME (2000) /* [FixMe][GeorgeKuo] a temp value */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* AIF FLAG definition */ +/* bit(0): share pin or not */ +#define WMT_LIB_AIF_FLAG_MASK (0x1UL) +#define WMT_LIB_AIF_FLAG_SHARE (0x1UL << 0) +#define WMT_LIB_AIF_FLAG_SEPARATE (0x0UL << 0) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* bit field offset definition */ +typedef enum { + WMT_STAT_PWR = 0, /* is powered on */ + WMT_STAT_STP_REG = 1, /* is STP driver registered: */ + WMT_STAT_STP_OPEN = 2, /* is STP opened: default FALSE */ + WMT_STAT_STP_EN = 3, /* is STP enabled: default FALSE */ + WMT_STAT_STP_RDY = 4, /* is STP ready for client: default FALSE */ + WMT_STAT_RX = 5, /* is rx data available */ + WMT_STAT_CMD = 6, /* is cmd string to be read */ + WMT_STAT_RST_ON = 7, + WMT_STAT_MAX +} WMT_STAT; + +typedef enum _ENUM_WMTRSTSRC_TYPE_T { + WMTRSTSRC_RESET_BT = 0x0, + WMTRSTSRC_RESET_FM = 0x1, + WMTRSTSRC_RESET_GPS = 0x2, + WMTRSTSRC_RESET_WIFI = 0x3, + WMTRSTSRC_RESET_STP = 0x4, + WMTRSTSRC_RESET_TEST = 0x5, + WMTRSTSRC_RESET_MAX +} ENUM_WMTRSTSRC_TYPE_T, *P_ENUM_WMTRSTSRC_TYPE_T; + +typedef struct { + PF_WMT_CB fDrvRst[4]; +} WMT_FDRV_CB, *P_WMT_FDRV_CB; + +typedef struct { + UINT32 dowloadSeq; + UINT8 addRess[4]; + UINT8 patchName[256]; +} WMT_PATCH_INFO, *P_WMT_PATCH_INFO; + +/* OS independent wrapper for WMT_OP */ +typedef struct _DEV_WMT_ { + + OSAL_SLEEPABLE_LOCK psm_lock; + OSAL_SLEEPABLE_LOCK idc_lock; + /* WMTd thread information */ + /* struct task_struct *pWmtd; */ + OSAL_THREAD thread; /* main thread (wmtd) handle */ + /* wait_queue_head_t rWmtdWq; */ + OSAL_EVENT rWmtdWq; /*WMTd command wait queue */ + /* ULONG state; */ + OSAL_BIT_OP_VAR state; /* bit field of WMT_STAT */ + + /* STP context information */ + /* wait_queue_head_t rWmtRxWq; */ + OSAL_EVENT rWmtRxWq; /* STP Rx wait queue */ + /* WMT_STP_FUNC rStpFunc; */ + WMT_FDRV_CB rFdrvCb; /* STP functions */ + + /* WMT Configurations */ + WMT_HIF_CONF rWmtHifConf; + WMT_GEN_CONF rWmtGenConf; + + /* Patch information */ + UINT8 cPatchName[NAME_MAX + 1]; + UINT8 cFullPatchName[NAME_MAX + 1]; + UINT32 patchNum; + + const osal_firmware *pPatch; + + UINT8 cWmtcfgName[NAME_MAX + 1]; + const osal_firmware *pWmtCfg; + + const osal_firmware *pNvram; + + /* Current used UART port description */ + INT8 cUartName[NAME_MAX + 1]; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP arQue[WMT_OP_BUF_SIZE]; /* real op instances */ + P_OSAL_OP pCurOP; /* current op */ + + /* cmd str buffer */ + UINT8 cCmd[NAME_MAX + 1]; + INT32 cmdResult; + /* struct completion cmd_comp; */ + /* wait_queue_head_t cmd_wq; */ + OSAL_SIGNAL cmdResp; /* read command queues */ + OSAL_EVENT cmdReq; + + /* WMT loopback Thread Information */ + /* WMT_CMB_VER combo_ver; */ + /* P_WMT_CMB_CHIP_INFO_S pChipInfo; */ + UINT32 chip_id; + UINT32 hw_ver; + UINT32 fw_ver; + /* TODO: [FixMe][GeorgeKuo] remove this translated version code in the */ + /* future. Just return the above 3 info to querist */ + ENUM_WMTHWVER_TYPE_T eWmtHwVer; + + P_WMT_PATCH_INFO pWmtPatchInfo; +} DEV_WMT, *P_DEV_WMT; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern DEV_WMT gDevWmt; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +extern INT32 wmt_lib_init(VOID); +extern INT32 wmt_lib_deinit(VOID); +extern INT32 wmt_lib_tx(PUINT8 data, UINT32 size, PUINT32 writtenSize); +extern INT32 wmt_lib_tx_raw(PUINT8 data, UINT32 size, PUINT32 writtenSize); +extern INT32 wmt_lib_rx(PUINT8 buff, UINT32 buffLen, PUINT32 readSize); +extern VOID wmt_lib_flush_rx(VOID); + +#if CFG_WMT_PS_SUPPORT +extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime); +extern INT32 wmt_lib_ps_init(VOID); +extern INT32 wmt_lib_ps_deinit(VOID); +extern INT32 wmt_lib_ps_enable(VOID); +extern INT32 wmt_lib_ps_ctrl(UINT32 state); + +extern INT32 wmt_lib_ps_disable(VOID); +extern VOID wmt_lib_ps_irq_cb(VOID); +#endif +extern VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb); + +/* LXOP functions: */ +extern P_OSAL_OP wmt_lib_get_free_op(VOID); +extern INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp); +extern MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp); + +/* extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); */ +extern UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T type); + +extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID); +extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID); +extern INT32 wmt_lib_trigger_cmd_signal(INT32 result); +extern PUINT8 wmt_lib_get_cmd(VOID); +extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID); +extern INT32 wmt_lib_set_patch_name(PUINT8 cPatchName); +extern INT32 wmt_lib_set_hif(unsigned long hifconf); +extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID); +extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID); + +/* GeorgeKuo: replace set_chip_gpio() with more specific ones */ +#if 0 /* moved to wmt_exp.h */ +extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ +#endif +extern INT32 wmt_lib_host_awake_get(VOID); +extern INT32 wmt_lib_host_awake_put(VOID); +extern UINT32 wmt_lib_dbg_level_set(UINT32 level); + +extern INT32 wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); + +extern INT32 wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); +ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src); +MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst); +MTK_WCN_BOOL wmt_lib_hw_rst(VOID); +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); +INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); + +extern INT32 DISABLE_PSM_MONITOR(void); +extern VOID ENABLE_PSM_MONITOR(void); +extern INT32 wmt_lib_notify_stp_sleep(void); +extern void wmt_lib_psm_lock_release(void); +extern INT32 wmt_lib_psm_lock_aquire(void); +extern VOID wmt_lib_idc_lock_release(VOID); +extern INT32 wmt_lib_idc_lock_aquire(VOID); +extern INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value); + +extern VOID wmt_lib_set_patch_num(UINT32 num); +extern VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo); +extern INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp); +extern P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev); +extern PUINT8 wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, PUINT8 buff, UINT32 len); +extern INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee); +extern PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 len); +extern INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl); +extern UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en); +extern INT8 wmt_lib_co_clock_get(VOID); +extern UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver); + +#if CFG_WMT_LTE_COEX_HANDLING +extern MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor); +#endif +#if CFG_WMT_PS_SUPPORT +extern UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en); +#endif +#if CONSYS_ENALBE_SET_JTAG +extern UINT32 wmt_lib_jtag_flag_set(UINT32 en); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_LIB_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c new file mode 100644 index 0000000000000..f37da4761009e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/psm_core.c @@ -0,0 +1,1889 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +#include "osal_typedef.h" +#include "osal.h" +#include "psm_core.h" +#include "stp_core.h" +#include + +INT32 gPsmDbgLevel = STP_PSM_LOG_INFO; +MTKSTP_PSM_T stp_psm_i; +MTKSTP_PSM_T *stp_psm = &stp_psm_i; + +STP_PSM_RECORD_T *g_stp_psm_dbg = NULL; +static UINT32 g_record_num; + +P_STP_PSM_OPID_RECORD g_stp_psm_opid_dbg = NULL; +static UINT32 g_opid_record_num; + +#define STP_PSM_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) \ + pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_PSM_DBG_FUNC(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ + pr_debug(PFX_PSM "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_PSM_INFO_FUNC(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_INFO) \ + pr_debug(PFX_PSM "[I]%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_PSM_WARN_FUNC(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_WARN) \ + pr_warn(PFX_PSM "[W]%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_PSM_ERR_FUNC(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_ERR) \ + pr_err(PFX_PSM "[E]%s(%d):ERROR! " fmt, __func__ , __LINE__, ##arg); \ +} while (0) +#define STP_PSM_TRC_FUNC(f) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ + pr_debug(PFX_PSM "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); +static INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); +static INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); +static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num); +static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg); + +static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num); +static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg); + +static const char *g_psm_state[STP_PSM_MAX_STATE] = { + "ACT", + "ACT_INACT", + "INACT", + "INACT_ACT" +}; + +static const char *g_psm_action[STP_PSM_MAX_ACTION] = { + "SLEEP", + "HOST_AWAKE", + "WAKEUP", + "EIRQ", + "ROLL_BACK" +}; + +static const char *g_psm_op_name[STP_OPID_PSM_NUM] = { + "STP_OPID_PSM_SLEEP", + "STP_OPID_PSM_WAKEUP", + "STP_OPID_PSM_HOST_AWAKE", + "STP_OPID_PSM_EXIT" +}; + +static int _stp_psm_release_data(MTKSTP_PSM_T *stp_psm); + +static inline int _stp_psm_get_state(MTKSTP_PSM_T *stp_psm); + +static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ); + +static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ); +static MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID); + +MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(UINT32 dbglevel) +{ + if (dbglevel <= 4) { + gPsmDbgLevel = dbglevel; + STP_PSM_INFO_FUNC("gPsmDbgLevel = %d\n", gPsmDbgLevel); + return true; + } + STP_PSM_INFO_FUNC("invalid psm debug level. gPsmDbgLevel = %d\n", gPsmDbgLevel); + + return false; +} + +static INT32 _stp_psm_handler(MTKSTP_PSM_T *stp_psm, P_STP_OP pStpOp) +{ + INT32 ret = -1; + + /* if (NULL == pStpOp) */ + /* { */ + /* return -1; */ + /* } */ + ret = _stp_psm_thread_lock_aquire(stp_psm); + if (ret) { + STP_PSM_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); + return ret; + } + + switch (pStpOp->opId) { + case STP_OPID_PSM_EXIT: + /* TODO: clean all up? */ + ret = 0; + break; + + case STP_OPID_PSM_SLEEP: + if (stp_psm_check_sleep_enable(stp_psm) > 0) + ret = _stp_psm_notify_wmt(stp_psm, SLEEP); + else + STP_PSM_INFO_FUNC("cancel sleep request\n"); + + break; + + case STP_OPID_PSM_WAKEUP: + ret = _stp_psm_notify_wmt(stp_psm, WAKEUP); + break; + + case STP_OPID_PSM_HOST_AWAKE: + ret = _stp_psm_notify_wmt(stp_psm, HOST_AWAKE); + break; + + default: + STP_PSM_ERR_FUNC("invalid operation id (%d)\n", pStpOp->opId); + ret = -1; + break; + } + _stp_psm_thread_lock_release(stp_psm); + return ret; +} + +static P_OSAL_OP _stp_psm_get_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + + if (!pOpQ) { + STP_PSM_WARN_FUNC("pOpQ == NULL\n"); + return NULL; + } + + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* acquire lock success */ + RB_GET(pOpQ, pOp); + + if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) { + /* stp_psm->current_active_op = pOp; */ + stp_psm->last_active_opId = pOp->op.opId; + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + + if ((pOpQ == &stp_psm->rActiveOpQ) && (NULL != pOp)) + STP_PSM_DBG_FUNC("last_active_opId(%d)\n", stp_psm->last_active_opId); + + if (!pOp) + STP_PSM_WARN_FUNC("RB_GET fail\n"); + + return pOp; +} + +static INT32 _stp_psm_dump_active_q(P_OSAL_OP_Q pOpQ) +{ + UINT32 read_idx; + UINT32 write_idx; + UINT32 opId; + + if (pOpQ == &stp_psm->rActiveOpQ) { + read_idx = stp_psm->rActiveOpQ.read; + write_idx = stp_psm->rActiveOpQ.write; + + STP_PSM_DBG_FUNC("Active op list:++\n"); + while ((read_idx & RB_MASK(pOpQ)) != (write_idx & RB_MASK(pOpQ))) { + opId = pOpQ->queue[read_idx & RB_MASK(pOpQ)]->op.opId; + if (opId < STP_OPID_PSM_NUM) + STP_PSM_DBG_FUNC("%s\n", g_psm_op_name[opId]); + else + STP_PSM_WARN_FUNC("Unknown OP Id\n"); + + ++read_idx; + } + STP_PSM_DBG_FUNC("Active op list:--\n"); + } else { + STP_PSM_DBG_FUNC("%s: not active queue, dont dump\n", __func__); + } + + return 0; +} + +static int _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ) +{ + unsigned int opId = 0; + unsigned int prev_opId = 0; + + /* if((pOpQ == &stp_psm->rActiveOpQ) && (NULL != stp_psm->current_active_op)) */ + if ((pOpQ == &stp_psm->rActiveOpQ) && (STP_OPID_PSM_INALID != stp_psm->last_active_opId)) { + opId = pOp->op.opId; + + if (opId == STP_OPID_PSM_SLEEP) { + if (RB_EMPTY(pOpQ)) { + /* prev_opId = stp_psm->current_active_op->op.opId; */ + prev_opId = stp_psm->last_active_opId; + } else { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + } + + if (prev_opId == STP_OPID_PSM_SLEEP) { + STP_PSM_DBG_FUNC("redundant sleep opId found\n"); + return 1; + } else { + return 0; + } + } else { + if (RB_EMPTY(pOpQ)) { + /* prev_opId = stp_psm->current_active_op->op.opId; */ + prev_opId = stp_psm->last_active_opId; + } else { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + } + + if (((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_WAKEUP)) || + ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_WAKEUP)) || + ((opId == STP_OPID_PSM_HOST_AWAKE) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) || + ((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) + ) { + STP_PSM_DBG_FUNC("redundant opId found, opId(%d), preOpid(%d)\n", opId, prev_opId); + return 1; + } else { + return 0; + } + } + } else { + return 0; + } + +} + +static int _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ) +{ + unsigned int prev_opId = 0; + unsigned int prev_prev_opId = 0; + + P_OSAL_OP pOp; + P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; + + if (pOpQ == &stp_psm->rActiveOpQ) { + /* sleep , wakeup | sleep, --> null | sleep (x) */ + /* wakeup , sleep , wakeup | sleep --> wakeup | sleep (v) */ + /* sleep , wakeup , sleep | wakeup --> sleep | wakeup (v) */ + /* xxx, sleep | sleep --> xxx, sleep (v) */ + /* xxx, wakeup | wakeup --> xxx, wakeup (v) */ + /* xxx, awake | awake --> xxx, awake (v) --> should never happen */ + while (RB_COUNT(pOpQ) > 2) { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + prev_prev_opId = pOpQ->queue[(pOpQ->write - 2) & RB_MASK(pOpQ)]->op.opId; + + if ((prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_WAKEUP) || + (prev_opId == STP_OPID_PSM_SLEEP && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE) || + (prev_opId == STP_OPID_PSM_WAKEUP && prev_prev_opId == STP_OPID_PSM_SLEEP) || + (prev_opId == STP_OPID_PSM_HOST_AWAKE && prev_prev_opId == STP_OPID_PSM_SLEEP) + ) { + RB_GET(pOpQ, pOp); + RB_PUT(pFreeOpQ, pOp); + RB_GET(pOpQ, pOp); + RB_PUT(pFreeOpQ, pOp); + } else if (prev_opId == prev_prev_opId) { + RB_GET(pOpQ, pOp); + STP_PSM_DBG_FUNC("redundant opId(%d) found, remove it\n", pOp->op.opId); + RB_PUT(pFreeOpQ, pOp); + } + } + } + + return 0; +} + +static INT32 _stp_psm_put_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 ret; + + /* if (!pOpQ || !pOp) */ + /* { */ + /* STP_PSM_WARN_FUNC("pOpQ = 0x%p, pLxOp = 0x%p\n", pOpQ, pOp); */ + /* return 0; */ + /* } */ + ret = 0; + + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* acquire lock success */ + if (pOpQ == &stp_psm->rActiveOpQ) { + if (!_stp_psm_is_redundant_active_op(pOp, pOpQ)) { + /* acquire lock success */ + if (!RB_FULL(pOpQ)) { + RB_PUT(pOpQ, pOp); + STP_PSM_DBG_FUNC("opId(%d) enqueue\n", pOp->op.opId); + } else { + STP_PSM_INFO_FUNC("************ Active Queue Full ************\n"); + ret = -1; + } + + _stp_psm_clean_up_redundant_active_op(pOpQ); + } else { + /*redundant opId, mark ret as success */ + P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; + + if (!RB_FULL(pFreeOpQ)) + RB_PUT(pFreeOpQ, pOp); + else + osal_assert(!RB_FULL(pFreeOpQ)); + + ret = 0; + } + } else { + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + ret = -1; + + } + + if (pOpQ == &stp_psm->rActiveOpQ) + _stp_psm_dump_active_q(&stp_psm->rActiveOpQ); + + + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + STP_PSM_DBG_FUNC("stp_psm do unlock,active queue? (%s)\n", (pOpQ == &stp_psm->rActiveOpQ) ? "y" : "n"); + + if (ret) { + STP_PSM_WARN_FUNC("RB_FULL, RB_COUNT=%d , RB_SIZE=%d\n", RB_COUNT(pOpQ), RB_SIZE(pOpQ)); + return 0; + } else + return 1; + +} + +P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + + if (stp_psm) { + pOp = _stp_psm_get_op(stp_psm, &stp_psm->rFreeOpQ); + if (pOp) + osal_memset(&pOp->op, 0, sizeof(pOp->op)); + + return pOp; + } else + return NULL; + +} + +INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp) +{ + INT32 bRet = 0; /* MTK_WCN_BOOL_FALSE; */ + INT32 bCleanup = 0; /* MTK_WCN_BOOL_FALSE; */ + INT32 wait_ret = -1; + P_OSAL_SIGNAL pSignal = NULL; + + do { + if (!stp_psm || !pOp) { + STP_PSM_ERR_FUNC("stp_psm = %p, pOp = %p\n", stp_psm, pOp); + break; + } + + pSignal = &pOp->signal; + + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(&pOp->signal); + } + + /* put to active Q */ + bRet = _stp_psm_put_op(stp_psm, &stp_psm->rActiveOpQ, pOp); + + if (0 == bRet) { + STP_PSM_WARN_FUNC("+++++++++++ Put op Active queue Fail\n"); + bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ + break; + } + _stp_psm_opid_dbg_dmp_in(g_stp_psm_opid_dbg, pOp->op.opId, __LINE__); + + /* wake up wmtd */ + osal_trigger_event(&stp_psm->STPd_event); + + if (pSignal->timeoutValue == 0) { + bRet = 1; /* MTK_WCN_BOOL_TRUE; */ + /* clean it in wmtd */ + break; + } + + /* wait result, clean it here */ + bCleanup = 1; /* MTK_WCN_BOOL_TRUE; */ + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(&pOp->signal); + STP_PSM_DBG_FUNC("wait completion:%d\n", wait_ret); + if (!wait_ret) { + STP_PSM_ERR_FUNC("wait completion timeout\n"); + /* TODO: how to handle it? retry? */ + } else { + if (pOp->result) + STP_PSM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); + /* op completes, check result */ + bRet = (pOp->result) ? 0 : 1; + } + } while (0); + + if (bCleanup) { + /* put Op back to freeQ */ + bRet = _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp); + if (bRet == 0) + STP_PSM_WARN_FUNC("+++++++++++ Put op active free fail, maybe disable/enable psm\n"); + } + + return bRet; +} + +static INT32 _stp_psm_wait_for_msg(void *pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; + + STP_PSM_DBG_FUNC("%s: stp_psm->rActiveOpQ = %d\n", __func__, RB_COUNT(&stp_psm->rActiveOpQ)); + + return (!RB_EMPTY(&stp_psm->rActiveOpQ)) || osal_thread_should_stop(&stp_psm->PSMd); +} + +static INT32 _stp_psm_proc(void *pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; + P_OSAL_OP pOp; + UINT32 id; + INT32 result; + + if (!stp_psm) { + STP_PSM_WARN_FUNC("!stp_psm\n"); + return -1; + } +/* STP_PSM_INFO_FUNC("wmtd starts running: pWmtDev(0x%p) [pol, rt_pri, n_pri, pri]=[%d, %d, %d, %d]\n", */ +/* stp_psm, current->policy, current->rt_priority, current->normal_prio, current->prio); */ + + for (;;) { + + pOp = NULL; + + osal_wait_for_event(&stp_psm->STPd_event, _stp_psm_wait_for_msg, (void *)stp_psm); + + /* we set reset flag when calling stp_reset after cleanup all op. */ + if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_RESET_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + if (osal_thread_should_stop(&stp_psm->PSMd)) { + STP_PSM_INFO_FUNC("should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeQ */ + pOp = _stp_psm_get_op(stp_psm, &stp_psm->rActiveOpQ); + if (!pOp) { + STP_PSM_WARN_FUNC("+++++++++++ Get op from activeQ fail, maybe disable/enable psm\n"); + continue; + } + + id = osal_op_get_id(pOp); + + if (id >= STP_OPID_PSM_NUM) { + STP_PSM_WARN_FUNC("abnormal opid id: 0x%x\n", id); + result = -1; + goto handler_done; + } + + result = _stp_psm_handler(stp_psm, &pOp->op); + +handler_done: + + if (result) { + STP_PSM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, + (id >= 4) ? ("???") : (g_psm_op_name[id]), result); + } + + if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, result); + else { + /* put Op back to freeQ */ + if (_stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp) == 0) + STP_PSM_WARN_FUNC("+++++++++++ Put op to FreeOpQ fail, maybe disable/enable psm\n"); + } + + if (STP_OPID_PSM_EXIT == id) + break; + } + STP_PSM_INFO_FUNC("exits\n"); + + return 0; +}; + +static inline INT32 _stp_psm_get_time(void) +{ + if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) + osal_printtimeofday(">>>"); + + return 0; +} + +static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm) +{ + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + if (stp_psm->work_state < STP_PSM_MAX_STATE) + return stp_psm->work_state; + STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); + + return STP_PSM_OPERATION_FAIL; +} + +static inline INT32 _stp_psm_set_state(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_STATE_T state) +{ + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + if (stp_psm->work_state < STP_PSM_MAX_STATE) { + _stp_psm_get_time(); + /* STP_PSM_INFO_FUNC("work_state = %s --> %s\n", + * g_psm_state[stp_psm->work_state], g_psm_state[state]); + */ + + stp_psm->work_state = state; + if (stp_psm->work_state != ACT) { + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + osal_set_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + } + } else + STP_PSM_ERR_FUNC("work_state = %d, invalid\n", stp_psm->work_state); + + + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) +{ + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_DBG_FUNC("STP-PSM DISABLE, DONT restart monitor!\n\r"); + return STP_PSM_OPERATION_SUCCESS; + } + + STP_PSM_LOUD_FUNC("start monitor\n"); + osal_timer_modify(&stp_psm->psm_timer, stp_psm->idle_time_to_sleep); + + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_stop_monitor(MTKSTP_PSM_T *stp_psm) +{ + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + STP_PSM_DBG_FUNC("stop monitor\n"); + osal_timer_stop_sync(&stp_psm->psm_timer); + + return STP_PSM_OPERATION_SUCCESS; +} + +INT32 _stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) +{ + INT32 available_space = 0; + INT32 needed_space = 0; + UINT8 delimiter[] = { 0xbb, 0xbb }; + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + available_space = STP_PSM_FIFO_SIZE - osal_fifo_len(&stp_psm->hold_fifo); + needed_space = len + sizeof(UINT8) + sizeof(UINT32) + 2; + + /* STP_PSM_INFO_FUNC("*******FIFO Available(%d), Need(%d)\n", available_space, needed_space); */ + + if (available_space < needed_space) { + STP_PSM_ERR_FUNC("FIFO Available!! Reset FIFO\n"); + osal_fifo_reset(&stp_psm->hold_fifo); + } + /* type */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); + /* length */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); + /* buffer */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) buffer, len); + /* delimiter */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); + + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + return len; + +} + +INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) +{ + return osal_fifo_len(&stp_psm->hold_fifo); +} + +INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm) +{ + + INT32 i = 20; /*Max buffered packet number */ + INT32 ret = 0; + UINT8 type = 0; + UINT32 len = 0; + UINT8 delimiter[2]; + + /* STP_PSM_ERR_FUNC("++++++++++release data++len=%d\n", osal_fifo_len(&stp_psm->hold_fifo)); */ + while (osal_fifo_len(&stp_psm->hold_fifo) && i > 0) { + /* acquire spinlock */ + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); + + if (len > STP_PSM_PACKET_SIZE_MAX) { + STP_PSM_ERR_FUNC("***psm packet's length too Long!****\n"); + STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); + } else { + osal_memset(stp_psm->out_buf, 0, STP_PSM_TX_SIZE); + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) stp_psm->out_buf, len); + } + + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); + + if (delimiter[0] == 0xbb && delimiter[1] == 0xbb) { + /* osal_buffer_dump(stp_psm->out_buf, "psm->out_buf", len, 32); */ + stp_send_data_no_ps(stp_psm->out_buf, len, type); + } else { + STP_PSM_ERR_FUNC("***psm packet fifo parsing fail****\n"); + STP_PSM_INFO_FUNC("***reset psm's fifo***\n"); + + osal_fifo_reset(&stp_psm->hold_fifo); + } + i--; + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + } + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_notify_wmt_host_awake_wq(MTKSTP_PSM_T *stp_psm) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + + pOp->op.opId = STP_OPID_PSM_HOST_AWAKE; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + + STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + + retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 0; + + return retval; +} + +static inline INT32 _stp_psm_notify_wmt_wakeup_wq(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + + pOp->op.opId = STP_OPID_PSM_WAKEUP; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + if (0 == bRet) { + STP_PSM_WARN_FUNC("OPID(%d) type(%zd) bRet(%s)\n\n", + pOp->op.opId, pOp->op.au4OpData[0], "fail"); + } + retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : (STP_PSM_OPERATION_SUCCESS); + + return retval; +} + +static inline INT32 _stp_psm_notify_wmt_sleep_wq(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag)) + return 0; +#if PSM_USE_COUNT_PACKAGE + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag)) + return 0; +#endif + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) + return 0; + + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_WARN_FUNC("get_free_lxop fail\n"); + return -1; /* break; */ + } + + pOp->op.opId = STP_OPID_PSM_SLEEP; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + + STP_PSM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + + retval = (0 == bRet) ? (STP_PSM_OPERATION_FAIL) : 1; + + return retval; +} + +/*internal function*/ + +static inline INT32 _stp_psm_reset(MTKSTP_PSM_T *stp_psm) +{ + INT32 i = 0; + P_OSAL_OP_Q pOpQ; + P_OSAL_OP pOp; + + STP_PSM_DBG_FUNC("PSM MODE RESET=============================>\n\r"); + + STP_PSM_DBG_FUNC("_stp_psm_reset\n"); + STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_unlock(&stp_psm->wake_lock); + STP_PSM_DBG_FUNC("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + + /* --> disable psm <--// */ + stp_psm->flag.data = 0; + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_stop_monitor(stp_psm); + + /* --> prepare the op list <--// */ + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); + RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); + + /* stp_psm->current_active_op = NULL; */ + stp_psm->last_active_opId = STP_OPID_PSM_INALID; + + pOpQ = &stp_psm->rFreeOpQ; + for (i = 0; i < STP_OP_BUF_SIZE; i++) { + if (!RB_FULL(pOpQ)) { + pOp = &stp_psm->arQue[i]; + RB_PUT(pOpQ, pOp); + } + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + + /* --> clean up interal data structure<--// */ + _stp_psm_set_state(stp_psm, ACT); + + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + osal_fifo_reset(&stp_psm->hold_fifo); + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + /* --> stop psm thread wait <--// */ + osal_set_bit(STP_PSM_RESET_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_trigger_event(&stp_psm->wait_wmt_q); + + STP_PSM_DBG_FUNC("PSM MODE RESET<============================\n\r"); + + return STP_PSM_OPERATION_SUCCESS; +} + +static INT32 _stp_psm_wait_wmt_event(void *pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; + + STP_PSM_DBG_FUNC("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data); + + return (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)); +} + +static inline INT32 _stp_psm_wait_wmt_event_wq(MTKSTP_PSM_T *stp_psm) +{ + + INT32 retval = 0; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + osal_wait_for_event_timeout(&stp_psm->wait_wmt_q, _stp_psm_wait_wmt_event, (void *)stp_psm); + + if (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); +/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + /* STP send data here: STP enqueue data to psm buffer. */ + _stp_psm_release_data(stp_psm); + /* STP send data here: STP enqueue data to psm buffer. We release packet by the next one. */ + osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* STP send data here: STP sends data directly without PSM. */ + _stp_psm_set_state(stp_psm, ACT); +/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + + if (stp_psm_is_quick_ps_support()) + stp_psm_notify_wmt_sleep(stp_psm); + else + _stp_psm_start_monitor(stp_psm); + } else if (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_set_state(stp_psm, INACT); + + STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle++\n"); + mt_combo_plt_enter_deep_idle(COMBO_IF_BTIF); + STP_PSM_DBG_FUNC("mt_combo_plt_enter_deep_idle--\n"); + + STP_PSM_DBG_FUNC("sleep-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_unlock(&stp_psm->wake_lock); + STP_PSM_DBG_FUNC("sleep-wake_lock#(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + } else if (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + if (_stp_psm_get_state(stp_psm) == ACT_INACT) { + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + _stp_psm_release_data(stp_psm); + osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_set_state(stp_psm, ACT); + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + } else if (_stp_psm_get_state(stp_psm) == INACT_ACT) { + _stp_psm_set_state(stp_psm, INACT); + STP_PSM_INFO_FUNC("[WARNING]PSM state rollback due too wakeup fail\n"); + } + } else if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } else { + STP_PSM_ERR_FUNC("flag = %ld<== Abnormal flag be set!!\n\r", stp_psm->flag.data); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + wcn_psm_flag_trigger_collect_ftrace(); /* trigger collect SYS_FTRACE */ + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + } + retval = STP_PSM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + + INT32 retval = 0; + + if (action == EIRQ) { + STP_PSM_DBG_FUNC("Call _stp_psm_notify_wmt_host_awake_wq\n\r"); + + _stp_psm_notify_wmt_host_awake_wq(stp_psm); + + return STP_PSM_OPERATION_FAIL; + } + + if ((_stp_psm_get_state(stp_psm) < STP_PSM_MAX_STATE) && (_stp_psm_get_state(stp_psm) >= 0)) { + STP_PSM_DBG_FUNC("state = %s, action=%s\n\r", g_psm_state[_stp_psm_get_state(stp_psm)], + g_psm_action[action]); + } + /* If STP trigger WAKEUP and SLEEP, to do the job below */ + switch (_stp_psm_get_state(stp_psm)) { + /* stp trigger */ + case ACT_INACT: + + if (action == SLEEP) { + STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, ready to INACT\n\r", g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == ROLL_BACK) { + STP_PSM_LOUD_FUNC("Action = %s, ACT_INACT state, back to ACT\n\r", g_psm_action[action]); + /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */ + osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else { + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_ERR_FUNC("Action = %s, ACT_INACT state, the case should not happens\n\r", + g_psm_action[action]); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = STP_PSM_OPERATION_FAIL; + } + break; + /* stp trigger */ + + case INACT_ACT: + + if (action == WAKEUP) { + STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == HOST_AWAKE) { + STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, ready to ACT\n\r", g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == ROLL_BACK) { + STP_PSM_LOUD_FUNC("Action = %s, INACT_ACT state, back to INACT\n\r", g_psm_action[action]); + osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else { + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_ERR_FUNC("Action = %s, INACT_ACT state, the case should not happens\n\r", + g_psm_action[action]); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = STP_PSM_OPERATION_FAIL; + } + break; + + case INACT: + + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_ERR_FUNC("Action = %s, INACT state, the case should not happens\n\r", + g_psm_action[action]); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = -1; + + break; + + case ACT: + + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_ERR_FUNC("Action = %s, ACT state, the case should not happens\n\r", + g_psm_action[action]); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = STP_PSM_OPERATION_FAIL; + + break; + + default: + + /*invalid */ + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_ERR_FUNC("Action = %s, Invalid state, the case should not happens\n\r", + g_psm_action[action]); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_ERR_FUNC("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = STP_PSM_OPERATION_FAIL; + + break; + } + + return retval; + +} + +static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + INT32 ret = 0; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + switch (_stp_psm_get_state(stp_psm)) { + case ACT: + + if (action == SLEEP) { + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_ERR_FUNC("psm monitor disabled, can't do sleep op\n"); + return STP_PSM_OPERATION_FAIL; + } + + _stp_psm_set_state(stp_psm, ACT_INACT); + + _stp_psm_release_data(stp_psm); + + if (stp_psm->wmt_notify) { + stp_psm->wmt_notify(SLEEP); + _stp_psm_wait_wmt_event_wq(stp_psm); + } else { + STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == WAKEUP || action == HOST_AWAKE) { + STP_PSM_INFO_FUNC("In ACT state, dont do WAKEUP/HOST_AWAKE again\n"); + _stp_psm_release_data(stp_psm); + } else { + STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + + } + + break; + + case INACT: + + if (action == WAKEUP) { + _stp_psm_set_state(stp_psm, INACT_ACT); + + if (stp_psm->wmt_notify) { + STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_DBG_FUNC("wakeup +wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); + + STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); + mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); + STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); + + stp_psm->wmt_notify(WAKEUP); + _stp_psm_wait_wmt_event_wq(stp_psm); + } else { + STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == HOST_AWAKE) { + _stp_psm_set_state(stp_psm, INACT_ACT); + + if (stp_psm->wmt_notify) { + STP_PSM_DBG_FUNC("host awake +wake_lock(%d)\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_DBG_FUNC("host awake +wake_lock(%d)#\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + + STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle++\n"); + mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); + STP_PSM_DBG_FUNC("mt_combo_plt_exit_deep_idle--\n"); + + stp_psm->wmt_notify(HOST_AWAKE); + _stp_psm_wait_wmt_event_wq(stp_psm); + } else { + STP_PSM_ERR_FUNC("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == SLEEP) { + STP_PSM_INFO_FUNC("In INACT state, dont do SLEEP again\n"); + } else { + STP_PSM_ERR_FUNC("invalid operation, the case should not happen\n"); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + } + + break; + + default: + + /*invalid */ + STP_PSM_ERR_FUNC("invalid state, the case should not happen\n"); + STP_PSM_ERR_FUNC("state = %d, flag = %ld\n", stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + + break; + } + return ret; +} + +static inline void _stp_psm_stp_is_idle(unsigned long data) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) data; + + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_DBG_FUNC("STP-PSM DISABLE!\n"); + return; + } + + if (1 == _stp_psm_notify_wmt_sleep_wq(stp_psm)) + STP_PSM_INFO_FUNC("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep); +} + +static inline INT32 _stp_psm_init_monitor(MTKSTP_PSM_T *stp_psm) +{ + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + STP_PSM_INFO_FUNC("init monitor\n"); + + stp_psm->psm_timer.timeoutHandler = _stp_psm_stp_is_idle; + stp_psm->psm_timer.timeroutHandlerData = (unsigned long)stp_psm; + osal_timer_create(&stp_psm->psm_timer); + + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_deinit_monitor(MTKSTP_PSM_T *stp_psm) +{ + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + STP_PSM_INFO_FUNC("deinit monitor\n"); + + osal_timer_stop_sync(&stp_psm->psm_timer); + + return 0; +} + +static inline INT32 _stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) +{ + INT32 iRet = -1; + +/* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + + if (osal_test_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag)) + iRet = 1; + else + iRet = 0; + +/* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + return iRet; +} + +static inline INT32 _stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) +{ + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) + return 1; + else + return 0; +} + +static inline INT32 _stp_psm_do_wait(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) +{ + +#define POLL_WAIT 20 /* 200 */ +#define POLL_WAIT_TIME 2000 + + INT32 i = 0; + INT32 limit = POLL_WAIT_TIME / POLL_WAIT; + + while (_stp_psm_get_state(stp_psm) != state && i < limit) { + osal_sleep_ms(POLL_WAIT); + i++; + STP_PSM_INFO_FUNC("STP is waiting state for %s, i=%d, state = %d\n", g_psm_state[state], i, + _stp_psm_get_state(stp_psm)); + } + + if (i == limit) { + STP_PSM_WARN_FUNC("-Wait for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); + _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg); + return STP_PSM_OPERATION_FAIL; + } + STP_PSM_DBG_FUNC("+Total waits for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); + /* _stp_psm_dbg_out_printk(g_stp_psm_opid_dbg); */ + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) +{ + + INT32 ret = 0; + INT32 retry = 10; + P_OSAL_OP_Q pOpQ; + P_OSAL_OP pOp; + + STP_PSM_LOUD_FUNC("*** Do Force Wakeup!***\n\r"); + + /* <1>If timer is active, we will stop it. */ + _stp_psm_stop_monitor(stp_psm); + + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + + pOpQ = &stp_psm->rFreeOpQ; + + while (!RB_EMPTY(&stp_psm->rActiveOpQ)) { + RB_GET(&stp_psm->rActiveOpQ, pOp); + if (NULL != pOp && !RB_FULL(pOpQ)) { + STP_PSM_DBG_FUNC("opid = %d\n", pOp->op.opId); + RB_PUT(pOpQ, pOp); + } else { + STP_PSM_ERR_FUNC("clear up active queue fail, freeQ full\n"); + } + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* <5>We issue wakeup request into op queue. and wait for active. */ + do { + ret = _stp_psm_notify_wmt_wakeup_wq(stp_psm); + + if (ret == STP_PSM_OPERATION_SUCCESS) { + ret = _stp_psm_do_wait(stp_psm, ACT); + + /* STP_PSM_INFO_FUNC("<< wait ret = %d, num of activeQ = %d\n", + * ret, RB_COUNT(&stp_psm->rActiveOpQ)); + */ + if (ret == STP_PSM_OPERATION_SUCCESS) + break; + } else + STP_PSM_ERR_FUNC("_stp_psm_notify_wmt_wakeup_wq fail!!\n"); + + /* STP_PSM_INFO_FUNC("retry = %d\n", retry); */ + retry--; + + if (retry == 0) + break; + } while (1); + + if (retry == 0) + return STP_PSM_OPERATION_FAIL; + else + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_disable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = STP_PSM_OPERATION_FAIL; + + STP_PSM_DBG_FUNC("PSM Disable start\n\r"); + + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + ret = _stp_psm_do_wakeup(stp_psm); + if (ret == STP_PSM_OPERATION_SUCCESS) + STP_PSM_DBG_FUNC("PSM Disable Success\n"); + else + STP_PSM_ERR_FUNC("***PSM Disable Fail***\n"); + + return ret; +} + +static inline INT32 _stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) +{ + INT32 ret = STP_PSM_OPERATION_FAIL; + + STP_PSM_LOUD_FUNC("PSM Enable start\n\r"); + + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + + ret = _stp_psm_do_wakeup(stp_psm); + if (ret == STP_PSM_OPERATION_SUCCESS) { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm->idle_time_to_sleep = idle_time_to_sleep; + + if (osal_wake_lock_count(&stp_psm->wake_lock) == 0) { + STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_DBG_FUNC("psm_en+wake_lock(%d)#\n", osal_wake_lock_count(&stp_psm->wake_lock)); + } + + _stp_psm_start_monitor(stp_psm); + + STP_PSM_DBG_FUNC("PSM Enable succeed\n\r"); + } else + STP_PSM_ERR_FUNC("***PSM Enable Fail***\n"); + + return ret; +} + +INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) +{ + return osal_lock_sleepable_lock(&stp_psm->stp_psm_lock); +} + +INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) +{ + osal_unlock_sleepable_lock(&stp_psm->stp_psm_lock); + return 0; +} + +MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID) +{ + if (stp_psm->is_wmt_quick_ps_support) + return (*(stp_psm->is_wmt_quick_ps_support)) (); + + STP_PSM_DBG_FUNC("stp_psm->is_wmt_quick_ps_support is NULL, return false\n\r"); + return MTK_WCN_BOOL_FALSE; +} + +MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID) +{ + return _stp_psm_is_quick_ps_support(); +} + +#if PSM_USE_COUNT_PACKAGE +int stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, int dir) +{ + + /* easy the variable maintain beween stp tx, rx thread. */ + /* so we create variable for tx, rx respectively. */ + + static int tx_cnt; + static int rx_cnt; + static int is_tx_first = 1; + static int is_rx_first = 1; + static unsigned long tx_end_time; + static unsigned long rx_end_time; + + /* */ + /* BT A2DP TX CNT = 220, RX CNT = 843 */ + /* BT FTP Transferring TX CNT = 574, RX CNT = 2233 (1228~1588) */ + /* BT FTP Receiving TX CNT = 204, RX CNT = 3301 (2072~2515) */ + /* BT OPP Tx TX_CNT= 330, RX CNT = 1300~1800 */ + /* BT OPP Rx TX_CNT= (109~157), RX CNT = 1681~2436 */ + if (dir == 0) { /* tx */ + + tx_cnt++; + + if (((long)jiffies - (long)tx_end_time >= 0) || (is_tx_first)) { + tx_end_time = jiffies + (3 * HZ); + STP_PSM_INFO_FUNC("tx cnt = %d in the previous 3 sec\n", tx_cnt); + /* if(tx_cnt > 400)//for high traffic , not to do sleep. */ + if (tx_cnt > 300) { + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm_start_monitor(stp_psm); + } else { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + tx_cnt = 0; + if (is_tx_first) + is_tx_first = 0; + } + } else { + rx_cnt++; + + if (((long)jiffies - (long)rx_end_time >= 0) || (is_rx_first)) { + rx_end_time = jiffies + (3 * HZ); + STP_PSM_INFO_FUNC("rx cnt = %d in the previous 3 sec\n", rx_cnt); + + /* if(rx_cnt > 2000)//for high traffic , not to do sleep. */ + if (rx_cnt > 1200) { /* for high traffic , not to do sleep. */ + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm_start_monitor(stp_psm); + } else { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + rx_cnt = 0; + if (is_rx_first) + is_rx_first = 0; + } + } + + return 0; +} + +#else +static struct timeval tv_now, tv_end; +static INT32 sample_start; +static INT32 tx_sum_len; +static INT32 rx_sum_len; + +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length) +{ + if (sample_start) { + if (dir) + rx_sum_len += length; + else + tx_sum_len += length; + + do_gettimeofday(&tv_now); + /* STP_PSM_INFO_FUNC("tv_now:%d.%d tv_end:%d.%d\n", + * tv_now.tv_sec,tv_now.tv_usec,tv_end.tv_sec,tv_end.tv_usec); + */ + if (((tv_now.tv_sec == tv_end.tv_sec) && (tv_now.tv_usec > tv_end.tv_usec)) || + (tv_now.tv_sec > tv_end.tv_sec)) { + STP_PSM_INFO_FUNC("STP speed rx:%d tx:%d\n", rx_sum_len, tx_sum_len); + if ((rx_sum_len + tx_sum_len) > RTX_SPEED_THRESHOLD) { + /* STP_PSM_INFO_FUNC("High speed,Disable monitor\n"); */ + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP_1000; + stp_psm_start_monitor(stp_psm); + } else { + /* STP_PSM_INFO_FUNC("Low speed,Enable monitor\n"); */ + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + } + sample_start = 0; + rx_sum_len = 0; + tx_sum_len = 0; + } + } else { + sample_start = 1; + do_gettimeofday(&tv_now); + tv_end = tv_now; + tv_end.tv_sec += SAMPLE_DURATION; + } + + return 0; +} +#endif + +/*external function for WMT module to do sleep/wakeup*/ +INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) +{ + return _stp_psm_set_state(stp_psm, state); +} + +INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_thread_lock_aquire(stp_psm); +} + +INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_thread_lock_release(stp_psm); +} + +INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_do_wakeup(stp_psm); +} + +INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + + return _stp_psm_notify_stp(stp_psm, action); +} + +INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_notify_wmt_wakeup_wq(stp_psm); +} + +int stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm) +{ + + return _stp_psm_notify_wmt_sleep_wq(stp_psm); +} + +INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_start_monitor(stp_psm); +} + +INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_is_to_block_traffic(stp_psm); +} + +INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_is_disable(stp_psm); +} + +INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_has_pending_data(stp_psm); +} + +INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_release_data(stp_psm); +} + +INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const UINT8 *buffer, const UINT32 len, const UINT8 type) +{ + return _stp_psm_hold_data(stp_psm, buffer, len, type); +} + +INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_disable(stp_psm); +} + +INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) +{ + return _stp_psm_enable(stp_psm, idle_time_to_sleep); +} + +INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm) +{ + stp_psm_set_sleep_enable(stp_psm); + + return _stp_psm_reset(stp_psm); +} + +INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_notify_wmt_sleep_wq(stp_psm); +} + +INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + stp_psm->sleep_en = 1; + STP_PSM_DBG_FUNC("\n"); + ret = 0; + } else { + STP_PSM_INFO_FUNC("Null pointer\n"); + ret = -1; + } + + return ret; +} + +INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + stp_psm->sleep_en = 0; + STP_PSM_DBG_FUNC("\n"); + ret = 0; + } else { + STP_PSM_INFO_FUNC("Null pointer\n"); + ret = -1; + } + + return ret; +} + +/* stp_psm_check_sleep_enable - to check if sleep cmd is enabled or not + * @ stp_psm - pointer of psm + * + * return 1 if sleep is enabled; else return 0 if disabled; else error code + */ +INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + ret = stp_psm->sleep_en; + STP_PSM_DBG_FUNC("%s\n", ret ? "enabled" : "disabled"); + } else { + STP_PSM_INFO_FUNC("Null pointer\n"); + ret = -1; + } + + return ret; +} + +static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num) +{ + INT32 index = 0; + struct timeval now; + + if (stp_psm_dbg) { + osal_lock_unsleepable_lock(&stp_psm_dbg->lock); + do_gettimeofday(&now); + index = stp_psm_dbg->in - 1; + index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; + STP_PSM_DBG_FUNC("index(%d)\n", index); + stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag = stp_psm_dbg->queue[index].cur_flag; + stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag = flag; + stp_psm_dbg->queue[stp_psm_dbg->in].line_num = line_num; + stp_psm_dbg->queue[stp_psm_dbg->in].package_no = g_record_num++; + stp_psm_dbg->queue[stp_psm_dbg->in].sec = now.tv_sec; + stp_psm_dbg->queue[stp_psm_dbg->in].usec = now.tv_usec; + stp_psm_dbg->size++; + STP_PSM_DBG_FUNC("pre_Flag = %d, cur_flag = %d\n", stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag, + stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag); + stp_psm_dbg->size = (stp_psm_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : stp_psm_dbg->size; + stp_psm_dbg->in = (stp_psm_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (stp_psm_dbg->in + 1); + STP_PSM_DBG_FUNC("record size = %d, in = %d num = %d\n", stp_psm_dbg->size, stp_psm_dbg->in, line_num); + + osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); + } + return 0; +} + +static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg) +{ + + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + + if (!stp_psm_dbg) { + STP_PSM_ERR_FUNC("NULL g_stp_psm_dbg reference\n"); + return -1; + } + osal_lock_unsleepable_lock(&stp_psm_dbg->lock); + + inIndex = stp_psm_dbg->in; + dumpSize = stp_psm_dbg->size; + if (STP_PSM_DBG_SIZE == dumpSize) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; + + STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + while (dumpSize > 0) { + + pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d)\n", + stp_psm_dbg->queue[outIndex].sec, + stp_psm_dbg->queue[outIndex].usec, + stp_psm_dbg->queue[outIndex].package_no, + stp_psm_dbg->queue[outIndex].prev_flag, + stp_psm_dbg->queue[outIndex].cur_flag, stp_psm_dbg->queue[outIndex].line_num); + + outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); + dumpSize--; + + } + + osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); + + return 0; +} + +static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num) +{ + INT32 index = 0; + struct timeval now; + + if (p_opid_dbg) { + osal_lock_unsleepable_lock(&p_opid_dbg->lock); + do_gettimeofday(&now); + index = p_opid_dbg->in - 1; + index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; + STP_PSM_DBG_FUNC("index(%d)\n", index); + p_opid_dbg->queue[p_opid_dbg->in].prev_flag = p_opid_dbg->queue[index].cur_flag; + p_opid_dbg->queue[p_opid_dbg->in].cur_flag = opid; + p_opid_dbg->queue[p_opid_dbg->in].line_num = line_num; + p_opid_dbg->queue[p_opid_dbg->in].package_no = g_opid_record_num++; + p_opid_dbg->queue[p_opid_dbg->in].sec = now.tv_sec; + p_opid_dbg->queue[p_opid_dbg->in].usec = now.tv_usec; + p_opid_dbg->queue[p_opid_dbg->in].pid = current->pid; + p_opid_dbg->size++; + STP_PSM_DBG_FUNC("pre_opid = %d, cur_opid = %d\n", p_opid_dbg->queue[p_opid_dbg->in].prev_flag, + p_opid_dbg->queue[p_opid_dbg->in].cur_flag); + p_opid_dbg->size = (p_opid_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : p_opid_dbg->size; + p_opid_dbg->in = (p_opid_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (p_opid_dbg->in + 1); + STP_PSM_DBG_FUNC("opid record size = %d, in = %d num = %d\n", p_opid_dbg->size, p_opid_dbg->in, + line_num); + + osal_unlock_unsleepable_lock(&p_opid_dbg->lock); + } + return 0; + +} + +static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg) +{ + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + + if (!p_opid_dbg) { + STP_PSM_ERR_FUNC("NULL p_opid_dbg reference\n"); + return -1; + } + osal_lock_unsleepable_lock(&p_opid_dbg->lock); + + inIndex = p_opid_dbg->in; + dumpSize = p_opid_dbg->size; + if (STP_PSM_DBG_SIZE == dumpSize) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; + + STP_PSM_INFO_FUNC("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + while (dumpSize > 0) { + + pr_debug("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d) pid(%d)\n", + p_opid_dbg->queue[outIndex].sec, + p_opid_dbg->queue[outIndex].usec, + p_opid_dbg->queue[outIndex].package_no, + p_opid_dbg->queue[outIndex].prev_flag, + p_opid_dbg->queue[outIndex].cur_flag, + p_opid_dbg->queue[outIndex].line_num, p_opid_dbg->queue[outIndex].pid); + + outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); + dumpSize--; + + } + + osal_unlock_unsleepable_lock(&p_opid_dbg->lock); + + return 0; + +} + +MTKSTP_PSM_T *stp_psm_init(void) +{ + INT32 err = 0; + INT32 i = 0; + INT32 ret = -1; + + STP_PSM_INFO_FUNC("psm init\n"); + + stp_psm->work_state = ACT; + stp_psm->wmt_notify = wmt_lib_ps_stp_cb; + stp_psm->is_wmt_quick_ps_support = wmt_lib_is_quick_ps_support; + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; + stp_psm->flag.data = 0; + stp_psm->stp_tx_cb = NULL; + stp_psm_set_sleep_enable(stp_psm); + + ret = osal_fifo_init(&stp_psm->hold_fifo, NULL, STP_PSM_FIFO_SIZE); + if (ret < 0) { + STP_PSM_ERR_FUNC("FIFO INIT FAILS\n"); + goto ERR_EXIT4; + } + + osal_fifo_reset(&stp_psm->hold_fifo); + osal_sleepable_lock_init(&stp_psm->hold_fifo_spinlock_global); + osal_unsleepable_lock_init(&stp_psm->wq_spinlock); + osal_sleepable_lock_init(&stp_psm->stp_psm_lock); + +/* osal_unsleepable_lock_init(&stp_psm->flagSpinlock); */ + + osal_memcpy(stp_psm->wake_lock.name, "MT662x", 6); + osal_wake_lock_init(&stp_psm->wake_lock); + + osal_event_init(&stp_psm->STPd_event); + RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); + RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); + /* Put all to free Q */ + for (i = 0; i < STP_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_psm->arQue[i].signal)); + _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, &(stp_psm->arQue[i])); + } + /* stp_psm->current_active_op = NULL; */ + stp_psm->last_active_opId = STP_OPID_PSM_INALID; + /*Generate BTM thread, to servie STP-CORE and WMT-CORE for sleeping, waking up and host awake */ + stp_psm->PSMd.pThreadData = (VOID *) stp_psm; + stp_psm->PSMd.pThreadFunc = (VOID *) _stp_psm_proc; + osal_memcpy(stp_psm->PSMd.threadName, PSM_THREAD_NAME, osal_strlen(PSM_THREAD_NAME)); + + ret = osal_thread_create(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_ERR_FUNC("osal_thread_create fail...\n"); + goto ERR_EXIT5; + } + /* init_waitqueue_head(&stp_psm->wait_wmt_q); */ + stp_psm->wait_wmt_q.timeoutValue = STP_PSM_WAIT_EVENT_TIMEOUT; + osal_event_init(&stp_psm->wait_wmt_q); + + err = _stp_psm_init_monitor(stp_psm); + if (err) { + STP_PSM_ERR_FUNC("__stp_psm_init ERROR\n"); + goto ERR_EXIT6; + } + /* Start STPd thread */ + ret = osal_thread_run(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_ERR_FUNC("osal_thread_run FAILS\n"); + goto ERR_EXIT6; + } + /* psm disable in default */ + _stp_psm_disable(stp_psm); + + g_stp_psm_dbg = (STP_PSM_RECORD_T *) osal_malloc(osal_sizeof(STP_PSM_RECORD_T)); + if (!g_stp_psm_dbg) { + STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); + return NULL; + } + osal_memset(g_stp_psm_dbg, 0, osal_sizeof(STP_PSM_RECORD_T)); + osal_unsleepable_lock_init(&g_stp_psm_dbg->lock); + + g_stp_psm_opid_dbg = (STP_PSM_OPID_RECORD *) osal_malloc(osal_sizeof(STP_PSM_OPID_RECORD)); + if (!g_stp_psm_opid_dbg) { + STP_PSM_ERR_FUNC("stp psm dbg allocate memory fail!\n"); + return NULL; + } + osal_memset(g_stp_psm_opid_dbg, 0, osal_sizeof(STP_PSM_OPID_RECORD)); + osal_unsleepable_lock_init(&g_stp_psm_opid_dbg->lock); + + return stp_psm; + +ERR_EXIT6: + + ret = osal_thread_destroy(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); + goto ERR_EXIT5; + } +ERR_EXIT5: + osal_fifo_deinit(&stp_psm->hold_fifo); +ERR_EXIT4: + + return NULL; +} + +INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = -1; + + STP_PSM_INFO_FUNC("psm deinit\n"); + + if (g_stp_psm_dbg) { + osal_unsleepable_lock_deinit(&g_stp_psm_dbg->lock); + osal_free(g_stp_psm_dbg); + g_stp_psm_dbg = NULL; + } + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + ret = osal_thread_destroy(&stp_psm->PSMd); + if (ret < 0) + STP_PSM_ERR_FUNC("osal_thread_destroy FAILS\n"); + + ret = _stp_psm_deinit_monitor(stp_psm); + if (ret < 0) + STP_PSM_ERR_FUNC("_stp_psm_deinit_monitor ERROR\n"); + + osal_wake_lock_deinit(&stp_psm->wake_lock); + osal_fifo_deinit(&stp_psm->hold_fifo); + osal_sleepable_lock_deinit(&stp_psm->hold_fifo_spinlock_global); + osal_unsleepable_lock_deinit(&stp_psm->wq_spinlock); + osal_sleepable_lock_deinit(&stp_psm->stp_psm_lock); +/* osal_unsleepable_lock_deinit(&stp_psm->flagSpinlock); */ + + return STP_PSM_OPERATION_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c new file mode 100644 index 0000000000000..046af2a58e69c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/stp_core.c @@ -0,0 +1,3358 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include "osal_typedef.h" +#include "stp_core.h" +#include "psm_core.h" +#include "btm_core.h" +#include "stp_dbg.h" +#include "stp_btif.h" + +#define PFX "[STP] " +#define STP_LOG_DBG 4 +#define STP_LOG_PKHEAD 3 +#define STP_LOG_INFO 2 +#define STP_LOG_WARN 1 +#define STP_LOG_ERR 0 + +#define STP_DEL_SIZE 2 /* STP delimiter length */ + +UINT32 gStpDbgLvl = STP_LOG_INFO; +unsigned int g_coredump_mode = 0; +#define REMOVE_USELESS_LOG 1 + +#define STP_POLL_CPUPCR_NUM 16 +#define STP_POLL_CPUPCR_DELAY 10 +#define STP_RETRY_OPTIMIZE 0 + +/* global variables */ +static const UINT8 stp_delimiter[STP_DEL_SIZE] = { 0x55, 0x55 }; + +static INT32 fgEnableNak; /* 0=enable NAK; 1=disable NAK */ +static INT32 fgEnableDelimiter; /* 0=disable Delimiter; 1=enable Delimiter */ +#if STP_RETRY_OPTIMIZE +static UINT32 g_retry_times; +#endif +/* common interface */ +static IF_TX sys_if_tx; +/* event/signal */ +static EVENT_SET sys_event_set; +static EVENT_TX_RESUME sys_event_tx_resume; +static FUNCTION_STATUS sys_check_function_status; +/* kernel lib */ +/* int g_block_tx = 0; */ +static mtkstp_context_struct stp_core_ctx = { 0 }; + +#define STP_PSM_CORE(x) ((x).psm) +#define STP_SET_PSM_CORE(x, v) ((x).psm = (v)) + +#define STP_BTM_CORE(x) ((x).btm) +#define STP_SET_BTM_CORE(x, v) ((x).btm = (v)) + +#define STP_IS_ENABLE(x) ((x).f_enable != 0) +#define STP_NOT_ENABLE(x) ((x).f_enable == 0) +#define STP_SET_ENABLE(x, v) ((x).f_enable = (v)) + +#define STP_IS_READY(x) ((x).f_ready != 0) +#define STP_NOT_READY(x) ((x).f_ready == 0) +#define STP_SET_READY(x, v) ((x).f_ready = (v)) + +#define STP_PENDING_TYPE(x) ((x).f_pending_type) +#define STP_SET_PENDING_TYPE(x, v) ((x).f_pending_type = (v)) + +#define STP_BLUE_ANGEL (0) +#define STP_BLUE_Z (1) +#define STP_BT_STK(x) ((x).f_bluez) +#define STP_BT_STK_IS_BLUEZ(x) ((x).f_bluez == (STP_BLUE_Z)) +#define STP_SET_BT_STK(x, v) ((x).f_bluez = (v)) + +#define STP_IS_ENABLE_DBG(x) ((x).f_dbg_en != 0) +#define STP_NOT_ENABLE_DBG(x) ((x).f_dbg_en == 0) +#define STP_SET_ENABLE_DBG(x, v) ((x).f_dbg_en = (v)) + +#define STP_IS_ENABLE_RST(x) ((x).f_autorst_en != 0) +#define STP_NOT_ENABLE_RST(x) ((x).f_autorst_en == 0) +#define STP_SET_ENABLE_RST(x, v) ((x).f_autorst_en = (v)) + +#define STP_SUPPORT_PROTOCOL(x) ((x).f_mode) +#define STP_SET_SUPPORT_PROTOCOL(x, v) ((x).f_mode = (v)) + +#define STP_FW_COREDUMP_FLAG(x) ((x).f_coredump) +#define STP_SET_FW_COREDUMP_FLAG(x, v) ((x).f_coredump = (v)) +#define STP_ENABLE_FW_COREDUMP(x, v) ((x).en_coredump = (v)) +#define STP_ENABLE_FW_COREDUMP_FLAG(x) ((x).en_coredump) + +#define STP_WMT_LAST_CLOSE(x) ((x).f_wmt_last_close) +#define STP_SET_WMT_LAST_CLOSE(x, v) ((x).f_wmt_last_close = (v)) + +#define STP_EVT_ERR_ASSERT(x) ((x).f_evt_err_assert) +#define STP_SET_EVT_ERR_ASSERT(x, v) ((x).f_evt_err_assert = (v)) + +/*[PatchNeed]Need to calculate the timeout value*/ +static UINT32 mtkstp_tx_timeout = MTKSTP_TX_TIMEOUT; +static mtkstp_parser_state prev_state = -1; + +#define CONFIG_DEBUG_STP_TRAFFIC_SUPPORT +#ifdef CONFIG_DEBUG_STP_TRAFFIC_SUPPORT +static MTKSTP_DBG_T *g_mtkstp_dbg; +#endif +static VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len); +static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc); +static VOID stp_update_tx_queue(UINT32 txseq); +static VOID stp_rest_ctx_state(VOID); +static VOID stp_change_rx_state(mtkstp_parser_state next); +static void stp_tx_timeout_handler(unsigned long data); +static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len); +static VOID stp_dump_tx_queue(UINT32 txseq); +static INT32 stp_is_apply_powersaving(VOID); +/*static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type);*/ +static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length); +static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length); +static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type); +static VOID stp_send_tx_queue(UINT32 txseq); +static VOID stp_send_ack(UINT8 txAck, UINT8 nak); +static INT32 stp_process_rxack(VOID); +static VOID stp_process_packet(VOID); + +/*private functions*/ + +static INT32 stp_ctx_lock_init(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_unsleepable_lock_init(&((pctx)->stp_mutex)); +#else + osal_sleepable_lock_init(&((pctx)->stp_mutex)); + return 0; +#endif +} + +static INT32 stp_ctx_lock_deinit(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_unsleepable_lock_deinit(&((pctx)->stp_mutex)); +#else + return osal_sleepable_lock_deinit(&((pctx)->stp_mutex)); +#endif +} + +static INT32 stp_ctx_lock(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_lock_unsleepable_lock(&((pctx)->stp_mutex)); +#else + return osal_lock_sleepable_lock(&((pctx)->stp_mutex)); +#endif +} + +static INT32 stp_ctx_unlock(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_unlock_unsleepable_lock(&((pctx)->stp_mutex)); +#else + return osal_unlock_sleepable_lock(&((pctx)->stp_mutex)); +#endif +} + +MTK_WCN_BOOL mtk_wcn_stp_dbg_level(UINT32 dbglevel) +{ + if (dbglevel <= 4) { + gStpDbgLvl = dbglevel; + STP_INFO_FUNC("gStpDbgLvl = %d\n", gStpDbgLvl); + return MTK_WCN_BOOL_TRUE; + } + STP_INFO_FUNC("invalid stp debug level. gStpDbgLvl = %d\n", gStpDbgLvl); + + return MTK_WCN_BOOL_FALSE; +} + +#if !(REMOVE_USELESS_LOG) +static UINT8 *stp_type_to_dbg_string(UINT32 type) +{ + UINT8 *type_name = NULL; + + if (type == BT_TASK_INDX) + type_name = "< BT>"; + else if (type == GPS_TASK_INDX) + type_name = ""; + else if (type == WMT_TASK_INDX) + type_name = ""; + else if (type == FM_TASK_INDX) + type_name = "< FM>"; + else if (type == ANT_TASK_INDX) + type_name = ""; + + return type_name; +} +#endif +#if 0 +/***************************************************************************** +* FUNCTION +* crc16 +* DESCRIPTION +* Compute the CRC-16 for the data buffer +* PARAMETERS +* crc [IN] previous CRC value +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* the updated CRC value +*****************************************************************************/ +static UINT16 crc16(const UINT8 *buffer, const UINT32 length) +{ + UINT32 crc, i; + + /* FIXME: Add STP checksum feature */ + crc = 0; + for (i = 0; i < length; i++, buffer++) + crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; + + return crc; +} + +#endif + +VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const UINT8 *pBuf, INT32 len) +{ + +#ifndef CONFIG_LOG_STP_INTERNAL + return; +#endif + + if (STP_IS_ENABLE_DBG(stp_core_ctx)) { + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_PKT, type, /* type */ + txAck, /* ack */ + seq, /* seq */ + crc, /* crc */ + dir, /* dir */ + len, /* len */ + pBuf); /* body */ + } else { + STP_DBG_FUNC("stp_dbg not enabled"); + } +} + +/***************************************************************************** +* FUNCTION +* stp_check_crc +* DESCRIPTION +* check the check sum of packet payload +* PARAMETERS +* pdata [IN] the data want to check +* length [IN] the length of pdata +* crc [IN] the crc of pdata +* RETURNS +* KAL_TRUE crc is ok +* KAL_FALSE crc is wrong +*****************************************************************************/ +static MTK_WCN_BOOL stp_check_crc(UINT8 *buffer, UINT32 length, UINT16 crc) +{ + /*----------------------------------------------------------------*/ + /* Local Variables */ + /*----------------------------------------------------------------*/ + UINT16 checksum; + + /*----------------------------------------------------------------*/ + /* Code Body */ + /*----------------------------------------------------------------*/ + + /* FIXME: Add STP feature: check or skip crc */ + + checksum = osal_crc16(buffer, length); + if (checksum == crc) + return MTK_WCN_BOOL_TRUE; + + STP_ERR_FUNC("CRC fail, length = %d, rx = %x, calc = %x \r\n", length, crc, checksum); + return MTK_WCN_BOOL_FALSE; + +} + +/***************************************************************************** +* FUNCTION +* stp_update_tx_queue +* DESCRIPTION +* update packet's ACK field +* PARAMETERS +* txseq [IN] index of the tx packet which we want to update +* RETURNS +* void +*****************************************************************************/ +static void stp_update_tx_queue(UINT32 txseq) +{ + INT32 tx_read, i; + UINT8 checksum = 0; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + stp_core_ctx.tx_buf[tx_read] &= 0xf8; + stp_core_ctx.tx_buf[tx_read] |= stp_core_ctx.sequence.txack; + + for (i = 0; i < 3; i++) { + checksum += stp_core_ctx.tx_buf[tx_read]; + tx_read++; + if (tx_read >= MTKSTP_BUFFER_SIZE) + tx_read -= MTKSTP_BUFFER_SIZE; + + } + + stp_core_ctx.tx_buf[tx_read] = checksum; + +} + +/***************************************************************************** +* FUNCTION +* stp_rest_ctx_state +* DESCRIPTION +* Reset stp context state variables only. Mutex and timer resources are not touched. +* +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static VOID stp_rest_ctx_state(VOID) +{ + INT32 i; + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + stp_core_ctx.rx_counter = 0; + + /*reset rx buffer pointer */ + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) { + stp_core_ctx.ring[i].read_p = 0; + stp_core_ctx.ring[i].write_p = 0; + } + + /*reset tx buffer pointer */ + stp_core_ctx.tx_write = 0; + stp_core_ctx.tx_read = 0; + + /*reset STP protocol context */ + stp_core_ctx.parser.state = MTKSTP_SYNC; + stp_core_ctx.sequence.txseq = 0; + stp_core_ctx.sequence.txack = 7; + stp_core_ctx.sequence.rxack = 7; + stp_core_ctx.sequence.winspace = MTKSTP_WINSIZE; + stp_core_ctx.sequence.expected_rxseq = 0; + stp_core_ctx.sequence.retry_times = 0; + stp_core_ctx.inband_rst_set = 0; + + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); +} + +/***************************************************************************** +* FUNCTION +* stp_change_rx_state +* DESCRIPTION +* change the rx fsm of STP to "next" +* PARAMETERS +* next [IN] the next state of rx fsm +* RETURNS +* void +*****************************************************************************/ +static VOID stp_change_rx_state(mtkstp_parser_state next) +{ + prev_state = stp_core_ctx.parser.state; + stp_core_ctx.parser.state = next; + +} + +/* static void stp_tx_timeout_handler(void){ */ +static void stp_tx_timeout_handler(unsigned long data) +{ + STP_WARN_FUNC("call retry btm retry wq ...\n"); + /*shorten the softirq lattency */ + stp_btm_notify_stp_retry_wq(STP_BTM_CORE(stp_core_ctx)); + STP_WARN_FUNC("call retry btm retry wq ...#\n"); +} + +VOID stp_do_tx_timeout(VOID) +{ + UINT32 seq; + UINT32 ret; + INT32 iRet; + ENUM_STP_FW_ISSUE_TYPE issue_type; + UINT8 resync[4]; + + STP_WARN_FUNC("==============================================================================\n"); + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + +#if STP_RETRY_OPTIMIZE + if ((g_retry_times != 0) && (stp_core_ctx.sequence.retry_times == 0)) { + STP_INFO_FUNC("STP TX timeout has been recoveryed by resend,record_retry_time(%d)\n", g_retry_times); + g_retry_times = 0; + stp_ctx_unlock(&stp_core_ctx); + return; + } +#endif + if (stp_core_ctx.sequence.retry_times > (MTKSTP_RETRY_LIMIT)) { + STP_INFO_FUNC("STP retry times(%d) have reached retry limit,stop it\n", + stp_core_ctx.sequence.retry_times); + stp_ctx_unlock(&stp_core_ctx); + return; + } +#if STP_RETRY_OPTIMIZE + else + STP_DBG_FUNC("current TX timeout package has not received ACK yet,retry_times(%d)\n", + g_retry_times); +#endif + /*polling cpupcr when no ack occurs at first retry */ + stp_notify_btm_poll_cpupcr(STP_BTM_CORE(stp_core_ctx), STP_POLL_CPUPCR_NUM, STP_POLL_CPUPCR_DELAY); + + seq = stp_core_ctx.sequence.rxack; + INDEX_INC(seq); + + if (seq != stp_core_ctx.sequence.txseq) { + osal_memset(&resync[0], 127, 4); + (*sys_if_tx) (&resync[0], 4, &ret); + if (ret != 4) { + STP_ERR_FUNC("mtkstp_tx_timeout_handler: send resync fail\n"); + osal_assert(0); + } + + do { + STP_WARN_FUNC("[stp.ctx]*rxack (=last rx ack) = %d\n\r", stp_core_ctx.sequence.rxack); + STP_WARN_FUNC("[stp.ctx]txack (=last rx seq)= %d\n\r", stp_core_ctx.sequence.txack); + STP_WARN_FUNC("[stp.ctx]*txseq (=next tx seq)= %d\n\r", stp_core_ctx.sequence.txseq); + STP_WARN_FUNC("Resend STP packet from %d -> %d\n\r", seq, + (stp_core_ctx.sequence.txseq <= 0) ? (7) : (stp_core_ctx.sequence.txseq - 1)); + stp_dump_tx_queue(seq); + + stp_send_tx_queue(seq); + INDEX_INC(seq); + } while (seq != stp_core_ctx.sequence.txseq); + + } + + osal_timer_stop(&stp_core_ctx.tx_timer); + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + + if (stp_core_ctx.sequence.winspace == MTKSTP_WINSIZE) { + osal_timer_stop(&stp_core_ctx.tx_timer); + STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); + } else { + stp_core_ctx.sequence.retry_times++; + STP_ERR_FUNC("mtkstp_tx_timeout_handler, retry = %d\n", stp_core_ctx.sequence.retry_times); +#if STP_RETRY_OPTIMIZE + g_retry_times = stp_core_ctx.sequence.retry_times; +#endif + /*If retry too much, try to recover STP by return back to initializatin state */ + /*And not to retry again */ + if (stp_core_ctx.sequence.retry_times > MTKSTP_RETRY_LIMIT) { +#if STP_RETRY_OPTIMIZE + g_retry_times = 0; +#endif + osal_timer_stop(&stp_core_ctx.tx_timer); + stp_ctx_unlock(&stp_core_ctx); + + STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); + + STP_ERR_FUNC("TX retry limit = %d\n", MTKSTP_RETRY_LIMIT); + osal_assert(0); + mtk_wcn_stp_dbg_dump_package(); + + /*Whole Chip Reset Procedure Invoke */ + /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ + + if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); + stp_dbg_set_host_assert_info(4, 36, 1); + STP_INFO_FUNC("**STP NoAck trigger firmware assert**\n"); + iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); + + if (iRet) { + STP_ERR_FUNC("host tigger fw assert fail(%d), do noack handle flow\n", iRet); + mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); + issue_type = STP_FW_NOACK_ISSUE; + iRet = stp_dbg_set_fw_info("STP NoAck", osal_strlen("STP NoAck"), issue_type); + + osal_dbg_assert_aee("[SOC_CONNSYS]NoAck", + "**[WCN_ISSUE_INFO]STP Tx Timeout**\n F/W has NO any RESPONSE. Please check F/W status first\n"); + if (STP_IS_ENABLE_RST(stp_core_ctx)) { + STP_SET_READY(stp_core_ctx, 0); + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + } else { + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } + } + } else { + STP_INFO_FUNC("do trigger assert & chip reset in wmt\n"); + } + return; + } + } + + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + STP_WARN_FUNC("==============================================================================#\n"); +} + +static VOID stp_dump_data(const UINT8 *buf, const UINT8 *title, const UINT32 len) +{ + osal_buffer_dump(buf, title, len, 32); +} + +/***************************************************************************** + * FUNCTION + * stp_tx_timeout_handler + * DESCRIPTION + * tx timeout handler, send resync & retransmitt + * PARAMETERS + * void + * RETURNS + * void + *****************************************************************************/ +static VOID stp_dump_tx_queue(UINT32 txseq) +{ + INT32 tx_read, tx_length, last_len; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + tx_length = stp_core_ctx.tx_length[txseq]; + + STP_ERR_FUNC("tx_seq=%d ..", txseq); + + if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { + stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q", (tx_length >= 8) ? (8) : (tx_length)); + } else { + last_len = MTKSTP_BUFFER_SIZE - tx_read; + stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q_0", (last_len >= 8) ? (8) : (last_len)); + stp_dump_data(&stp_core_ctx.tx_buf[0], "tx_q_0", + ((tx_length - last_len) ? (8) : (tx_length - last_len))); + } +} + +/***************************************************************************** +* FUNCTION +* stp_is_apply_powersaving +* DESCRIPTION +* Check if STP support power saving mode. +* PARAMETERS +* +* RETURNS +* True: support power saving False: not support power saving +*****************************************************************************/ +static INT32 stp_is_apply_powersaving(VOID) +{ + + if (STP_IS_READY(stp_core_ctx) && !stp_psm_is_disable(STP_PSM_CORE(stp_core_ctx))) { + /* osal_dbg_print("apply power saving\n"); */ + return MTK_WCN_BOOL_TRUE; + } + if (mtk_wcn_stp_is_sdio_mode()) + return MTK_WCN_BOOL_FALSE; + + STP_DBG_FUNC("not apply power saving\n"); + return MTK_WCN_BOOL_FALSE; +} +#if 0 +/***************************************************************************** +* FUNCTION +* stp_is_privileges_cmd +* DESCRIPTION +* Check if the data is privilege command +* PARAMETERS +* +* RETURNS +* True/False +*****************************************************************************/ +static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type) +{ + typedef struct privileges_cmd { + UINT32 length; + UINT8 type; + UINT8 buf[7]; /* MAX length of target command is only 5 currently */ + } p_cmd_t; + + p_cmd_t p_cmd_table[] = { + {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x01} }, /* sleep command */ + {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x02} }, /* host_awake command */ + }; + + UINT32 i; + UINT32 size = sizeof(p_cmd_table) / sizeof(p_cmd_table[0]); + + for (i = 0; i < size; i++) { + if (type != p_cmd_table[i].type) + continue; + + if (length != p_cmd_table[i].length) + continue; + + if (osal_memcmp(p_cmd_table[i].buf, buffer, length)) + continue; + + /* matched entry is found */ + STP_DBG_FUNC("It's p_cmd_t\n"); + return MTK_WCN_BOOL_TRUE; + } + + return MTK_WCN_BOOL_FALSE; +} +#endif +/***************************************************************************** +* FUNCTION +* tx_queue_room_available +* DESCRIPTION +* check room if available, +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length) +{ + UINT32 roomLeft; + + /* + Get available space of TX Queue + */ + if (stp_core_ctx.tx_read <= stp_core_ctx.tx_write) + roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write + stp_core_ctx.tx_read - 1; + else + roomLeft = stp_core_ctx.tx_read - stp_core_ctx.tx_write - 1; + + if (roomLeft < length) { + STP_ERR_FUNC("%s: tx queue room shortage\n", __func__); + return MTK_WCN_BOOL_FALSE; + } else + return MTK_WCN_BOOL_TRUE; +} + +/***************************************************************************** +* FUNCTION +* stp_add_to_tx_queue +* DESCRIPTION +* put data to tx queue +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +static VOID stp_add_to_tx_queue(const UINT8 *buffer, UINT32 length) +{ + UINT32 last_len; + + /* Get available space of TX Queue */ + if (length + stp_core_ctx.tx_write < MTKSTP_BUFFER_SIZE) { + osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, length); + stp_core_ctx.tx_write += length; + } else { + last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write; + osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, last_len); + osal_memcpy(stp_core_ctx.tx_buf, buffer + last_len, length - last_len); + + stp_core_ctx.tx_write = length - last_len; + } + +} + +/***************************************************************************** +* FUNCTION +* stp_add_to_rx_queue +* DESCRIPTION +* put data to corresponding task's rx queue and notify corresponding task +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] corresponding task index +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type) +{ + UINT32 roomLeft, last_len; + + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if (stp_core_ctx.ring[type].read_p <= stp_core_ctx.ring[type].write_p) + roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p + stp_core_ctx.ring[type].read_p - 1; + else + roomLeft = stp_core_ctx.ring[type].read_p - stp_core_ctx.ring[type].write_p - 1; + + if (roomLeft < length) { + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + STP_ERR_FUNC("Queue is full !!!, type = %d\n", type); + osal_assert(0); + return -1; + } + + if (length + stp_core_ctx.ring[type].write_p < MTKSTP_BUFFER_SIZE) { + osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, length); + stp_core_ctx.ring[type].write_p += length; + } else { + last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p; + osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, last_len); + osal_memcpy(stp_core_ctx.ring[type].buffer, buffer + last_len, length - last_len); + stp_core_ctx.ring[type].write_p = length - last_len; + } + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* stp_send_tx_queue +* DESCRIPTION +* send data in tx buffer to common interface +* PARAMETERS +* txseq [IN] sequence number of outgoing packet in tx buffer +* RETURNS +* void +*****************************************************************************/ +static VOID stp_send_tx_queue(UINT32 txseq) +{ + UINT32 ret; + INT32 tx_read, tx_length, last_len; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + tx_length = stp_core_ctx.tx_length[txseq]; + + stp_update_tx_queue(txseq); + + if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { + + (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], tx_length, &ret); + + if (ret != tx_length) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length, ret); + osal_assert(0); + } + } else { + last_len = MTKSTP_BUFFER_SIZE - tx_read; + (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], last_len, &ret); + + if (ret != last_len) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", last_len, ret); + osal_assert(0); + } + + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], tx_length - last_len, &ret); + + if (ret != tx_length - last_len) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length - last_len, ret); + osal_assert(0); + } + } + +} + +/***************************************************************************** +* FUNCTION +* stp_send_ack +* DESCRIPTION +* send ack packet to the peer +* PARAMETERS +* txAck [IN] Ack number +* nak [IN] 0 = ack; !0 = NAK +* RETURNS +* void +*****************************************************************************/ +static VOID stp_send_ack(UINT8 txAck, UINT8 nak) +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE]; + UINT32 ret; + INT32 iStatus; + + mtkstp_header[0] = 0x80 + (0 << 3) + txAck; /* stp_core_ctx.sequence.txack; */ + + if (fgEnableNak == 0) + mtkstp_header[1] = 0x00; /* disable NAK */ + else + mtkstp_header[1] = ((nak == 0) ? 0x00 : 0x80); + + mtkstp_header[2] = 0; + mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + + stp_dbg_pkt_log(STP_TASK_INDX, txAck, 0, 0, PKT_DIR_TX, NULL, 0); + + if (fgEnableDelimiter == 1) { + iStatus = (*sys_if_tx) ((PUINT8) &stp_delimiter[0], STP_DEL_SIZE, &ret); + STP_DUMP_PACKET_HEAD((PUINT8) &stp_delimiter[0], "tx del", STP_DEL_SIZE); + if (ret != STP_DEL_SIZE) { + STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", STP_DEL_SIZE, ret, iStatus); + osal_assert(0); + } + } + + iStatus = (*sys_if_tx) (&mtkstp_header[0], MTKSTP_HEADER_SIZE, &ret); + + if (ret != MTKSTP_HEADER_SIZE) { + STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", MTKSTP_HEADER_SIZE, ret, iStatus); + osal_assert(0); + } + +} + +INT32 stp_send_data_no_ps(UINT8 *buffer, UINT32 length, UINT8 type) +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; + UINT8 *p_tx_buf = NULL; + UINT16 crc; + INT32 ret = 0; + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + + /*Only WMT can set raw data */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { + /* no op */ + /* NULL; */ + } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { + /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ + /* NULL; */ + } + /* STP over SDIO */ + else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { + osal_printtimeofday("[ STP][SDIO][ B][W]"); + + mtkstp_header[0] = 0x80; + mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); + mtkstp_header[2] = (length) & 0xff; + mtkstp_header[3] = 0x00; + + p_tx_buf = &stp_core_ctx.tx_buf[0]; + osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); + p_tx_buf += MTKSTP_HEADER_SIZE; + + osal_memcpy(p_tx_buf, buffer, length); + p_tx_buf += length; + + temp[0] = 0x00; + temp[1] = 0x00; + osal_memcpy(p_tx_buf, temp, 2); + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, 0, PKT_DIR_TX, buffer, length); + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); + if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { + STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); + osal_assert(0); + ret = 0; + } else { + ret = (INT32) length; + } + + osal_printtimeofday("[ STP][SDIO][ E][W]"); + } + /* STP over BTIF OR UART */ + else if ((mtk_wcn_stp_is_btif_fullset_mode()) && STP_IS_ENABLE(stp_core_ctx)) { + + if ((stp_core_ctx.sequence.winspace > 0) && + (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { + mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; + mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); + mtkstp_header[2] = length & 0xff; + mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + + stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; + + if (fgEnableDelimiter == 1) { + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; + stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); + } + + stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); + + /*Make Payload */ + stp_add_to_tx_queue(buffer, length); + + /*Make CRC */ + crc = osal_crc16(buffer, length); + temp[0] = crc & 0xff; + temp[1] = (crc & 0xff00) >> 8; + stp_add_to_tx_queue(temp, 2); + + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); + + /*Kick to UART */ + stp_send_tx_queue(stp_core_ctx.sequence.txseq); + INDEX_INC(stp_core_ctx.sequence.txseq); + stp_core_ctx.sequence.winspace--; + + /*Setup the Retry Timer */ + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + else + STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); + + ret = (INT32) length; + } else { + /* No winspace to send. Let caller retry */ + STP_ERR_FUNC("%s: There is no winspace/txqueue to send !!!\n", __func__); + ret = 0; + } + } + + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + + return ret; +} + +/***************************************************************************** +* FUNCTION +* stp_process_rxack +* DESCRIPTION +* process ack packet +* PARAMETERS +* void +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +static INT32 stp_process_rxack(VOID) +{ + INT32 j, k; + UINT8 rxack; + INT32 fgResult = (-1); + + if (stp_core_ctx.sequence.rxack != stp_core_ctx.parser.ack) { + j = k = 0; + rxack = stp_core_ctx.sequence.rxack; + INDEX_INC(rxack); + while (rxack != stp_core_ctx.sequence.txseq) { + j++; + if (rxack == stp_core_ctx.parser.ack) { + k = 1; + break; + } + INDEX_INC(rxack); + } + if (k == 1) { + stp_core_ctx.sequence.rxack = stp_core_ctx.parser.ack; + stp_core_ctx.tx_read = stp_core_ctx.tx_start_addr[rxack] + stp_core_ctx.tx_length[rxack]; + if (stp_core_ctx.tx_read >= MTKSTP_BUFFER_SIZE) + stp_core_ctx.tx_read -= MTKSTP_BUFFER_SIZE; + + stp_core_ctx.sequence.winspace += j; + stp_core_ctx.sequence.retry_times = 0; + + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + + fgResult = 0; + } + } + + return fgResult; +} + +/***************************************************************************** +* FUNCTION +* stp_process_packet +* DESCRIPTION +* process STP packet +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static VOID stp_process_packet(VOID) +{ + INT32 fgTriggerResume = (-1); + UINT8 txAck = 0; + static INT32 fgRxOk; + MTK_WCN_BOOL b; + MTK_WCN_BOOL is_function_active = 0; + static INT32 stp_process_packet_fail_count; + INT32 iRet = -1; + + stp_dbg_pkt_log(stp_core_ctx.parser.type, + stp_core_ctx.parser.ack, + stp_core_ctx.parser.seq, + stp_core_ctx.parser.crc, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.parser.length); + /*Optimization */ + /*If bluez, direct send packet to hci_core not through RX buffer! */ + if ((stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) && + (stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { + /*Indicate packet to hci_stp */ + STP_DBG_FUNC("Send Packet to BT_SUBFUCTION, len = %d\n", stp_core_ctx.rx_counter); + + b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + if (b) + STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + /*Process rx ack */ + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + txAck = stp_core_ctx.sequence.txack; + + /*Send ack back */ + stp_send_ack(txAck, 0); + + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + fgRxOk = 0; + } + /* sequence matches expected, enqueue packet */ + else if (stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) { + is_function_active = + ((*sys_check_function_status) (stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) == + STATUS_FUNCTION_ACTIVE); + /*If type is valid and function works, then try to enqueue */ + if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && (is_function_active == MTK_WCN_BOOL_TRUE)) { + if (stp_core_ctx.parser.type == BT_TASK_INDX) { + static const UINT8 rst_buf[7] = { 0x04, 0x0e, 0x04, 0x01, 0x3, 0xc, 0x00 }; + + if (!osal_strncmp(stp_core_ctx.rx_buf, rst_buf, 7)) + osal_printtimeofday("############ BT Rest end <--"); + } + + stp_ctx_lock(&stp_core_ctx); + + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + + /*Send tx ack */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 0); + + stp_ctx_unlock(&stp_core_ctx); +#if CFG_WMT_LTE_COEX_HANDLING + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && + (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { + fgRxOk = + stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, COEX_TASK_INDX); + } else { + fgRxOk = + stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + } +#else + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && + (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { + STP_WARN_FUNC("BT/WIFI & LTE coex in non-LTE projects,drop it...\n"); + } else { + fgRxOk = + stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + } +#endif + } else { + if (is_function_active == MTK_WCN_BOOL_FALSE) { + STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n", + stp_core_ctx.parser.type); + fgRxOk = 0; /*drop packet */ + } else { + STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n", + stp_core_ctx.parser.type); + fgRxOk = 0; /*drop packet */ + } + stp_ctx_lock(&stp_core_ctx); + + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + + /*Send tx ack */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 0); + + stp_ctx_unlock(&stp_core_ctx); + } + + /* enqueue successfully */ + if (fgRxOk == 0) { + stp_process_packet_fail_count = 0; + /*notify corresponding subfunction of incoming data */ +#if CFG_WMT_LTE_COEX_HANDLING + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && + (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { +#if 1 + STP_DBG_FUNC + ("WMT/LTE package:[0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x][0x%2x]\n", + stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], stp_core_ctx.rx_buf[2], + stp_core_ctx.rx_buf[3], stp_core_ctx.rx_buf[4], stp_core_ctx.rx_buf[5], + stp_core_ctx.rx_buf[6], stp_core_ctx.rx_buf[7]); +#endif + stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); + } else { + (*sys_event_set) (stp_core_ctx.parser.type); + } +#else + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) && + (stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG)) { + STP_WARN_FUNC("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); + } else { + (*sys_event_set) (stp_core_ctx.parser.type); + } +#endif + } else { + stp_process_packet_fail_count++; + /*Queue is full */ + if (stp_core_ctx.parser.type == GPS_TASK_INDX) { + /*Clear Rx Queue if GPS */ + mtk_wcn_stp_flush_rx_queue(GPS_TASK_INDX); + } else { + /*notify corresponding subfunction of incoming data */ + (*sys_event_set) (stp_core_ctx.parser.type); + } + /*enqueue fail, don't send ack and wait for peer retry */ + STP_ERR_FUNC("Enqueue to Rx queue fail, maybe function %d queue is full\n", + stp_core_ctx.parser.type); + } + } + /*sequence not match && previous packet enqueue successfully, send the previous ACK */ + else if (fgRxOk == 0) { + STP_ERR_FUNC("mtkstp_process_packet: expected_rxseq = %d, parser.seq = %d\n", + stp_core_ctx.sequence.expected_rxseq, stp_core_ctx.parser.seq); + stp_process_packet_fail_count++; + + stp_ctx_lock(&stp_core_ctx); + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 1); + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + STP_ERR_FUNC + ("sequence not match && previous packet enqueue successfully, send the previous ACK (ack no =%d)\n", + txAck); + } + /*sequence not match && previous packet enqueue failed, do nothing, make the other side timeout */ + else { + stp_process_packet_fail_count++; + STP_ERR_FUNC + ("sequence not match && previous packet enqueue failed, do nothing, make the other side timeout\n"); + } + + if (fgTriggerResume == 0) { + /*[PatchNeed]Just Notificaiton, not blocking call */ + /* notify adaptation layer for possible tx resume mechanism */ + (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); + } + + if (stp_process_packet_fail_count > MTKSTP_RETRY_LIMIT) { + stp_process_packet_fail_count = 0; + STP_ERR_FUNC("The process packet fail count > 10 lastly\n\r, whole chip reset\n\r"); + mtk_wcn_stp_dbg_dump_package(); + /*Whole Chip Reset Procedure Invoke */ + /*if(STP_NOT_ENABLE_DBG(stp_core_ctx)) */ + if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); + stp_dbg_set_host_assert_info(4, 37, 1); + STP_INFO_FUNC("**Ack Miss trigger firmware assert**\n"); + iRet = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); + if (iRet) { + mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); + /* (*sys_dbg_assert_aee)("[MT662x]Ack Miss", "**STP Ack Miss**\n Ack Miss.\n"); */ + osal_dbg_assert_aee("[SOC_CONSYS]Ack Miss", + "**[WCN_ISSUE_INFO]STP Ack Miss**\n Ack Miss.\n"); + + if (STP_IS_ENABLE_RST(stp_core_ctx)) { + STP_SET_READY(stp_core_ctx, 0); + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + } else { + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } + } + } + } + +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_init +* DESCRIPTION +* init STP kernel +* PARAMETERS +* cb_func [IN] function pointers of system APIs +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func) +{ + INT32 ret = 0; + INT32 i = 0; + + /* Function pointer to point to the currently used transmission interface + */ + sys_if_tx = cb_func->cb_if_tx; + + /* Used to inform the function driver has received the corresponding type of information */ + sys_event_set = cb_func->cb_event_set; + + /* Used to inform the function driver can continue to send information and + STP has resources to deal with + */ + sys_event_tx_resume = cb_func->cb_event_tx_resume; + + /* STP driver determines whether the function is enable. If not enable and + STP has received the kind of information, and STP have the right to put it away. + */ + sys_check_function_status = cb_func->cb_check_funciton_status; + + /* osal_unsleepable_lock_init(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock_init(&stp_core_ctx); + /* Setup timer to be used to check if f/w receive the data in the specific time + interval after being sent + */ + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) + osal_unsleepable_lock_init(&stp_core_ctx.ring[i].mtx); + + stp_core_ctx.tx_timer.timeoutHandler = stp_tx_timeout_handler; + stp_core_ctx.tx_timer.timeroutHandlerData = 0; + osal_timer_create(&stp_core_ctx.tx_timer); + + STP_SET_BT_STK(stp_core_ctx, 0); + STP_SET_ENABLE(stp_core_ctx, 0); + STP_SET_ENABLE_DBG(stp_core_ctx, 0); + STP_SET_ENABLE_RST(stp_core_ctx, 0); + STP_SET_PENDING_TYPE(stp_core_ctx, 0); + STP_SET_READY(stp_core_ctx, 0); + STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, 0); + STP_SET_PSM_CORE(stp_core_ctx, stp_psm_init()); + STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, 0); + STP_ENABLE_FW_COREDUMP(stp_core_ctx, 0); + STP_SET_WMT_LAST_CLOSE(stp_core_ctx, 0); + STP_SET_EVT_ERR_ASSERT(stp_core_ctx, 0); + + if (!STP_PSM_CORE(stp_core_ctx)) { + ret = (-3); + goto ERROR; + } + + STP_SET_BTM_CORE(stp_core_ctx, stp_btm_init()); + if (!STP_BTM_CORE(stp_core_ctx)) { + STP_ERR_FUNC("STP_BTM_CORE(stp_core_ctx) initialization fail!\n"); + ret = (-3); + goto ERROR; + } + + if (STP_BTM_CORE(stp_core_ctx) != NULL) + g_mtkstp_dbg = stp_dbg_init(STP_BTM_CORE(stp_core_ctx)); + else + g_mtkstp_dbg = stp_dbg_init(NULL); + + if (!g_mtkstp_dbg) { + STP_ERR_FUNC("g_mtkstp_dbg initialization fail!\n"); + ret = (-3); + goto ERROR; + } + STP_SET_ENABLE_RST(stp_core_ctx, 1); +#ifdef CONFIG_LOG_STP_INTERNAL + mtk_wcn_stp_dbg_enable(); +#else + mtk_wcn_stp_dbg_enable(); +#endif + goto RETURN; + +ERROR: + stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); + +RETURN: + return ret; + +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_deinit +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +INT32 mtk_wcn_stp_deinit(void) +{ + UINT32 i = 0; + + sys_if_tx = NULL; + sys_event_set = NULL; + sys_event_tx_resume = NULL; + sys_check_function_status = NULL; + + stp_dbg_deinit(g_mtkstp_dbg); + stp_btm_deinit(STP_BTM_CORE(stp_core_ctx)); + stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); + + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) + osal_unsleepable_lock_deinit(&stp_core_ctx.ring[i].mtx); + + stp_ctx_lock_deinit(&stp_core_ctx); + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_btm_get_dmp +* DESCRIPTION +* get stp dump related information +* PARAMETERS +* buffer: dump placement, len: dump size +* RETURNS +* 0: Success Negative Value: Fail +*****************************************************************************/ + +int mtk_wcn_stp_btm_get_dmp(char *buf, int *len) +{ + return stp_dbg_dmp_out(g_mtkstp_dbg, buf, len); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_notify_stp +* DESCRIPTION +* WMT notification to STP that power saving job is done or not +* PARAMETERS +* +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +int mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action) +{ + return stp_psm_notify_stp(STP_PSM_CORE(stp_core_ctx), action); +} + +int mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state) +{ + return stp_psm_set_state(STP_PSM_CORE(stp_core_ctx), state); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_enable +* DESCRIPTION +* enable STP sleep/wakeup support +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep) +{ +#if 0 + if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { + if (mtk_wcn_stp_is_ready()) + return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; + } + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { + return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + } else if (mtk_wcn_stp_is_sdio_mode()) { + stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + STP_DBG_FUNC("PSM is not support under SDIO mode\n"); + return 0; + } + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; + +#else + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { + return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + } else if (mtk_wcn_stp_is_sdio_mode()) { + stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + STP_DBG_FUNC("PSM is not support under SDIO mode\n"); + return 0; + } + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; +#endif +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_disable +* DESCRIPTION +* disable STP sleep/wakeup support +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_psm_disable(VOID) +{ +#if 0 + if (MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) { + if (mtk_wcn_stp_is_ready()) + return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; + } + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { + return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + } else if (mtk_wcn_stp_is_sdio_mode()) { + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + return 0; + } + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; + +#else + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_btif_fullset_mode()) { + return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + } else if (mtk_wcn_stp_is_sdio_mode()) { + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + return 0; + } + STP_DBG_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return 0; + +#endif +} + +extern INT32 mtk_wcn_stp_psm_reset(VOID) +{ + return stp_psm_reset(STP_PSM_CORE(stp_core_ctx)); +} + +extern INT32 mtk_wcn_stp_dbg_disable(VOID) +{ + if (STP_IS_ENABLE_DBG(stp_core_ctx)) { + STP_DBG_FUNC("STP dbg mode is turned off\n"); + STP_SET_ENABLE_DBG(stp_core_ctx, 0); + stp_dbg_disable(g_mtkstp_dbg); + } else { + STP_WARN_FUNC("STP dbg mode has been turned off\n"); + } + + return 0; +} + +extern INT32 mtk_wcn_stp_dbg_enable(VOID) +{ + if (STP_NOT_ENABLE_DBG(stp_core_ctx)) { + STP_DBG_FUNC("STP dbg mode is turned on\n"); + STP_SET_ENABLE_DBG(stp_core_ctx, 1); + stp_dbg_enable(g_mtkstp_dbg); + } else { + STP_WARN_FUNC("STP dbg mode has been turned on\n"); + } + + return 0; +} + +INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on) +{ + stp_dbg_log_ctrl(on); + return 0; +} + +INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on) +{ + STP_ENABLE_FW_COREDUMP(stp_core_ctx, on); + STP_INFO_FUNC("coredump function mode: %d.\n", on); + g_coredump_mode = on; + return 0; +} + +INT32 mtk_wcn_stp_coredump_flag_get(VOID) +{ + return STP_ENABLE_FW_COREDUMP_FLAG(stp_core_ctx); +} + +static INT32 stp_parser_data_in_mand_mode(UINT32 length, UINT8 *p_data) +{ + UINT8 padding_len = 0; + INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ + MTK_WCN_BOOL is_function_active = 0; + INT32 i = length; + + while (i > 0) { + switch (stp_core_ctx.parser.state) { + case MTKSTP_SYNC: /* b'10 */ + /* if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) */ + /* if(*p_data == 0x80) */ + if ((*p_data & 0x80) == 0x80) { + /* STP_DBG_FUNC("[STP] STP Packet Start =========>\n"); */ + if (*p_data != 0x80) + STP_WARN_FUNC("SDIO not 0x80!!(0x%x)\n", *p_data); + + if (i >= 4) { +#if !(REMOVE_USELESS_LOG) + /*print header, when get the full STP header */ + UINT32 type = (*(p_data + 1) & 0x70) >> 4; + UINT8 *type_name = ""; + + type_name = stp_type_to_dbg_string(type); + STP_DBG_FUNC( + "STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", + *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), + type_name, ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), + (*p_data & 0x38) >> 3, *p_data & 0x07); +#endif + } else { + STP_WARN_FUNC("STP Rx: discard due to i < 4 (%d)\n", i); + } + + /* STP_DBG_FUNC("[STP] sync->nak\n"); */ + stp_change_rx_state(MTKSTP_NAK); + stp_core_ctx.rx_counter++; + } else { + STP_WARN_FUNC("sync to sync!!(0x%x)\n", *p_data); + stp_change_rx_state(MTKSTP_SYNC); + } + break; + + case MTKSTP_NAK: + /* STP_DBG_FUNC("[STP] nak->length\n"); */ + stp_change_rx_state(MTKSTP_LENGTH); + stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; + if (stp_core_ctx.parser.type <= MTKSTP_MAX_TASK_NUM) { + stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; + stp_core_ctx.rx_counter++; + } else { + STP_WARN_FUNC("nak to sync\n"); + stp_change_rx_state(MTKSTP_SYNC); + } + break; + + case MTKSTP_LENGTH: + /* STP_DBG_FUNC("[STP] length -> checksum\n"); */ + stp_change_rx_state(MTKSTP_CHECKSUM); + stp_core_ctx.parser.length += *p_data; + + /*Valid length checking */ + if (stp_core_ctx.parser.length < 2000) { + stp_core_ctx.rx_counter++; + } else { + STP_WARN_FUNC("The length of STP packet is not valid !!! length = %d\n", + stp_core_ctx.parser.length); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + /* return -1; */ + } + + break; + + case MTKSTP_CHECKSUM: + + if ((stp_core_ctx.parser.type == STP_TASK_INDX) || + (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_change_rx_state(MTKSTP_FW_MSG); + stp_core_ctx.rx_counter = 0; + i -= 1; + if (i != 0) + p_data += 1; + + continue; + } + + if (stp_core_ctx.parser.length == 0) { + STP_WARN_FUNC("checksum to sync\n"); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + } else { + /* STP_DBG_FUNC("[STP] checksum->data\n"); */ + stp_change_rx_state(MTKSTP_DATA); + stp_core_ctx.rx_counter = 0; + } + break; + + case MTKSTP_DATA: + + /* block copy instead of byte copy */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + /*boundary checking */ + if (stp_core_ctx.rx_counter + remain_length >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC("Abnormal!! Memory operation over boundary!!\n"); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + return -1; + } + + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, + remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_core_ctx.parser.state = MTKSTP_CRC1; + continue; + + } else { /* only copy by data length */ + + /*fixed klocwork insight issue */ + /*boundary checking */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC("Abnormal!! Memory operation over boundary 2!!\n"); + stp_core_ctx.rx_counter = 0; + return -1; + } + + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + break; + + case MTKSTP_CRC1: + stp_change_rx_state(MTKSTP_CRC2); + break; + + case MTKSTP_CRC2: +#if 1 + if (stp_core_ctx.parser.type == WMT_TASK_INDX) { + stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; + STP_DBG_FUNC("wmt sub type (0x%x)\n", stp_core_ctx.parser.wmtsubtype); + } +#endif + /*SDIO mode do it. */ + if (mtk_wcn_stp_is_sdio_mode()) { + /*STP packet 4-bytes alignment */ + /*Discard padding bytes , otherwise make parser state machine disorder */ + if (i <= 4) { + /*STP_DBG_FUNC("STP last block padding %d bytes\n", i-1); */ + p_data += (i - 1); + i -= (i - 1); + } else { + padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; + p_data += padding_len; + i -= padding_len; + /*STP_DBG_FUNC("STP Agg padding %d bytes\n", padding_len); */ + } + } + stp_dbg_pkt_log(stp_core_ctx.parser.type, + 0, 0, 0, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + if ((stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { + int b; + + /*Indicate packet to hci_stp */ + if (gStpDbgLvl >= STP_LOG_DBG) { + stp_dump_data(stp_core_ctx.rx_buf, "indicate_to_bt_core", + stp_core_ctx.rx_counter); + } + + b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + if (b) + STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); + + } else { + + is_function_active = ( + (*sys_check_function_status)(stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) + == STATUS_FUNCTION_ACTIVE); + + /*check type and function if active? */ + if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) + && (is_function_active == MTK_WCN_BOOL_TRUE)) { +#if CFG_WMT_LTE_COEX_HANDLING + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) + && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { + STP_INFO_FUNC("wmt/lte coex package!\n"); + stp_add_to_rx_queue(stp_core_ctx.rx_buf, + stp_core_ctx.rx_counter, COEX_TASK_INDX); + stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); + } else { + stp_add_to_rx_queue(stp_core_ctx.rx_buf, + stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + + /*notify corresponding subfunction of incoming data */ + (*sys_event_set) (stp_core_ctx.parser.type); + } +#else + if ((stp_core_ctx.parser.type == WMT_TASK_INDX) + && stp_core_ctx.parser.wmtsubtype == WMT_LTE_COEX_FLAG) { + STP_WARN_FUNC + ("omit BT/WIFI & LTE coex msg handling in non-LTE projects\n"); + } else { + stp_add_to_rx_queue(stp_core_ctx.rx_buf, + stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + + /*notify corresponding subfunction of incoming data */ + (*sys_event_set) (stp_core_ctx.parser.type); + } +#endif + } else { + if (is_function_active == MTK_WCN_BOOL_FALSE) { + STP_ERR_FUNC + ("function type = %d is inactive, so no en-queue to rx\n", + stp_core_ctx.parser.type); + } else { + STP_ERR_FUNC + ("mtkstp_process_packet: type = %x, the type is invalid\n", + stp_core_ctx.parser.type); + } + } + } + + /* STP_DBG_FUNC("[STP] crc2->sync\n"); */ + /* STP_DBG_FUNC("[STP] STP Packet End <=========\n"); */ + stp_core_ctx.rx_counter = 0; + stp_change_rx_state(MTKSTP_SYNC); + + break; + + case MTKSTP_FW_MSG: + + /*f/w assert and exception information */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + } + + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, + remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; + /*Trace32 Dump */ + if (stp_core_ctx.parser.type == STP_TASK_INDX) { + /* g_block_tx = 1; */ + mtk_wcn_stp_coredump_start_ctrl(1); + pr_debug("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, + stp_core_ctx.parser.type, stp_core_ctx.rx_buf); + /*use paged dump or full dump */ + stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); +#if 0 + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_DMP /*STP_DBG_FW_ASSERT */ , 5, + 0, 0, 0, 0, + (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); +#endif + } + + /*discard CRC */ + /* we will discard antoher CRC on the outer switch procedure. */ + if (i >= 1) { + STP_INFO_FUNC("crc discard.. i = %d\n", i); + i -= 1; + if (i > 0) + p_data += 1; + + } + + /*STP packet 4-bytes alignment */ + /*Discard padding bytes , otherwise make parser state machine disorder */ + if (i <= 4) { + STP_INFO_FUNC + ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", + i - 1); + p_data += (i - 1); + i -= (i - 1); + } else { + padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; + p_data += padding_len; + i -= padding_len; + STP_INFO_FUNC + ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n", + padding_len); + } + stp_change_rx_state(MTKSTP_SYNC); + + } else { /* only copy by data length */ + + STP_ERR_FUNC("raw data doesn't contain full stp packet!!\n"); + } + break; + default: + break; + } + p_data++; + i--; + } + + return 0; +} + +static INT32 stp_parser_data_in_full_mode(UINT32 length, UINT8 *p_data) +{ + INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ + INT32 i = length; + + while (i > 0) { + switch (stp_core_ctx.parser.state) { + + case MTKSTP_RESYNC1: /* RESYNC must be 4 _continuous_ 0x7f */ + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC2); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC2: + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC3); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC3: + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC4); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC4: + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_SYNC); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_SYNC: /* b'10 */ + STP_DUMP_PACKET_HEAD(p_data, "rx (uart):", length > 4 ? 4 : length); + if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) { + stp_change_rx_state(MTKSTP_NAK); + stp_core_ctx.parser.seq = (*p_data & 0x38) >> 3; + stp_core_ctx.parser.ack = *p_data & 0x07; + stp_core_ctx.rx_buf[0] = *p_data; + /* Geoge FIXME: WHY comment the following line? */ + /* stp_core_ctx.rx_counter++; */ + + if (i >= 4 && gStpDbgLvl >= STP_LOG_DBG) { + /*print header, when get the full STP header */ +#if !(REMOVE_USELESS_LOG) + int type = (*(p_data + 1) & 0x70) >> 4; + char *type_name = ""; + + type_name = stp_type_to_dbg_string(type); + + STP_DBG_FUNC + ("STP Rx Header: [%02x %02x %02x %02x] type=%s, len=%d, seq=%d, ack=%d\n", + *p_data, *(p_data + 1), *(p_data + 2), *(p_data + 3), type_name, + ((*(p_data + 1) & 0x0f) << 8) + *(p_data + 2), + (*p_data & 0x38) >> 3, *p_data & 0x07); +#endif + } else { + STP_DBG_FUNC("STP Rx: discard due to i < 4\n"); + } + } else if ((*p_data == 0x7f) && (prev_state == MTKSTP_RESYNC4)) { + /* if this 0x7f is continuous to resync pattern */ + /* skip this continuous 0x7f, remain current & prev state */ + osal_assert(0); + STP_ERR_FUNC("MTKSTP_SYNC: continuous resync pattern, buff = %x\n", *p_data); + } else if (*p_data == 0x7f) { /* a start of 0x7f, maybe this is resync pattern */ + stp_change_rx_state(MTKSTP_RESYNC2); + osal_assert(0); + STP_ERR_FUNC("MTKSTP_SYNC: go to MTKSTP_RESYNC2, buff = %x\n", *p_data); + } else if (*p_data == 0x55) { /* STP delimiter */ + /* do nothing for delimiter */ + } else { /* unexpected, go to resync1 */ + osal_assert(0); + STP_ERR_FUNC("MTKSTP_SYNC: unexpected data, buff = %x\n", *p_data); + } + break; + + case MTKSTP_NAK: + /* (*sys_dbg_print)("MTKSTP_NAK : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ + if (fgEnableNak == 0) + stp_core_ctx.parser.nak = 0; /* disable NAK */ + else + stp_core_ctx.parser.nak = (*p_data & 0x80) >> 7; + + stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; + stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; + stp_core_ctx.rx_buf[1] = *p_data; + /* Geoge FIXME: WHY comment the following line? */ + /*stp_core_ctx.rx_counter++; */ + if (stp_core_ctx.parser.nak) + STP_ERR_FUNC("MTKSTP_NAK TRUE: mtk_wcn_stp_parser_data, buff = %x\n", *p_data); + + if (stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) + stp_change_rx_state(MTKSTP_LENGTH); + else + stp_change_rx_state(MTKSTP_SYNC); + break; + + case MTKSTP_LENGTH: + /* (*sys_dbg_print)("MTKSTP_LENGTH : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ + stp_change_rx_state(MTKSTP_CHECKSUM); + stp_core_ctx.parser.length += *p_data; + + /*Valid length checking */ + if (stp_core_ctx.parser.length > 2048) { + STP_ERR_FUNC("The length of STP packet is not valid !!! length = %d\n", + stp_core_ctx.parser.length); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + STP_TRACE_FUNC("--\n"); + return -1; + } + + stp_core_ctx.rx_buf[2] = *p_data; + /* Geoge FIXME: WHY comment the following line? */ + /*stp_core_ctx.rx_counter++; */ + break; + + case MTKSTP_CHECKSUM: + /* (*sys_dbg_print)("MTKSTP_CHECKSUM : mtk_wcn_stp_parser_data, buff = %x", *p_data); */ + if ((stp_core_ctx.parser.type == STP_TASK_INDX) || + (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_change_rx_state(MTKSTP_FW_MSG); + stp_core_ctx.rx_counter = 0; + i -= 1; + if (i != 0) + p_data += 1; + + continue; + } + + if (((stp_core_ctx.rx_buf[0] + + stp_core_ctx.rx_buf[1] + stp_core_ctx.rx_buf[2]) & 0xff) == *p_data) { + /* header only packet */ + if (stp_core_ctx.parser.length == 0) { + INT32 fgTriggerResume = (-1); + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + if (stp_core_ctx.inband_rst_set == 0) { + stp_dbg_pkt_log(STP_TASK_INDX, + stp_core_ctx.parser.ack, + stp_core_ctx.parser.seq, + 5, /* STP type id */ + PKT_DIR_RX, + NULL, + 0); + fgTriggerResume = stp_process_rxack(); + } else { + STP_WARN_FUNC + ("Now it's inband reset process and drop ACK packet.\n"); + } + + if (fgTriggerResume == 0) { + /* notify adaptation layer for + * possible tx resume mechanism + */ + (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); + } + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + } else { + stp_change_rx_state(MTKSTP_DATA); + stp_core_ctx.rx_counter = 0; + } + } else { + STP_ERR_FUNC("The checksum of header is error !!! %02x %02x %02x %02x\n", + stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], + stp_core_ctx.rx_buf[2], *p_data); + /* George FIXME: error handling mechanism shall be refined */ + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + + /* since checksum error is usually related to interface + * buffer overflow, so we just let timeout mechanism to + * handle such error. + */ + STP_TRACE_FUNC("--\n"); + /* return and purge COMM port */ + return -1; + /*stp_send_ack(1); NAK mechanism is removed */ + } + break; + + case MTKSTP_DATA: +#if 0 + if (stp_core_ctx.rx_counter < stp_core_ctx.parser.length) { + stp_core_ctx.rx_buf[stp_core_ctx.rx_counter] = *p_data; + stp_core_ctx.rx_counter++; + } + if (stp_core_ctx.rx_counter == stp_core_ctx.parser.length) + stp_change_rx_state(MTKSTP_CRC1); +#else + /* block copy instead of byte copy */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, + remain_length); + + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_core_ctx.parser.state = MTKSTP_CRC1; + continue; + } else { /* only copy by data length */ + + /*fixed klocwork insight issue */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC + ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + STP_TRACE_FUNC("--\n"); + return -1; + } + + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } +#endif + break; + + case MTKSTP_CRC1: + stp_change_rx_state(MTKSTP_CRC2); + stp_core_ctx.parser.crc = *p_data; + break; + case MTKSTP_CRC2: + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.parser.crc += (*p_data) << 8; +#if 1 + if (stp_core_ctx.parser.type == WMT_TASK_INDX) { + stp_core_ctx.parser.wmtsubtype = stp_core_ctx.rx_buf[1]; + STP_DBG_FUNC("wmt sub type is (0x%x)\n", stp_core_ctx.parser.wmtsubtype); + } +#endif + if (stp_check_crc(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, stp_core_ctx.parser.crc) + == MTK_WCN_BOOL_TRUE) { + if (stp_core_ctx.inband_rst_set == 0) + stp_process_packet(); + else + STP_WARN_FUNC("Now it's inband reset process and drop packet.\n"); + } else { + STP_ERR_FUNC("The CRC of packet is error !!!\n"); + /* George FIXME: error handling mechanism shall be refined */ + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + + /* since checksum error is usually related to interface + * buffer overflow, so we just let timeout mechanism to + * handle such error. + */ + STP_TRACE_FUNC("--\n"); + /* return and purge COMM port */ + return -1; + /*stp_send_ack(1); NAK mechanism is removed */ + } + break; + + case MTKSTP_FW_MSG: +#if CFG_WMT_DUMP_INT_STATUS + if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) + wmt_plat_BGF_irq_dump_status(); +#endif + if (STP_IS_READY(stp_core_ctx)) + mtk_wcn_stp_dbg_dump_package(); + + STP_SET_READY(stp_core_ctx, 0); + /*stp inband reset */ + if (stp_core_ctx.parser.type == STP_TASK_INDX && + stp_core_ctx.parser.seq == 0 && + stp_core_ctx.parser.ack == 0 && + stp_core_ctx.parser.length == 0 && stp_core_ctx.inband_rst_set == 1) { + STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r"); + stp_rest_ctx_state(); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.inband_rst_set = 0; + /* STP_INFO_FUNC("Restart STP Timer\n\r"); */ + /* (*sys_timer_start)(stp_core_ctx.tx_timer, + * mtkstp_tx_timeout, + * (MTK_WCN_TIMER_CB)stp_tx_timeout_handler, + * NULL); + */ + STP_TRACE_FUNC("--\n"); + return 0; + } + + /*f/w assert and exception information */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, + remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_change_rx_state(MTKSTP_SYNC); + *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; + /* STP_ERR_FUNC("%s [%d]\n", stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); */ +#if 0 + if ((stp_core_ctx.rx_counter == 1) && (stp_core_ctx.rx_buf[0] == 0xFF)) { + /* For MT6620, enable/disable coredump function is controlled by + * firmware for the moment, we need to set coredump enable flag + * to be 1 after see firmware send a pariticallar character(0xff) + * before any coredump packet is sent + */ + mtk_wcn_stp_coredump_flag_ctrl(1); + } +#endif + /*Trace32 Dump */ + if (STP_IS_ENABLE_DBG(stp_core_ctx) && + (stp_core_ctx.parser.type == STP_TASK_INDX)) { + if (0 != stp_core_ctx.rx_counter) { + STP_SET_READY(stp_core_ctx, 0); + mtk_wcn_stp_ctx_save(); + STP_INFO_FUNC("++ start to read paged dump and paged trace ++\n"); + stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); + stp_btm_notify_wmt_trace_wq(stp_core_ctx.btm); + STP_INFO_FUNC("++ start to read paged dump and paged trace --\n"); + + } + STP_INFO_FUNC("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, + stp_core_ctx.parser.type, stp_core_ctx.rx_buf); + } + + /*Runtime FW Log */ + else if (STP_IS_ENABLE_DBG(stp_core_ctx) + && (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0, + (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); + mtk_wcn_stp_dbg_dump_package(); + } + /*Normal mode: whole chip reset */ + else { + /*Aee Kernel Warning Message Shown First */ + /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */ + mtk_wcn_stp_coredump_start_ctrl(0); + mtk_wcn_stp_dbg_dump_package(); + + osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf); + /*Whole Chip Reset Procedure Invoke */ + if (STP_IS_ENABLE_RST(stp_core_ctx)) { + STP_SET_READY(stp_core_ctx, 0); + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + } else { + STP_INFO_FUNC + ("No to launch whole chip reset! for debugging purpose\n"); + } + } + /*discard CRC */ + if (i >= 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + if (i > 0) + p_data += 2; + } + continue; + } else { /* only copy by data length */ + + /*fixed klocwork insight issue */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC + ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + return -1; + } + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + + break; + default: + break; + } + p_data++; + i--; + } + + return 0; +} +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* int 0 = success; -1 = crc/checksum error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +int _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) +#else +int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length) +#endif +{ + /*----------------------------------------------------------------*/ + /* Local Variables */ + /*----------------------------------------------------------------*/ + INT32 i; + UINT8 *p_data; + INT32 ret = 0; +#ifdef DEBUG_DUMP_PACKET_HEAD + static UINT32 counter; + + STP_TRACE_FUNC("++, rx (cnt=%d,len=%d)\n", ++counter, length); +#endif + +#if 0 +#ifdef CONFIG_POWER_SAVING_SUPPORT + if (stp_is_apply_powersaving()) { + /* If now chip is awake, to restart monitor! */ + if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { + STP_DBG_FUNC("To restart moinotr when rx\n\r"); + stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); + } + } +#endif +#endif + + /*----------------------------------------------------------------*/ + /* Code Body */ + /*----------------------------------------------------------------*/ + /* George FIXME: WHY or HOW can we reduct the locked region? */ + /*flags = (*sys_mutex_lock)(stp_core_ctx.stp_mutex); */ + i = length; + p_data = (UINT8 *) buffer; + +/* stp_dump_data(buffer, "rx queue", length); */ + + /*STP is not enabled and only WMT can use Raw data path */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == STP_PENDING_TYPE(stp_core_ctx)) { + /* route to task who send command */ + stp_add_to_rx_queue(buffer, length, STP_PENDING_TYPE(stp_core_ctx)); + + /* mike: notify corresponding subfunction of incoming data */ + (*sys_event_set) (STP_PENDING_TYPE(stp_core_ctx)); + } + /* STP over SDIO */ + else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { +#if !(REMOVE_USELESS_LOG) + if (gStpDbgLvl >= STP_LOG_DBG) + stp_dump_data(buffer, "sdio parser_in", length); +#endif + /* STP_DBG_FUNC("sdio stp parser data length = %d\n", length); */ + ret = stp_parser_data_in_mand_mode(i, p_data); + } + /* STP over UART */ + else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) + ret = stp_parser_data_in_full_mode(i, p_data); + + /* George FIXME: WHY or HOW can we reduct the locked region? */ + /*(*sys_mutex_unlock)(stp_core_ctx.stp_mutex, flags); */ + STP_TRACE_FUNC("--\n"); + return ret; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_parser_data); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_enable +* DESCRIPTION +* enable/disable STP +* PARAMETERS +* value [IN] 0=disable, others=enable +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_enable(INT32 value) +{ + STP_DBG_FUNC("%s: set the current enable = (%d)\n", __func__, value); + + stp_rest_ctx_state(); + STP_SET_ENABLE(stp_core_ctx, value); + if (!value) { + mtk_wcn_stp_psm_reset(); + } else { +/* g_block_tx = 0; */ + mtk_wcn_stp_coredump_start_ctrl(0); + } + return 0; +} + +INT32 mtk_wcn_stp_dbg_dump_package(VOID) +{ + if (STP_NOT_ENABLE(stp_core_ctx)) { + STP_INFO_FUNC("STP dbg mode is off\n"); + + } else { + STP_INFO_FUNC("STP dbg mode is on\n"); + /* if (0 == g_block_tx) */ + if (0 == mtk_wcn_stp_coredump_start_get()) { + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); + stp_dbg_dmp_printk(g_mtkstp_dbg); + } else { + STP_INFO_FUNC("assert start flag is set, disable packet dump function\n"); + } + } + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_ready +* DESCRIPTION +* ready/un-ready STP +* PARAMETERS +* value [IN] 0=un-ready, others=ready +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_ready(INT32 value) +{ + STP_DBG_FUNC("set ready (%d)\n", value); + + STP_SET_READY(stp_core_ctx, value); + /*if whole chip reset, reset the debuggine mode */ +#ifndef CONFIG_LOG_STP_INTERNAL + /* mtk_wcn_stp_dbg_disable(); */ +#endif + + if (stp_is_apply_powersaving()) { + STP_INFO_FUNC("Restart the stp-psm monitor !!\n"); + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + } + + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_ctrl +* DESCRIPTION +* set f/w assert flag in STP context +* PARAMETERS +* value [IN] 0=assert end, others=assert begins +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value) +{ + STP_DBG_FUNC("set f/w assert (%d)\n", value); + + STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, value); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get f/w assert flag in STP context +* PARAMETERS +* VOID +* RETURNS +* INT32 0= f/w assert flag is not set, others=f/w assert flag is set +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_coredump_start_get(VOID) +#else +INT32 mtk_wcn_stp_coredump_start_get(VOID) +#endif +{ + return STP_FW_COREDUMP_FLAG(stp_core_ctx); +} + +/* mtk_wcn_stp_set_wmt_last_close -- set the state of link(UART or SDIO) + * @ value - 1, link already be closed; 0, link is open + * + * Return 0 if success; else error code + */ +INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value) +{ + STP_INFO_FUNC("set wmt_last_close flag (%d)\n", value); + + STP_SET_WMT_LAST_CLOSE(stp_core_ctx, value); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 > 0: length transmitted; = 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#else +INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#endif +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; + UINT8 *p_tx_buf = NULL; + UINT16 crc; + INT32 ret = 0; + MTK_WCN_BOOL is_quick_enable = MTK_WCN_BOOL_TRUE; + + /* osal_buffer_dump(buffer,"tx", length, 32); */ + + if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { + STP_ERR_FUNC("WMT lats close,should not have tx request!\n"); + return length; + } + /* if(g_block_tx) */ + if (0 != mtk_wcn_stp_coredump_start_get()) { + STP_ERR_FUNC("STP fw coredump start flag set...\n"); + return length; + } +#ifdef CONFIG_POWER_SAVING_SUPPORT + is_quick_enable = stp_psm_is_quick_ps_support(); + STP_DBG_FUNC("is quick sleep enable:%s\n", is_quick_enable ? "yes" : "no"); + if (MTK_WCN_BOOL_TRUE == is_quick_enable) { + if (type != WMT_TASK_INDX) { +#if PSM_USE_COUNT_PACKAGE + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0); +#else + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0, length); +#endif + } + /* if(stp_is_apply_powersaving()) */ + { + if (type == WMT_TASK_INDX) + goto DONT_MONITOR; + /*-----------------------------STP_PSM_Lock----------------------------------------*/ + ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); + if (ret) { + STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); + return ret; + } + + if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { + if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { + STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); + stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); + } + } else { + ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); + stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); + /*-----------------------------STP_PSM_UnLock----------------------------------------*/ + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + return ret; + } + } + } else { + /* if(stp_is_apply_powersaving()) */ + { + if (type == WMT_TASK_INDX) + goto DONT_MONITOR; + /* If now chip is awake, to restart monitor! */ + /* STP_INFO_FUNC("check if block traffic !!\n"); */ + /*-----------------------------STP_PSM_Lock----------------------------------------*/ + ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); + if (ret) { + STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); + return ret; + } + + if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { + /* STP_INFO_FUNC("not to block !!\n"); */ + if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { + STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); + stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); + } + stp_psm_start_monitor(STP_PSM_CORE(stp_core_ctx)); + } else { + /* STP_INFO_FUNC("to block !!\n"); */ + + /* STP_INFO_FUNC("*****hold data in psm queue data length = %d\n", + * length); + */ + /* stp_dump_data(buffer, "Hold in psm queue", length); */ + /* hold datas */ + ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); + /* wmt notification */ + STP_INFO_FUNC("#####Type = %d, to inform WMT to wakeup chip, ret = %d:0x%2x,0x%2x\n", + type, ret, *buffer, *(buffer + 1)); + stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); + /* STP_INFO_FUNC("*********Type = %d, to inform WMT to wakeup chip>end\n", type); */ + /*-----------------------------STP_PSM_UnLock----------------------------------------*/ + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + return ret; + } + } + } +DONT_MONITOR: +#endif + if (type == BT_TASK_INDX) { + static const UINT8 rst_buf[4] = { 0x01, 0x03, 0x0c, 0x00 }; + + if (!osal_strncmp(buffer, rst_buf, 4)) + osal_printtimeofday("############ BT Rest start -->"); + } + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + /*Only WMT can set raw data */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { + /* no-op */ + /* NULL; */ + } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { + /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ + /* NULL; */ + } + /* STP over SDIO */ + else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { + + /* osal_printtimeofday("[ STP][SDIO][ B][W]"); */ + + mtkstp_header[0] = 0x80; + mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); + mtkstp_header[2] = (length) & 0xff; + mtkstp_header[3] = 0x00; + + /* HEADER */ + p_tx_buf = &stp_core_ctx.tx_buf[0]; + osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); + p_tx_buf += MTKSTP_HEADER_SIZE; + + /* PAYLOAD */ + osal_memcpy(p_tx_buf, buffer, length); + p_tx_buf += length; + + /* CRC */ + temp[0] = 0x00; + temp[1] = 0x00; + osal_memcpy(p_tx_buf, temp, 2); + stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length); + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); + + if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { + STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); + osal_assert(0); + ret = 0; + } else { + ret = (INT32) length; + } + + /* osal_printtimeofday("[ STP][SDIO][ E][W]"); */ + } + /* STP over UART */ + else if (mtk_wcn_stp_is_btif_fullset_mode() && STP_IS_ENABLE(stp_core_ctx)) { + + /* osal_printtimeofday("[ STP][UART][ B][W]"); */ + /* STP_INFO_FUNC("Write byte %d\n", length); */ + + if ((stp_core_ctx.sequence.winspace > 0) && + (stp_core_ctx.inband_rst_set == 0) && + (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { + /*Make Header */ + /* (*sys_dbg_print)("mtk_wcn_stp_send_data 1, txseq = %d, winspace = %d", + * stp_core_ctx.sequence.txseq, stp_core_ctx.sequence.winspace); + */ + mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; + mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); + mtkstp_header[2] = length & 0xff; + mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = stp_core_ctx.tx_write; + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = MTKSTP_HEADER_SIZE + length + 2; + if (fgEnableDelimiter == 1) { + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; + stp_add_to_tx_queue(&stp_delimiter[0], STP_DEL_SIZE); + } + stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); + + /*Make Payload */ + stp_add_to_tx_queue(buffer, length); + + /*Make CRC */ + crc = osal_crc16(buffer, length); + temp[0] = crc & 0xff; + temp[1] = (crc & 0xff00) >> 8; + stp_add_to_tx_queue(temp, 2); + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, crc, PKT_DIR_TX, buffer, length); + + /*Kick to UART */ + stp_send_tx_queue(stp_core_ctx.sequence.txseq); + + INDEX_INC(stp_core_ctx.sequence.txseq); + stp_core_ctx.sequence.winspace--; + + /*Setup the Retry Timer */ + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + else + STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); + + ret = (INT32) length; + } else { + /* + No winspace to send. Let caller retry + */ + if (stp_core_ctx.inband_rst_set == 1) + STP_WARN_FUNC("Now it's inband reset process and drop sent packet.\n"); + else + STP_ERR_FUNC("There is no winspace/txqueue to send !!!\n"); + + ret = 0; + } + + /* osal_printtimeofday("[ STP][UART][ E][W]"); */ + } + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + +#ifdef CONFIG_POWER_SAVING_SUPPORT + + if (MTK_WCN_BOOL_TRUE == is_quick_enable) { + if (type != WMT_TASK_INDX) { + stp_psm_notify_wmt_sleep(STP_PSM_CORE(stp_core_ctx)); + /*-----------------------STP_PSM_UnLock-------------------------*/ + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + } + } else { + /* if(stp_is_apply_powersaving()) */ + /* { */ + if (type != WMT_TASK_INDX) { + + /*--------------------STP_PSM_UnLock--------------------------*/ + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + } + /* } */ + } +#endif + + return ret; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_send_data); +#endif +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data_raw +* DESCRIPTION +* send raw data to common interface, bypass STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#else +INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#endif +{ + UINT32 written = 0; + INT32 ret = 0; + + if (0 != STP_WMT_LAST_CLOSE(stp_core_ctx)) { + STP_ERR_FUNC("WMT lats close,should not have tx request!"); + return length; + } + + STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d, data = %x %x %x %x %x %x ", type, buffer[0], buffer[1], + buffer[2], buffer[3], buffer[4], buffer[5]); + STP_SET_PENDING_TYPE(stp_core_ctx, type); /* remember tx type, forward following rx to this type */ + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, 1); + (*sys_if_tx) (&buffer[0], length, &written); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + + if (written == 0) + stp_dump_data(&buffer[0], "tx raw failed:", length); + + if (written == length) + ret = (INT32) written; + else + ret = (-1); + + return ret; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); +#endif +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) +#else +INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type) +#endif +{ + /* GeorgeKuo modify: reduce "if" branch */ + UINT16 copyLen = 0; + UINT16 tailLen = 0; + + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + while (stp_core_ctx.ring[type].read_p != stp_core_ctx.ring[type].write_p) { + /* GeorgeKuo modify: reduce if branch */ + if (stp_core_ctx.ring[type].write_p > stp_core_ctx.ring[type].read_p) { + copyLen = stp_core_ctx.ring[type].write_p - stp_core_ctx.ring[type].read_p; + if (copyLen > length) + copyLen = length; + + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, copyLen); + stp_core_ctx.ring[type].read_p += copyLen; + } else { + tailLen = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].read_p; + if (tailLen > length) { /* exclude equal case to skip wrap check */ + copyLen = length; + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, + copyLen); + stp_core_ctx.ring[type].read_p += copyLen; + } else { + /* part 1: copy tailLen */ + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, + tailLen); + + buffer += tailLen; /* update buffer offset */ + + /* part 2: check if head length is enough */ + copyLen = length - tailLen; + copyLen = + (stp_core_ctx.ring[type].write_p < + copyLen) ? stp_core_ctx.ring[type].write_p : copyLen; + + if (copyLen) + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + 0, copyLen); + + /* Update read_p final position */ + stp_core_ctx.ring[type].read_p = copyLen; + + /* update return length: head + tail */ + copyLen += tailLen; + } + } + break; + } + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if ((MTK_WCN_BOOL_TRUE == stp_psm_is_quick_ps_support()) && (type != WMT_TASK_INDX)) { +#if PSM_USE_COUNT_PACKAGE + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1); +#else + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1, copyLen); +#endif + } + + return copyLen; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_receive_data); +#endif +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +#else +INT32 mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +#endif +{ + INT32 ret; + + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if (stp_core_ctx.ring[type].read_p == stp_core_ctx.ring[type].write_p) + ret = 1; /* queue is empty */ + else + ret = 0; /* queue is not empty */ + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + return ret; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); +#endif +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_set_sdio_mode +* DESCRIPTION +* Set stp for SDIO mode +* PARAMETERS +* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) +* RETURNS +* void +*****************************************************************************/ + +void mtk_wcn_stp_set_mode(UINT32 mode) +{ + STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, mode); + + STP_DBG_FUNC("STP_SUPPORT_PROTOCOL = %08x\n", STP_SUPPORT_PROTOCOL(stp_core_ctx)); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_fullset_mode +* DESCRIPTION +* Is stp use UART fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:Uart Fullset mode, FALSE:Not UART Fullset mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(void) +{ + /* + bit 0: uart fullset mode + bit 1: uart mandatory mode + bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_FULL_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_mand_mode +* DESCRIPTION +* Is stp use UART mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:Uart Mandatory mode, FALSE:Not UART Mandotary mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(void) +{ + /* + bit 0: uart fullset mode + bit 1: uart mandatory mode + bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_MAND_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_fullset_mode +* DESCRIPTION +* Is stp use BTIF fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Fullset mode, FALSE:Not BTIF Fullset mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(void) +{ + + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_FULL_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_mand_mode +* DESCRIPTION +* Is stp use BTIF mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Mandatory mode, FALSE:Not BTIF Mandotary mode +*****************************************************************************/ + +MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void) +{ + + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_MAND_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_sdio_mode +* DESCRIPTION +* Is stp use SDIO mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(void) +{ + /* + bit 0: uart fullset mode + bit 1: uart mandatory mode + bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_SDIO_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To sync to oringnal stp state with f/w stp +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +void mtk_wcn_stp_inband_reset(void) +{ + UINT8 inband_reset_packet[64]; + UINT32 txseq = 0; + UINT32 txack = 0; + UINT32 crc = 0; + UINT32 ret = 0; + UINT32 reset_payload_len = 0; + + /*512 bytes */ + UINT8 reset_payload[] = { + 0xc0, 0x01, 0xc0, 0xde, 0x3e, 0xd1, 0xa7, 0xef + }; + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + + /*RESYNC*/ inband_reset_packet[0] = 0x7f; + inband_reset_packet[1] = 0x7f; + inband_reset_packet[2] = 0x7f; + inband_reset_packet[3] = 0x7f; + inband_reset_packet[4] = 0x7f; + inband_reset_packet[5] = 0x7f; + inband_reset_packet[6] = 0x7f; + inband_reset_packet[7] = 0x7f; + + /*header */ + reset_payload_len = sizeof(reset_payload) / sizeof(reset_payload[0]); + inband_reset_packet[8] = 0x80 + (txseq << 3) + txack; + inband_reset_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); + inband_reset_packet[10] = reset_payload_len & 0xff; + inband_reset_packet[11] = (inband_reset_packet[8] + inband_reset_packet[9] + inband_reset_packet[10]) & 0xff; + + /*payload */ + osal_memcpy(&inband_reset_packet[12], reset_payload, reset_payload_len); + + /*crc */ + crc = osal_crc16(&reset_payload[0], reset_payload_len); + inband_reset_packet[12 + reset_payload_len] = crc & 0xff; + inband_reset_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; + + (*sys_if_tx) (&inband_reset_packet[0], 14 + reset_payload_len, &ret); + + if (ret != (14 + reset_payload_len)) + STP_ERR_FUNC("Inband sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, ret); + + stp_core_ctx.inband_rst_set = 1; + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ +} + +void mtk_wcn_stp_debug_ctrl(INT32 op, INT32 filter, INT32 filter_param) +{ + /*nothing at now*/ +} + +void mtk_wcn_stp_test_cmd(INT32 cmd_no) +{ + UINT8 test_packet[64]; + UINT32 txseq = 0; + UINT32 txack = 0; + UINT32 crc = 0; + UINT32 ret = 0; + UINT32 reset_payload_len = 0; + + UINT8 test_payload[] = { + 0xAA, 0xAA, 0xC0, 0xDE, 0x3E, 0xD1, 0xA7, 0xEF + }; +/* */ +/* select your test command by cmd_no */ +/* */ + if (cmd_no == 0) { + /* to test new command to chip */ + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + + /*RESYNC*/ test_packet[0] = 0x7f; + test_packet[1] = 0x7f; + test_packet[2] = 0x7f; + test_packet[3] = 0x7f; + test_packet[4] = 0x7f; + test_packet[5] = 0x7f; + test_packet[6] = 0x7f; + test_packet[7] = 0x7f; + + /*header */ + reset_payload_len = sizeof(test_payload) / sizeof(test_payload[0]); + test_packet[8] = 0x80 + (txseq << 3) + txack; + test_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); + test_packet[10] = reset_payload_len & 0xff; + test_packet[11] = (test_packet[8] + test_packet[9] + test_packet[10]) & 0xff; + + /*payload */ + osal_memcpy(&test_packet[12], test_payload, reset_payload_len); + + /*crc */ + crc = osal_crc16(&test_payload[0], reset_payload_len); + test_packet[12 + reset_payload_len] = crc & 0xff; + test_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; + + (*sys_if_tx) (&test_packet[0], 14 + reset_payload_len, &ret); + if (ret != (14 + reset_payload_len)) { + STP_ERR_FUNC("stp test sending error, sending %d , but ret = %d\n", 10 + reset_payload_len, + ret); + } + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + } + +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush_context +* DESCRIPTION +* Flush STP Context +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +void mtk_wcn_stp_flush_context(void) +{ + stp_rest_ctx_state(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush_rx_queue +* DESCRIPTION +* Flush STP Rx Queue +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ + +void mtk_wcn_stp_flush_rx_queue(UINT32 type) +{ + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + if (type < MTKSTP_MAX_TASK_NUM) { + stp_core_ctx.ring[type].read_p = 0; + stp_core_ctx.ring[type].write_p = 0; + } + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* STP is ready? +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void) +#else +MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) +#endif +{ + return STP_IS_READY(stp_core_ctx); +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_is_ready); +#endif +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) +#else +void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) +#endif +{ + /* g_mtkstp_bluez_flag = bluez_flag; */ + STP_SET_BT_STK(stp_core_ctx, bluez_flag); +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); +#endif +/***************************************************************************** +* FUNCTION +* set stp debugging mdoe +* DESCRIPTION +* set stp debugging mdoe +* PARAMETERS +* dbg_mode: switch to dbg mode ? +* RETURNS +* void +*****************************************************************************/ +void mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode) +{ + STP_SET_ENABLE_DBG(stp_core_ctx, dbg_mode); +} + +/***************************************************************************** +* FUNCTION +* set stp auto reset mdoe +* DESCRIPTION +* set stp auto reset mdoe +* PARAMETERS +* auto_rst: switch to auto reset mode ? +* RETURNS +* void +*****************************************************************************/ +void mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst) +{ + STP_SET_ENABLE_RST(stp_core_ctx, auto_rst); +} + +INT32 mtk_wcn_stp_notify_sleep_for_thermal(void) +{ + return stp_psm_sleep_for_thermal(STP_PSM_CORE(stp_core_ctx)); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_open_btif +* DESCRIPTION +* init btif hw & sw by owner stp +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_open_btif(VOID) +{ + return mtk_wcn_consys_stp_btif_open(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_open_close +* DESCRIPTION +* close btif hw & sw by owner stp +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_close_btif(VOID) +{ + return mtk_wcn_consys_stp_btif_close(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_rx_cb_register +* DESCRIPTION +* register stp rx cb to btif +* PARAMETERS +* MTK_WCN_BTIF_RX_CB stp rx handle function +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb) +{ + return mtk_wcn_consys_stp_btif_rx_cb_register(rx_cb); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_tx +* DESCRIPTION +* send stp package by btif +* PARAMETERS +* pBuf:package buffer pointer,len:package length +* written_len:package written length +* RETURNS +* INT32 package length-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len) +{ + INT32 iRet = -1; + + iRet = mtk_wcn_consys_stp_btif_tx(pBuf, len, written_len); + return iRet; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_wakeup_consys +* DESCRIPTION +* STP wakeup consys by btif +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_wakeup_consys(VOID) +{ + /*log wakeup int for debug */ + stp_dbg_pkt_log(7, 0, 0, 0, PKT_DIR_TX, NULL, 0); + return mtk_wcn_consys_stp_btif_wakeup(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_dpidle_ctrl +* DESCRIPTION +* decide AP enter or exit deep idle +* PARAMETERS +* en_flag:1,enter,0,exit +* RETURNS +* always 0 +*****************************************************************************/ +INT32 mtk_wcn_stp_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + mtk_wcn_consys_stp_btif_dpidle_ctrl(en_flag); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_lpbk_ctrl +* DESCRIPTION +* enable stp internal lpbk test or not +* PARAMETERS +* mode:1,enable,0,disabel +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) +{ + return mtk_wcn_consys_stp_btif_lpbk_ctrl(mode); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_logger_ctrl +* DESCRIPTION +* dump btif buffer or register status when No ACK or assert occurs +* PARAMETERS +* flag:see enum value in ENUM_BTIF_DBG_ID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_logger_ctrl(ENUM_BTIF_DBG_ID flag) +{ + return mtk_wcn_consys_stp_btif_logger_ctrl(flag); +} + +VOID mtk_wcn_stp_ctx_save(void) +{ + STP_INFO_FUNC("start ++\n"); + mtk_wcn_stp_coredump_start_ctrl(1); + stp_psm_set_sleep_disable(stp_core_ctx.psm); + STP_INFO_FUNC("exit --\n"); +} + +VOID mtk_wcn_stp_ctx_restore(void) +{ + STP_INFO_FUNC("start ++\n"); + stp_psm_set_sleep_enable(stp_core_ctx.psm); + stp_btm_reset_btm_wq(STP_BTM_CORE(stp_core_ctx)); + + if (STP_IS_ENABLE_RST(stp_core_ctx)) + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); +#if STP_RETRY_OPTIMIZE + g_retry_times = 0; +#endif + STP_INFO_FUNC("exit --\n"); +} + +INT32 mtk_wcn_stp_wmt_evt_err_trg_assert(void) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_coredump_start_get() != 0) { + STP_INFO_FUNC("firmware assert has been triggered\n"); + return 0; + } + + ret = stp_notify_btm_do_fw_assert_via_emi(STP_BTM_CORE(stp_core_ctx)); + if (ret) { + STP_ERR_FUNC("evt err trigger assert fail,do chip reset to recovery\n"); + + mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); + if (STP_IS_ENABLE_RST(stp_core_ctx)) + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } + + return ret; +} + +VOID mtk_wcn_stp_set_wmt_evt_err_trg_assert(UINT32 value) +{ + STP_INFO_FUNC("set evt err tigger assert flag to %d\n", value); + STP_SET_EVT_ERR_ASSERT(stp_core_ctx, value); +} + +UINT32 mtk_wcn_stp_get_wmt_evt_err_trg_assert(void) +{ + return STP_EVT_ERR_ASSERT(stp_core_ctx); +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c new file mode 100644 index 0000000000000..3009bd26df41a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_conf.c @@ -0,0 +1,529 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONF]" + +#include "osal_typedef.h" +/* #include "osal.h" */ +#include "wmt_lib.h" +#include "wmt_dev.h" +#include "wmt_conf.h" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +struct parse_data { + PINT8 name; + INT32 (*parser)(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 value); + PINT8 (*writer)(P_DEV_WMT pWmtDev, const struct parse_data *data); + /*PINT8 param1, *param2, *param3; */ + /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */ + PINT8 param1; + PINT8 param2; + PINT8 param3; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ +static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal); + +static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size); + +#define OFFSET(v) ((void *) &((P_DEV_WMT) 0)->v) + +#define CHAR(f) \ +{ \ + #f, \ + wmt_conf_parse_char, \ + wmt_conf_write_char, \ + OFFSET(rWmtGenConf.f), \ + NULL, \ + NULL \ +} +/* #define CHAR(f) _CHAR(f), NULL, NULL} */ + +#define SHORT(f) \ +{ \ + #f, \ + wmt_conf_parse_short, \ + wmt_conf_write_short, \ + OFFSET(rWmtGenConf.f), \ + NULL, \ + NULL \ +} +/* #define SHORT(f) _SHORT(f), NULL, NULL */ + +#define INT(f) \ +{ \ + #f, \ + wmt_conf_parse_int, \ + wmt_conf_write_int, \ + OFFSET(rWmtGenConf.f), \ + NULL, \ + NULL \ +} +/* #define INT(f) _INT(f), NULL, NULL */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static const struct parse_data wmtcfg_fields[] = { + CHAR(coex_wmt_ant_mode), + CHAR(coex_wmt_ext_component), + CHAR(coex_wmt_wifi_time_ctl), + CHAR(coex_wmt_ext_pta_dev_on), + CHAR(coex_wmt_filter_mode), + + CHAR(coex_bt_rssi_upper_limit), + CHAR(coex_bt_rssi_mid_limit), + CHAR(coex_bt_rssi_lower_limit), + CHAR(coex_bt_pwr_high), + CHAR(coex_bt_pwr_mid), + CHAR(coex_bt_pwr_low), + + CHAR(coex_wifi_rssi_upper_limit), + CHAR(coex_wifi_rssi_mid_limit), + CHAR(coex_wifi_rssi_lower_limit), + CHAR(coex_wifi_pwr_high), + CHAR(coex_wifi_pwr_mid), + CHAR(coex_wifi_pwr_low), + + CHAR(coex_ext_pta_hi_tx_tag), + CHAR(coex_ext_pta_hi_rx_tag), + CHAR(coex_ext_pta_lo_tx_tag), + CHAR(coex_ext_pta_lo_rx_tag), + SHORT(coex_ext_pta_sample_t1), + SHORT(coex_ext_pta_sample_t2), + CHAR(coex_ext_pta_wifi_bt_con_trx), + + INT(coex_misc_ext_pta_on), + INT(coex_misc_ext_feature_set), + + CHAR(wmt_gps_lna_pin), + CHAR(wmt_gps_lna_enable), + + CHAR(pwr_on_rtc_slot), + CHAR(pwr_on_ldo_slot), + CHAR(pwr_on_rst_slot), + CHAR(pwr_on_off_slot), + CHAR(pwr_on_on_slot), + CHAR(co_clock_flag), + + INT(sdio_driving_cfg), + +}; + +#define NUM_WMTCFG_FIELDS (osal_sizeof(wmtcfg_fields) / osal_sizeof(wmtcfg_fields[0])) + +static int wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PINT8 dst; + long res; + int ret; + + dst = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + ret = osal_strtol(pos + 2, 16, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + ret = osal_strtol(pos, 10, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + return 0; +} + +static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT8 src; + INT32 res; + PINT8 value; + + src = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static int wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT16 dst; + long res; + int ret; + + dst = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); + + /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + ret = osal_strtol(pos + 2, 16, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + ret = osal_strtol(pos, 10, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT16 src; + INT32 res; + PINT8 value; + + /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */ + src = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static int wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT32 dst; + long res; + int ret; + + dst = (PINT32) (((PUINT8) pWmtDev) + (long)data->param1); + + /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + ret = osal_strtol(pos + 2, 16, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + ret = osal_strtol(pos, 10, &res); + if (ret) + WMT_ERR_FUNC("fail(%d)\n", ret); + *dst = res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT32 src; + INT32 res; + PINT8 value; + + src = (PUINT32) (((PUINT8) pWmtDev) + (long)data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal) +{ + int i = 0; + int ret = 0; + + /* WMT_INFO_FUNC( DBG_NAME "cfg(%s) val(%s)\n", pKey, pVal); */ + + for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { + const struct parse_data *field = &wmtcfg_fields[i]; + + if (osal_strcmp(pKey, field->name) != 0) + continue; + if (field->parser(pWmtDev, field, pVal)) { + WMT_ERR_FUNC("failed to parse %s '%s'.\n", pKey, pVal); + ret = -1; + } + break; + } + if (i == NUM_WMTCFG_FIELDS) { + WMT_ERR_FUNC("unknown field '%s'.\n", pKey); + ret = -1; + } + + return ret; +} + +static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size) +{ + PINT8 pch; + PINT8 pBuf; + PINT8 pLine; + PINT8 pKey; + PINT8 pVal; + PINT8 pPos; + INT32 ret = 0; + INT32 i = 0; + PINT8 pa = NULL; + + pBuf = osal_malloc(size); + if (!pBuf) + return -1; + + osal_memcpy(pBuf, pInBuf, size); + pBuf[size] = '\0'; + + pch = pBuf; + /* pch is to be updated by strsep(). Keep pBuf unchanged!! */ + +#if 0 + { + PINT8 buf_ptr = pBuf; + INT32 k = 0; + + WMT_INFO_FUNC("%s len=%d", "wmcfg.content:", size); + for (k = 0; k < size; k++) { + /* if(k%16 == 0) WMT_INFO_FUNC("\n"); */ + WMT_INFO_FUNC("%c", buf_ptr[k]); + } + WMT_INFO_FUNC("--end\n"); + } +#endif + + while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) { + /* pch is updated to the end of pLine by strsep() and updated to '\0' */ + /*WMT_INFO_FUNC("strsep offset(%d), char(%d, '%c' )\n", pLine-pBuf, *pLine, *pLine); */ + /* parse each line */ + + /* WMT_INFO_FUNC("==> Line = (%s)\n", pLine); */ + + if (!*pLine) + continue; + + pVal = osal_strchr(pLine, '='); + if (!pVal) { + WMT_WARN_FUNC("mal-format cfg string(%s)\n", pLine); + continue; + } + + /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */ + *pVal = '\0'; /* replace '=' with '\0' to get key */ + /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */ + pKey = pLine; + + if ((pVal - pBuf) < size) + pVal++; + + /*key handling */ + pPos = pKey; + /*skip space characeter */ + while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key head */ + pKey = pPos; + while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key tail */ + (*pPos) = '\0'; + + /*value handling */ + pPos = pVal; + /*skip space characeter */ + while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value head */ + pVal = pPos; + while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value tail */ + (*pPos) = '\0'; + + /* WMT_DBG_FUNC("parse (key: #%s#, value: #%s#)\n", pKey, pVal); */ + ret = wmt_conf_parse_pair(pWmtDev, pKey, pVal); + WMT_DBG_FUNC("parse (%s, %s, %d)\n", pKey, pVal, ret); + if (ret) + WMT_WARN_FUNC("parse fail (%s, %s, %d)\n", pKey, pVal, ret); + } + + for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { + const struct parse_data *field = &wmtcfg_fields[i]; + + pa = field->writer(pWmtDev, field); + if (pa) { + WMT_DBG_FUNC("#%d(%s)=>%s\n", i, field->name, pa); + osal_free(pa); + } else { + WMT_ERR_FUNC("failed to parse '%s'.\n", field->name); + } + } + osal_free(pBuf); + return 0; +} + +INT32 wmt_conf_set_cfg_file(const char *name) +{ + if (NULL == name) { + WMT_ERR_FUNC("name is NULL\n"); + return -1; + } + if (osal_strlen(name) >= osal_sizeof(gDevWmt.cWmtcfgName)) { + WMT_ERR_FUNC("name is too long, length=%d, expect to < %d\n", osal_strlen(name), + osal_sizeof(gDevWmt.cWmtcfgName)); + return -2; + } + osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); + osal_strcpy(&(gDevWmt.cWmtcfgName[0]), name); + WMT_ERR_FUNC("WMT config file is set to (%s)\n", &(gDevWmt.cWmtcfgName[0])); + + return 0; +} + +INT32 wmt_conf_read_file(VOID) +{ + INT32 ret = -1; + + osal_memset(&gDevWmt.rWmtGenConf, 0, osal_sizeof(gDevWmt.rWmtGenConf)); + osal_memset(&gDevWmt.pWmtCfg, 0, osal_sizeof(gDevWmt.pWmtCfg)); + +#if 1 + osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); + + osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT_PREFIX, osal_sizeof(CUST_CFG_WMT_PREFIX)); + osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT, osal_sizeof(CUST_CFG_WMT)); +#endif + + if (!osal_strlen(&(gDevWmt.cWmtcfgName[0]))) { + WMT_ERR_FUNC("empty Wmtcfg name\n"); + osal_assert(0); + return ret; + } + WMT_DBG_FUNC("WMT config file:%s\n", &(gDevWmt.cWmtcfgName[0])); + if (0 == wmt_dev_patch_get(&gDevWmt.cWmtcfgName[0], (osal_firmware **) &gDevWmt.pWmtCfg, 0)) { + /*get full name patch success */ + WMT_DBG_FUNC("get full file name(%s) buf(0x%p) size(%d)\n", + &gDevWmt.cWmtcfgName[0], gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size); + + if (0 == wmt_conf_parse(&gDevWmt, (const PINT8)gDevWmt.pWmtCfg->data, gDevWmt.pWmtCfg->size)) { + /*config file exists */ + gDevWmt.rWmtGenConf.cfgExist = 1; + + WMT_DBG_FUNC("&gDevWmt.rWmtGenConf=%p\n", &gDevWmt.rWmtGenConf); + ret = 0; + } else { + WMT_ERR_FUNC("wmt conf parsing fail\n"); + osal_assert(0); + ret = -1; + } + wmt_dev_patch_put((osal_firmware **) &gDevWmt.pWmtCfg); +/* + if (gDevWmt.pWmtCfg) + { + if (gDevWmt.pWmtCfg->data) + { + osal_free(gDevWmt.pWmtCfg->data); + } + osal_free(gDevWmt.pWmtCfg); + gDevWmt.pWmtCfg = 0; + } +*/ + return ret; + } + WMT_ERR_FUNC("read %s file fails\n", &(gDevWmt.cWmtcfgName[0])); + osal_assert(0); + + gDevWmt.rWmtGenConf.cfgExist = 0; + return ret; +} + +P_WMT_GEN_CONF wmt_conf_get_cfg(VOID) +{ + if (0 == gDevWmt.rWmtGenConf.cfgExist) + return NULL; + + return &gDevWmt.rWmtGenConf; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c new file mode 100644 index 0000000000000..cca6729d53a07 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_core.c @@ -0,0 +1,2521 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CORE]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" + +#include "wmt_lib.h" +#include "wmt_core.h" +#include "wmt_ctrl.h" +#include "wmt_ic.h" +#include "wmt_conf.h" + +#include "wmt_func.h" +#include "stp_core.h" +#include "psm_core.h" + + +P_WMT_FUNC_OPS gpWmtFuncOps[4] = { +#if CFG_FUNC_BT_SUPPORT + [0] = &wmt_func_bt_ops, +#else + [0] = NULL, +#endif + +#if CFG_FUNC_FM_SUPPORT + [1] = &wmt_func_fm_ops, +#else + [1] = NULL, +#endif + +#if CFG_FUNC_GPS_SUPPORT + [2] = &wmt_func_gps_ops, +#else + [2] = NULL, +#endif + +#if CFG_FUNC_WIFI_SUPPORT + [3] = &wmt_func_wifi_ops, +#else + [3] = NULL, +#endif + +}; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* TODO:[FixMe][GeorgeKuo]: is it an MT6620 only or general general setting? +*move to wmt_ic_6620 temporarily. +*/ +/* BT Port 2 Feature. */ +/* #define CFG_WMT_BT_PORT2 (1) */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +static WMT_CTX gMtkWmtCtx; +static UINT8 gLpbkBuf[1024+5] = { 0 }; +#ifdef CONFIG_MTK_COMBO_ANT +static UINT8 gAntBuf[1024] = { 0 }; +#define CFG_CHECK_WMT_RESULT (1) +#endif +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp); +static INT32 opfunc_func_on(P_WMT_OP pWmtOp); +static INT32 opfunc_func_off(P_WMT_OP pWmtOp); +static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp); +static INT32 opfunc_exit(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp); +static INT32 opfunc_dsns(P_WMT_OP pWmtOp); +static INT32 opfunc_lpbk(P_WMT_OP pWmtOp); +static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp); +static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp); +static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_pin_state(P_WMT_OP pWmtOp); +static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp); +static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp); +static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp); +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp); +#endif +#ifdef CONFIG_MTK_COMBO_ANT +static INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp); +static INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp); +#endif +static VOID wmt_core_dump_func_state(PINT8 pSource); +static INT32 wmt_core_stp_init(VOID); +static INT32 wmt_core_stp_deinit(VOID); +static INT32 wmt_core_hw_check(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static const UINT8 WMT_SLEEP_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x01 }; +static const UINT8 WMT_SLEEP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; + +static const UINT8 WMT_HOST_AWAKE_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x02 }; +static const UINT8 WMT_HOST_AWAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; + +static const UINT8 WMT_WAKEUP_CMD[] = { 0xFF }; +static const UINT8 WMT_WAKEUP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; + +static UINT8 WMT_THERM_CMD[] = { 0x01, 0x11, 0x01, 0x00, + 0x00 /*thermal sensor operation */ +}; +static UINT8 WMT_THERM_CTRL_EVT[] = { 0x02, 0x11, 0x01, 0x00, 0x00 }; +static UINT8 WMT_THERM_READ_EVT[] = { 0x02, 0x11, 0x02, 0x00, 0x00, 0x00 }; + +static UINT8 WMT_EFUSE_CMD[] = { 0x01, 0x0D, 0x08, 0x00, + 0x01, /*[4]operation, 0:init, 1:write 2:read */ + 0x01, /*[5]Number of register setting */ + 0xAA, 0xAA, /*[6-7]Address */ + 0xBB, 0xBB, 0xBB, 0xBB /*[8-11] Value */ +}; + +static UINT8 WMT_EFUSE_EVT[] = { 0x02, 0x0D, 0x08, 0x00, + 0xAA, /*[4]operation, 0:init, 1:write 2:read */ + 0xBB, /*[5]Number of register setting */ + 0xCC, 0xCC, /*[6-7]Address */ + 0xDD, 0xDD, 0xDD, 0xDD /*[8-11] Value */ +}; + +static UINT8 WMT_DSNS_CMD[] = { 0x01, 0x0E, 0x02, 0x00, 0x01, + 0x00 /*desnse type */ +}; +static UINT8 WMT_DSNS_EVT[] = { 0x02, 0x0E, 0x01, 0x00, 0x00 }; + +/* TODO:[NewFeature][GeorgeKuo] Update register group in ONE CMD/EVT */ +static UINT8 WMT_SET_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x00 /*op: w(1) & r(2) */ + , 0x01 /*type: reg */ + , 0x00 /*res */ + , 0x01 /*1 register */ + , 0x00, 0x00, 0x00, 0x00 /* addr */ + , 0x00, 0x00, 0x00, 0x00 /* value */ + , 0xFF, 0xFF, 0xFF, 0xFF /*mask */ +}; + +static UINT8 WMT_SET_REG_WR_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 register */ + /* , 0x00, 0x00, 0x00, 0x00 */ /* addr */ + /* , 0x00, 0x00, 0x00, 0x00 */ /* value */ +}; + +static UINT8 WMT_SET_REG_RD_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 register */ + , 0x00, 0x00, 0x00, 0x00 /* addr */ + , 0x00, 0x00, 0x00, 0x00 /* value */ +}; + +#ifdef CONFIG_MTK_COMBO_ANT +static UINT8 WMT_ANT_RAM_STA_GET_CMD[] = { 0x01, 0x06, 0x02, 0x00, 0x05, 0x02 +}; + +static UINT8 WMT_ANT_RAM_STA_GET_EVT[] = { 0x02, 0x06, 0x03, 0x00 /*length */ + , 0x05, 0x02, 0x00 /*S: result */ +}; + +static UINT8 WMT_ANT_RAM_DWN_CMD[] = { 0x01, 0x15, 0x00, 0x00, 0x01 +}; + +static UINT8 WMT_ANT_RAM_DWN_EVT[] = { 0x02, 0x15, 0x01, 0x00 /*length */ + , 0x00 +}; +#endif + +/* GeorgeKuo: Use designated initializers described in + * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html + */ + +static const WMT_OPID_FUNC wmt_core_opfunc[] = { + [WMT_OPID_HIF_CONF] = opfunc_hif_conf, + [WMT_OPID_PWR_ON] = opfunc_pwr_on, + [WMT_OPID_PWR_OFF] = opfunc_pwr_off, + [WMT_OPID_FUNC_ON] = opfunc_func_on, + [WMT_OPID_FUNC_OFF] = opfunc_func_off, + [WMT_OPID_REG_RW] = opfunc_reg_rw, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ + [WMT_OPID_EXIT] = opfunc_exit, + [WMT_OPID_PWR_SV] = opfunc_pwr_sv, + [WMT_OPID_DSNS] = opfunc_dsns, + [WMT_OPID_LPBK] = opfunc_lpbk, + [WMT_OPID_CMD_TEST] = opfunc_cmd_test, + [WMT_OPID_HW_RST] = opfunc_hw_rst, + [WMT_OPID_SW_RST] = opfunc_sw_rst, + [WMT_OPID_STP_RST] = opfunc_stp_rst, + [WMT_OPID_THERM_CTRL] = opfunc_therm_ctrl, + [WMT_OPID_EFUSE_RW] = opfunc_efuse_rw, + [WMT_OPID_GPIO_CTRL] = opfunc_gpio_ctrl, + [WMT_OPID_GPIO_STATE] = opfunc_pin_state, + [WMT_OPID_BGW_DS] = opfunc_bgw_ds, + [WMT_OPID_SET_MCU_CLK] = opfunc_set_mcu_clk, + [WMT_OPID_ADIE_LPBK_TEST] = opfunc_adie_lpbk_test, +#if CFG_WMT_LTE_COEX_HANDLING + [WMT_OPID_IDC_MSG_HANDLING] = opfunc_idc_msg_handling, +#endif +#ifdef CONFIG_MTK_COMBO_ANT + [WMT_OPID_ANT_RAM_DOWN] = opfunc_ant_ram_down, + [WMT_OPID_ANT_RAM_STA_GET] = opfunc_ant_ram_stat_get, +#endif +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_core_init(VOID) +{ + INT32 i = 0; + + osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); + /* gMtkWmtCtx.p_ops is cleared to NULL */ + + /* default FUNC_OFF state */ + for (i = 0; i < WMTDRV_TYPE_MAX; ++i) { + /* WinMo is default to DRV_STS_UNREG; */ + gMtkWmtCtx.eDrvStatus[i] = DRV_STS_POWER_OFF; + } + + return 0; +} + +INT32 wmt_core_deinit(VOID) +{ + /* return to init state */ + osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); + /* gMtkWmtCtx.p_ops is cleared to NULL */ + return 0; +} + +/* TODO: [ChangeFeature][George] Is wmt_ctrl a good interface? maybe not...... */ +/* parameters shall be copied in/from ctrl buffer, which is also a size-wasting buffer. */ +INT32 wmt_core_tx(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) +{ + INT32 iRet; +#if 0 /* Test using direct function call instead of wmt_ctrl() interface */ + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_TX; + ctrlData.au4CtrlData[0] = (UINT32) pData; + ctrlData.au4CtrlData[1] = size; + ctrlData.au4CtrlData[2] = (UINT32) writtenSize; + ctrlData.au4CtrlData[3] = bRawFlag; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_TX, iRet:%d\n", iRet); + /* (*sys_dbg_assert)(0, __FILE__, __LINE__); */ + osal_assert(0); + } +#endif + iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); + if (0 == *writtenSize) { + INT32 retry_times = 0; + INT32 max_retry_times = 3; + INT32 retry_delay_ms = 360; + + WMT_WARN_FUNC("WMT-CORE: wmt_ctrl_tx_ex failed and written ret:%d, maybe no winspace in STP layer\n", + *writtenSize); + while ((0 == *writtenSize) && (retry_times < max_retry_times)) { + WMT_ERR_FUNC("WMT-CORE: retrying, wait for %d ms\n", retry_delay_ms); + osal_sleep_ms(retry_delay_ms); + + iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); + retry_times++; + } + } + return iRet; +} + +INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, UINT32 *readSize) +{ + INT32 iRet; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_RX; + ctrlData.au4CtrlData[0] = (SIZE_T) pBuf; + ctrlData.au4CtrlData[1] = bufLen; + ctrlData.au4CtrlData[2] = (SIZE_T) readSize; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX, iRet:%d\n", iRet); + mtk_wcn_stp_dbg_dump_package(); + osal_assert(0); + } + return iRet; +} + +INT32 wmt_core_rx_flush(UINT32 type) +{ + INT32 iRet; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_RX_FLUSH; + ctrlData.au4CtrlData[0] = (UINT32) type; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX_FLUSH, iRet:%d\n", iRet); + osal_assert(0); + } + return iRet; +} + +INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn) +{ + INT32 iRet = 0; + UINT32 u4WmtCmdPduLen; + UINT32 u4WmtEventPduLen; + UINT32 u4ReadSize; + UINT32 u4WrittenSize; + WMT_PKT rWmtPktCmd; + WMT_PKT rWmtPktEvent; + MTK_WCN_BOOL fgFail; + + /* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ + /* Using this struct relies on compiler's implementation and pack() settings */ + osal_memset(&rWmtPktCmd, 0, osal_sizeof(rWmtPktCmd)); + osal_memset(&rWmtPktEvent, 0, osal_sizeof(rWmtPktEvent)); + + rWmtPktCmd.eType = (UINT8) PKT_TYPE_CMD; + rWmtPktCmd.eOpCode = (UINT8) OPCODE_FUNC_CTRL; + + /* Flag field: driver type */ + rWmtPktCmd.aucParam[0] = (UINT8) type; + /* Parameter field: ON/OFF */ + rWmtPktCmd.aucParam[1] = (fgEn == WMT_FUNC_CTRL_ON) ? 1 : 0; + rWmtPktCmd.u2SduLen = WMT_FLAG_LEN + WMT_FUNC_CTRL_PARAM_LEN; /* (2) */ + + /* WMT Header + WMT SDU */ + u4WmtCmdPduLen = WMT_HDR_LEN + rWmtPktCmd.u2SduLen; /* (6) */ + u4WmtEventPduLen = WMT_HDR_LEN + WMT_STS_LEN; /* (5) */ + + do { + fgFail = MTK_WCN_BOOL_TRUE; +/* iRet = (*kal_stp_tx)((PUINT8)&rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize); */ + iRet = wmt_core_tx((PUINT8) &rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize, MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_tx failed\n"); + break; + } + + iRet = wmt_core_rx((PUINT8) &rWmtPktEvent, u4WmtEventPduLen, &u4ReadSize); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_rx failed\n"); + break; + } + + /* Error Checking */ + if (PKT_TYPE_EVENT != rWmtPktEvent.eType) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd PKT_TYPE_EVENT != rWmtPktEvent.eType %d\n", + rWmtPktEvent.eType); + break; + } + + if (rWmtPktCmd.eOpCode != rWmtPktEvent.eOpCode) { + WMT_ERR_FUNC + ("WMT-CORE: wmt_func_ctrl_cmd rWmtPktCmd.eOpCode(0x%x) != rWmtPktEvent.eType(0x%x)\n", + rWmtPktCmd.eOpCode, rWmtPktEvent.eOpCode); + break; + } + + if (u4WmtEventPduLen != (rWmtPktEvent.u2SduLen + WMT_HDR_LEN)) { + WMT_ERR_FUNC + ("WMT-CORE: wmt_func_ctrl_cmd u4WmtEventPduLen(0x%x) != rWmtPktEvent.u2SduLen(0x%x)+4\n", + u4WmtEventPduLen, rWmtPktEvent.u2SduLen); + break; + } + /* Status field of event check */ + if (0 != rWmtPktEvent.aucParam[0]) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd, 0 != status(%d)\n", rWmtPktEvent.aucParam[0]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + } while (0); + + if (MTK_WCN_BOOL_FALSE == fgFail) { + /* WMT_INFO_FUNC("WMT-CORE: wmt_func_ctrl_cmd OK!\n"); */ + return 0; + } + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd 0x%x FAIL\n", rWmtPktCmd.aucParam[0]); + return -3; +} + +INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp) +{ + UINT32 opId; + INT32 ret; + + opId = pWmtOp->opId; + + if (wmt_core_opfunc[opId]) { + ret = (*(wmt_core_opfunc[opId])) (pWmtOp); /*wmtCoreOpidHandlerPack[].opHandler */ + return ret; + } + WMT_ERR_FUNC("WMT-CORE: null handler (%d)\n", pWmtOp->opId); + return -2; + +} + +INT32 wmt_core_opid(P_WMT_OP pWmtOp) +{ + + /*sanity check */ + if (NULL == pWmtOp) { + WMT_ERR_FUNC("null pWmtOP\n"); + /*print some message with error info */ + return -1; + } + + if (WMT_OPID_MAX <= pWmtOp->opId) { + WMT_ERR_FUNC("WMT-CORE: invalid OPID(%d)\n", pWmtOp->opId); + return -2; + } + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + return wmt_core_opid_handler(pWmtOp); +} + +INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, unsigned long *pPa1, unsigned long *pPa2) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + SIZE_T val1 = (pPa1) ? *pPa1 : 0; + SIZE_T val2 = (pPa2) ? *pPa2 : 0; + + ctrlData.ctrlId = (SIZE_T) ctrId; + ctrlData.au4CtrlData[0] = val1; + ctrlData.au4CtrlData[1] = val2; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: id(%d), type(%d), value(%d) iRet:(%d)\n", ctrId, val1, + val2, iRet); + osal_assert(0); + } else { + if (pPa1) + *pPa1 = ctrlData.au4CtrlData[0]; + if (pPa2) + *pPa2 = ctrlData.au4CtrlData[1]; + } + return iRet; +} + +VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len) +{ + PUINT8 ptr = pData; + INT32 k = 0; + + WMT_INFO_FUNC("%s len=%d\n", pTitle, len); + for (k = 0; k < len; k++) { + if (k % 16 == 0) + WMT_INFO_FUNC("\n"); + WMT_INFO_FUNC("0x%02x ", *ptr); + ptr++; + } + WMT_INFO_FUNC("--end\n"); +} + +/*! + * \brief An WMT-CORE function to support read, write, and read after write to + * an internal register. + * + * Detailed description. + * + * \param isWrite 1 for write, 0 for read + * \param offset of register to be written or read + * \param pVal a pointer to the 32-bit value to be writtern or read + * \param mask a 32-bit mask to be applied for the read or write operation + * + * \retval 0 operation success + * \retval -1 invalid parameters + * \retval -2 tx cmd fail + * \retval -3 rx event fail + * \retval -4 read check error + */ +INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask) +{ + INT32 iRet; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_SET_REG_CMD[4] = (isWrite) ? 0x1 : 0x2; /* w:1, r:2 */ + osal_memcpy(&WMT_SET_REG_CMD[8], &offset, 4); /* offset */ + osal_memcpy(&WMT_SET_REG_CMD[12], pVal, 4); /* [2] is var addr */ + osal_memcpy(&WMT_SET_REG_CMD[16], &mask, 4); /* mask */ + + /* send command */ + iRet = wmt_core_tx(WMT_SET_REG_CMD, sizeof(WMT_SET_REG_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if ((iRet) || (u4Res != sizeof(WMT_SET_REG_CMD))) { + WMT_ERR_FUNC("Tx REG_CMD fail!(%d) len (%d, %d)\n", iRet, u4Res, sizeof(WMT_SET_REG_CMD)); + return -2; + } + + /* receive event */ + evtLen = (isWrite) ? sizeof(WMT_SET_REG_WR_EVT) : sizeof(WMT_SET_REG_RD_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if ((iRet) || (u4Res != evtLen)) { + WMT_ERR_FUNC("Rx REG_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + return -3; + } + + if (!isWrite) { + UINT32 rxEvtAddr; + UINT32 txCmdAddr; + + osal_memcpy(&txCmdAddr, &WMT_SET_REG_CMD[8], 4); + osal_memcpy(&rxEvtAddr, &evtBuf[8], 4); + + /* check read result */ + if (txCmdAddr != rxEvtAddr) { + WMT_ERR_FUNC("Check read addr fail (0x%08x, 0x%08x)\n", rxEvtAddr, txCmdAddr); + return -4; + } + WMT_DBG_FUNC("Check read addr(0x%08x) ok\n", rxEvtAddr); + + osal_memcpy(pVal, &evtBuf[12], 4); + } + + /* no error here just return 0 */ + return 0; +} + +INT32 wmt_core_init_script(struct init_script *script, INT32 count) +{ + UINT8 evtBuf[256]; + UINT32 u4Res; + INT32 i = 0; + INT32 iRet; + + for (i = 0; i < count; i++) { + WMT_DBG_FUNC("WMT-CORE: init_script operation %s start\n", script[i].str); + /* CMD */ + /* iRet = (*kal_stp_tx)(script[i].cmd, script[i].cmdSz, &u4Res); */ + iRet = wmt_core_tx(script[i].cmd, script[i].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != script[i].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", script[i].str, iRet, u4Res, + script[i].cmdSz); + break; + } + /* EVENT BUF */ + osal_memset(evtBuf, 0, sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, script[i].evtSz, &u4Res); + if (iRet || (u4Res != script[i].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", script[i].str, iRet, + u4Res, script[i].evtSz); + mtk_wcn_stp_dbg_dump_package(); + break; + } + /* RESULT */ + if (0x14 != evtBuf[1]) { /* workaround RF calibration data EVT,do not care this EVT */ + if (osal_memcmp(evtBuf, script[i].evt, script[i].evtSz) != 0) { + WMT_ERR_FUNC("WMT-CORE:compare %s result error\n", script[i].str); + WMT_ERR_FUNC + ("WMT-CORE:rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], script[i].evtSz, + script[i].evt[0], script[i].evt[1], script[i].evt[2], script[i].evt[3], + script[i].evt[4]); + mtk_wcn_stp_dbg_dump_package(); + break; + } + } + WMT_DBG_FUNC("init_script operation %s ok\n", script[i].str); + } + + return (i == count) ? 0 : -1; +} + +static INT32 wmt_core_stp_init(VOID) +{ + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT8 co_clock_type; + P_WMT_CTX pctx = &gMtkWmtCtx; + P_WMT_GEN_CONF pWmtGenConf = NULL; + + wmt_conf_read_file(); + pWmtGenConf = wmt_conf_get_cfg(); + if (!(pctx->wmtInfoBit & WMT_OP_HIF_BIT)) { + WMT_ERR_FUNC("WMT-CORE: no hif info!\n"); + osal_assert(0); + return -1; + } + /* 4 <1> open stp */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -2; + } + /* 4 <1.5> disable and un-ready stp */ + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + /* 4 <2> set mode and enable */ + if (WMT_HIF_BTIF == pctx->wmtHifConf.hifType) { + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_MAND_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + } + + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); + return -3; + } + /* TODO: [ChangeFeature][GeorgeKuo] can we apply raise UART baud rate firstly for ALL supported chips??? */ + + iRet = wmt_core_hw_check(); + if (iRet) { + WMT_ERR_FUNC("hw_check fail:%d\n", iRet); + return -4; + } + /* mtkWmtCtx.p_ic_ops is identified and checked ok */ + if ((NULL != pctx->p_ic_ops->co_clock_ctrl) && (pWmtGenConf != NULL)) { + co_clock_type = (pWmtGenConf->co_clock_flag & 0x0f); + (*(pctx->p_ic_ops->co_clock_ctrl)) (co_clock_type == 0 ? WMT_CO_CLOCK_DIS : WMT_CO_CLOCK_EN); + } else { + WMT_WARN_FUNC("pctx->p_ic_ops->co_clock_ctrl(0x%x), pWmtGenConf(0x%x)\n", pctx->p_ic_ops->co_clock_ctrl, + pWmtGenConf); + } + osal_assert(NULL != pctx->p_ic_ops->sw_init); + if (NULL != pctx->p_ic_ops->sw_init) { + iRet = (*(pctx->p_ic_ops->sw_init)) (&pctx->wmtHifConf); + } else { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); + return -5; + } + if (iRet) { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init fail:%d\n", iRet); + return -6; + } + /* 4 <10> set stp ready */ + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 1; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + return iRet; +} + +static INT32 wmt_core_stp_deinit(VOID) +{ + INT32 iRet; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + WMT_DBG_FUNC(" start\n"); + + if (NULL == gMtkWmtCtx.p_ic_ops) { + WMT_WARN_FUNC("gMtkWmtCtx.p_ic_ops is NULL\n"); + goto deinit_ic_ops_done; + } + if (NULL != gMtkWmtCtx.p_ic_ops->sw_deinit) { + iRet = (*(gMtkWmtCtx.p_ic_ops->sw_deinit)) (&gMtkWmtCtx.wmtHifConf); + /* unbind WMT-IC */ + gMtkWmtCtx.p_ic_ops = NULL; + } else { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); + } + +deinit_ic_ops_done: + + /* 4 <1> un-ready, disable, and close stp. */ + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + + if (iRet) + WMT_WARN_FUNC("end with fail:%d\n", iRet); + + return iRet; +} + +static VOID wmt_core_dump_func_state(PINT8 pSource) +{ + WMT_WARN_FUNC("[%s]status(b:%d f:%d g:%d w:%d lpbk:%d coredump:%d wmt:%d stp:%d)\n", + (pSource == NULL ? (PINT8) "CORE" : pSource), + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] + ); + return; + +} + +MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer) +{ + if (MAJORNUM(u4HwVer) != MAJORNUM(u4PatchVer)) { + /*major no. does not match */ + WMT_ERR_FUNC("WMT-CORE: chip version(0x%d) does not match patch version(0x%d)\n", u4HwVer, u4PatchVer); + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} + +static INT32 wmt_core_hw_check(VOID) +{ + UINT32 chipid; + P_WMT_IC_OPS p_ops; + INT32 iret; + + /* 1. get chip id */ + chipid = 0; + WMT_LOUD_FUNC("before read hwcode (chip id)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HCR, &chipid, GEN_HCR_MASK); /* read 0x80000008 */ + if (iret) { + WMT_ERR_FUNC("get hwcode (chip id) fail (%d)\n", iret); + return -2; + } + WMT_DBG_FUNC("get hwcode (chip id) (0x%x)\n", chipid); + + /* TODO:[ChangeFeature][George]: use a better way to select a correct ops table based on chip id */ + switch (chipid) { +#if CFG_CORE_MT6620_SUPPORT + case 0x6620: + p_ops = &wmt_ic_ops_mt6620; + break; +#endif +#if CFG_CORE_MT6628_SUPPORT + case 0x6628: + p_ops = &wmt_ic_ops_mt6628; + break; +#endif +#if CFG_CORE_SOC_SUPPORT + case 0x6572: + case 0x6582: + case 0x6592: + case 0x8127: + case 0x6571: + case 0x6752: + case 0x0279: + case 0x0326: + case 0x0321: + case 0x0335: + case 0x0337: + case 0x8163: + case 0x6580: + p_ops = &wmt_ic_ops_soc; + break; +#endif + default: + p_ops = (P_WMT_IC_OPS) NULL; +#if CFG_CORE_SOC_SUPPORT + if (0x7f90 == chipid - 0x600) { + p_ops = &wmt_ic_ops_soc; + chipid -= 0xf6d; + } +#endif + break; + } + + if (NULL == p_ops) { + WMT_ERR_FUNC("unsupported chip id (hw_code): 0x%x\n", chipid); + return -3; + } else if (MTK_WCN_BOOL_FALSE == wmt_core_ic_ops_check(p_ops)) { + WMT_ERR_FUNC + ("chip id(0x%x) with null operation fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", + chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); + return -4; + } + WMT_DBG_FUNC("chip id(0x%x) fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", + chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, p_ops->ic_ver_check); + + wmt_ic_ops_soc.icId = chipid; + WMT_DBG_FUNC("wmt_ic_ops_soc.icId(0x%x)\n", wmt_ic_ops_soc.icId); + iret = p_ops->ic_ver_check(); + if (iret) { + WMT_ERR_FUNC("chip id(0x%x) ver_check error:%d\n", chipid, iret); + return -5; + } + + WMT_DBG_FUNC("chip id(0x%x) ver_check ok\n", chipid); + gMtkWmtCtx.p_ic_ops = p_ops; + return 0; +} + +static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp) +{ + if (!(pWmtOp->u4InfoBit & WMT_OP_HIF_BIT)) { + WMT_ERR_FUNC("WMT-CORE: no HIF_BIT in WMT_OP!\n"); + return -1; + } + + if (gMtkWmtCtx.wmtInfoBit & WMT_OP_HIF_BIT) { + WMT_ERR_FUNC("WMT-CORE: WMT HIF already exist. overwrite! old (%d), new(%d))\n", + gMtkWmtCtx.wmtHifConf.hifType, pWmtOp->au4OpData[0]); + } else { + gMtkWmtCtx.wmtInfoBit |= WMT_OP_HIF_BIT; + WMT_ERR_FUNC("WMT-CORE: WMT HIF info added\n"); + } + + osal_memcpy(&gMtkWmtCtx.wmtHifConf, &pWmtOp->au4OpData[0], osal_sizeof(gMtkWmtCtx.wmtHifConf)); + return 0; + +} + +static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + INT32 retry = WMT_PWRON_RTY_DFT; + + if (DRV_STS_POWER_OFF != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_ERR_FUNC("WMT-CORE: already powered on, WMT DRV_STS_[0x%x]\n", + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); + osal_assert(0); + return -1; + } + /* TODO: [FixMe][GeorgeKuo]: clarify the following is reqiured or not! */ + if (pWmtOp->u4InfoBit & WMT_OP_HIF_BIT) + opfunc_hif_conf(pWmtOp); + +pwr_on_rty: + /* power on control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); + if (0 == retry--) { + WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); + goto pwr_on_rty; + } + return -1; + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + + /* init stp */ + iRet = wmt_core_stp_init(); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_init fail (%d)\n", iRet); + osal_assert(0); + + /* deinit stp */ + iRet = wmt_core_stp_deinit(); + iRet = opfunc_pwr_off(pWmtOp); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: opfunc_pwr_off fail during pwr_on retry\n"); + + if (0 < retry--) { + WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); + goto pwr_on_rty; + } + iRet = -2; + return iRet; + } + + WMT_DBG_FUNC("WMT-CORE: WMT [FUNC_ON]\n"); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; + + /* What to do when state is changed from POWER_OFF to POWER_ON? + * 1. STP driver does s/w reset + * 2. UART does 0xFF wake up + * 3. SDIO does re-init command(changed to trigger by host) + */ + return iRet; + +} + +static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_WARN_FUNC("WMT-CORE: WMT already off, WMT DRV_STS_[0x%x]\n", + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); + osal_assert(0); + return -1; + } + if (MTK_WCN_BOOL_FALSE == g_pwr_off_flag) { + WMT_WARN_FUNC("CONNSYS power off be disabled, maybe need trigger core dump!\n"); + osal_assert(0); + return -2; + } + + /* wmt and stp are initialized successfully */ + if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + iRet = wmt_core_stp_deinit(); + if (iRet) { + WMT_WARN_FUNC("wmt_core_stp_deinit fail (%d)\n", iRet); + /*should let run to power down chip */ + } + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + + /* power off control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_OFF, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_WARN_FUNC("HW_PWR_OFF fail (%d)\n", iRet); + WMT_WARN_FUNC("HW_PWR_OFF ok\n"); + + /*anyway, set to POWER_OFF state */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; + return iRet; + +} + +static INT32 opfunc_func_on(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + INT32 iPwrOffRet = -1; + UINT32 drvType; + + drvType = pWmtOp->au4OpData[0]; + + /* Check abnormal type */ + if (WMTDRV_TYPE_COREDUMP < drvType) { + WMT_ERR_FUNC("abnormal Fun(%d)\n", drvType); + osal_assert(0); + return -1; + } + + /* Check abnormal state */ + if ((DRV_STS_POWER_OFF > gMtkWmtCtx.eDrvStatus[drvType]) + || (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType])) { + WMT_ERR_FUNC("func(%d) status[0x%x] abnormal\n", drvType, gMtkWmtCtx.eDrvStatus[drvType]); + osal_assert(0); + return -2; + } + + /* check if func already on */ + if (DRV_STS_FUNC_ON == gMtkWmtCtx.eDrvStatus[drvType]) { + WMT_WARN_FUNC("func(%d) already on\n", drvType); + return 0; + } + /*enable power off flag, if flag=0, power off connsys will not be executed */ + mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); + /* check if chip power on is needed */ + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + iRet = opfunc_pwr_on(pWmtOp); + + if (iRet) { + WMT_ERR_FUNC("func(%d) pwr_on fail(%d)\n", drvType, iRet); + osal_assert(0); + + /* check all sub-func and do power off */ + return -3; + } + } + + if (WMTDRV_TYPE_WMT > drvType) { + if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_on) { + iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (0 != iRet) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + else + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + } else { + WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); + iRet = -5; + } + } else { + if (WMTDRV_TYPE_LPBK == drvType) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + else if (WMTDRV_TYPE_COREDUMP == drvType) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + iRet = 0; + } + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet); + osal_assert(0); + /* FIX-ME:[Chaozhong Liang], Error handling? check subsystem state and do pwr off if necessary? */ + /* check all sub-func and do power off */ + if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { + WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); + mtk_wcn_wmt_system_state_reset(); + + iPwrOffRet = opfunc_pwr_off(pWmtOp); + if (iPwrOffRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iPwrOffRet, + drvType); + osal_assert(0); + } + } + return iRet; + } + + wmt_core_dump_func_state("AF FUNC ON"); + + return 0; +} + +static INT32 opfunc_func_off(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 drvType; + + drvType = pWmtOp->au4OpData[0]; + /* Check abnormal type */ + if (WMTDRV_TYPE_COREDUMP < drvType) { + WMT_ERR_FUNC("WMT-CORE: abnormal Fun(%d) in wmt_func_off\n", drvType); + osal_assert(0); + return -1; + } + + /* Check abnormal state */ + if (DRV_STS_MAX <= gMtkWmtCtx.eDrvStatus[drvType]) { + WMT_ERR_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] abnormal in wmt_func_off\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + osal_assert(0); + return -2; + } + + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[drvType]) { + WMT_WARN_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + /* needs to check 4 subsystem's state? */ + return 0; + } else if (WMTDRV_TYPE_WMT > drvType) { + if (NULL != gpWmtFuncOps[drvType] && NULL != gpWmtFuncOps[drvType]->func_off) { + iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + } else { + WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); + iRet = -3; + } + } else { + if (WMTDRV_TYPE_LPBK == drvType) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + else if (WMTDRV_TYPE_COREDUMP == drvType) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + iRet = 0; + } + + /* shall we put device state to POWER_OFF state when fail? */ + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet); + osal_assert(0); + /* no matter subsystem function control fail or not, + *chip should be powered off when no subsystem is active + */ + /* return iRet; */ + } + + /* check all sub-func and do power off */ + if ((DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK]) && + (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP])) { + WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); + + iRet = opfunc_pwr_off(pWmtOp); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", iRet, drvType); + osal_assert(0); + } + } + + wmt_core_dump_func_state("AF FUNC OFF"); + return iRet; +} + +/* TODO:[ChangeFeature][George] is this OP obsoleted? */ +static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp) +{ + INT32 iret; + + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_ERR_FUNC("reg_rw when WMT is powered off\n"); + return -1; + } + iret = wmt_core_reg_rw_raw(pWmtOp->au4OpData[0], + pWmtOp->au4OpData[1], (PUINT32) pWmtOp->au4OpData[2], pWmtOp->au4OpData[3]); + + return iret; +} + +static INT32 opfunc_exit(P_WMT_OP pWmtOp) +{ + /* TODO: [FixMe][George] is ok to leave this function empty??? */ + WMT_WARN_FUNC("EMPTY FUNCTION\n"); + return 0; +} + +static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp) +{ + INT32 ret = -1; + UINT32 u4_result = 0; + UINT32 evt_len; + UINT8 evt_buf[16] = { 0 }; + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + + typedef INT32(*STP_PSM_CB) (INT32); + STP_PSM_CB psm_cb = NULL; + + if (SLEEP == pWmtOp->au4OpData[0]) { + WMT_DBG_FUNC("**** Send sleep command\n"); + /* mtk_wcn_stp_set_psm_state(ACT_INACT); */ + /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ + ret = wmt_core_tx((PUINT8) &WMT_SLEEP_CMD[0], sizeof(WMT_SLEEP_CMD), &u4_result, 0); + if (ret || (u4_result != sizeof(WMT_SLEEP_CMD))) { + WMT_ERR_FUNC("wmt_core: SLEEP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, + sizeof(WMT_SLEEP_CMD)); + goto pwr_sv_done; + } + + evt_len = sizeof(WMT_SLEEP_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + unsigned long type = WMTDRV_TYPE_WMT; + unsigned long reason = 33; + unsigned long ctrlpa = 1; + + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: read SLEEP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); + mtk_wcn_stp_dbg_dump_package(); + ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); + if (!ret) { /* parser ok */ + reason = 38; /* host schedule issue reason code */ + WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); + } + wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); + goto pwr_sv_done; + } + + if (osal_memcmp(evt_buf, WMT_SLEEP_EVT, sizeof(WMT_SLEEP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_SLEEP_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + u4_result, + evt_buf[0], + evt_buf[1], + evt_buf[2], + evt_buf[3], + evt_buf[4], + evt_buf[5]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_SLEEP_EVT), + WMT_SLEEP_EVT[0], + WMT_SLEEP_EVT[1], + WMT_SLEEP_EVT[2], + WMT_SLEEP_EVT[3], + WMT_SLEEP_EVT[4], + WMT_SLEEP_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + goto pwr_sv_done; + } else { + WMT_DBG_FUNC("Send sleep command OK!\n"); + } + } else if (pWmtOp->au4OpData[0] == WAKEUP) { + WMT_DBG_FUNC("wakeup connsys by btif"); + + ret = wmt_core_ctrl(WMT_CTRL_SOC_WAKEUP_CONSYS, &ctrlPa1, &ctrlPa2); + if (ret) { + WMT_ERR_FUNC("wmt-core:WAKEUP_CONSYS by BTIF fail(%d)", ret); + goto pwr_sv_done; + } +#if 0 + WMT_DBG_FUNC("**** Send wakeup command\n"); + ret = wmt_core_tx(WMT_WAKEUP_CMD, sizeof(WMT_WAKEUP_CMD), &u4_result, 1); + + if (ret || (u4_result != sizeof(WMT_WAKEUP_CMD))) { + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: WAKEUP_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, + sizeof(WMT_WAKEUP_CMD)); + goto pwr_sv_done; + } +#endif + evt_len = sizeof(WMT_WAKEUP_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + unsigned long type = WMTDRV_TYPE_WMT; + unsigned long reason = 34; + unsigned long ctrlpa = 2; + + WMT_ERR_FUNC("wmt_core: read WAKEUP_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); + mtk_wcn_stp_dbg_dump_package(); + ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); + if (!ret) { /* parser ok */ + reason = 39; /* host schedule issue reason code */ + WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); + } + wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); + goto pwr_sv_done; + } + + if (osal_memcmp(evt_buf, WMT_WAKEUP_EVT, sizeof(WMT_WAKEUP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_WAKEUP_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + u4_result, + evt_buf[0], + evt_buf[1], + evt_buf[2], + evt_buf[3], + evt_buf[4], + evt_buf[5]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_WAKEUP_EVT), + WMT_WAKEUP_EVT[0], + WMT_WAKEUP_EVT[1], + WMT_WAKEUP_EVT[2], + WMT_WAKEUP_EVT[3], + WMT_WAKEUP_EVT[4], + WMT_WAKEUP_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + goto pwr_sv_done; + } else { + WMT_DBG_FUNC("Send wakeup command OK!\n"); + } + } else if (pWmtOp->au4OpData[0] == HOST_AWAKE) { + + WMT_DBG_FUNC("**** Send host awake command\n"); + + psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; + /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ + ret = wmt_core_tx((PUINT8) WMT_HOST_AWAKE_CMD, sizeof(WMT_HOST_AWAKE_CMD), &u4_result, 0); + if (ret || (u4_result != sizeof(WMT_HOST_AWAKE_CMD))) { + WMT_ERR_FUNC("wmt_core: HOST_AWAKE_CMD ret(%d) cmd len err(%d, %d) ", ret, u4_result, + sizeof(WMT_HOST_AWAKE_CMD)); + goto pwr_sv_done; + } + + evt_len = sizeof(WMT_HOST_AWAKE_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + unsigned long type = WMTDRV_TYPE_WMT; + unsigned long reason = 35; + unsigned long ctrlpa = 3; + + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: read HOST_AWAKE_EVT fail(%d) len(%d, %d)", ret, u4_result, evt_len); + mtk_wcn_stp_dbg_dump_package(); + ret = wmt_core_ctrl(WMT_CTRL_EVT_PARSER, &ctrlpa, 0); + if (!ret) { /* parser ok */ + reason = 40; /* host schedule issue reason code */ + WMT_WARN_FUNC("This evt error may be caused by system schedule issue\n"); + } + wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &type, &reason); + goto pwr_sv_done; + } + + if (osal_memcmp(evt_buf, WMT_HOST_AWAKE_EVT, sizeof(WMT_HOST_AWAKE_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_HOST_AWAKE_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + u4_result, + evt_buf[0], + evt_buf[1], + evt_buf[2], + evt_buf[3], + evt_buf[4], + evt_buf[5]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_HOST_AWAKE_EVT), + WMT_HOST_AWAKE_EVT[0], + WMT_HOST_AWAKE_EVT[1], + WMT_HOST_AWAKE_EVT[2], + WMT_HOST_AWAKE_EVT[3], + WMT_HOST_AWAKE_EVT[4], + WMT_HOST_AWAKE_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + /* goto pwr_sv_done; */ + } else { + WMT_DBG_FUNC("Send host awake command OK!\n"); + } + } +pwr_sv_done: + + if (pWmtOp->au4OpData[0] < STP_PSM_MAX_ACTION) { + psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; + WMT_DBG_FUNC("Do STP-CB! %d %p / %p\n", pWmtOp->au4OpData[0], (PVOID) pWmtOp->au4OpData[1], + (PVOID) psm_cb); + if (NULL != psm_cb) { + psm_cb(pWmtOp->au4OpData[0]); + } else { + WMT_ERR_FUNC("fatal error !!!, psm_cb = %p, god, someone must have corrupted our memory.\n", + psm_cb); + } + } + + return ret; +} + +static INT32 opfunc_dsns(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_DSNS_CMD[4] = (UINT8) pWmtOp->au4OpData[0]; + WMT_DSNS_CMD[5] = (UINT8) pWmtOp->au4OpData[1]; + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res); */ + iRet = wmt_core_tx((PUINT8) WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_DSNS_CMD))) { + WMT_ERR_FUNC("WMT-CORE: DSNS_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, + osal_sizeof(WMT_DSNS_CMD)); + return iRet; + } + + evtLen = osal_sizeof(WMT_DSNS_EVT); + + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read DSNS_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + mtk_wcn_stp_dbg_dump_package(); + return iRet; + } + + if (osal_memcmp(evtBuf, WMT_DSNS_EVT, osal_sizeof(WMT_DSNS_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_DSNS_EVT error\n"); + WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + osal_sizeof(WMT_DSNS_EVT), WMT_DSNS_EVT[0], WMT_DSNS_EVT[1], WMT_DSNS_EVT[2], + WMT_DSNS_EVT[3], WMT_DSNS_EVT[4]); + } else { + WMT_INFO_FUNC("Send WMT_DSNS_CMD command OK!\n"); + } + + return iRet; +} + +#if CFG_CORE_INTERNAL_TXRX +INT32 wmt_core_lpbk_do_stp_init(void) +{ + INT32 iRet = 0; + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -1; + } + + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_MAND_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); + return -2; + } +} + +INT32 wmt_core_lpbk_do_stp_deinit(void) +{ + INT32 iRet = 0; + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -1; + } + + return 0; +} +#endif +static INT32 opfunc_lpbk(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT32 buf_length = 0; + UINT32 *pbuffer = NULL; + UINT16 len_in_cmd; + + /* UINT32 offset; */ + UINT8 WMT_TEST_LPBK_CMD[] = { 0x1, 0x2, 0x0, 0x0, 0x7 }; + UINT8 WMT_TEST_LPBK_EVT[] = { 0x2, 0x2, 0x0, 0x0, 0x0 }; + + /* UINT8 lpbk_buf[1024 + 5] = {0}; */ + MTK_WCN_BOOL fgFail; + + buf_length = pWmtOp->au4OpData[0]; /* packet length */ + pbuffer = (VOID *) pWmtOp->au4OpData[1]; /* packet buffer pointer */ + WMT_DBG_FUNC("WMT-CORE: -->wmt_do_lpbk\n"); + +#if 0 + osal_memcpy(&WMT_TEST_LPBK_EVT[0], &WMT_TEST_LPBK_CMD[0], osal_sizeof(WMT_TEST_LPBK_CMD)); +#endif +#if !CFG_CORE_INTERNAL_TXRX + /*check if WMTDRV_TYPE_LPBK function is already on */ + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] + || buf_length + osal_sizeof(WMT_TEST_LPBK_CMD) > osal_sizeof(gLpbkBuf)) { + WMT_ERR_FUNC("WMT-CORE: abnormal LPBK in wmt_do_lpbk\n"); + osal_assert(0); + return -2; + } +#endif + /*package loopback for STP */ + + /* init buffer */ + osal_memset(gLpbkBuf, 0, osal_sizeof(gLpbkBuf)); + + len_in_cmd = buf_length + 1; /* add flag field */ + + osal_memcpy(&WMT_TEST_LPBK_CMD[2], &len_in_cmd, 2); + osal_memcpy(&WMT_TEST_LPBK_EVT[2], &len_in_cmd, 2); + + /* wmt cmd */ + osal_memcpy(gLpbkBuf, WMT_TEST_LPBK_CMD, osal_sizeof(WMT_TEST_LPBK_CMD)); + osal_memcpy(gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), pbuffer, buf_length); + + do { + fgFail = MTK_WCN_BOOL_TRUE; + /*send packet through STP */ + + /* iRet = (*kal_stp_tx)( + *(PUINT8)gLpbkBuf, + *osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length, + *&u4WrittenSize); + */ + iRet = wmt_core_tx((PUINT8) gLpbkBuf, + (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length), + &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("opfunc_lpbk wmt_core_tx failed\n"); + break; + } + WMT_INFO_FUNC("opfunc_lpbk wmt_core_tx OK\n"); + + /*receive firmware response from STP */ + iRet = wmt_core_rx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_EVT) + buf_length), &u4ReadSize); + if (iRet) { + WMT_ERR_FUNC("opfunc_lpbk wmt_core_rx failed\n"); + break; + } + WMT_INFO_FUNC("opfunc_lpbk wmt_core_rx OK\n"); + /*check if loopback response ok or not */ + if (u4ReadSize != (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)) { + WMT_ERR_FUNC("lpbk event read size wrong(%d, %d)\n", u4ReadSize, + (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); + break; + } + WMT_INFO_FUNC("lpbk event read size right(%d, %d)\n", u4ReadSize, + (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); + + if (osal_memcmp(WMT_TEST_LPBK_EVT, gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_EVT))) { + WMT_ERR_FUNC("WMT-CORE WMT_TEST_LPBK_EVT error! read len %d [%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4ReadSize, gLpbkBuf[0], gLpbkBuf[1], gLpbkBuf[2], gLpbkBuf[3], gLpbkBuf[4] + ); + break; + } + pWmtOp->au4OpData[0] = u4ReadSize - osal_sizeof(WMT_TEST_LPBK_EVT); + osal_memcpy((VOID *) pWmtOp->au4OpData[1], gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), buf_length); + fgFail = MTK_WCN_BOOL_FALSE; + } while (0); + /*return result */ + /* WMT_DBG_FUNC("WMT-CORE: <--wmt_do_lpbk, fgFail = %d\n", fgFail); */ + return fgFail; + +} + +static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp) +{ + + INT32 iRet = 0; + UINT32 cmdNo = 0; + UINT32 cmdNoPa = 0; + + UINT8 tstCmd[64]; + UINT8 tstEvt[64]; + UINT8 tstEvtTmp[64]; + UINT32 u4Res; + SIZE_T tstCmdSz = 0; + SIZE_T tstEvtSz = 0; + + UINT8 *pRes = NULL; + UINT32 resBufRoom = 0; + /*test command list */ + /*1 */ + UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; + UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_NOACK_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0A }; + UINT8 WMT_NOACK_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_WARNRST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0B }; + UINT8 WMT_WARNRST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_FWLOGTST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0C }; + UINT8 WMT_FWLOGTST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + + UINT8 WMT_EXCEPTION_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x09 }; + UINT8 WMT_EXCEPTION_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + /*2 */ + UINT8 WMT_COEXDBG_CMD[] = { 0x01, 0x10, 0x02, 0x00, + 0x08, + 0xAA /*Debugging Parameter */ + }; + UINT8 WMT_COEXDBG_1_EVT[] = { 0x02, 0x10, 0x05, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA /*event content */ + }; + UINT8 WMT_COEXDBG_2_EVT[] = { 0x02, 0x10, 0x07, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB /*event content */ + }; + UINT8 WMT_COEXDBG_3_EVT[] = { 0x02, 0x10, 0x0B, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB /*event content */ + }; + /*test command list -end */ + + cmdNo = pWmtOp->au4OpData[0]; + + WMT_INFO_FUNC("Send Test command %d!\n", cmdNo); + if (cmdNo == 0) { + /*dead command */ + WMT_INFO_FUNC("Send Assert command !\n"); + tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); + tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); + osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); + } else if (cmdNo == 1) { + /*dead command */ + WMT_INFO_FUNC("Send Exception command !\n"); + tstCmdSz = osal_sizeof(WMT_EXCEPTION_CMD); + tstEvtSz = osal_sizeof(WMT_EXCEPTION_EVT); + osal_memcpy(tstCmd, WMT_EXCEPTION_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_EXCEPTION_EVT, tstEvtSz); + } else if (cmdNo == 2) { + cmdNoPa = pWmtOp->au4OpData[1]; + pRes = (PUINT8) pWmtOp->au4OpData[2]; + resBufRoom = pWmtOp->au4OpData[3]; + if (cmdNoPa <= 0xf) { + WMT_INFO_FUNC("Send Coexistence Debug command [0x%x]!\n", cmdNoPa); + tstCmdSz = osal_sizeof(WMT_COEXDBG_CMD); + osal_memcpy(tstCmd, WMT_COEXDBG_CMD, tstCmdSz); + if (tstCmdSz > 5) + tstCmd[5] = cmdNoPa; + + /*setup the expected event length */ + if (cmdNoPa <= 0x4) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_1_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_1_EVT, tstEvtSz); + } else if (cmdNoPa == 0x5) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_2_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_2_EVT, tstEvtSz); + } else if (cmdNoPa >= 0x6 && cmdNoPa <= 0xf) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_3_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_3_EVT, tstEvtSz); + } else { + + } + } else { + WMT_ERR_FUNC("cmdNoPa is wrong\n"); + return iRet; + } + } else if (cmdNo == 3) { + /*dead command */ + WMT_INFO_FUNC("Send No Ack command !\n"); + tstCmdSz = osal_sizeof(WMT_NOACK_CMD); + tstEvtSz = osal_sizeof(WMT_NOACK_EVT); + osal_memcpy(tstCmd, WMT_NOACK_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_NOACK_EVT, tstEvtSz); + } else if (cmdNo == 4) { + /*dead command */ + WMT_INFO_FUNC("Send Warm reset command !\n"); + tstCmdSz = osal_sizeof(WMT_WARNRST_CMD); + tstEvtSz = osal_sizeof(WMT_WARNRST_EVT); + osal_memcpy(tstCmd, WMT_WARNRST_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_WARNRST_EVT, tstEvtSz); + } else if (cmdNo == 5) { + /*dead command */ + WMT_INFO_FUNC("Send f/w log test command !\n"); + tstCmdSz = osal_sizeof(WMT_FWLOGTST_CMD); + tstEvtSz = osal_sizeof(WMT_FWLOGTST_EVT); + osal_memcpy(tstCmd, WMT_FWLOGTST_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_FWLOGTST_EVT, tstEvtSz); + } + + else { + /*Placed youer test WMT command here, easiler to integrate and test with F/W side */ + } + + /* send command */ + /* iRet = (*kal_stp_tx)(tstCmd, tstCmdSz, &u4Res); */ + iRet = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != tstCmdSz)) { + WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, tstCmdSz); + return -1; + } + + if ((cmdNo == 0) || (cmdNo == 1) || cmdNo == 3) { + WMT_INFO_FUNC("WMT-CORE: not to rx event for assert command\n"); + return 0; + } + + iRet = wmt_core_rx(tstEvtTmp, tstEvtSz, &u4Res); + + /*Event Post Handling */ + if (cmdNo == 2) { + WMT_INFO_FUNC("#=========================================================#\n"); + WMT_INFO_FUNC("coext debugging id = %d", cmdNoPa); + if (tstEvtSz > 5) { + wmt_core_dump_data(&tstEvtTmp[5], "coex debugging ", tstEvtSz - 5); + } else { + /* error log */ + WMT_ERR_FUNC("error coex debugging event\n"); + } + /*put response to buffer for shell to read */ + if (pRes != NULL && resBufRoom > 0) { + pWmtOp->au4OpData[3] = resBufRoom < tstEvtSz - 5 ? resBufRoom : tstEvtSz - 5; + osal_memcpy(pRes, &tstEvtTmp[5], pWmtOp->au4OpData[3]); + } else + pWmtOp->au4OpData[3] = 0; + WMT_INFO_FUNC("#=========================================================#\n"); + } + + return iRet; + +} + +static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + wmt_core_dump_func_state("BE HW RST"); + /*-->Reset WMT data structure*/ + /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] = DRV_STS_POWER_OFF; + /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = DRV_STS_POWER_OFF; + /*enable power off flag, if flag=0, power off connsys will not be executed */ + mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); + /* if wmt is poweroff, we need poweron chip first */ + /* Zhiguo : this action also needed in BTIF interface to avoid KE */ +#if 1 + if (DRV_STS_POWER_OFF == gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_WARN_FUNC("WMT-CORE: WMT is off, need re-poweron\n"); + /* power on control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); + return -1; + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + } +#endif + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_FUNC_ON) { + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); + + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; + } + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_FUNC_ON) { + + if (NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI] && NULL != gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off) { + iRet = gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off(gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off WIFI func fail (%d)\n", iRet); + + /* check all sub-func and do power off */ + } else { + WMT_INFO_FUNC("wmt core: turn off WIFI func ok!!\n"); + } + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; + } +#if 0 + /*<4>Power off Combo chip */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF fail (%d)", iRet); + WMT_INFO_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF ok (%d)", iRet); +#endif + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; + + /*-->PesetCombo chip*/ + iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: -->[HW RST] fail iRet(%d)\n", iRet); + WMT_WARN_FUNC("WMT-CORE: -->[HW RST] ok\n"); + + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + + /* 4 close stp */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + if (iRet) { + if (iRet == -2) { + WMT_INFO_FUNC("WMT-CORE:stp should have be closed\n"); + return 0; + } + WMT_ERR_FUNC("WMT-CORE: wmt close stp failed\n"); + return -1; + } + + wmt_core_dump_func_state("AF HW RST"); + return iRet; + +} + +static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + + iRet = wmt_core_stp_init(); + if (!iRet) + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; + return iRet; +} + +static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp) +{ + + return 0; +} + +static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_THERM_CMD[4] = pWmtOp->au4OpData[0]; /*CMD type, refer to ENUM_WMTTHERM_TYPE_T */ + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res); */ + iRet = wmt_core_tx((PUINT8) WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_THERM_CMD))) { + WMT_ERR_FUNC("WMT-CORE: THERM_CTRL_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, + osal_sizeof(WMT_THERM_CMD)); + return iRet; + } + + evtLen = 16; + + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || ((u4Res != osal_sizeof(WMT_THERM_CTRL_EVT)) && (u4Res != osal_sizeof(WMT_THERM_READ_EVT)))) { + WMT_ERR_FUNC("WMT-CORE: read THERM_CTRL_EVT/THERM_READ_EVENT fail(%d) len(%d, %d)\n", iRet, u4Res, + evtLen); + mtk_wcn_stp_dbg_dump_package(); + return iRet; + } + if (u4Res == osal_sizeof(WMT_THERM_CTRL_EVT)) { + if (osal_memcmp(evtBuf, WMT_THERM_CTRL_EVT, osal_sizeof(WMT_THERM_CTRL_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_CTRL_EVT error\n"); + WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + osal_sizeof(WMT_THERM_CTRL_EVT), WMT_THERM_CTRL_EVT[0], WMT_THERM_CTRL_EVT[1], + WMT_THERM_CTRL_EVT[2], WMT_THERM_CTRL_EVT[3], WMT_THERM_CTRL_EVT[4]); + pWmtOp->au4OpData[1] = MTK_WCN_BOOL_FALSE; /*will return to function driver */ + mtk_wcn_stp_dbg_dump_package(); + } else { + WMT_DBG_FUNC("Send WMT_THERM_CTRL_CMD command OK!\n"); + pWmtOp->au4OpData[1] = MTK_WCN_BOOL_TRUE; /*will return to function driver */ + } + } else { + /*no need to judge the real thermal value */ + if (osal_memcmp(evtBuf, WMT_THERM_READ_EVT, osal_sizeof(WMT_THERM_READ_EVT) - 1) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_READ_EVT error\n"); + WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5], + osal_sizeof(WMT_THERM_READ_EVT), WMT_THERM_READ_EVT[0], WMT_THERM_READ_EVT[1], + WMT_THERM_READ_EVT[2], WMT_THERM_READ_EVT[3]); + pWmtOp->au4OpData[1] = 0xFF; /*will return to function driver */ + mtk_wcn_stp_dbg_dump_package(); + } else { + WMT_DBG_FUNC("Send WMT_THERM_READ_CMD command OK!\n"); + pWmtOp->au4OpData[1] = evtBuf[5]; /*will return to function driver */ + } + } + + return iRet; + +} + +static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_ERR_FUNC("WMT-CORE: wmt_efuse_rw fail: chip is powered off\n"); + return -1; + } + + WMT_EFUSE_CMD[4] = (pWmtOp->au4OpData[0]) ? 0x1 : 0x2; /* w:2, r:1 */ + osal_memcpy(&WMT_EFUSE_CMD[6], (PUINT8) &pWmtOp->au4OpData[1], 2); /* address */ + osal_memcpy(&WMT_EFUSE_CMD[8], (PUINT32) pWmtOp->au4OpData[2], 4); /* value */ + + wmt_core_dump_data(&WMT_EFUSE_CMD[0], "efuse_cmd", osal_sizeof(WMT_EFUSE_CMD)); + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res); */ + iRet = wmt_core_tx((PUINT8) WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_EFUSE_CMD))) { + WMT_ERR_FUNC("WMT-CORE: EFUSE_CMD iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, + osal_sizeof(WMT_EFUSE_CMD)); + return iRet; + } + + evtLen = (pWmtOp->au4OpData[0]) ? osal_sizeof(WMT_EFUSE_EVT) : osal_sizeof(WMT_EFUSE_EVT); + + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) + WMT_ERR_FUNC("WMT-CORE: read REG_EVB fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + wmt_core_dump_data(&evtBuf[0], "efuse_evt", osal_sizeof(evtBuf)); + + return iRet; + +} + +static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + WMT_IC_PIN_ID id; + WMT_IC_PIN_STATE stat; + UINT32 flag; + + if (DRV_STS_FUNC_ON != gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]) { + WMT_ERR_FUNC("WMT-CORE: wmt_gpio_ctrl fail: chip is powered off\n"); + return -1; + } + + if (!gMtkWmtCtx.p_ic_ops->ic_pin_ctrl) { + WMT_ERR_FUNC("WMT-CORE: error, gMtkWmtCtx.p_ic_ops->ic_pin_ctrl(NULL)\n"); + return -1; + } + + id = pWmtOp->au4OpData[0]; + stat = pWmtOp->au4OpData[1]; + flag = pWmtOp->au4OpData[2]; + + WMT_INFO_FUNC("ic pin id:%d, stat:%d, flag:0x%x\n", id, stat, flag); + + iRet = (*(gMtkWmtCtx.p_ic_ops->ic_pin_ctrl)) (id, stat, flag); + + return iRet; +} + +MTK_WCN_BOOL wmt_core_is_quick_ps_support(void) +{ + P_WMT_CTX pctx = &gMtkWmtCtx; + + if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_quick_sleep)) + return (*(pctx->p_ic_ops->is_quick_sleep)) (); + + return MTK_WCN_BOOL_FALSE; +} + +MTK_WCN_BOOL wmt_core_get_aee_dump_flag(void) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_WMT_CTX pctx = &gMtkWmtCtx; + + if ((NULL != pctx->p_ic_ops) && (NULL != pctx->p_ic_ops->is_aee_dump_support)) + bRet = (*(pctx->p_ic_ops->is_aee_dump_support)) (); + else + bRet = MTK_WCN_BOOL_FALSE; + + return bRet; +} + +INT32 opfunc_pin_state(P_WMT_OP pWmtOp) +{ + + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + UINT32 iRet = 0; + + iRet = wmt_core_ctrl(WMT_CTRL_HW_STATE_DUMP, &ctrlPa1, &ctrlPa2); + return iRet; +} + +static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT32 buf_len = 0; + UINT8 *buffer = NULL; + UINT8 evt_buffer[8] = { 0 }; + MTK_WCN_BOOL fgFail; + + UINT8 WMT_BGW_DESENSE_CMD[] = { + 0x01, 0x0e, 0x0f, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + }; + UINT8 WMT_BGW_DESENSE_EVT[] = { 0x02, 0x0e, 0x01, 0x00, 0x00 }; + + buf_len = pWmtOp->au4OpData[0]; + buffer = (PUINT8) pWmtOp->au4OpData[1]; + + osal_memcpy(&WMT_BGW_DESENSE_CMD[5], buffer, buf_len); + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = + wmt_core_tx(&WMT_BGW_DESENSE_CMD[0], osal_sizeof(WMT_BGW_DESENSE_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_BGW_DESENSE_CMD))) { + WMT_ERR_FUNC("bgw desense tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_BGW_DESENSE_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_BGW_DESENSE_EVT))) { + WMT_ERR_FUNC("bgw desense rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + break; + } + + if (osal_memcmp(evt_buffer, WMT_BGW_DESENSE_EVT, osal_sizeof(WMT_BGW_DESENSE_EVT)) != 0) { + WMT_ERR_FUNC + ("bgw desense WMT_BGW_DESENSE_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + return fgFail; +} + +static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp) +{ + UINT32 kind = 0; + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT8 evt_buffer[12] = { 0 }; + MTK_WCN_BOOL fgFail; + PUINT8 set_mcu_clk_str[] = { + "Enable MCU PLL", + "SET MCU CLK to 26M", + "SET MCU CLK to 37M", + "SET MCU CLK to 64M", + "SET MCU CLK to 69M", + "SET MCU CLK to 104M", + "SET MCU CLK to 118.857M", + "SET MCU CLK to 138.67M", + "Disable MCU PLL" + }; + UINT8 WMT_SET_MCU_CLK_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff + }; + UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + + UINT8 WMT_EN_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00 }; /* enable pll clk */ + UINT8 WMT_26_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x00, 0x4d, 0x84, 0x00 }; /* set 26M */ + UINT8 WMT_37_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1e, 0x4d, 0x84, 0x00 }; /* set 37.8M */ + UINT8 WMT_64_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1d, 0x4d, 0x84, 0x00 }; /* set 64M */ + UINT8 WMT_69_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1c, 0x4d, 0x84, 0x00 }; /* set 69M */ + UINT8 WMT_104_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5b, 0x4d, 0x84, 0x00 }; /* set 104M */ + UINT8 WMT_108_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5a, 0x4d, 0x84, 0x00 }; /* set 118.857M */ + UINT8 WMT_138_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x59, 0x4d, 0x84, 0x00 }; /* set 138.67M */ + UINT8 WMT_DIS_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 }; /* disable pll clk */ + + kind = pWmtOp->au4OpData[0]; + WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]); + + switch (kind) { + case 0: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_EN_MCU_CLK_CMD[0], osal_sizeof(WMT_EN_MCU_CLK_CMD)); + break; + case 1: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_26_MCU_CLK_CMD[0], osal_sizeof(WMT_26_MCU_CLK_CMD)); + break; + case 2: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_37_MCU_CLK_CMD[0], osal_sizeof(WMT_37_MCU_CLK_CMD)); + break; + case 3: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_64_MCU_CLK_CMD[0], osal_sizeof(WMT_64_MCU_CLK_CMD)); + break; + case 4: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_69_MCU_CLK_CMD[0], osal_sizeof(WMT_69_MCU_CLK_CMD)); + break; + case 5: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_104_MCU_CLK_CMD[0], osal_sizeof(WMT_104_MCU_CLK_CMD)); + break; + case 6: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_108_MCU_CLK_CMD[0], osal_sizeof(WMT_108_MCU_CLK_CMD)); + break; + case 7: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_138_MCU_CLK_CMD[0], osal_sizeof(WMT_138_MCU_CLK_CMD)); + break; + case 8: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_DIS_MCU_CLK_CMD[0], osal_sizeof(WMT_DIS_MCU_CLK_CMD)); + break; + default: + WMT_ERR_FUNC("unknown kind\n"); + break; + } + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = + wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + break; + } + + if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4], + evt_buffer[5], evt_buffer[6], evt_buffer[7]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + if (MTK_WCN_BOOL_FALSE == fgFail) + WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]); + + WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]); + + return fgFail; +} + +static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp) +{ + UINT8 *buffer = NULL; + MTK_WCN_BOOL fgFail; + UINT32 u4Res; + UINT32 aDieChipid = 0; + UINT8 soc_adie_chipid_cmd[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; + UINT8 soc_adie_chipid_evt[] = { 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00 }; + UINT8 evtbuf[20]; + INT32 iRet = -1; + + buffer = (PUINT8) pWmtOp->au4OpData[1]; + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + /* read A die chipid by wmt cmd */ + iRet = + wmt_core_tx((PUINT8) &soc_adie_chipid_cmd[0], osal_sizeof(soc_adie_chipid_cmd), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_cmd))) { + WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); + break; + } + osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, osal_sizeof(soc_adie_chipid_evt), &u4Res); + if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_evt))) { + WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); + break; + } + osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); + osal_memcpy(buffer, &evtbuf[u4Res - 2], 2); + pWmtOp->au4OpData[0] = 2; + WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + return fgFail; +} + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp) +{ + MTK_WCN_BOOL fgFail; + UINT32 u4Res; + UINT8 host_lte_btwf_coex_cmd[] = { 0x01, 0x10, 0x00, 0x00, 0x00 }; + UINT8 host_lte_btwf_coex_evt[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + UINT8 *pTxBuf = NULL; + UINT8 evtbuf[8] = { 0 }; + INT32 iRet = -1; + UINT16 msg_len = 0; + UINT32 total_len = 0; + UINT32 index = 0; + UINT8 *msg_local_buffer = NULL; + + msg_local_buffer = kmalloc(1300, GFP_KERNEL); + if (!msg_local_buffer) { + WMT_ERR_FUNC("msg_local_buffer kmalloc memory fail\n"); + return 0; + } + + pTxBuf = (UINT8 *) pWmtOp->au4OpData[0]; + if (NULL == pTxBuf) { + WMT_ERR_FUNC("idc msg buffer is NULL\n"); + return -1; + } + iRet = wmt_lib_idc_lock_aquire(); + if (iRet) { + WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", iRet); + return iRet; + } + osal_memcpy(&msg_len, &pTxBuf[0], osal_sizeof(msg_len)); + if (msg_len > 1200) { + wmt_lib_idc_lock_release(); + WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len); + return -2; + } + msg_len += 1; /*flag byte */ + + osal_memcpy(&host_lte_btwf_coex_cmd[2], &msg_len, 2); + host_lte_btwf_coex_cmd[4] = (pWmtOp->au4OpData[1] & 0x00ff); + osal_memcpy(&msg_local_buffer[0], &host_lte_btwf_coex_cmd[0], osal_sizeof(host_lte_btwf_coex_cmd)); + osal_memcpy(&msg_local_buffer[osal_sizeof(host_lte_btwf_coex_cmd)], + &pTxBuf[osal_sizeof(msg_len)], msg_len - 1); + + wmt_lib_idc_lock_release(); + total_len = osal_sizeof(host_lte_btwf_coex_cmd) + msg_len - 1; + + WMT_DBG_FUNC("wmt_core:idc msg payload len form lte(%d),wmt msg total len(%d)\n", msg_len - 1, + total_len); + WMT_DBG_FUNC("wmt_core:idc msg payload:\n"); + + for (index = 0; index < total_len; index++) + WMT_DBG_FUNC("0x%02x ", msg_local_buffer[index]); + + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + /* read A die chipid by wmt cmd */ + iRet = wmt_core_tx((PUINT8) &msg_local_buffer[0], total_len, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != total_len)) { + WMT_ERR_FUNC("wmt_core:send lte idc msg to connsys fail(%d),size(%d)\n", iRet, u4Res); + break; + } + osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, osal_sizeof(host_lte_btwf_coex_evt), &u4Res); + if (iRet || (u4Res != osal_sizeof(host_lte_btwf_coex_evt))) { + WMT_ERR_FUNC("wmt_core:recv host_lte_btwf_coex_evt fail(%d),size(%d)\n", iRet, u4Res); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + kfree(msg_local_buffer); + return fgFail; +} +#endif + +VOID wmt_core_set_coredump_state(ENUM_DRV_STS state) +{ + WMT_INFO_FUNC("wmt-core: set coredump state(%d)\n", state); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = state; +} +#ifdef CONFIG_MTK_COMBO_ANT +INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + size_t ctrlPa1 = pWmtOp->au4OpData[0]; + UINT32 ctrlPa2 = pWmtOp->au4OpData[1]; + PUINT8 pbuf = (PUINT8) ctrlPa1; + UINT32 fragSeq = 0; + UINT16 fragSize = 0; + UINT16 wmtCmdLen; + UINT16 wmtPktLen; + UINT32 u4Res = 0; + UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_DWN_EVT)]; +#if 1 + UINT32 ctrlPa3 = pWmtOp->au4OpData[2]; + + do { + fragSize = ctrlPa2; + fragSeq = ctrlPa3; + gAntBuf[5] = fragSeq; + + + wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_DWN_CMD) + 1; + + /*WMT command length cal */ + wmtCmdLen = wmtPktLen - 4; +#if 0 + WMT_ANT_RAM_DWN_CMD[2] = wmtCmdLen & 0xFF; + WMT_ANT_RAM_DWN_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; +#else + osal_memcpy(&WMT_ANT_RAM_DWN_CMD[2], &wmtCmdLen, 2); +#endif + + + + WMT_ANT_RAM_DWN_CMD[4] = 1; /*RAM CODE download */ + + osal_memcpy(gAntBuf, WMT_ANT_RAM_DWN_CMD, sizeof(WMT_ANT_RAM_DWN_CMD)); + + /*copy ram code content to global buffer */ + osal_memcpy(&gAntBuf[osal_sizeof(WMT_ANT_RAM_DWN_CMD) + 1], pbuf, fragSize); + + iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + wmtPktLen, u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, wmtPktLen, u4Res); + + osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); + + WMT_ANT_RAM_DWN_EVT[4] = 0; /*download result; 0 */ + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_DWN_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_ANT_RAM_DWN_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_ANT_RAM_DWN_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_DWN_EVT, sizeof(WMT_ANT_RAM_DWN_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_DWN_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], + antEvtBuf[4], sizeof(WMT_ANT_RAM_DWN_EVT), WMT_ANT_RAM_DWN_EVT[0], + WMT_ANT_RAM_DWN_EVT[1], WMT_ANT_RAM_DWN_EVT[2], WMT_ANT_RAM_DWN_EVT[3], + WMT_ANT_RAM_DWN_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) ok\n", + sizeof(WMT_ANT_RAM_DWN_EVT), u4Res); + + } while (0); +#else + UINT32 patchSize = ctrlPa2; + UINT32 patchSizePerFrag = 1000; + UINT32 offset; + UINT32 fragNum = 0; + /*cal patch fragNum */ + fragNum = (patchSize + patchSizePerFrag - 1) / patchSizePerFrag; + if (2 >= fragNum) { + WMT_WARN_FUNC("ANT ramcode size(%d) too short\n", patchSize); + return -1; + } + + while (fragSeq < fragNum) { + /*update fragNum */ + fragSeq++; + + if (1 == fragSeq) { + fragSize = patchSizePerFrag; + /*first package */ + gAntBuf[5] = 1; /*RAM CODE start */ + } else if (fragNum == fragSeq) { + /*last package */ + fragSize = patchSizePerFrag; + gAntBuf[5] = 3; /*RAM CODE end */ + } else { + /*middle package */ + fragSize = patchSize - ((fragNum - 1) * patchSizePerFrag); + gAntBuf[5] = 2; /*RAM CODE confinue */ + } + wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_OP_CMD) + 1; + + /*WMT command length cal */ + wmtCmdLen = wmtPktLen - 4; + + WMT_ANT_RAM_OP_CMD[2] = wmtCmdLen & 0xFF; + WMT_ANT_RAM_OP_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; + + WMT_ANT_RAM_OP_CMD[4] = 1; /*RAM CODE download */ + + osal_memcpy(gAntBuf, WMT_ANT_RAM_OP_CMD, sizeof(WMT_ANT_RAM_OP_CMD)); + + /*copy ram code content to global buffer */ + osal_memcpy(&gAntBuf[6], pbuf, fragSize); + + /*update offset */ + offset += fragSize; + pbuf += offset; + + iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + wmtPktLen, u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, wmtPktLen, u4Res); + + osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); + + WMT_SET_RAM_OP_EVT[4] = 0; /*download result; 0 */ + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_SET_RAM_OP_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_SET_RAM_OP_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) fail(%d)\n", + sizeof(WMT_SET_RAM_OP_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_SET_RAM_OP_EVT, sizeof(WMT_SET_RAM_OP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_SET_RAM_OP_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], + antEvtBuf[4], sizeof(WMT_SET_RAM_OP_EVT), WMT_SET_RAM_OP_EVT[0], + WMT_SET_RAM_OP_EVT[1], WMT_SET_RAM_OP_EVT[2], WMT_SET_RAM_OP_EVT[3], + WMT_SET_RAM_OP_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) ok\n", + sizeof(WMT_SET_RAM_OP_EVT), u4Res); + + + } + if (fragSeq != fragNum) + iRet = -7; +#endif + return iRet; +} + + +INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + UINT32 u4Res = 0; + UINT32 wmtPktLen = osal_sizeof(WMT_ANT_RAM_STA_GET_CMD); + UINT32 u4AntRamStatus = 0; + UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_STA_GET_EVT)]; + + + iRet = wmt_core_tx(WMT_ANT_RAM_STA_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC + ("wmt_core: write wmt and ramcode status query command failed, (%d, %d), iRet(%d)\n", + wmtPktLen, u4Res, iRet); + iRet = -4; + return iRet; + } + + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_STA_GET_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_ANT_RAM_STA_GET_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_STA_GET_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_ANT_RAM_STA_GET_EVT), u4Res, iRet); + iRet = -5; + return iRet; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_STA_GET_EVT, sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1) != + 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_STA_GET_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], antEvtBuf[4], + sizeof(WMT_ANT_RAM_STA_GET_EVT), WMT_ANT_RAM_STA_GET_EVT[0], + WMT_ANT_RAM_STA_GET_EVT[1], WMT_ANT_RAM_STA_GET_EVT[2], + WMT_ANT_RAM_STA_GET_EVT[3], WMT_ANT_RAM_STA_GET_EVT[4]); + iRet = -6; + return iRet; + } +#endif + if (0 == iRet) { + u4AntRamStatus = antEvtBuf[sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1]; + pWmtOp->au4OpData[2] = u4AntRamStatus; + WMT_INFO_FUNC("ANT ram code %s\n", + 1 == u4AntRamStatus ? "exist already" : "not exist"); + } + return iRet; +} +#endif + +#if CFG_WMT_LTE_COEX_HANDLING +/*TEST CODE*/ +static UINT32 g_open_wmt_lte_flag; +VOID wmt_core_set_flag_for_test(UINT32 enable) +{ + WMT_INFO_FUNC("%s wmt_lte_flag\n", enable ? "enable" : "disable"); + g_open_wmt_lte_flag = enable; +} + +UINT32 wmt_core_get_flag_for_test(VOID) +{ + return g_open_wmt_lte_flag; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c new file mode 100644 index 0000000000000..fa603c208e59b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ctrl.c @@ -0,0 +1,1019 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CTRL]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "osal.h" + +#include "wmt_ctrl.h" +#include "wmt_core.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "wmt_dev.h" +#include "wmt_plat.h" +#include "stp_core.h" +#include "stp_dbg.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* moved to wmt_ctrl.h */ +/*static INT32 wmt_ctrl_tx_ex (UINT8 *pData, UINT32 size, UINT32 *writtenSize, MTK_WCN_BOOL bRawFlag);*/ + +static INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value); + +static INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA); +#if 0 +static INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA); +#endif +static INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_others(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData); +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA); +#endif + +static INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA); + +static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData); + +static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData); + +static INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData); + +/* TODO: [FixMe][GeorgeKuo]: remove unused function */ +/*static INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA);*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* GeorgeKuo: Use designated initializers described in + * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html + */ +static const WMT_CTRL_FUNC wmt_ctrl_func[] = { + [WMT_CTRL_HW_PWR_OFF] = wmt_ctrl_hw_pwr_off, + [WMT_CTRL_HW_PWR_ON] = wmt_ctrl_hw_pwr_on, + [WMT_CTRL_HW_RST] = wmt_ctrl_hw_rst, + [WMT_CTRL_STP_CLOSE] = wmt_ctrl_stp_close, + [WMT_CTRL_STP_OPEN] = wmt_ctrl_stp_open, + [WMT_CTRL_STP_CONF] = wmt_ctrl_stp_conf, + [WMT_CTRL_FREE_PATCH] = wmt_ctrl_free_patch, + [WMT_CTRL_GET_PATCH] = wmt_ctrl_get_patch, + [WMT_CTRL_GET_PATCH_NAME] = wmt_ctrl_get_patch_name, + [WMT_CTRL_HWIDVER_SET] = wmt_ctrl_hwidver_set, + [WMT_CTRL_STP_RST] = wmt_ctrl_stp_rst, + [WMT_CTRL_GET_WMT_CONF] = wmt_ctrl_get_wmt_conf, + [WMT_CTRL_TX] = wmt_ctrl_tx, + [WMT_CTRL_RX] = wmt_ctrl_rx, + [WMT_CTRL_RX_FLUSH] = wmt_ctrl_rx_flush, + [WMT_CTRL_GPS_SYNC_SET] = wmt_ctrl_gps_sync_set, + [WMT_CTRL_GPS_LNA_SET] = wmt_ctrl_gps_lna_set, + [WMT_CTRL_PATCH_SEARCH] = wmt_ctrl_patch_search, + [WMT_CTRL_CRYSTAL_TRIMING_GET] = wmt_ctrl_crystal_triming_get, + [WMT_CTRL_CRYSTAL_TRIMING_PUT] = wmt_ctrl_crystal_triming_put, + [WMT_CTRL_HW_STATE_DUMP] = wmt_ctrl_hw_state_show, + [WMT_CTRL_GET_PATCH_NUM] = wmt_ctrl_get_patch_num, + [WMT_CTRL_GET_PATCH_INFO] = wmt_ctrl_get_patch_info, + [WMT_CTRL_SOC_PALDO_CTRL] = wmt_ctrl_soc_paldo_ctrl, + [WMT_CTRL_SOC_WAKEUP_CONSYS] = wmt_ctrl_soc_wakeup_consys, + [WMT_CTRL_SET_STP_DBG_INFO] = wmt_ctrl_set_stp_dbg_info, + [WMT_CTRL_BGW_DESENSE_CTRL] = wmt_ctrl_bgw_desense_ctrl, + [WMT_CTRL_EVT_ERR_TRG_ASSERT] = wmt_ctrl_evt_err_trg_assert, +#if CFG_WMT_LTE_COEX_HANDLING + [WMT_CTRL_GET_TDM_REQ_ANTSEL] = wmt_ctrl_get_tdm_req_antsel, +#endif + [WMT_CTRL_EVT_PARSER] = wmt_ctrl_evt_parser, + [WMT_CTRL_MAX] = wmt_ctrl_others, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 ctrlId; + + if (NULL == pWmtCtrlData) { + osal_assert(0); + return -1; + } + + ctrlId = pWmtCtrlData->ctrlId; + /*1sanity check, including wmtCtrlId */ + if ((NULL == pWmtCtrlData) + || (WMT_CTRL_MAX <= ctrlId)) + /* || (ctrlId < WMT_CTRL_HW_PWR_OFF) ) [FixMe][GeorgeKuo]: useless comparison */ + { + osal_assert(NULL != pWmtCtrlData); + osal_assert(WMT_CTRL_MAX > ctrlId); + /* osal_assert(ctrlId >= WMT_CTRL_HW_PWR_OFF); [FixMe][GeorgeKuo]: useless comparison */ + return -2; + } + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + if (wmt_ctrl_func[ctrlId]) { + /*call servicd handling API */ + return (*(wmt_ctrl_func[ctrlId])) (pWmtCtrlData); /* serviceHandlerPack[ctrlId].serviceHandler */ + } + osal_assert(NULL != wmt_ctrl_func[ctrlId]); + return -3; + +} + +INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pData, UINT32 size, UINT32 *writtenSize */) +{ + UINT8 *pData = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + UINT32 size = pWmtCtrlData->au4CtrlData[1]; + PUINT32 writtenSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + MTK_WCN_BOOL bRawFlag = pWmtCtrlData->au4CtrlData[3]; + + return wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); +} + +INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pBuff, UINT32 buffLen, UINT32 *readSize */) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 readLen; + long waitRet = -1; + PUINT8 pBuff = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + UINT32 buffLen = pWmtCtrlData->au4CtrlData[1]; + PUINT32 readSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + + if (readSize) + *readSize = 0; + + /* sanity check */ + if (!buffLen) { + WMT_WARN_FUNC("buffLen = 0\n"); + osal_assert(buffLen); + return 0; + } +#if 0 + if (!pDev) { + WMT_WARN_FUNC("gpDevWmt = NULL\n"); + osal_assert(pDev); + return -1; + } +#endif + + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { + WMT_WARN_FUNC("state(0x%lx)\n", pDev->state); + osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); + return -2; + } + + /* sanity ok, proceeding rx operation */ + /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ + readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); + + while (readLen == 0) { /* got nothing, wait for STP's signal */ + WMT_LOUD_FUNC("before wmt_dev_rx_timeout\n"); + /* iRet = wait_event_interruptible(pdev->rWmtRxWq, osal_test_bit(WMT_STAT_RX, &pdev->state)); */ + /* waitRet = wait_event_interruptible_timeout( + * pDev->rWmtRxWq, + * osal_test_bit(WMT_STAT_RX, &pdev->state), + * msecs_to_jiffies(WMT_LIB_RX_TIMEOUT)); + */ + pDev->rWmtRxWq.timeoutValue = WMT_LIB_RX_TIMEOUT; + /* waitRet = osal_wait_for_event_bit_timeout(&pDev->rWmtRxWq, &pDev->state, WMT_STAT_RX); */ + waitRet = wmt_dev_rx_timeout(&pDev->rWmtRxWq); + + WMT_LOUD_FUNC("wmt_dev_rx_timeout returned\n"); + + if (0 == waitRet) { + WMT_ERR_FUNC("wmt_dev_rx_timeout: timeout,jiffies(%lu),timeoutvalue(%d)\n", + jiffies, pDev->rWmtRxWq.timeoutValue); + return -1; + } else if (waitRet < 0) { + WMT_WARN_FUNC("wmt_dev_rx_timeout: interrupted by signal (%ld)\n", waitRet); + return waitRet; + } + WMT_DBG_FUNC("wmt_dev_rx_timeout, iRet(%ld)\n", waitRet); + /* read_len = mtk_wcn_stp_receive_data(data, size, WMT_TASK_INDX); */ + readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); + + if (0 == readLen) + WMT_WARN_FUNC("wmt_ctrl_rx be signaled, but no rx data(%ld)\n", waitRet); + + } + + if (readSize) + *readSize = readLen; + + return 0; + +} + +INT32 wmt_ctrl_tx_ex(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + + if (NULL != writtenSize) + *writtenSize = 0; + + /* sanity check */ + if (0 == size) { + WMT_WARN_FUNC("size to tx is 0\n"); + osal_assert(size); + return -1; + } + + /* if STP is not enabled yet, can't use this function. Use tx_raw instead */ + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state) || !osal_test_bit(WMT_STAT_STP_EN, &pDev->state)) { + WMT_ERR_FUNC("wmt state(0x%lx)\n", pDev->state); + osal_assert(osal_test_bit(WMT_STAT_STP_EN, &pDev->state)); + osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); + return -2; + } + + /* sanity ok, proceeding tx operation */ + /*retval = mtk_wcn_stp_send_data(data, size, WMTDRV_TYPE_WMT); */ + mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); + if (bRawFlag) + iRet = mtk_wcn_stp_send_data_raw(pData, size, WMT_TASK_INDX); + else + iRet = mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX); + + if (iRet != size) { + WMT_WARN_FUNC("write(%d) written(%d)\n", size, iRet); + osal_assert(iRet == size); + } + + if (writtenSize) + *writtenSize = iRet; + + return 0; + +} + +INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 type = pWmtCtrlData->au4CtrlData[0]; + + WMT_INFO_FUNC("flush rx %d queue\n", type); + mtk_wcn_stp_flush_rx_queue(type); + + return 0; +} + +INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iret; + +/*psm should be disabled before wmt_ic_deinit*/ + P_DEV_WMT pDev = &gDevWmt; + + if (osal_test_and_clear_bit(WMT_STAT_PWR, &pDev->state)) { + WMT_DBG_FUNC("on->off\n"); + iret = wmt_plat_pwr_ctrl(FUNC_OFF); + } else { + WMT_WARN_FUNC("already off\n"); + iret = 0; + } + + return iret; +} + +INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iret; + /*psm should be enabled right after wmt_ic_init */ + P_DEV_WMT pDev = &gDevWmt; + if (osal_test_and_set_bit(WMT_STAT_PWR, &pDev->state)) { + WMT_WARN_FUNC("already on\n"); + iret = 0; + } else { + WMT_DBG_FUNC("off->on\n"); + iret = wmt_plat_pwr_ctrl(FUNC_ON); + } + + return iret; +} + +INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const UINT8 *pCmdStr) +{ + INT32 waitRet = -1; + P_OSAL_SIGNAL pCmdSignal; + P_OSAL_EVENT pCmdReq; + + if (osal_test_and_set_bit(WMT_STAT_CMD, &pWmtDev->state)) { + WMT_WARN_FUNC("cmd buf is occupied by (%s)\n", pWmtDev->cCmd); + return -1; + } + + /* indicate baud rate change to user space app */ +#if 0 + INIT_COMPLETION(pWmtDev->cmd_comp); + pWmtDev->cmd_result = -1; + strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); + pWmtDev->cCmd[NAME_MAX] = '\0'; + wake_up_interruptible(&pWmtDev->cmd_wq); +#endif + + pCmdSignal = &pWmtDev->cmdResp; + osal_signal_init(pCmdSignal); + pCmdSignal->timeoutValue = 2000; + osal_strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); + pWmtDev->cCmd[NAME_MAX] = '\0'; + + pCmdReq = &pWmtDev->cmdReq; + + osal_trigger_event(&pWmtDev->cmdReq); + WMT_DBG_FUNC("str(%s) request ok\n", pCmdStr); + +/* waitRet = wait_for_completion_interruptible_timeout(&pWmtDev->cmd_comp, msecs_to_jiffies(2000)); */ + waitRet = osal_wait_for_signal_timeout(pCmdSignal); + WMT_LOUD_FUNC("wait signal iRet:%d\n", waitRet); + if (0 == waitRet) { + WMT_ERR_FUNC("wait signal timeout\n"); + return -2; + } + + WMT_DBG_FUNC("str(%s) result(%d)\n", pCmdStr, pWmtDev->cmdResult); + + return pWmtDev->cmdResult; +} + +INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA pWmtCtrlData) +{ + wmt_plat_pwr_ctrl(FUNC_RST); + return 0; +} + +INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData) +{ + wmt_plat_pwr_ctrl(FUNC_STAT); + return 0; +} + +INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet = 0; + /* un-register to STP-core for rx */ + iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, NULL); /* mtk_wcn_stp_register_event_cb */ + if (iRet) { + WMT_WARN_FUNC("stp_reg cb unregister fail(%d)\n", iRet); + return -1; + } + + /*un-register rxcb to btif */ + iRet = mtk_wcn_stp_rxcb_register(NULL); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_rxcb_unregister fail(%d)\n", iRet); + return -2; + } + + iRet = mtk_wcn_stp_close_btif(); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_close_btif fail(%d)\n", iRet); + return -3; + } + osal_clear_bit(WMT_STAT_STP_OPEN, &pDev->state); + + return 0; +} + +INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + + iRet = mtk_wcn_stp_open_btif(); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_open_btif fail(%d)\n", iRet); + return -1; + } + + /*register stp rx call back to btif */ + iRet = mtk_wcn_stp_rxcb_register((MTK_WCN_BTIF_RX_CB) mtk_wcn_stp_parser_data); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_rxcb_register fail(%d)\n", iRet); + return -2; + } + /* register to STP-core for rx */ + iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, wmt_dev_rx_event_cb); + if (iRet) { + WMT_WARN_FUNC("stp_reg cb fail(%d)\n", iRet); + return -3; + } + + osal_set_bit(WMT_STAT_STP_OPEN, &pDev->state); + +#if 0 + iRet = mtk_wcn_stp_lpbk_ctrl(1); +#endif + + return 0; +} + +INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + + osal_snprintf(cmdStr, NAME_MAX, "srh_patch"); + iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (iRet) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); + return -1; + } + return 0; +} + +INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + pWmtCtrlData->au4CtrlData[0] = pDev->patchNum; + return 0; +} + +INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + UINT32 downLoadSeq = 0; + P_WMT_PATCH_INFO pPatchinfo = NULL; + PUINT8 pNbuf = NULL; + PUINT8 pAbuf = NULL; + + downLoadSeq = pWmtCtrlData->au4CtrlData[0]; + WMT_DBG_FUNC("download seq is %d\n", downLoadSeq); + + pPatchinfo = pDev->pWmtPatchInfo + downLoadSeq - 1; + pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1]; + pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2]; + if (pPatchinfo) { + osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName)); + osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess)); + WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", pAbuf[0], pAbuf[1], pAbuf[2], pAbuf[3]); + } else { + WMT_ERR_FUNC("NULL patchinfo pointer\n"); + } + + return 0; +} + +INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + ENUM_PALDO_TYPE ept = pWmtCtrlData->au4CtrlData[0]; + ENUM_PALDO_OP epo = pWmtCtrlData->au4CtrlData[1]; + + WMT_DBG_FUNC("ept(%d),epo(%d)\n", ept, epo); + iRet = wmt_plat_soc_paldo_ctrl(ept, epo); + if (iRet) { + if (PMIC_CHIPID_PALDO == ept) { + /* special handling for PMIC CHIPID */ + pWmtCtrlData->au4CtrlData[2] = iRet; + } else { + /* for other PA handling */ + WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); + } + } + + return iRet; +} + +INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + + iRet = mtk_wcn_stp_wakeup_consys(); + if (iRet) + WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); + + return iRet; +} + +INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value) +{ + INT32 iRet = -1; + + switch (type) { + case WMT_STP_CONF_EN: + iRet = mtk_wcn_stp_enable(value); + break; + + case WMT_STP_CONF_RDY: + iRet = mtk_wcn_stp_ready(value); + break; + + case WMT_STP_CONF_MODE: + mtk_wcn_stp_set_mode(value); + iRet = 0; + break; + + default: + WMT_WARN_FUNC("invalid type(%d) value(%d)\n", type, value); + break; + } + return iRet; +} + +INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + UINT32 type; + UINT32 value; + + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { + WMT_WARN_FUNC("CTRL_STP_ENABLE but invalid Handle of WmtStp\n"); + return -1; + } + + type = pWmtCtrlData->au4CtrlData[0]; + value = pWmtCtrlData->au4CtrlData[1]; + iRet = wmt_ctrl_stp_conf_ex(type, value); + + if (!iRet) { + if (WMT_STP_CONF_EN == type) { + if (value) { + osal_set_bit(WMT_STAT_STP_EN, &pDev->state); + WMT_DBG_FUNC("enable STP\n"); + } else { + osal_clear_bit(WMT_STAT_STP_EN, &pDev->state); + WMT_DBG_FUNC("disable STP\n"); + } + } + } + + return iRet; +} + +INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 patchSeq = pWmtCtrlData->au4CtrlData[0]; + + WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); + if (NULL != gDevWmt.pPatch) + wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pPatch)); + + WMT_DBG_FUNC("AF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); + if (patchSeq == gDevWmt.patchNum) { + WMT_DBG_FUNC("the %d patch has been download\n", patchSeq); + wmt_dev_patch_info_free(); + } + return 0; +} + +INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData) +{ + PUINT8 pBuf = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + + osal_memcpy(pBuf, gDevWmt.cPatchName, osal_sizeof(gDevWmt.cPatchName)); + return 0; +} + +INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData) +{ + WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(0x%08x)\n", gDevWmt.pPatch); + if (NULL != gDevWmt.pNvram) + wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pNvram)); + + WMT_DBG_FUNC("AF free patch, gDevWmt.pNvram(0x%08x)\n", gDevWmt.pNvram); + return 0; +} + +INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0x0; + PUINT8 pFileName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[1]; + PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + + osal_firmware *pNvram = NULL; + + if ((NULL == pFileName) || (NULL == pSize)) { + WMT_ERR_FUNC("parameter error, pFileName(0x%08x), pSize(0x%08x)\n", pFileName, pSize); + iRet = -1; + return iRet; + } + if (0 == wmt_dev_patch_get(pFileName, &pNvram, 0)) { + *ppBuf = (PUINT8) (pNvram)->data; + *pSize = (pNvram)->size; + gDevWmt.pNvram = pNvram; + return 0; + } + return -1; + +} + +INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT8 *pFullPatchName = NULL; + UINT8 *pDefPatchName = NULL; + PUINT8 *ppBuf = (PUINT8 *) pWmtCtrlData->au4CtrlData[2]; + PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[3]; + + osal_firmware *pPatch = NULL; + + pFullPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[1]; + WMT_DBG_FUNC("BF get patch, pPatch(0x%08x)\n", pPatch); + if ((NULL != pFullPatchName) + && (0 == wmt_dev_patch_get(pFullPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { + /*get full name patch success */ + WMT_DBG_FUNC("get full patch name(%s) buf(0x%p) size(%d)\n", + pFullPatchName, (pPatch)->data, (pPatch)->size); + WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); + *ppBuf = (PUINT8) (pPatch)->data; + *pSize = (pPatch)->size; + gDevWmt.pPatch = pPatch; + return 0; + } + + pDefPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + if ((NULL != pDefPatchName) + && (0 == wmt_dev_patch_get(pDefPatchName, &pPatch, BCNT_PATCH_BUF_HEADROOM))) { + WMT_DBG_FUNC("get def patch name(%s) buf(0x%p) size(%d)\n", + pDefPatchName, (pPatch)->data, (pPatch)->size); + WMT_DBG_FUNC("AF get patch, pPatch(0x%08x)\n", pPatch); + /*get full name patch success */ + *ppBuf = (PUINT8) (pPatch)->data; + *pSize = (pPatch)->size; + gDevWmt.pPatch = pPatch; + return 0; + } + return -1; + +} + +/*do not need contol uart because B/G/F send/receive data by BTIF*/ +#if 0 +INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + char cmdStr[NAME_MAX + 1] = { 0 }; + UINT32 u4Baudrate = pWmtCtrlData->au4CtrlData[0]; + UINT32 u4FlowCtrl = pWmtCtrlData->au4CtrlData[1]; + + WMT_DBG_FUNC("baud(%d), flowctrl(%d)\n", u4Baudrate, u4FlowCtrl); + + if (osal_test_bit(WMT_STAT_STP_OPEN, &gDevWmt.state)) { + osal_snprintf(cmdStr, NAME_MAX, "baud_%d_%d", u4Baudrate, u4FlowCtrl); + iRet = wmt_ctrl_ul_cmd(&gDevWmt, cmdStr); + if (iRet) { + WMT_WARN_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) fail(%d)\n", + u4Baudrate, pWmtCtrlData->au4CtrlData[1], iRet); + } else { + WMT_DBG_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) ok\n", u4Baudrate, u4FlowCtrl); + } + } else { + WMT_INFO_FUNC("CTRL_BAUDRATE but invalid Handle of WmtStp\n"); + } + return iRet; +} +#endif +/*do not need control SDIO because wifi send/receive data by sdio*/ +#if 0 +INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + UINT32 statBit = WMT_STAT_SDIO1_ON; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + WMT_SDIO_SLOT_NUM sdioSlotNum = pWmtCtrlData->au4CtrlData[0]; + ENUM_FUNC_STATE funcState = pWmtCtrlData->au4CtrlData[1]; + + if ((WMT_SDIO_SLOT_INVALID == sdioSlotNum) + || (WMT_SDIO_SLOT_MAX <= sdioSlotNum)) { + WMT_WARN_FUNC("CTRL_SDIO_SLOT(%d) but invalid slot num\n", sdioSlotNum); + return -1; + } + + WMT_DBG_FUNC("WMT_CTRL_SDIO_HW (0x%x, %d)\n", sdioSlotNum, funcState); + + if (WMT_SDIO_SLOT_SDIO2 == sdioSlotNum) + statBit = WMT_STAT_SDIO2_ON; + + if (funcState) { + if (osal_test_and_set_bit(statBit, &pDev->state)) { + WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already ON\n", sdioSlotNum); + /* still return 0 */ + iRet = 0; + } else { + iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_ON); + } + } else { + if (osal_test_and_clear_bit(statBit, &pDev->state)) { + iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_OFF); + } else { + WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already OFF\n", sdioSlotNum); + /* still return 0 */ + iRet = 0; + } + } + + return iRet; +} + +INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + UINT32 statBit = WMT_STAT_SDIO_WIFI_ON; + INT32 retry = 10; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + WMT_SDIO_FUNC_TYPE sdioFuncType = pWmtCtrlData->au4CtrlData[0]; + UINT32 u4On = pWmtCtrlData->au4CtrlData[1]; + + if (WMT_SDIO_FUNC_MAX <= sdioFuncType) { + WMT_ERR_FUNC("CTRL_SDIO_FUNC, invalid func type (%d)\n", sdioFuncType); + return -1; + } + + if (WMT_SDIO_FUNC_STP == sdioFuncType) + statBit = WMT_STAT_SDIO_STP_ON; + + if (u4On) { + if (osal_test_bit(statBit, &pDev->state)) { + WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already ON\n", sdioFuncType); + iRet = 0; + } else { + while (retry-- > 0 && iRet != 0) { + if (iRet) { + /* sleep 150ms before sdio slot ON ready */ + osal_sleep_ms(150); + } + iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_TRUE); + if (HIF_SDIO_ERR_NOT_PROBED == iRet) { + /* not probed case, retry */ + continue; + } else if (HIF_SDIO_ERR_CLT_NOT_REG == iRet) { + /* For WiFi, client not reg yet, no need to retry, + *WiFi function can work any time when wlan.ko + *is insert into system + */ + iRet = 0; + } else { + /* other fail cases, stop */ + break; + } + } + if (!retry || iRet) { + WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, TRUE) fail(%d) retry(%d)\n", + sdioFuncType, iRet, retry); + } else { + osal_set_bit(statBit, &pDev->state); + } + } + } else { + if (osal_test_bit(statBit, &pDev->state)) { + iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_FALSE); + if (iRet) + WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, FALSE) fail(%d)\n", sdioFuncType, iRet); + /*any way, set to OFF state */ + osal_clear_bit(statBit, &pDev->state); + } else { + WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already OFF\n", sdioFuncType); + iRet = 0; + } + } + + return iRet; +} +#endif + + +INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + /* input sanity check is done in wmt_ctrl() */ + pDev->chip_id = (pWmtCtrlData->au4CtrlData[0] & 0xFFFF0000) >> 16; + pDev->hw_ver = pWmtCtrlData->au4CtrlData[0] & 0x0000FFFF; + pDev->fw_ver = pWmtCtrlData->au4CtrlData[1] & 0x0000FFFF; + + /* TODO: [FixMe][GeorgeKuo] remove translated ENUM_WMTHWVER_TYPE_T in the future!!! */ + /* Only use hw_ver read from hw. */ + pDev->eWmtHwVer = (ENUM_WMTHWVER_TYPE_T) (pWmtCtrlData->au4CtrlData[1] & 0xFFFF0000) >> 16; + + return 0; +} + +INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT8 *pRomVer = NULL; + P_WMT_PATCH pPatch = NULL; + UINT32 chipID = 0; + + chipID = pWmtCtrlData->au4CtrlData[0]; + pRomVer = (PUINT8) (pWmtCtrlData->au4CtrlData[1]); + pPatch = (P_WMT_PATCH) (pWmtCtrlData->au4CtrlData[2]); + if (!pRomVer) { + WMT_ERR_FUNC("pRomVer null pointer\n"); + return -1; + } + if (!pPatch) { + WMT_ERR_FUNC("pPatch null pointer\n"); + return -2; + } + WMT_DBG_FUNC("chipid(0x%x),rom(%s),patch date(%s),patch plat(%s)\n", chipID, pRomVer, pPatch->ucDateTime, + pPatch->ucPLat); + return stp_dbg_set_version_info(chipID, pRomVer, &(pPatch->ucDateTime[0]), &(pPatch->ucPLat[0])); +} + +static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 cmd = pWmtCtrlData->au4CtrlData[0]; + + WMT_INFO_FUNC("wmt-ctrl:send native cmd(%d)\n", cmd); + wmt_dev_send_cmd_to_daemon(cmd); + + return 0; +} + +static INT32 wmt_ctrl_evt_err_trg_assert(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + + ENUM_WMTDRV_TYPE_T drv_type; + UINT32 reason = 0; + + drv_type = pWmtCtrlData->au4CtrlData[0]; + reason = pWmtCtrlData->au4CtrlData[1]; + WMT_WARN_FUNC("wmt-ctrl:drv_type(%d),reason(%d)\n", drv_type, reason); + + if (0 == mtk_wcn_stp_get_wmt_evt_err_trg_assert()) { + mtk_wcn_stp_set_wmt_evt_err_trg_assert(1); + wmt_lib_set_host_assert_info(drv_type, reason, 1); + + iRet = mtk_wcn_stp_wmt_evt_err_trg_assert(); + if (iRet) + mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); + } else { + /* maybe assert triggered by stp noack*/ + WMT_INFO_FUNC("do trigger assert & chip reset in stp noack\n"); + } + return 0; +} + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 antsel_index = wmt_plat_get_tdm_antsel_index(); + + if (0 <= antsel_index) + pWmtCtrlData->au4CtrlData[0] = antsel_index; + else + pWmtCtrlData->au4CtrlData[0] = 0xff; + + WMT_INFO_FUNC("get tdm req antsel index is %d\n", antsel_index); + + return 0; +} +#endif + +static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 ret = -1; + UINT32 evt_idx = (UINT32) pWmtCtrlData->au4CtrlData[0]; + UINT8 *p_buf = NULL; + + static UINT8 sleep_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; + static UINT8 wakeup_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; + static UINT8 hostawake_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; + static UINT8 *evt_array[] = { sleep_evt, wakeup_evt, hostawake_evt }; + + p_buf = evt_array[evt_idx - 1]; + + WMT_INFO_FUNC("evt index:%d,p_buf:%p\n", evt_idx, p_buf); + + ret = mtk_wcn_consys_stp_btif_parser_wmt_evt(p_buf, 6); + if (ret == 1) { + WMT_INFO_FUNC("parser wmt evt from BTIF buf is OK\n"); + return 0; + } + WMT_ERR_FUNC("parser wmt evt from BTIF buf fail(%d)\n", ret); + return -1; +} + +static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData) +{ + INT32 iret; + + WMT_INFO_FUNC("ctrl GPS_SYNC(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); + iret = wmt_plat_gpio_ctrl(PIN_GPS_SYNC, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX); + + if (iret) { + WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", + (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_MUX, iret); + } + + return 0; +} + +static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData) +{ + INT32 iret; + + WMT_INFO_FUNC("ctrl GPS_LNA(%d)\n", (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); + iret = wmt_plat_gpio_ctrl(PIN_GPS_LNA, (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H); + + if (iret) { + WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", + (0 == pData->au4CtrlData[0]) ? PIN_STA_DEINIT : PIN_STA_OUT_H, iret); + } + + return 0; +} + +INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA pWmtCtrlData) +{ + return 0; +} + +INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + pWmtCtrlData->au4CtrlData[0] = (SIZE_T) &pDev->rWmtGenConf; + + return 0; +} + +INT32 wmt_ctrl_others(P_WMT_CTRL_DATA pWmtCtrlData) +{ + WMT_ERR_FUNC("wmt_ctrl_others, invalid CTRL ID (%d)\n", pWmtCtrlData->ctrlId); + return -1; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c new file mode 100644 index 0000000000000..d42d572c92922 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_func.c @@ -0,0 +1,713 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-FUNC]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" + +#include "wmt_func.h" +#include "wmt_lib.h" +#include "wmt_core.h" +#include "wmt_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CFG_FUNC_BT_SUPPORT + +static INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_bt_ops = { + /* BT subsystem function on/off */ + .func_on = wmt_func_bt_on, + .func_off = wmt_func_bt_off +}; +#endif + +#if CFG_FUNC_FM_SUPPORT + +static INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_fm_ops = { + /* FM subsystem function on/off */ + .func_on = wmt_func_fm_on, + .func_off = wmt_func_fm_off +}; +#endif + +#if CFG_FUNC_GPS_SUPPORT + +static INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_gps_ops = { + /* GPS subsystem function on/off */ + .func_on = wmt_func_gps_on, + .func_off = wmt_func_gps_off +}; + +#endif + +#if CFG_FUNC_WIFI_SUPPORT +static INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_wifi_ops = { + /* Wi-Fi subsystem function on/off */ + .func_on = wmt_func_wifi_on, + .func_off = wmt_func_wifi_off +}; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if CFG_FUNC_GPS_SUPPORT +CMB_PIN_CTRL_REG eediPinOhRegs[] = { + { + /* pull down ctrl register */ + .regAddr = 0x80050020, + .regValue = ~(0x1 << 5), + .regMask = 0x00000020, + }, + { + /* pull up ctrl register */ + .regAddr = 0x80050000, + .regValue = 0x1 << 5, + .regMask = 0x00000020, + }, + { + /* iomode ctrl register */ + .regAddr = 0x80050110, + .regValue = 0x1 << 0, + .regMask = 0x00000007, + }, + { + /* output high/low ctrl register */ + .regAddr = 0x80050040, + .regValue = 0x1 << 5, + .regMask = 0x00000020, + } + +}; + +CMB_PIN_CTRL_REG eediPinOlRegs[] = { + { + .regAddr = 0x80050020, + .regValue = 0x1 << 5, + .regMask = 0x00000020UL, + }, + { + .regAddr = 0x80050000, + .regValue = ~(0x1 << 5), + .regMask = 0x00000020, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1 << 0, + .regMask = 0x00000007, + }, + { + .regAddr = 0x80050040, + .regValue = ~(0x1 << 5), + .regMask = 0x00000020, + } +}; + +CMB_PIN_CTRL_REG eedoPinOhRegs[] = { + { + .regAddr = 0x80050020, + .regValue = ~(0x1 << 7), + .regMask = 0x00000080UL, + }, + { + .regAddr = 0x80050000, + .regValue = 0x1 << 7, + .regMask = 0x00000080UL, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1 << 12, + .regMask = 0x00007000UL, + }, + { + .regAddr = 0x80050040, + .regValue = 0x1 << 7, + .regMask = 0x00000080, + } +}; + +CMB_PIN_CTRL_REG eedoPinOlRegs[] = { + { + .regAddr = 0x80050020, + .regValue = 0x1 << 7, + .regMask = 0x00000080, + }, + { + .regAddr = 0x80050000, + .regValue = ~(0x1 << 7), + .regMask = 0x00000080, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1 << 12, + .regMask = 0x00007000, + }, + { + .regAddr = 0x80050040, + .regValue = ~(0x1 << 7), + .regMask = 0x00000080, + } + +}; + +CMB_PIN_CTRL_REG gsyncPinOnRegs[] = { + { + .regAddr = 0x80050110, + .regValue = 0x3 << 20, + .regMask = 0x7 << 20, + } + +}; + +CMB_PIN_CTRL_REG gsyncPinOffRegs[] = { + { + .regAddr = 0x80050110, + .regValue = 0x0 << 20, + .regMask = 0x7 << 20, + } +}; + +/* templete usage for GPIO control */ +CMB_PIN_CTRL gCmbPinCtrl[3] = { + { + .pinId = CMB_PIN_EEDI_ID, + .regNum = 4, + .pFuncOnArray = eediPinOhRegs, + .pFuncOffArray = eediPinOlRegs, + }, + { + .pinId = CMB_PIN_EEDO_ID, + .regNum = 4, + .pFuncOnArray = eedoPinOhRegs, + .pFuncOffArray = eedoPinOlRegs, + }, + { + .pinId = CMB_PIN_GSYNC_ID, + .regNum = 1, + .pFuncOnArray = gsyncPinOnRegs, + .pFuncOffArray = gsyncPinOffRegs, + } +}; +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if CFG_FUNC_BT_SUPPORT + +INT32 _osal_inline_ wmt_func_bt_ctrl(ENUM_FUNC_STATE funcState) +{ + /*only need to send turn BT subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + /* return wmt_func_bt_ctrl(FUNC_ON); */ + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl failed(%d)(%d)(%d)\n", iRet, ctrlPa1, ctrlPa2); + return -1; + } + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE); + if (iRet) { + WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_on) failed(%d)\n", iRet); + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + /*do coredump when bt on fail */ + wmt_core_set_coredump_state(DRV_STS_FUNC_ON); + ctrlPa1 = WMTDRV_TYPE_BT; + ctrlPa2 = 32; + wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); + return -2; + } + osal_set_bit(WMT_BT_ON, &gBtWifiGpsState); + if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + return 0; +} + +INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + /* return wmt_func_bt_ctrl(FUNC_OFF); */ + INT32 iRet1 = -1; + INT32 iRet2 = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + iRet1 = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE); + if (iRet1) + WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_off) failed(%d)\n", iRet1); + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet2 = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet2) + WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl(bt_off) failed(%d)\n", iRet2); + + if (iRet1 + iRet2) { + /*do coredump when bt off fail */ + wmt_core_set_coredump_state(DRV_STS_FUNC_ON); + ctrlPa1 = WMTDRV_TYPE_BT; + ctrlPa2 = 32; + wmt_core_ctrl(WMT_CTRL_EVT_ERR_TRG_ASSERT, &ctrlPa1, &ctrlPa2); + return -1; + } + + osal_clear_bit(WMT_BT_ON, &gBtWifiGpsState); + if ((!osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stopping send de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + return 0; +} + +#endif + +#if CFG_FUNC_GPS_SUPPORT + +INT32 _osal_inline_ wmt_func_gps_ctrl(ENUM_FUNC_STATE funcState) +{ + /*send turn GPS subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_GPS, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_gps_pre_ctrl(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf, ENUM_FUNC_STATE funcStatus) +{ + UINT32 i = 0; + INT32 iRet = 0; + UINT32 regAddr = 0; + UINT32 regValue = 0; + UINT32 regMask = 0; + UINT32 regNum = 0; + P_CMB_PIN_CTRL_REG pReg; + P_CMB_PIN_CTRL pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; + WMT_CTRL_DATA ctrlData; + WMT_IC_PIN_ID wmtIcPinId = WMT_IC_PIN_MAX; + /* sanity check */ + if (FUNC_ON != funcStatus && FUNC_OFF != funcStatus) { + WMT_ERR_FUNC("invalid funcStatus(%d)\n", funcStatus); + return -1; + } + /* turn on GPS sync function on both side */ + ctrlData.ctrlId = WMT_CTRL_GPS_SYNC_SET; + ctrlData.au4CtrlData[0] = (FUNC_ON == funcStatus) ? 1 : 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /*we suppose this would never print */ + WMT_ERR_FUNC("ctrl GPS_SYNC_SET(%d) fail, ret(%d)\n", funcStatus, iRet); + /* TODO:[FixMe][George] error handling? */ + return -2; + } + WMT_INFO_FUNC("ctrl GPS_SYNC_SET(%d) ok\n", funcStatus); + + + if ((NULL == pOps->ic_pin_ctrl) || + (0 > pOps->ic_pin_ctrl( + WMT_IC_PIN_GSYNC, + FUNC_ON == funcStatus ? WMT_IC_PIN_MUX : WMT_IC_PIN_GPIO, + 1))) { /*WMT_IC_PIN_GSYNC */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; + regNum = pCmbPinCtrl->regNum; + for (i = 0; i < regNum; i++) { + if (FUNC_ON == funcStatus) + pReg = &pCmbPinCtrl->pFuncOnArray[i]; + else + pReg = &pCmbPinCtrl->pFuncOffArray[i]; + + regAddr = pReg->regAddr; + regValue = pReg->regValue; + regMask = pReg->regMask; + + iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); + if (iRet) { + WMT_ERR_FUNC("set reg for GPS_SYNC function fail(%d)\n", iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -2; + } + + } + } else { + WMT_INFO_FUNC("set reg for GPS_SYNC function okay by chip ic_pin_ctrl\n"); + } + WMT_INFO_FUNC("ctrl combo chip gps sync function succeed\n"); + /* turn on GPS lna ctrl function */ + if (NULL != pConf) { + if (0 == pConf->wmt_gps_lna_enable) { + + WMT_INFO_FUNC("host pin used for gps lna\n"); + /* host LNA ctrl pin needed */ + ctrlData.ctrlId = WMT_CTRL_GPS_LNA_SET; + ctrlData.au4CtrlData[0] = FUNC_ON == funcStatus ? 1 : 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /*we suppose this would never print */ + WMT_ERR_FUNC("ctrl host GPS_LNA output high fail, ret(%d)\n", iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -3; + } + WMT_INFO_FUNC("ctrl host gps lna function succeed\n"); + } else { + WMT_INFO_FUNC("combo chip pin(%s) used for gps lna\n", + 0 == pConf->wmt_gps_lna_pin ? "EEDI" : "EEDO"); + wmtIcPinId = 0 == pConf->wmt_gps_lna_pin ? WMT_IC_PIN_EEDI : WMT_IC_PIN_EEDO; + if ((NULL == pOps->ic_pin_ctrl) || + (0 > pOps->ic_pin_ctrl( + wmtIcPinId, + FUNC_ON == funcStatus ? WMT_IC_PIN_GPIO_HIGH : WMT_IC_PIN_GPIO_LOW, + 1))) { /*WMT_IC_PIN_GSYNC */ + if (0 == pConf->wmt_gps_lna_pin) { + /* EEDI needed */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDI_ID]; + } else if (1 == pConf->wmt_gps_lna_pin) { + /* EEDO needed */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDO_ID]; + } + regNum = pCmbPinCtrl->regNum; + for (i = 0; i < regNum; i++) { + if (FUNC_ON == funcStatus) + pReg = &pCmbPinCtrl->pFuncOnArray[i]; + else + pReg = &pCmbPinCtrl->pFuncOffArray[i]; + regAddr = pReg->regAddr; + regValue = pReg->regValue; + regMask = pReg->regMask; + + iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); + if (iRet) { + WMT_ERR_FUNC("set reg for GPS_LNA function fail(%d)\n", iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -3; + } + } + WMT_INFO_FUNC("ctrl combo chip gps lna succeed\n"); + } else { + WMT_INFO_FUNC("set reg for GPS_LNA function okay by chip ic_pin_ctrl\n"); + } + } + } + return 0; + +} + +INT32 wmt_func_gps_pre_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_ON); +} + +INT32 wmt_func_gps_pre_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + + return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_OFF); +} + +INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ + if (!osal_test_bit(WMT_FM_ON, &gGpsFmState)) { + ctrlPa1 = GPS_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_INFO_FUNC("LDO VCN28 has been turn on by FM\n"); + } + } + + iRet = wmt_func_gps_pre_on(pOps, pConf); + if (0 == iRet) { + iRet = wmt_func_gps_ctrl(FUNC_ON); + if (!iRet) { + osal_set_bit(WMT_GPS_ON, &gBtWifiGpsState); + if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) + || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + + if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) /* use SOC external LNA */ + osal_set_bit(WMT_GPS_ON, &gGpsFmState); + } + } + return iRet; +} + +INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + iRet = wmt_func_gps_pre_off(pOps, pConf); + if (0 == iRet) { + iRet = wmt_func_gps_ctrl(FUNC_OFF); + if (!iRet) { + osal_clear_bit(WMT_GPS_ON, &gBtWifiGpsState); + if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) + || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stop sending de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + } + + if ((co_clock_type) && (0 == pConf->wmt_gps_lna_enable)) { /* use SOC external LNA */ + if (osal_test_bit(WMT_FM_ON, &gGpsFmState)) + WMT_INFO_FUNC("FM is still on, do not turn off LDO VCN28\n"); + else { + ctrlPa1 = GPS_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } + + osal_clear_bit(WMT_GPS_ON, &gGpsFmState); + } + + return iRet; + +} +#endif + +#if CFG_FUNC_FM_SUPPORT + +INT32 _osal_inline_ wmt_func_fm_ctrl(ENUM_FUNC_STATE funcState) +{ + /*only need to send turn FM subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, (FUNC_ON == funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + /* return wmt_func_fm_ctrl(FUNC_ON); */ + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + INT32 iRet = -1; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if (co_clock_type) { + if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { + ctrlPa1 = FM_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_INFO_FUNC("LDO VCN28 has been turn on by GPS\n"); + } + } + + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE); + if (!iRet) { + if (co_clock_type) + osal_set_bit(WMT_FM_ON, &gGpsFmState); + } + + return iRet; +} + +INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + /* return wmt_func_fm_ctrl(FUNC_OFF); */ + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + INT32 iRet = -1; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE); + + if (co_clock_type) { + if (osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { + WMT_INFO_FUNC("GPS is still on, do not turn off LDO VCN28\n"); + } else { + ctrlPa1 = FM_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } + + osal_clear_bit(WMT_FM_ON, &gGpsFmState); + } + + return iRet; +} + +#endif + +#if CFG_FUNC_WIFI_SUPPORT + +/*in soc, wmt turn on wifi directly, no not need operate SDIO*/ +#if 0 +INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState) +{ + INT32 iRet = 0; + unsigned long ctrlPa1 = WMT_SDIO_FUNC_WIFI; + unsigned long ctrlPa2 = (FUNC_ON == funcState) ? 1 : 0; /* turn on Wi-Fi driver */ + + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: turn on WIFI function fail (%d)", iRet); + return -1; + } + return 0; +} +#endif + +INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + int iRet = 0; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + if (NULL != mtk_wcn_wlan_probe) { + + WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan probe\n"); + iRet = (*mtk_wcn_wlan_probe) (); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: wmt call wlan probe fail(%d)\n", iRet); + iRet = -1; + } else { + WMT_WARN_FUNC("WMT-FUNC: wmt call wlan probe ok\n"); + } + } else { + WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_probe\n"); + gWifiProbed = 1; + iRet = -2; + } + + if (!iRet) { + osal_set_bit(WMT_WIFI_ON, &gBtWifiGpsState); + if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + return iRet; +#if 0 + return wmt_func_wifi_ctrl(FUNC_ON); +#endif +} + +INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + int iRet = 0; + + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + + if (NULL != mtk_wcn_wlan_remove) { + + WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan remove\n"); + iRet = (*mtk_wcn_wlan_remove) (); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: wmt call wlan remove fail(%d)\n", iRet); + iRet = -1; + } else { + WMT_WARN_FUNC("WMT-FUNC: wmt call wlan remove ok\n"); + } + } else { + WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_remove\n"); + iRet = -2; + } + + if (!iRet) { + osal_clear_bit(WMT_WIFI_ON, &gBtWifiGpsState); + if ((!osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stopping send de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + return iRet; +#if 0 + return wmt_func_wifi_ctrl(FUNC_OFF); +#endif +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c new file mode 100644 index 0000000000000..c07052bce8e6d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_ic_soc.c @@ -0,0 +1,2452 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" +#define CFG_IC_SOC 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need + * after coex command is downconfirmed by LC, + */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_SUBSYS_COEX_NEED 0 + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#define CFG_WMT_MULTI_PATCH (1) + +#define CFG_WMT_CRYSTAL_TIMING_SET (0) + +#define CFG_WMT_SDIO_DRIVING_SET (0) + +#define CFG_WMT_UART_HIF_USE (0) + +#define CFG_WMT_WIFI_5G_SUPPORT (1) + +#define CFG_WMT_PATCH_DL_OPTM (1) +#if CFG_WMT_LTE_COEX_HANDLING +#define CFG_WMT_FILTER_MODE_SETTING (1) +#else +#define CFG_WMT_FILTER_MODE_SETTING (0) +#endif +#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT (0) + +#define CFG_WMT_POWER_ON_DLM (1) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_soc_info; +static WMT_PATCH gp_soc_patch_info; +static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; +#if 0 +static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; +static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; + +static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; +static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; +#endif + +#if CFG_WMT_UART_HIF_USE +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; +#endif +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +/*soc patial patch address cmd & evt need firmware owner provide*/ +#if CFG_WMT_MULTI_PATCH +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x3c, 0x02, 0x09, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0xc4, 0x04, 0x09, 0x02, + 0x00, 0x3f, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_SUBSYS_COEX_NEED +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; +static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; + +#if 0 +static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; +static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; +#endif + +#if 0 +/* to enable dump feature */ +static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 }; +static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get task and system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get bt related memory dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A }; +static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; +#endif +/* to get full dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; +static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_START_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x1, 0x00, 0x01 }; +static UINT8 WMT_CORE_START_RF_CALIBRATION_EVT[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x01 }; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */ + , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */ + , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */ + , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */ + , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; +#endif + +#if !(CFG_IC_SOC) /* For MT6628 no need to set ALLEINT registers, done in f/w */ +/* enable all interrupt */ +static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ + , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ + , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ +}; + +static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +#endif + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +#if 1 /* Ray */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#elif 0 /* KC */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ + , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ + , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ + , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ + , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ + , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ + , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ + , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ + , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ +}; +#endif +#endif + +#if CFG_WMT_CRYSTAL_TIMING_SET +static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; + +static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; +static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; +#endif + +#ifdef CFG_WMT_READ_EFUSE_VCN33 +static UINT8 WMT_GET_EFUSE_VCN33_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x04, 0x00 }; +static UINT8 WMT_GET_EFUSE_VCN33_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x04, 0x00 }; +#endif + +/* set sdio driving */ +#if CFG_WMT_SDIO_DRIVING_SET +static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ + , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ + , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ +}; + +static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; +#endif + +#if CFG_WMT_WIFI_5G_SUPPORT +static UINT8 WMT_GET_SOC_ADIE_CHIPID_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; +static UINT8 WMT_GET_SOC_ADIE_CHIPID_EVT[] = { + 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_GET_SOC_6625_L_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x20, 0x01 }; +static UINT8 WMT_GET_SOC_6625_L_EVT[] = { + 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x20, + 0x01, 0x00, 0x00, 0x00, 0x00 +}; +#endif + +#if CFG_WMT_PATCH_DL_OPTM +static UINT8 WMT_SET_MCU_CLK_EN_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x34, 0x03, 0x00, 0x80, + 0x00, 0x00, 0x01, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_EN_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_138_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, + 0x59, 0x4d, 0x84, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_138_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_26_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, + 0x00, 0x4d, 0x84, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_26_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_DIS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x34, 0x03, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_DIS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +/*only for 6797,enable high clock frequency*/ +/*CLK EN*/ +static UINT8 WMT_SET_MCU_CLK_EN_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x10 +}; +/*RATIO SET*/ +static UINT8 WMT_SET_MCU_RATIO_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00 +}; +/*DIV SET*/ +static UINT8 WMT_SET_MCU_DIV_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x18, 0x11, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00 +}; +/*HCLK SET*/ +static UINT8 WMT_SET_MCU_HCLK_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x00, 0x11, 0x02, 0x81, 0x04, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00 +}; + +/*Change clock to 26MHz*/ +/*HCLK DIS*/ +static UINT8 WMT_SET_MCU_HCLK_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x00, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00 +}; +/*RATIO DIS*/ +static UINT8 WMT_SET_MCU_RATIO_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00 +}; +/*CLK DIS*/ +static UINT8 WMT_SET_MCU_CLK_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10 +}; + +static UINT8 WMT_SET_MCU_CLK_EVT_6797[] = { + 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 +}; + +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = {0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00}; +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, + 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x00, 0x0a, 0x0c, 0x0e, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xd4, + 0x09, 0xe3, 0x09, 0x5a, 0x0a, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x60, 0x09, 0xd3, 0x09, 0xe2, + 0x09, 0x59, 0x0a, 0x8B, 0x0a}; +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; +static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; + +#if 0 +static UINT8 WMT_COEX_SPLIT_FILTER_CMD_TEST[] = { + 0x01, 0x10, 0x19, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x6c, 0x09, 0x8a, 0x09, 0x8a, 0x09, 0x9e, + 0x09, 0x01, 0x07, 0x07, 0x0b, 0x07, 0x07, 0x00, + 0x32, 0x27, 0x4e, 0x27, 0x32 +}; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x07, 0x07, 0x07, 0x54, 0x54, 0x00, 0x00, + 0x00, 0x50, 0x50, 0x50, 0x54, 0x54, 0x39, 0x39, + 0x39, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, + 0x09, 0xf6, 0x09, 0x0f, 0xaf, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, + 0x09, 0x0d, 0x0a, 0x27, 0x0a +}; +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; +static UINT8 WMT_COEX_EXT_COMPONENT_CMD_TEST[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x7f, 0x03 }; +#endif + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_0[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x63, 0x3c, 0x3c, 0x3c, + 0x3c, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, + 0x09, 0xf6, 0x09, 0x0f, 0x0a, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, + 0x09, 0x0d, 0x0a, 0x27, 0x0a +}; +static UINT8 WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x14, 0x00 }; +static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; +static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_6752[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, + 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x0E, 0x0E, 0x0E, 0x00, 0x0A, 0x0C, 0x0E, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xFC, 0x08, 0x15, + 0x09, 0x2E, 0x09, 0x47, 0x09, 0xC4, 0x09, 0xD4, + 0x09, 0xE3, 0x09, 0x5A, 0x0A, 0x14, 0x09, 0x2D, + 0x09, 0x46, 0x09, 0x60, 0x09, 0xD3, 0x09, 0xE2, + 0x09, 0x59, 0x0A, 0x8B, 0x0A +}; +#endif + +#if CFG_WMT_POWER_ON_DLM +static UINT8 WMT_POWER_CTRL_DLM_CMD1[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x00, 0x00 +}; + +static UINT8 WMT_POWER_CTRL_DLM_CMD2[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x00, 0x00, 0x00 +}; + +static UINT8 WMT_POWER_CTRL_DLM_CMD3[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_POWER_CTRL_DLM_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +#if (!CFG_IC_SOC) + +/* stp sdio init scripts */ +static struct init_script init_table_1_1[] = { + /* table_1_1 is only applied to common SDIO interface */ + INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), + /* applied to MT6628 ? */ + INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), +}; + +#endif + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), +}; + +#if CFG_WMT_UART_HIF_USE +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; +#endif + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +#if CFG_WMT_CRYSTAL_TIMING_SET +static struct init_script set_crystal_timing_script[] = { + INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, "set crystal trim value"), +}; + +static struct init_script get_crystal_timing_script[] = { + INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, "get crystal trim value"), +}; +#endif +#ifdef CFG_WMT_READ_EFUSE_VCN33 +static struct init_script get_efuse_vcn33_script[] = { + INIT_CMD(WMT_GET_EFUSE_VCN33_CMD, WMT_GET_EFUSE_VCN33_EVT, "get efuse vcn33 value"), +}; +#endif + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT, "query stp"), +}; + +static struct init_script init_table_5_1[] = { + INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), +}; + +static struct init_script init_table_6[] = { + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + +static struct init_script calibration_table[] = { + INIT_CMD(WMT_CORE_START_RF_CALIBRATION_CMD, WMT_CORE_START_RF_CALIBRATION_EVT, "start RF calibration data"), +}; + +#if CFG_WMT_PATCH_DL_OPTM +static struct init_script set_mcuclk_table_1[] = { + INIT_CMD(WMT_SET_MCU_CLK_EN_CMD, WMT_SET_MCU_CLK_EN_EVT, "enable set mcu clk"), + INIT_CMD(WMT_SET_MCU_CLK_138_CMD, WMT_SET_MCU_CLK_138_EVT, "set mcu clk to 138.67MH"), +}; + +static struct init_script set_mcuclk_table_2[] = { + INIT_CMD(WMT_SET_MCU_CLK_26_CMD, WMT_SET_MCU_CLK_26_EVT, "set mcu clk to 26MH"), + INIT_CMD(WMT_SET_MCU_CLK_DIS_CMD, WMT_SET_MCU_CLK_DIS_EVT, "disable set mcu clk"), +}; + +static struct init_script set_mcuclk_table_3[] = { + INIT_CMD(WMT_SET_MCU_CLK_EN_6797, WMT_SET_MCU_CLK_EVT_6797, "enable set mcu clk"), + INIT_CMD(WMT_SET_MCU_RATIO_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu ratio set"), + INIT_CMD(WMT_SET_MCU_DIV_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu div set"), + INIT_CMD(WMT_SET_MCU_HCLK_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "set mcu clk to hclk"), +}; +static struct init_script set_mcuclk_table_4[] = { + INIT_CMD(WMT_SET_MCU_HCLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu hclk"), + INIT_CMD(WMT_SET_MCU_RATIO_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu ratio set"), + INIT_CMD(WMT_SET_MCU_CLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu clk set"), +}; + +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +static struct init_script set_wifi_lte_coex_table_1[] = { + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"), +}; + +static struct init_script set_wifi_lte_coex_table_2[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), +}; + +static struct init_script set_wifi_lte_coex_table_0[] = { +#if 0 + INIT_CMD(WMT_COEX_SPLIT_FILTER_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex split filter"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte channel unsafe"), + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi coex ext component"), +#endif + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte freq idx"), +}; + +static struct init_script get_tdm_req_antsel_num_table[] = { + INIT_CMD(WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD, WMT_COEX_SPLIT_MODE_EVT, "get tdm req antsel num"), +}; +#endif + +#if CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + +#if CFG_SUBSYS_COEX_NEED +/* no need in MT6628 */ + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +#endif +}; + +static struct init_script osc_type_table[] = { + INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), +}; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static struct init_script merge_pcm_table[] = { + INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"), + INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"), + INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"), +}; +#endif + +#if CFG_WMT_SDIO_DRIVING_SET +static struct init_script sdio_driving_table[] = { + INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), +}; +#endif + +#if CFG_WMT_POWER_ON_DLM +static struct init_script wmt_power_on_dlm_table[] = { + INIT_CMD(WMT_POWER_CTRL_DLM_CMD1, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd1"), + INIT_CMD(WMT_POWER_CTRL_DLM_CMD2, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd2"), + INIT_CMD(WMT_POWER_CTRL_DLM_CMD3, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd3") +}; +#endif + +/* SOC Chip Version and Info Table */ +static const WMT_IC_INFO_S mtk_wcn_soc_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + /* need to refine? */ + .eWmtHwVer = WMTHWVER_E1, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A01, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .eWmtHwVer = WMTHWVER_E2, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B01, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .eWmtHwVer = WMTHWVER_E3, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + } +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mtk_wcn_soc_ver_check(VOID); + +static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID); +#endif + +#if CFG_WMT_MULTI_PATCH +static INT32 mtk_wcn_soc_patch_dwn(UINT32 index); +static INT32 mtk_wcn_soc_patch_info_prepare(VOID); +#else +static INT32 mtk_wcn_soc_patch_dwn(VOID); +#endif + +static INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on); +static WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID); + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mtk_wcn_soc_crystal_triming_set(VOID); +#endif + +static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID); + +#if CFG_WMT_SDIO_DRIVING_SET +static INT32 mtk_wcn_soc_set_sdio_driving(void); +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* SOC Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_soc = { + .icId = 0x0000, /* soc may have mt6572/82/71/83,but they have the same sw init flow */ + .sw_init = mtk_wcn_soc_sw_init, + .sw_deinit = mtk_wcn_soc_sw_deinit, + .ic_pin_ctrl = mtk_wcn_soc_pin_ctrl, + .ic_ver_check = mtk_wcn_soc_ver_check, + .co_clock_ctrl = mtk_wcn_soc_co_clock_ctrl, + .is_quick_sleep = mtk_wcn_soc_quick_sleep_flag_get, + .is_aee_dump_support = mtk_wcn_soc_aee_dump_flag_get, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT32 hw_ver; + WMT_CTRL_DATA ctrlData; +#ifdef CFG_WMT_READ_EFUSE_VCN33 + UINT32 efuse_d3_vcn33 = 2; /*default voltage is 3.5V*/ +#endif +#if CFG_WMT_MULTI_PATCH + UINT32 patch_num = 0; + UINT32 patch_index = 0; +#endif +#if CFG_WMT_WIFI_5G_SUPPORT + UINT32 dDieChipid = 0; + UINT32 aDieChipid = 0; + UINT8 evtbuf[20]; + UINT32 u4Res; + UINT32 pmicChipid = 0; +#endif + WMT_DBG_FUNC(" start\n"); + + osal_assert(NULL != gp_soc_info); + if ((NULL == gp_soc_info) + || (NULL == pWmtHifConf) + ) { + WMT_ERR_FUNC("null pointers: gp_soc_info(0x%p), pWmtHifConf(0x%p)\n", gp_soc_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_soc_info->u4HwVer; + + /* 4 <3.2> start init for BTIF */ + if (WMT_HIF_BTIF == pWmtHifConf->hifType) { + /* 1. Query chip STP default options (TEST-ONLY) */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ + iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + /* 2. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -3; + } + + /* 3. Enable host full mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("enable host STP-BTIF-FULL mode fail(%d)\n", iRet); + return -4; + } + WMT_DBG_FUNC("enable host STP-BTIF-FULL mode\n"); + /*4. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 5. Query chip STP options (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -5; + } + } +#if CFG_WMT_POWER_ON_DLM + iRet = wmt_core_init_script(wmt_power_on_dlm_table, osal_array_size(wmt_power_on_dlm_table)); + if (iRet) + WMT_ERR_FUNC("wmt_power_on_dlm_table fail(%d)\n", iRet); + WMT_DBG_FUNC("wmt_power_on_dlm_table ok\n"); +#endif + /* 6. download patch */ +#if CFG_WMT_MULTI_PATCH + /* 6.1 Let launcher to search patch info */ + iRet = mtk_wcn_soc_patch_info_prepare(); + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -6; + } + + /* 6.2 Read patch number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + patch_num = ctrlPa1; + WMT_DBG_FUNC("patch total num = [%d]\n", patch_num); + +#if CFG_WMT_PATCH_DL_OPTM + if (0x0279 == wmt_ic_ops_soc.icId) { + iRet = wmt_core_init_script(set_mcuclk_table_3, osal_array_size(set_mcuclk_table_3)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_3 fail(%d)\n", iRet); + } else { + iRet = wmt_core_init_script(set_mcuclk_table_1, osal_array_size(set_mcuclk_table_1)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_1 fail(%d)\n", iRet); + } +#endif + /* 6.3 Multi-patch Patch download */ + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mtk_wcn_soc_patch_dwn(patch_index); + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -7; + } + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -8; + } + } + +#if CFG_WMT_PATCH_DL_OPTM + if (0x0279 == wmt_ic_ops_soc.icId) { + iRet = wmt_core_init_script(set_mcuclk_table_4, osal_array_size(set_mcuclk_table_4)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_4 fail(%d)\n", iRet); + } else { + iRet = wmt_core_init_script(set_mcuclk_table_2, osal_array_size(set_mcuclk_table_2)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_2 fail(%d)\n", iRet); + } +#endif + +#else + /* 6.3 Patch download */ + iRet = mtk_wcn_soc_patch_dwn(); + /* If patch download fail, we just ignore this error and let chip init process goes on */ + if (iRet) + WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); + + /* 6.4. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -8; + } +#endif + +#ifdef CFG_WMT_READ_EFUSE_VCN33 + /*get CrystalTiming value before set it */ + iRet = wmt_core_tx(get_efuse_vcn33_script[0].cmd, get_efuse_vcn33_script[0].cmdSz, &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != get_efuse_vcn33_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].cmdSz); + } + /* EVENT BUF */ + osal_memset(get_efuse_vcn33_script[0].evt, 0, get_efuse_vcn33_script[0].evtSz); + iRet = wmt_core_rx(get_efuse_vcn33_script[0].evt, get_efuse_vcn33_script[0].evtSz, &u4Res); + if (iRet || (u4Res != get_efuse_vcn33_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + } + efuse_d3_vcn33 = WMT_GET_EFUSE_VCN33_EVT[5] & 0x03; + WMT_INFO_FUNC("Read efuse to set PMIC voltage:(%d)\n", efuse_d3_vcn33); + wmt_set_pmic_voltage(efuse_d3_vcn33); +#endif + +#if CFG_WMT_FILTER_MODE_SETTING + if ((0x6580 == wmt_ic_ops_soc.icId) || + (0x8163 == wmt_ic_ops_soc.icId) || + (0x6752 == wmt_ic_ops_soc.icId) || + (0x6582 == wmt_ic_ops_soc.icId) || + (0x6592 == wmt_ic_ops_soc.icId) || + (0x0279 == wmt_ic_ops_soc.icId) || + (0x0326 == wmt_ic_ops_soc.icId) || + (0x0321 == wmt_ic_ops_soc.icId) || (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { + wmt_stp_wifi_lte_coex(); + WMT_DBG_FUNC("wmt_stp_wifi_lte_coex done!\n"); + } + if ((0x6582 == wmt_ic_ops_soc.icId) || (0x6592 == wmt_ic_ops_soc.icId)) { + /*get gpio tdm req antsel number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_TDM_REQ_ANTSEL, &ctrlPa1, &ctrlPa2); + WMT_INFO_FUNC("get GPIO TDM REQ ANTSEL number(%d)\n", ctrlPa1); + /*set gpio tdm req antsel number to firmware */ + WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[5] = ctrlPa1; + iRet = wmt_core_init_script(get_tdm_req_antsel_num_table, + osal_array_size(get_tdm_req_antsel_num_table)); + if (iRet) + WMT_ERR_FUNC("get_tdm_req_antsel_num_table fail(%d)\n", iRet); + } +#endif + /* 7. start RF calibration data */ + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WIFI_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + iRet = wmt_core_init_script(calibration_table, osal_array_size(calibration_table)); + if (iRet) { + /* pwrap_read(0x0210,&ctrlPa1); */ + /* pwrap_read(0x0212,&ctrlPa2); */ + WMT_ERR_FUNC("power status: 210:(%d),212:(%d)!\n", ctrlPa1, ctrlPa2); + WMT_ERR_FUNC("calibration_table fail(%d)\n", iRet); + return -9; + } + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WIFI_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_DBG_FUNC("init_coex ok\n"); + +#if CFG_WMT_CRYSTAL_TIMING_SET + mtk_wcn_soc_crystal_triming_set(); +#endif + +#if CFG_WMT_SDIO_DRIVING_SET + mtk_wcn_soc_set_sdio_driving(); +#endif + + if (WMT_CO_CLOCK_EN == mtk_wcn_soc_co_clock_get()) { + WMT_INFO_FUNC("co-clock enabled.\n"); + + iRet = wmt_core_init_script(osc_type_table, osal_array_size(osc_type_table)); + if (iRet) { + WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); + return -11; + } + } else { + WMT_WARN_FUNC("co-clock disabled.\n"); + } +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + iRet = wmt_core_init_script(merge_pcm_table, osal_array_size(merge_pcm_table)); + if (iRet) { + WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); + return -12; + } +#endif + + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", pWmtHifConf->au4StrapConf[0], iRet); + return -13; + } + WMT_DBG_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -14; + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + if (0 != mtk_wcn_stp_coredump_flag_get()) { + iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -15; + } + WMT_DBG_FUNC("enable soc_consys firmware coredump\n"); + } else { + WMT_DBG_FUNC("disable soc_consys firmware coredump\n"); + } + +#if CFG_WMT_WIFI_5G_SUPPORT + dDieChipid = wmt_ic_ops_soc.icId; + WMT_DBG_FUNC("current SOC chipid is 0x%x\n", dDieChipid); + if (0x6592 == dDieChipid) { + /* read A die chipid by wmt cmd */ + iRet = + wmt_core_tx((PUINT8) &WMT_GET_SOC_ADIE_CHIPID_CMD[0], sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD))) { + WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); + return -16; + } + osal_memset(evtbuf, 0, sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT))) { + WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); + return -17; + } + + osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); + WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); + + if (0x6625 == aDieChipid) { + iRet = + wmt_core_tx((PUINT8) &WMT_GET_SOC_6625_L_CMD[0], sizeof(WMT_GET_SOC_6625_L_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_CMD))) + WMT_ERR_FUNC("wmt_core:read A die efuse CMD fail(%d),size(%d)\n", iRet, u4Res); + osal_memset(evtbuf, 0, sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_6625_L_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_EVT))) + WMT_ERR_FUNC("wmt_core:read A die efuse EVT fail(%d),size(%d)\n", iRet, u4Res); + + WMT_INFO_FUNC("read SOC Adie Efuse(0x120) value:0x%2x,0x%2x,0x%2x,0x%2x -> %s\n", + evtbuf[u4Res - 4], evtbuf[u4Res - 3], evtbuf[u4Res - 2], evtbuf[u4Res - 1], + evtbuf[u4Res - 2] == 0x31 ? "MT6625L" : "MT6625"); + } + /* get PMIC chipid */ + + ctrlData.ctrlId = WMT_CTRL_SOC_PALDO_CTRL; + ctrlData.au4CtrlData[0] = PMIC_CHIPID_PALDO; + ctrlData.au4CtrlData[1] = 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet < 0) { + WMT_ERR_FUNC("wmt_core: read PMIC chipid fail(%d)\n", iRet); + return -18; + } + pmicChipid = ctrlData.au4CtrlData[2]; + WMT_INFO_FUNC("current PMIC chipid(0x%x)\n", pmicChipid); + + /* MT6625 & MT6322, write 1 to 0x0414[12] */ + /* MT6625 & MT6323, assert */ + /* MT6627 & (MT6322 or MT6323),write 0 to 0x0414[12] */ + + switch (aDieChipid) { + case 0x6625: + if (0x6322 == pmicChipid) { + WMT_INFO_FUNC("wmt-core:enable wifi 5G support\n"); + ctrlPa1 = WIFI_5G_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else if (0x6323 == pmicChipid) { + osal_assert(0); + } else { + WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); + } + break; + case 0x6627: + if ((0x6322 == pmicChipid) || (0x6323 == pmicChipid)) { + WMT_INFO_FUNC("wmt-core: disable wifi 5G support\n"); + ctrlPa1 = WIFI_5G_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); + } + break; + default: + WMT_WARN_FUNC("wmt-core: unknown A die chipid(0x%x)\n", aDieChipid); + break; + } + } +#endif + +#if 1 + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_soc.icId; + ctrlData.au4CtrlData[1] = (SIZE_T) gp_soc_info->cChipVersion; + ctrlData.au4CtrlData[2] = (SIZE_T) &gp_soc_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -19; + } +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(NULL != gp_soc_info); + if (NULL != gp_soc_info) { + if (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + return 0; +} + +static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + osal_assert(NULL != gp_soc_info); + if ((NULL != gp_soc_info) + && (MTK_WCN_BOOL_FALSE != gp_soc_info->bPsmSupport)) { + wmt_lib_ps_disable(); + } +#endif + + gp_soc_info = NULL; + + return 0; +} + +static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + UINT32 val; + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000710; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + WMT_WARN_FUNC("TBD!!"); + ret = 0; +#endif + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000070; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + case WMT_IC_AIF_3: + val = 0x00000000; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + ret = 0; + break; + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x01110000; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); + + break; + case WMT_IC_AIF_3: + ret = 0; + break; + + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#endif + } + + if (!ret) + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); + WMT_INFO_FUNC("new state(%d) ok\n", state); + + return ret; +} + +static INT32 mtk_wcn_soc_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 iRet = -1; + UINT32 uVal = 0; + + /* mt6797 can not access reg:0x80050078 and no need to do GPS SYNC */ + if (0x0279 != wmt_ic_ops_soc.icId) { + if (WMT_IC_PIN_MUX == state) + uVal = 0x1 << 28; + else + uVal = 0x5 << 28; + iRet = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28); + if (iRet) + WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet); + } else + WMT_INFO_FUNC("This chip no need to sync GPS and MODEM!\n"); + + /* anyway, we return 0 */ + return 0; +} + +static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mtk_wcn_soc_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + case WMT_IC_PIN_GSYNC: + ret = mtk_wcn_soc_gps_sync_ctrl(state, flag); + break; + default: + break; + } + WMT_INFO_FUNC("ret = (%d)\n", ret); + + return ret; +} + +INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on) +{ + INT32 iRet = 0; + + if ((WMT_CO_CLOCK_DIS <= on) && (WMT_CO_CLOCK_MAX > on)) { + gCoClockEn = on; + } else { + WMT_DBG_FUNC("0x%x: error parameter:%d\n", wmt_ic_ops_soc.icId, on); + iRet = -1; + } + WMT_DBG_FUNC("0x%x: Co-clock %s\n", wmt_ic_ops_soc.icId, + (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled"); + + return iRet; +} + +static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + +static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID) +{ + return MTK_WCN_BOOL_FALSE; +} + +WMT_CO_CLOCK mtk_wcn_soc_co_clock_get(VOID) +{ + return gCoClockEn; +} + +static INT32 mtk_wcn_soc_ver_check(VOID) +{ + UINT32 hw_ver; + UINT32 fw_ver; + INT32 iret; + const WMT_IC_INFO_S *p_info; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("0x%x: before read hw_ver (hw version)\n", wmt_ic_ops_soc.icId); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("0x%x: read hw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); + return -2; + } + WMT_WARN_FUNC("0x%x: read hw_ver (hw version) (0x%x)\n", wmt_ic_ops_soc.icId, hw_ver); + + WMT_LOUD_FUNC("0x%x: before fw_ver (rom version)\n", wmt_ic_ops_soc.icId); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("0x%x: read fw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); + return -2; + } + WMT_WARN_FUNC("0x%x: read fw_ver (rom version) (0x%x)\n", wmt_ic_ops_soc.icId, fw_ver); + + p_info = mtk_wcn_soc_find_wmt_ic_info(hw_ver); + if (NULL == p_info) { + WMT_ERR_FUNC("0x%x: hw_ver(0x%x) find wmt ic info fail\n", wmt_ic_ops_soc.icId); + return -3; + } + WMT_WARN_FUNC("0x%x: ic info: %s.%s (0x%x/0x%x, WMTHWVER:%d, patch_ext:%s)\n", + wmt_ic_ops_soc.icId, p_info->cChipName, p_info->cChipVersion, + hw_ver, fw_ver, p_info->eWmtHwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (wmt_ic_ops_soc.icId << 16) | (hw_ver & 0x0000FFFF); + /* translated hw version & fw rom version */ + ctrlPa2 = ((UINT32) (p_info->eWmtHwVer) << 16) | (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + if (iret) + WMT_WARN_FUNC("0x%x: WMT_CTRL_HWIDVER_SET fail(%d)\n", wmt_ic_ops_soc.icId, iret); + + gp_soc_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mtk_wcn_soc_info_table */ + const UINT32 size = osal_array_size(mtk_wcn_soc_info_table); + INT32 index = 0; + + /* George: reverse the search order to favor newer version products + * TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() + * is changed correctly in the future!! + * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. + */ + index = size - 1; + /* full match */ + while ((0 <= index) && (hw_ver != mtk_wcn_soc_info_table[index].u4HwVer)) + --index; + if (0 <= index) { + WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mtk_wcn_soc_info_table[index]; + } + + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + /* major num match */ + while ((0 <= index) && + (MAJORNUM(hw_ver) != MAJORNUM(mtk_wcn_soc_info_table[index].u4HwVer))) { + --index; + } + if (0 <= index) { + WMT_DBG_FUNC("0x%x: found ic info for hw_ver(0x%x) by major num! index:%d\n", + wmt_ic_ops_soc.icId, hw_ver, index); + return &mtk_wcn_soc_info_table[index]; + } + + WMT_ERR_FUNC("0x%x: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + wmt_ic_ops_soc.icId, hw_ver); + WMT_ERR_FUNC("Set default chip version: E1!\n"); + return &mtk_wcn_soc_info_table[0]; +} + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID) +{ + INT32 iRet; + unsigned long addr; + WMT_GEN_CONF *pWmtGenConf; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + osal_sleep_ms(5); + + if (pWmtGenConf->coex_wmt_filter_mode == 0) { + if ((0x6752 == wmt_ic_ops_soc.icId) || + (0x6580 == wmt_ic_ops_soc.icId) || + (0x8163 == wmt_ic_ops_soc.icId) || + (0x0326 == wmt_ic_ops_soc.icId) || + (0x0321 == wmt_ic_ops_soc.icId) || + (0x0335 == wmt_ic_ops_soc.icId) || (0x0337 == wmt_ic_ops_soc.icId)) { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_1, osal_array_size(set_wifi_lte_coex_table_1)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_1 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } else if (0x0279 == wmt_ic_ops_soc.icId) { + /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/ + if (pWmtGenConf->coex_wmt_ext_component) { + WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); + set_wifi_lte_coex_table_2[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; + } + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_2, osal_array_size(set_wifi_lte_coex_table_2)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_2 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } else { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_0, osal_array_size(set_wifi_lte_coex_table_0)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } + } + + return iRet; +} +#endif + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + unsigned long addr; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 + +#if CFG_SUBSYS_COEX_NEED + /* no need for MT6628 */ +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 +#endif + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode); +#if CFG_SUBSYS_COEX_NEED + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); +#endif + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + +#if CFG_SUBSYS_COEX_NEED + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, coex_table[COEX_MISC].cmdSz); +#endif + + iRet = wmt_core_init_script(coex_table, sizeof(coex_table) / sizeof(coex_table[0])); + + return iRet; +} + +#if CFG_WMT_SDIO_DRIVING_SET +static INT32 mtk_wcn_soc_set_sdio_driving(void) +{ + INT32 ret = 0; + + unsigned long addr; + WMT_GEN_CONF *pWmtGenConf; + UINT32 drv_val = 0; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -1; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + drv_val = pWmtGenConf->sdio_driving_cfg; + + /*Dump the sdio driving related info */ + WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); + + sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ + sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ + sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ + + ret = wmt_core_init_script(sdio_driving_table, sizeof(sdio_driving_table) / sizeof(sdio_driving_table[0])); + + return ret; +} +#endif + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mtk_wcn_soc_crystal_triming_set(VOID) +{ + INT32 iRet = 0; + PUINT8 pbuf = NULL; + UINT32 bufLen = 0; + WMT_CTRL_DATA ctrlData; + UINT32 uCryTimOffset = 0x6D; + MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; + INT8 cCrystalTimingOffset = 0x0; + UINT8 cCrystalTiming = 0x0; + INT32 iCrystalTiming = 0x0; + MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + UINT32 u4Res; + + bIsNvramExist = MTK_WCN_BOOL_FALSE; + /**/ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; + ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; + ctrlData.au4CtrlData[1] = (UINT32) &pbuf; + ctrlData.au4CtrlData[2] = (UINT32) &bufLen; + + iRet = wmt_ctrl(&ctrlData); + if (0 != iRet) { + WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", wmt_ic_ops_soc.icId, iRet); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + iRet = -1; + } else { + WMT_DBG_FUNC("0x%x: nvram pBuf(0x%08x), bufLen(%d)\n", wmt_ic_ops_soc.icId, pbuf, bufLen); + if (bufLen < (uCryTimOffset + 1)) { + WMT_ERR_FUNC("0x%x: nvram len(%d) too short, crystalTimging value offset(%d)\n", + wmt_ic_ops_soc.icId, bufLen, uCryTimOffset); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + } else { + bIsNvramExist = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = *(pbuf + uCryTimOffset); + if (cCrystalTimingOffset & 0x80) { + bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; + } + WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", cCrystalTimingOffset, + bIsCrysTrimEnabled); + } + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; + ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; + iRet = wmt_ctrl(&ctrlData); + if (0 != iRet) { + WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", wmt_ic_ops_soc.icId, iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n", wmt_ic_ops_soc.icId); + } + } + if ((MTK_WCN_BOOL_TRUE == bIsNvramExist) && (MTK_WCN_BOOL_TRUE == bIsCrysTrimEnabled)) { + /*get CrystalTiming value before set it */ + iRet = + wmt_core_tx(get_crystal_timing_script[0].cmd, get_crystal_timing_script[0].cmdSz, &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].cmdSz); + iRet = -3; + goto done; + } + /* EVENT BUF */ + osal_memset(get_crystal_timing_script[0].evt, 0, get_crystal_timing_script[0].evtSz); + iRet = wmt_core_rx(get_crystal_timing_script[0].evt, get_crystal_timing_script[0].evtSz, &u4Res); + if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + iRet = -4; + goto done; + } + + iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; + if (cCrystalTimingOffset & 0x40) { + /*nagative offset value */ + iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; + } else { + iCrystalTiming += cCrystalTimingOffset; + } + WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); + cCrystalTiming = iCrystalTiming > 0x7f ? 0x7f : iCrystalTiming; + cCrystalTiming = iCrystalTiming < 0 ? 0 : iCrystalTiming; + WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); + /* set_crystal_timing_script */ + WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; + WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; + + iRet = wmt_core_init_script(set_crystal_timing_script, osal_array_size(set_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); + iRet = -5; + } else { + WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", WMT_SET_CRYSTAL_TRIMING_CMD[5]); + iRet = + wmt_core_init_script(get_crystal_timing_script, osal_array_size(get_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); + iRet = -6; + } else { + WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", + WMT_GET_CRYSTAL_TRIMING_EVT[5]); + iRet = 0x0; + } + } + } +done: + return iRet; +} +#endif + +#if CFG_WMT_MULTI_PATCH +static INT32 mtk_wcn_soc_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + +static INT32 mtk_wcn_soc_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + UINT8 addressevtBuf[12]; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (NULL == gp_soc_info) { + WMT_ERR_FUNC("null gp_soc_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T) &addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_DBG_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (SIZE_T) NULL; + ctrlData.au4CtrlData[1] = (SIZE_T) &gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T) &pbuf; + ctrlData.au4CtrlData[3] = (SIZE_T) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + if (index == 0) { + WMT_DBG_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Patch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], + patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("===========================================\n"); + } + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + /* gp_soc_patch_info = patchHdr; */ + osal_memcpy(&gp_soc_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /*send wmt part patch address command */ + if (0x6752 == wmt_ic_ops_soc.icId || + 0x8127 == wmt_ic_ops_soc.icId || + 0x7623 == wmt_ic_ops_soc.icId || + 0x6571 == wmt_ic_ops_soc.icId || + 0x0326 == wmt_ic_ops_soc.icId || + 0x0321 == wmt_ic_ops_soc.icId || + 0x0335 == wmt_ic_ops_soc.icId || + 0x0337 == wmt_ic_ops_soc.icId || 0x8163 == wmt_ic_ops_soc.icId || 0x6580 == wmt_ic_ops_soc.icId) { + /* MT6571 patch RAM base */ + WMT_PATCH_ADDRESS_CMD[8] = 0x40; + WMT_PATCH_P_ADDRESS_CMD[8] = 0xc8; + } + /*send wmt part patch address command */ + if (0x0279 == wmt_ic_ops_soc.icId) { + /* MT6797 patch RAM base */ + WMT_PATCH_ADDRESS_CMD[8] = 0x08; + WMT_PATCH_ADDRESS_CMD[9] = 0x05; + WMT_PATCH_P_ADDRESS_CMD[8] = 0x2c; + WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b; + } + + /*send wmt part patch address command */ + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + iRet -= 1; + goto done; + } +#endif + + /*send part patch address command */ + osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); + WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_P_ADDRESS_CMD[12], + WMT_PATCH_P_ADDRESS_CMD[13], WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, u4Res, index); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", index); + iRet -= 1; + goto done; + } +#endif + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); + + /* iRet = + *(*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + *&u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), + u4Res, iRet); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, + evtBuf[0], + evtBuf[1], + evtBuf[2], + evtBuf[3], + evtBuf[4]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_PATCH_EVT), + WMT_PATCH_EVT[0], + WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], + WMT_PATCH_EVT[3], + WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + + return iRet; +} + +#else +static INT32 mtk_wcn_soc_patch_dwn(VOID) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (NULL == gp_soc_info) { + WMT_ERR_FUNC("null gp_soc_info!\n"); + return -1; + } + /* <2> search patch and read patch content */ + /* <2.1> search patch */ + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + if (0 == iRet) { + /* patch with correct Hw Ver Major Num found */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (UINT32) &gFullPatchName; + iRet = wmt_ctrl(&ctrlData); + + WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (UINT32) NULL; + ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName; + + } else { + iRet -= 1; + return iRet; + } + ctrlData.au4CtrlData[2] = (UINT32) &pbuf; + ctrlData.au4CtrlData[3] = (UINT32) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + WMT_DBG_FUNC("===========================================\n"); + WMT_INFO_FUNC("[ConsysPatch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], + patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("===========================================\n"); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); + + /* iRet = + * (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + * &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), + u4Res, iRet); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, + evtBuf[0], + evtBuf[1], + evtBuf[2], + evtBuf[3], + evtBuf[4]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_PATCH_EVT), + WMT_PATCH_EVT[0], + WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], + WMT_PATCH_EVT[3], + WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); + + return iRet; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c new file mode 100644 index 0000000000000..747ed64af2d2d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/core/wmt_lib.c @@ -0,0 +1,1938 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-LIB]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" + +#include "wmt_dev.h" +#include "wmt_lib.h" +#include "wmt_conf.h" +#include "wmt_core.h" +#include "wmt_plat.h" + +#include "stp_core.h" +#include "btm_core.h" +#include "psm_core.h" +#include "stp_dbg.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* A table for translation: CMB_STUB_AIF_X=>WMT_IC_PIN_STATE */ +static const WMT_IC_PIN_STATE cmb_aif2pin_stat[] = { + [CMB_STUB_AIF_0] = WMT_IC_AIF_0, + [CMB_STUB_AIF_1] = WMT_IC_AIF_1, + [CMB_STUB_AIF_2] = WMT_IC_AIF_2, + [CMB_STUB_AIF_3] = WMT_IC_AIF_3, +}; + +#if CFG_WMT_PS_SUPPORT +static UINT32 gPsIdleTime = STP_PSM_IDLE_TIME_SLEEP; +static UINT32 gPsEnable = 1; +static PF_WMT_SDIO_PSOP sdio_own_ctrl; +#endif + +#define WMT_STP_CPUPCR_BUF_SIZE 6144 +static UINT8 g_cpupcr_buf[WMT_STP_CPUPCR_BUF_SIZE] = { 0 }; + +static UINT32 g_quick_sleep_ctrl = 1; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +DEV_WMT gDevWmt; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#if CFG_WMT_PS_SUPPORT +static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action); +static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID); +static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID); +static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID); +static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action); +#endif + +static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pLxOp); + +static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ); + +static INT32 wmtd_thread(PVOID pvData); + +static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag); +static MTK_WCN_BOOL wmt_lib_hw_state_show(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_lib_idc_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.idc_lock); +} + +VOID wmt_lib_idc_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.idc_lock); +} +INT32 wmt_lib_psm_lock_aquire(void) +{ + return osal_lock_sleepable_lock(&gDevWmt.psm_lock); +} + +void wmt_lib_psm_lock_release(void) +{ + osal_unlock_sleepable_lock(&gDevWmt.psm_lock); +} + +INT32 DISABLE_PSM_MONITOR(void) +{ + INT32 ret = 0; + + /* osal_lock_sleepable_lock(&gDevWmt.psm_lock); */ + ret = wmt_lib_psm_lock_aquire(); + if (ret) { + WMT_ERR_FUNC("--->lock psm_lock failed, ret=%d\n", ret); + return ret; + } +#if CFG_WMT_PS_SUPPORT + ret = wmt_lib_ps_disable(); + if (ret) { + WMT_ERR_FUNC("wmt_lib_ps_disable fail, ret=%d\n", ret); + wmt_lib_psm_lock_release(); + } +#endif + + return ret; +} + +void ENABLE_PSM_MONITOR(void) +{ +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_enable(); +#endif + /* osal_unlock_sleepable_lock(&gDevWmt.psm_lock); */ + wmt_lib_psm_lock_release(); +} + +INT32 wmt_lib_init(VOID) +{ + INT32 iRet; + UINT32 i; + P_DEV_WMT pDevWmt; + P_OSAL_THREAD pThraed; + + /* create->init->start */ + /* 1. create: static allocation with zero initialization */ + pDevWmt = &gDevWmt; + osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); + + iRet = wmt_conf_read_file(); + if (iRet) { + WMT_ERR_FUNC("read wmt config file fail(%d)\n", iRet); + return -1; + } + + pThraed = &gDevWmt.thread; + + /* Create mtk_wmtd thread */ + osal_strncpy(pThraed->threadName, "mtk_wmtd", sizeof(pThraed->threadName)); + pThraed->pThreadData = (VOID *) pDevWmt; + pThraed->pThreadFunc = (VOID *) wmtd_thread; + iRet = osal_thread_create(pThraed); + if (iRet) { + WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThraed, iRet); + return -2; + } + + /* 2. initialize */ + /* Initialize wmt_core */ + + iRet = wmt_core_init(); + if (iRet) { + WMT_ERR_FUNC("wmt_core_init() fail(%d)\n", iRet); + return -1; + } + + /* Initialize WMTd Thread Information: Thread */ + osal_event_init(&pDevWmt->rWmtdWq); + osal_sleepable_lock_init(&pDevWmt->psm_lock); + osal_sleepable_lock_init(&pDevWmt->idc_lock); + osal_sleepable_lock_init(&pDevWmt->rActiveOpQ.sLock); + osal_sleepable_lock_init(&pDevWmt->rFreeOpQ.sLock); + pDevWmt->state.data = 0; + + /* Initialize op queue */ + RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); + RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); + /* Put all to free Q */ + for (i = 0; i < WMT_OP_BUF_SIZE; i++) { + osal_signal_init(&(pDevWmt->arQue[i].signal)); + wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); + } + + /* initialize stp resources */ + osal_event_init(&pDevWmt->rWmtRxWq); + + /*function driver callback */ + for (i = 0; i < WMTDRV_TYPE_WIFI; i++) + pDevWmt->rFdrvCb.fDrvRst[i] = NULL; + + pDevWmt->hw_ver = WMTHWVER_MAX; + WMT_INFO_FUNC("***********Init, hw->ver = %x\n", pDevWmt->hw_ver); + + /* TODO:[FixMe][GeorgeKuo]: wmt_lib_conf_init */ + /* initialize default configurations */ + /* i4Result = wmt_lib_conf_init(VOID); */ + /* WMT_WARN_FUNC("wmt_drv_conf_init(%d)\n", i4Result); */ + + osal_signal_init(&pDevWmt->cmdResp); + osal_event_init(&pDevWmt->cmdReq); + + /* initialize platform resources */ + if (0 != gDevWmt.rWmtGenConf.cfgExist) + iRet = wmt_plat_init(gDevWmt.rWmtGenConf.co_clock_flag & 0x0f); + else + iRet = wmt_plat_init(0); + + if (iRet) { + WMT_ERR_FUNC("wmt_plat_init() fail(%d)\n", iRet); + return -3; + } +#if CFG_WMT_PS_SUPPORT + iRet = wmt_lib_ps_init(); + if (iRet) { + WMT_ERR_FUNC("wmt_lib_ps_init() fail(%d)\n", iRet); + return -4; + } +#endif + + /* 3. start: start running mtk_wmtd */ + iRet = osal_thread_run(pThraed); + if (iRet) { + WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", pThraed, iRet); + return -5; + } + + /*4. register irq callback to WMT-PLAT */ + wmt_plat_irq_cb_reg(wmt_lib_ps_irq_cb); + + /*5. register audio if control callback to WMT-PLAT */ + wmt_plat_aif_cb_reg(wmt_lib_set_aif); + + /*6. register function control callback to WMT-PLAT */ + wmt_plat_func_ctrl_cb_reg(mtk_wcn_wmt_func_ctrl_for_plat); + + wmt_plat_deep_idle_ctrl_cb_reg(mtk_wcn_consys_stp_btif_dpidle_ctrl); + /*7 reset gps/bt state */ + + mtk_wcn_wmt_system_state_reset(); + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_wmt_exp_init(); +#endif + +#if CFG_WMT_LTE_COEX_HANDLING + wmt_idc_init(); +#endif + WMT_DBG_FUNC("init success\n"); + return 0; +} + +INT32 wmt_lib_deinit(VOID) +{ + INT32 iRet; + P_DEV_WMT pDevWmt; + P_OSAL_THREAD pThraed; + INT32 i; + INT32 iResult; + + pDevWmt = &gDevWmt; + pThraed = &gDevWmt.thread; + iResult = 0; + + /* stop->deinit->destroy */ + + /* 1. stop: stop running mtk_wmtd */ + iRet = osal_thread_stop(pThraed); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); + iResult += 1; + } + + /* 2. deinit: */ + +#if CFG_WMT_PS_SUPPORT + iRet = wmt_lib_ps_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_lib_ps_deinit fail(%d)\n", iRet); + iResult += 2; + } +#endif + + iRet = wmt_plat_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_plat_deinit fail(%d)\n", iRet); + iResult += 4; + } + + osal_event_deinit(&pDevWmt->cmdReq); + osal_signal_deinit(&pDevWmt->cmdResp); + + /* de-initialize stp resources */ + osal_event_deinit(&pDevWmt->rWmtRxWq); + + for (i = 0; i < WMT_OP_BUF_SIZE; i++) + osal_signal_deinit(&(pDevWmt->arQue[i].signal)); + + + osal_sleepable_lock_deinit(&pDevWmt->rFreeOpQ.sLock); + osal_sleepable_lock_deinit(&pDevWmt->rActiveOpQ.sLock); + osal_sleepable_lock_deinit(&pDevWmt->idc_lock); + osal_sleepable_lock_deinit(&pDevWmt->psm_lock); + osal_event_deinit(&pDevWmt->rWmtdWq); + + iRet = wmt_core_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_core_deinit fail(%d)\n", iRet); + iResult += 8; + } + + /* 3. destroy */ + iRet = osal_thread_destroy(pThraed); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThraed, iRet); + iResult += 16; + } + osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_wmt_exp_deinit(); +#endif + +#if CFG_WMT_LTE_COEX_HANDLING + wmt_idc_deinit(); +#endif + + return iResult; +} + +VOID wmt_lib_flush_rx(VOID) +{ + mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); +} + +INT32 wmt_lib_trigger_cmd_signal(INT32 result) +{ + P_OSAL_SIGNAL pSignal = &gDevWmt.cmdResp; + + gDevWmt.cmdResult = result; + osal_raise_signal(pSignal); + WMT_DBG_FUNC("wakeup cmdResp\n"); + return 0; +} + +P_OSAL_EVENT wmt_lib_get_cmd_event(VOID) +{ + return &gDevWmt.cmdReq; +} + +INT32 wmt_lib_set_patch_name(PUINT8 cPatchName) +{ + osal_strncpy(gDevWmt.cPatchName, cPatchName, NAME_MAX); + return 0; +} + +INT32 wmt_lib_set_hif(unsigned long hifconf) +{ + UINT32 val; + P_WMT_HIF_CONF pHif = &gDevWmt.rWmtHifConf; + + val = hifconf & 0xF; + if (STP_UART_FULL == val) { + pHif->hifType = WMT_HIF_UART; + val = (hifconf >> 8); + pHif->au4HifConf[0] = val; + pHif->au4HifConf[1] = val; + mtk_wcn_stp_set_if_tx_type(STP_UART_IF_TX); + } else if (STP_SDIO == val) { + pHif->hifType = WMT_HIF_SDIO; + mtk_wcn_stp_set_if_tx_type(STP_SDIO_IF_TX); + } else if (STP_BTIF_FULL == val) { + pHif->hifType = WMT_HIF_BTIF; + mtk_wcn_stp_set_if_tx_type(STP_BTIF_IF_TX); + } else { + WMT_WARN_FUNC("invalid stp mode: %u\n", val); + mtk_wcn_stp_set_if_tx_type(STP_MAX_IF_TX); + return -1; + } + + val = (hifconf & 0xF0) >> 4; + if (WMT_FM_COMM == val) { + pHif->au4StrapConf[0] = WMT_FM_COMM; + } else if (WMT_FM_I2C == val) { + pHif->au4StrapConf[0] = WMT_FM_I2C; + } else { + WMT_WARN_FUNC("invalid fm mode: %u\n", val); + return -2; + } + + WMT_WARN_FUNC("new hifType: %d, fm:%d\n", pHif->hifType, pHif->au4StrapConf[0]); + return 0; +} + +P_WMT_HIF_CONF wmt_lib_get_hif(VOID) +{ + return &gDevWmt.rWmtHifConf; +} + +PUINT8 wmt_lib_get_cmd(VOID) +{ + if (osal_test_and_clear_bit(WMT_STAT_CMD, &gDevWmt.state)) + return gDevWmt.cCmd; + + return NULL; +} + +MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID) +{ + return osal_test_bit(WMT_STAT_CMD, &gDevWmt.state) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} + +#if CFG_WMT_PS_SUPPORT +INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime) +{ + gPsIdleTime = psIdleTime; + return gPsIdleTime; +} + +INT32 wmt_lib_ps_ctrl(UINT32 state) +{ + if (0 == state) { + wmt_lib_ps_disable(); + gPsEnable = 0; + } else { + gPsEnable = 1; + wmt_lib_ps_enable(); + } + return 0; +} + +INT32 wmt_lib_ps_enable(VOID) +{ + if (gPsEnable) + mtk_wcn_stp_psm_enable(gPsIdleTime); + + return 0; +} + +INT32 wmt_lib_ps_disable(VOID) +{ + if (gPsEnable) + return mtk_wcn_stp_psm_disable(); + + return 0; +} + +INT32 wmt_lib_ps_init(VOID) +{ + /* mtk_wcn_stp_psm_register_wmt_cb(wmt_lib_ps_stp_cb); */ + return 0; +} + +INT32 wmt_lib_ps_deinit(VOID) +{ + /* mtk_wcn_stp_psm_unregister_wmt_cb(); */ + return 0; +} + +static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action) +{ + P_OSAL_OP lxop; + MTK_WCN_BOOL bRet; + UINT32 u4Wait; + P_OSAL_SIGNAL pSignal; + + lxop = wmt_lib_get_free_op(); + if (!lxop) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + pSignal = &lxop->signal; + pSignal->timeoutValue = 0; + lxop->op.opId = WMT_OPID_PWR_SV; + lxop->op.au4OpData[0] = action; + lxop->op.au4OpData[1] = (SIZE_T) mtk_wcn_stp_psm_notify_stp; + u4Wait = 0; + bRet = wmt_lib_put_act_op(lxop); + return bRet; +} + +#if CFG_WMT_LTE_COEX_HANDLING +MTK_WCN_BOOL wmt_lib_handle_idc_msg(ipc_ilm_t *idc_infor) +{ + P_OSAL_OP lxop; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + INT32 ret = 0; + UINT16 msg_len = 0; + static UINT8 msg_local_buffer[1300]; +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; +#endif + WMT_DBG_FUNC("idc_infor from conn_md is 0x%p\n", idc_infor); + ret = wmt_lib_idc_lock_aquire(); + if (ret) { + WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", ret); + return MTK_WCN_BOOL_FALSE; + } + msg_len = idc_infor->local_para_ptr->msg_len - osal_sizeof(local_para_struct); + osal_memcpy(&msg_local_buffer[0], &msg_len, osal_sizeof(msg_len)); + osal_memcpy(&msg_local_buffer[osal_sizeof(msg_len)], + &(idc_infor->local_para_ptr->data[0]), msg_len - 1); + wmt_lib_idc_lock_release(); + lxop = wmt_lib_get_free_op(); + if (!lxop) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + pSignal = &lxop->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + lxop->op.opId = WMT_OPID_IDC_MSG_HANDLING; + lxop->op.au4OpData[0] = (size_t) msg_local_buffer; + /*msg opcode fill rule is still not clrear,need scott comment */ + /***********************************************************/ + WMT_DBG_FUNC("ilm msg id is (0x%08x)\n", idc_infor->msg_id); + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + switch (idc_infor->msg_id) { + case IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_PARA; + break; + case IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_FREQ; + break; + case IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_WIFI_MAX_POWER; + break; + case IPC_MSG_ID_EL1_LTE_TX_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_INDICATION; + break; + case IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS; + break; + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + break; + } + + if (MTK_WCN_BOOL_FALSE == unknown_msgid) { + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(lxop); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(lxop); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) + WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); + else + WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", lxop->op.opId, lxop->op.au4OpData[1]); + } else { + bRet = MTK_WCN_BOOL_FALSE; + wmt_lib_put_op_to_free_queue(lxop); + WMT_ERR_FUNC("unknown msgid from LTE(%d)\n", idc_infor->msg_id); + } +#else + if ((idc_infor->msg_id >= IPC_EL1_MSG_ID_BEGIN) + && (idc_infor->msg_id <= IPC_EL1_MSG_ID_BEGIN + IPC_EL1_MSG_ID_RANGE)) { + lxop->op.au4OpData[1] = idc_infor->msg_id - IPC_EL1_MSG_ID_BEGIN + LTE_MSG_ID_OFFSET - 1; + + WMT_DBG_FUNC("LTE->CONN:(0x%x->0x%zx)\n", idc_infor->msg_id, lxop->op.au4OpData[1]); + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(lxop); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(lxop); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); + } else { + WMT_DBG_FUNC("wmt_lib_handle_idc_msg OPID(%d) type(%d) ok\n", + lxop->op.opId, lxop->op.au4OpData[1]); + } + } else { + wmt_lib_put_op_to_free_queue(lxop); + WMT_ERR_FUNC("msgid(%d) out of range,wmt drop it!\n", idc_infor->msg_id); + } +#endif + + return bRet; +} +#endif + +static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID) +{ + return wmt_lib_ps_action(SLEEP); +} + +static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID) +{ + return wmt_lib_ps_action(WAKEUP); +} + +static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID) +{ +#if 1 + return wmt_lib_ps_action(WAKEUP); +#else + return wmt_lib_ps_action(HOST_AWAKE); +#endif +} + +/* extern int g_block_tx; */ +static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action) +{ + INT32 ret; + + ret = 0; /* TODO:[FixMe][George] initial value or compile warning? */ + /* if(g_block_tx && (action == SLEEP)) */ + if ((0 != mtk_wcn_stp_coredump_start_get()) && (action == SLEEP)) { + mtk_wcn_stp_psm_notify_stp(SLEEP); + return ret; + } + + /*MT662x Not Ready */ + if (!mtk_wcn_stp_is_ready()) { + WMT_DBG_FUNC("MT662x Not Ready, Dont Send Sleep/Wakeup Command\n"); + mtk_wcn_stp_psm_notify_stp(ROLL_BACK); + return 0; + } + + if (SLEEP == action) { + WMT_DBG_FUNC("send op-----------> sleep job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + ret = wmt_lib_ps_do_sleep(); + WMT_DBG_FUNC("enable host eirq\n"); + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_EN); +#if CFG_WMT_DUMP_INT_STATUS + if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) + wmt_plat_BGF_irq_dump_status(); +#endif + } else { + /* ret = mtk_wcn_stp_sdio_do_own_set(); */ + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_SET); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + if (!ret) { + mtk_wcn_stp_psm_notify_stp(SLEEP); + } else if (ret == -2) { + mtk_wcn_stp_psm_notify_stp(ROLL_BACK); + WMT_WARN_FUNC("===[SDIO-PS] rollback due to tx busy===%%\n"); + } else { + mtk_wcn_stp_psm_notify_stp(SLEEP); + WMT_ERR_FUNC("===[SDIO-PS] set own fails!===%%\n"); + } + } + + WMT_DBG_FUNC("send op<---------- sleep job\n"); + } else if (WAKEUP == action) { + WMT_DBG_FUNC("send op --------> wake job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("disable host eirq\n"); +#if CFG_WMT_DUMP_INT_STATUS + if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) + wmt_plat_BGF_irq_dump_status(); +#endif + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + ret = wmt_lib_ps_do_wakeup(); + } else { + /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ + + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_CLR); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + if (!ret) { + mtk_wcn_stp_psm_notify_stp(WAKEUP); + } else { + mtk_wcn_stp_psm_notify_stp(WAKEUP); + WMT_ERR_FUNC("===[SDIO-PS] set own back fails!===%%\n"); + } + } + + WMT_DBG_FUNC("send op<---------- wake job\n"); + } else if (HOST_AWAKE == action) { + WMT_DBG_FUNC("send op-----------> host awake job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("disable host eirq\n"); + /* IRQ already disabled */ + /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ +#if 0 + if (MTK_WCN_BOOL_TRUE == wmt_plat_dump_BGF_irq_status()) + wmt_plat_BGF_irq_dump_status(); +#endif + ret = wmt_lib_ps_do_host_awake(); + } else { + WMT_DBG_FUNC("[SDIO-PS] SDIO host awake! ####\n"); + + /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ + + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_CLR); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + /* Here we set ret to 0 directly */ + ret = 0; + if (!ret) { + mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); + } else { + mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); + WMT_ERR_FUNC("===[SDIO-PS]set own back fails!===%%\n"); + } + } + + WMT_DBG_FUNC("send op<----------- host awake job\n"); + } else if (EIRQ == action) { + WMT_DBG_FUNC("send op -------------> eirq job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("disable host eirq\n"); + /* Disable interrupt */ + /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ + ret = mtk_wcn_stp_psm_notify_stp(EIRQ); + } else { + WMT_ERR_FUNC("[SDIO-PS]sdio own-back eirq!######\n"); + ret = mtk_wcn_stp_psm_notify_stp(EIRQ); + } + + WMT_DBG_FUNC("send op<----------- eirq job\n"); + } + + return ret; +} +#endif /* end of CFG_WMT_PS_SUPPORT */ + +INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action) +{ +#if CFG_WMT_PS_SUPPORT + return wmt_lib_ps_handler(action); +#else + WMT_WARN_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); + return 0; +#endif +} + +MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID) +{ + if ((g_quick_sleep_ctrl) && (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_TRUE)) + return wmt_core_is_quick_ps_support(); + else + return MTK_WCN_BOOL_FALSE; +} + +VOID wmt_lib_ps_irq_cb(VOID) +{ +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_handler(EIRQ); +#else + WMT_DBG_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); + return; +#endif +} + +VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb) +{ +#if CFG_WMT_PS_SUPPORT + sdio_own_ctrl = own_cb; +#endif +} + +UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread) +{ + P_DEV_WMT pDevWmt; + + if (pThread) { + pDevWmt = (P_DEV_WMT) (pThread->pThreadData); + return !RB_EMPTY(&pDevWmt->rActiveOpQ); + } + WMT_ERR_FUNC("pThread(NULL)\n"); + return 0; +} + +static INT32 wmtd_thread(void *pvData) +{ + P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData; + P_OSAL_EVENT pEvent = NULL; + P_OSAL_OP pOp; + INT32 iResult; + + if (NULL == pWmtDev) { + WMT_ERR_FUNC("pWmtDev(NULL)\n"); + return -1; + } + WMT_INFO_FUNC("wmtd thread starts\n"); + + pEvent = &(pWmtDev->rWmtdWq); + + for (;;) { + pOp = NULL; + pEvent->timeoutValue = 0; +/* osal_thread_wait_for_event(&pWmtDev->thread, pEvent);*/ + osal_thread_wait_for_event(&pWmtDev->thread, pEvent, wmt_lib_wait_event_checker); + + if (osal_thread_should_stop(&pWmtDev->thread)) { + WMT_INFO_FUNC("wmtd thread should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeQ */ + pOp = wmt_lib_get_op(&pWmtDev->rActiveOpQ); + if (!pOp) { + WMT_WARN_FUNC("get_lxop activeQ fail\n"); + continue; + } +#if 0 /* wmt_core_opid_handler will do sanity check on opId, so no usage here */ + id = lxop_get_opid(pLxOp); + if (id >= WMT_OPID_MAX) { + WMT_WARN_FUNC("abnormal opid id: 0x%x\n", id); + iResult = -1; + goto handlerDone; + } +#endif + + if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) { + /* when whole chip reset, only HW RST and SW RST cmd can execute */ + if ((pOp->op.opId == WMT_OPID_HW_RST) || (pOp->op.opId == WMT_OPID_SW_RST) + || (pOp->op.opId == WMT_OPID_GPIO_STATE)) { + iResult = wmt_core_opid(&pOp->op); + } else { + iResult = -2; + WMT_WARN_FUNC("Whole chip resetting, opid (%d) failed, iRet(%d)\n", pOp->op.opId, + iResult); + } + } else { + wmt_lib_set_current_op(pWmtDev, pOp); + iResult = wmt_core_opid(&pOp->op); + wmt_lib_set_current_op(pWmtDev, NULL); + } + + if (iResult) + WMT_WARN_FUNC("opid (%d) failed, iRet(%d)\n", pOp->op.opId, iResult); + + if (osal_op_is_wait_for_signal(pOp)) { + osal_op_raise_signal(pOp, iResult); + } else { + /* put Op back to freeQ */ + wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); + } + + if (WMT_OPID_EXIT == pOp->op.opId) { + WMT_INFO_FUNC("wmtd thread received exit signal\n"); + break; + } + } + + WMT_INFO_FUNC("wmtd thread exits succeed\n"); + + return 0; +}; + +static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 iRet; + + if (!pOpQ || !pOp) { + WMT_WARN_FUNC("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", pOpQ, pOp); + osal_assert(pOpQ); + osal_assert(pOp); + return MTK_WCN_BOOL_FALSE; + } + + iRet = osal_lock_sleepable_lock(&pOpQ->sLock); + if (iRet) { + WMT_WARN_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); + return MTK_WCN_BOOL_FALSE; + } +#if 0 + if (pOpQ == &gDevWmt.rFreeOpQ) + WMT_INFO_FUNC("current wmt free queue count is(%d),opid(%d)\n", RB_COUNT(pOpQ), pOp->op.opId); +#endif + /* acquire lock success */ + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + iRet = -1; + + osal_unlock_sleepable_lock(&pOpQ->sLock); + + if (iRet) { + WMT_WARN_FUNC("RB_FULL(0x%p)\n", pOpQ); + return MTK_WCN_BOOL_FALSE; + } else { + return MTK_WCN_BOOL_TRUE; + } +} + +static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + INT32 iRet; + + if (NULL == pOpQ) { + WMT_ERR_FUNC("pOpQ = NULL\n"); + osal_assert(pOpQ); + return NULL; + } + + iRet = osal_lock_sleepable_lock(&pOpQ->sLock); + if (iRet) { + WMT_ERR_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); + return NULL; + } + + /* acquire lock success */ + RB_GET(pOpQ, pOp); + osal_unlock_sleepable_lock(&pOpQ->sLock); + + if (NULL == pOp) { + WMT_WARN_FUNC("RB_GET return NULL\n"); + osal_assert(pOp); + } + + return pOp; +} + +INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + if (MTK_WCN_BOOL_FALSE == wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp)) + return -1; + else + return 0; +} + +P_OSAL_OP wmt_lib_get_free_op(VOID) +{ + P_OSAL_OP pOp = NULL; + P_DEV_WMT pDevWmt = &gDevWmt; + + osal_assert(pDevWmt); + + pOp = wmt_lib_get_op(&pDevWmt->rFreeOpQ); + if (pOp) + osal_memset(&pOp->op, 0, osal_sizeof(pOp->op)); + return pOp; +} + +MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + MTK_WCN_BOOL bCleanup = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal = NULL; + long waitRet = -1; + P_OSAL_THREAD pThread; + + osal_assert(pWmtDev); + osal_assert(pOp); + + do { + if (!pWmtDev || !pOp) { + WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp); + break; + } + if ((0 != mtk_wcn_stp_coredump_start_get()) && + (WMT_OPID_HW_RST != pOp->op.opId) && + (WMT_OPID_SW_RST != pOp->op.opId) && (WMT_OPID_GPIO_STATE != pOp->op.opId)) { + bCleanup = MTK_WCN_BOOL_TRUE; + WMT_WARN_FUNC("block tx flag is set\n"); + break; + } + pSignal = &pOp->signal; +/* pOp->u4WaitMs = u4WaitMs; */ + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(pSignal); + } + + /* put to active Q */ + bRet = wmt_lib_put_op(&pWmtDev->rActiveOpQ, pOp); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("put to active queue fail\n"); + bCleanup = MTK_WCN_BOOL_TRUE; + break; + } + + /* wake up wmtd */ + /* wake_up_interruptible(&pWmtDev->rWmtdWq); */ + osal_trigger_event(&pWmtDev->rWmtdWq); + + if (0 == pSignal->timeoutValue) { + bRet = MTK_WCN_BOOL_TRUE; + /* clean it in wmtd */ + break; + } + /* wait result, clean it here */ + bCleanup = MTK_WCN_BOOL_TRUE; + + /* check result */ + /* wait_ret = wait_for_completion_interruptible_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ + /* wait_ret = wait_for_completion_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ + waitRet = osal_wait_for_signal_timeout(pSignal); + WMT_DBG_FUNC("osal_wait_for_signal_timeout:%ld\n", waitRet); + + /* if (unlikely(!wait_ret)) { */ + if (0 == waitRet) { + pThread = &gDevWmt.thread; + WMT_ERR_FUNC + ("wait completion timeout, opId(%d), show wmtd_thread stack!\n", pOp->op.opId); + /* TODO: how to handle it? retry? */ + wcn_wmtd_timeout_collect_ftrace(); /* trigger collect SYS_FTRACE */ + osal_thread_show_stack(pThread); + } else { + if (pOp->result) + WMT_WARN_FUNC("opId(%d) result:%d\n", pOp->op.opId, pOp->result); + } + /* op completes, check result */ + bRet = (pOp->result) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; + } while (0); + + if (bCleanup) { + /* put Op back to freeQ */ + wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); + } + + return bRet; +} + +/* TODO:[ChangeFeature][George] is this function obsoleted? */ +#if 0 +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_WMT_LXOP lxop; + MTK_WCN_BOOL bRet; + PUINT32 plv = NULL; + UINT32 pbuf[2]; + P_OSAL_EVENT pSignal = NULL; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + lxop = wmt_lib_get_free_lxop(); + if (!lxop) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + + return -1; + } + + plv = (PUINT32) (((UINT32) pbuf + 0x3) & ~0x3UL); + *plv = *pvalue; + pSignal = &lxop->signal; + WMT_DBG_FUNC("OPID_REG_RW isWrite(%d) offset(0x%x) value(0x%x) mask(0x%x)\n", isWrite, offset, *pvalue, mask); + + lxop->op.opId = WMT_OPID_REG_RW; + lxop->op.au4OpData[0] = isWrite; + lxop->op.au4OpData[1] = offset; + lxop->op.au4OpData[2] = (UINT32) plv; + lxop->op.au4OpData[3] = mask; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + DISABLE_PSM_MONITOR(); + bRet = wmt_lib_put_act_lxop(lxop); + ENABLE_PSM_MONITOR(); + + if (MTK_WCN_BOOL_FALSE != bRet) { + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, *plv, mask); + if (!isWrite) + *pvalue = *plv; + } else { + WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, *plv, mask, bRet); + } + + return bRet; +} +#endif + +/* TODO:[ChangeFeature][George] is this function obsoleted? */ +#if 0 +static VOID wmt_lib_clear_chip_id(VOID) +{ +/* + gDevWmt.pChipInfo = NULL; +*/ + gDevWmt.hw_ver = WMTHWVER_INVALID; +} +#endif + +/* TODO: [FixMe][GeorgeKuo]: change this API to report real chip id, hw_ver, and */ +/* fw_ver instead of WMT-translated WMTHWVER */ +ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver(VOID) +{ +/* + P_WMT_CMB_CHIP_INFO_S pChipInfo = NULL; + P_DEV_WMT pWmtDev = gpDevWmt; + pChipInfo = wmt_lib_get_chip_info(pWmtDev); + return pChipInfo != NULL ? pChipInfo->eHwVersion : WMTHWVER_INVALID; + */ + return gDevWmt.eWmtHwVer; +} + +UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T index) +{ + if (WMTCHIN_CHIPID == index) + return gDevWmt.chip_id; + else if (WMTCHIN_HWVER == index) + return gDevWmt.hw_ver; + else if (WMTCHIN_MAPPINGHWVER == index) + return gDevWmt.eWmtHwVer; + else if (WMTCHIN_FWVER == index) + return gDevWmt.fw_ver; + + return 0; + +} + +PUINT8 wmt_lib_def_patch_name(VOID) +{ + WMT_INFO_FUNC("wmt-lib: use default patch name (%s)\n", gDevWmt.cPatchName); + return gDevWmt.cPatchName; +} + +MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(VOID) +{ + MTK_WCN_BOOL bIsSupportTherm = MTK_WCN_BOOL_TRUE; + /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ + if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) + || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { + WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); + bIsSupportTherm = MTK_WCN_BOOL_FALSE; + } + if (!mtk_wcn_stp_is_ready()) { + WMT_ERR_FUNC("thermal command can not be send: STP is not ready\n"); + bIsSupportTherm = MTK_WCN_BOOL_FALSE; + } + + return bIsSupportTherm; +} + +MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID) +{ + /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ + if (((0x6620 == gDevWmt.chip_id) && (WMTHWVER_E3 > gDevWmt.eWmtHwVer)) + || (WMTHWVER_INVALID == gDevWmt.eWmtHwVer)) { + WMT_ERR_FUNC("thermal command fail: chip version(WMTHWVER_TYPE:%d) is not valid\n", gDevWmt.eWmtHwVer); + return MTK_WCN_BOOL_FALSE; + } + + return MTK_WCN_BOOL_TRUE; +} + +/*! + * \brief Update combo chip pin settings (GPIO) + * + * An internal library function to support various settings for chip GPIO. It is + * updated in a grouping way: configure all required pins in a single call. + * + * \param id desired pin ID to be controlled + * \param stat desired pin states to be set + * \param flag supplementary options for this operation + * + * \retval 0 operation success + * \retval -1 invalid id + * \retval -2 invalid stat + * \retval < 0 error for operation fail + */ +static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /* input sanity check */ + if (WMT_IC_PIN_MAX <= id) { + WMT_ERR_FUNC("invalid ic pin id(%d)\n", id); + return -1; + } + if (WMT_IC_PIN_STATE_MAX <= stat) { + WMT_ERR_FUNC("invalid ic pin state (%d)\n", stat); + return -2; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_GPIO_CTRL (ic pin id:%d, stat:%d, flag:0x%x)\n", id, stat, flag); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_GPIO_CTRL; + pOp->op.au4OpData[0] = id; + pOp->op.au4OpData[1] = stat; + pOp->op.au4OpData[2] = flag; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) + WMT_WARN_FUNC("PIN_ID(%d) PIN_STATE(%d) flag(%d) fail\n", id, stat, flag); + else + WMT_DBG_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return 0; +} + +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 value; + P_OSAL_SIGNAL pSignal; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + value = *pvalue; + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", isWrite, offset, *pvalue, mask); + pOp->op.opId = WMT_OPID_REG_RW; + pOp->op.au4OpData[0] = isWrite; + pOp->op.au4OpData[1] = offset; + pOp->op.au4OpData[2] = (SIZE_T)&value; + pOp->op.au4OpData[3] = mask; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (MTK_WCN_BOOL_FALSE != bRet) { + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, value, mask); + if (!isWrite) + *pvalue = value; + + return 0; + } + WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, value, mask, bRet); + return -1; +} + +INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 value; + P_OSAL_SIGNAL pSignal; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + value = *pvalue; + WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", + isWrite, offset, *pvalue, mask); + pOp->op.opId = WMT_OPID_EFUSE_RW; + pOp->op.au4OpData[0] = isWrite; + pOp->op.au4OpData[1] = offset; + pOp->op.au4OpData[2] = (SIZE_T)&value; + pOp->op.au4OpData[3] = mask; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (MTK_WCN_BOOL_FALSE != bRet) { + WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, value, mask); + if (!isWrite) + *pvalue = value; + + return 0; + } + WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, value, mask, bRet); + return -1; + +} + +/*! + * \brief update combo chip AUDIO Interface (AIF) settings + * + * A library function to support updating chip AUDIO pin settings. A group of + * pins is updated as a whole. + * + * \param aif desired audio interface state to use + * \param flag whether audio pin is shared or not + * + * \retval 0 operation success + * \retval -1 invalid aif + * \retval < 0 error for invalid parameters or operation fail + */ +INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share) +{ + if (CMB_STUB_AIF_MAX <= aif) { + WMT_ERR_FUNC("invalid aif (%d)\n", aif); + return -1; + } + WMT_DBG_FUNC("call pin_ctrl for aif:%d, share:%d\n", aif, (MTK_WCN_BOOL_TRUE == share) ? 1 : 0); + /* Translate CMB_STUB_AIF_X into WMT_IC_PIN_STATE by array */ + return wmt_lib_pin_ctrl(WMT_IC_PIN_AUDIO, + cmb_aif2pin_stat[aif], + (MTK_WCN_BOOL_TRUE == share) ? WMT_LIB_AIF_FLAG_SHARE : WMT_LIB_AIF_FLAG_SEPARATE); +} + +INT32 wmt_lib_host_awake_get(VOID) +{ + return wmt_plat_wake_lock_ctrl(WL_OP_GET); +} + +INT32 wmt_lib_host_awake_put(VOID) +{ + return wmt_plat_wake_lock_ctrl(WL_OP_PUT); +} + +MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + if (op == BTM_RST_OP) { + /* high priority, not to enqueue into the queue of wmtd */ + WMT_INFO_FUNC("Invoke whole chip reset from stp_btm!!!\n"); + wmt_lib_cmb_rst(WMTRSTSRC_RESET_STP); + bRet = MTK_WCN_BOOL_TRUE; + } else if (op == BTM_DMP_OP) { + + WMT_WARN_FUNC("TBD!!!\n"); + } else if (op == BTM_GET_AEE_SUPPORT_FLAG) { + bRet = wmt_core_get_aee_dump_flag(); + } + return bRet; +} + +MTK_WCN_BOOL wmt_cdev_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg) +{ + + INT32 i = 0; + P_DEV_WMT pDevWmt = &gDevWmt; + PUINT8 drv_name[] = { + "DRV_TYPE_BT", + "DRV_TYPE_FM", + "DRV_TYPE_GPS", + "DRV_TYPE_WIFI" + }; + + for (i = 0; i <= WMTDRV_TYPE_WIFI; i++) { + /* <1> check if reset callback is registered */ + if (pDevWmt->rFdrvCb.fDrvRst[i]) { + /* <2> send the msg to this subfucntion */ + /*src, dst, msg_type, msg_data, msg_size */ + pDevWmt->rFdrvCb.fDrvRst[i] (WMTDRV_TYPE_WMT, i, WMTMSG_TYPE_RESET, &msg, + sizeof(ENUM_WMTRSTMSG_TYPE_T)); + WMT_INFO_FUNC("type = %s, msg sent\n", drv_name[i]); + } else { + WMT_DBG_FUNC("type = %s, unregistered\n", drv_name[i]); + } + } + + return MTK_WCN_BOOL_TRUE; +} + +VOID wmt_lib_state_init(VOID) +{ + /* UINT32 i = 0; */ + P_DEV_WMT pDevWmt = &gDevWmt; + P_OSAL_OP pOp; + + /* Initialize op queue */ + /* RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); */ + /* RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); */ + + while (!RB_EMPTY(&pDevWmt->rActiveOpQ)) { +#if 0 + osal_signal_init(&(pOp->signal)); + wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); +#endif + pOp = wmt_lib_get_op(&pDevWmt->rActiveOpQ); + if (pOp) { + if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, -1); + else + wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); + } + } + + /* Put all to free Q */ + /* + for (i = 0; i < WMT_OP_BUF_SIZE; i++) { + osal_signal_init(&(pDevWmt->arQue[i].signal)); + wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); + } */ +} + +#if 0 +INT32 wmt_lib_sdio_ctrl(UINT32 on) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_SDIO_CTRL\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_SDIO_CTRL; + pOp->op.au4OpData[0] = on; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + bRet = wmt_lib_put_act_op(pOp); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("WMT_OPID_SDIO_CTRL failed\n"); + return -1; + } + WMT_DBG_FUNC("OPID(WMT_OPID_SDIO_CTRL)ok\n"); + + return 0; +} +#endif + +MTK_WCN_BOOL wmt_lib_hw_state_show(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_HW_STATE_SHOW\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_GPIO_STATE; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + bRet = wmt_lib_put_act_op(pOp); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("WMT_OPID_HW_STATE_SHOW failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_HW_STATE_SHOW)ok\n"); + return MTK_WCN_BOOL_TRUE; +} + +MTK_WCN_BOOL wmt_lib_hw_rst(VOID) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + P_DEV_WMT pDevWmt = &gDevWmt; + + wmt_lib_state_init(); + + osal_clear_bit(WMT_STAT_STP_REG, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_OPEN, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_EN, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_RDY, &pDevWmt->state); + osal_clear_bit(WMT_STAT_RX, &pDevWmt->state); + osal_clear_bit(WMT_STAT_CMD, &pDevWmt->state); + + /*Before do hardware reset, we show GPIO state to check if others modified our pin state accidentially */ + wmt_lib_hw_state_show(); + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_HW_RST\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_HW_RST; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + bRet = wmt_lib_put_act_op(pOp); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("WMT_OPID_HW_RST failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_HW_RST)ok\n"); + return MTK_WCN_BOOL_TRUE; +} + +MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /* <1> wmt state reset */ + wmt_lib_state_init(); + + /* <2> Reset STP data structure */ + WMT_DBG_FUNC("Cleanup STP context\n"); + mtk_wcn_stp_flush_context(); + /* <3> Reset STP-PSM data structure */ + WMT_DBG_FUNC("Cleanup STP-PSM context\n"); + mtk_wcn_stp_psm_reset(); + + /* <4> do sw reset in wmt-core */ + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_SW_RST\n"); + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_FUNC_ON_TIME; + + pOp->op.opId = WMT_OPID_SW_RST; + pOp->op.au4OpData[0] = baudRst; + + bRet = wmt_lib_put_act_op(pOp); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("WMT_OPID_SW_RST failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_SW_RST)ok\n"); + return MTK_WCN_BOOL_TRUE; +} + +ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src) +{ +#define RETRYTIMES 10 + MTK_WCN_BOOL bRet; + ENUM_WMTRSTRET_TYPE_T retval = WMTRSTRET_MAX; + ENUM_WMTRSTMSG_TYPE_T rstMsg = WMTRSTMSG_RESET_MAX; + INT32 retries = RETRYTIMES; + P_DEV_WMT pDevWmt = &gDevWmt; + P_OSAL_OP pOp; + PUINT8 srcName[] = { "WMTRSTSRC_RESET_BT", + "WMTRSTSRC_RESET_FM", + "WMTRSTSRC_RESET_GPS", + "WMTRSTSRC_RESET_WIFI", + "WMTRSTSRC_RESET_STP", + "WMTRSTSRC_RESET_TEST" + }; + + if (src < WMTRSTSRC_RESET_MAX) + WMT_INFO_FUNC("reset source = %s\n", srcName[src]); + + if (WMTRSTSRC_RESET_TEST == src) { + pOp = wmt_lib_get_current_op(pDevWmt); + if (pOp && ((WMT_OPID_FUNC_ON == pOp->op.opId) + || (WMT_OPID_FUNC_OFF == pOp->op.opId))) { + WMT_INFO_FUNC("can't do reset by test src when func on/off\n"); + return -1; + } + } + /* <1> Consider the multi-context combo_rst case. */ + if (osal_test_and_set_bit(WMT_STAT_RST_ON, &pDevWmt->state)) { + retval = WMTRSTRET_ONGOING; + goto rstDone; + } + /* <2> Block all STP request */ + mtk_wcn_stp_enable(0); + + /* <3> RESET_START notification */ + bRet = wmt_cdev_rstmsg_snd(WMTRSTMSG_RESET_START); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); + retval = WMTRSTRET_FAIL; + goto rstDone; + } + /* wakeup blocked opid */ + pOp = wmt_lib_get_current_op(pDevWmt); + if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, -1); + + /* wakeup blocked cmd */ + wmt_dev_rx_event_cb(); + + /* <4> retry until reset flow successful */ + while (retries > 0) { + /* <4.1> reset combo hw */ + bRet = wmt_lib_hw_rst(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_hw_rst!\n"); + retries--; + continue; + } + /* <4.2> reset driver/combo sw */ + bRet = wmt_lib_sw_rst(1); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_sw_rst!\n"); + retries--; + continue; + } + break; + } + + osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state); + + if (bRet == MTK_WCN_BOOL_FALSE) { + rstMsg = WMTRSTMSG_RESET_END_FAIL; + WMT_WARN_FUNC("[whole chip reset] fail! retries = %d\n", RETRYTIMES - retries); + } else { + rstMsg = WMTRSTMSG_RESET_END; + WMT_INFO_FUNC("[whole chip reset] ok! retries = %d\n", RETRYTIMES - retries); + } + + /* <5> RESET_END notification */ + bRet = wmt_cdev_rstmsg_snd(rstMsg); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); + retval = WMTRSTRET_FAIL; + } else { + retval = WMTRSTMSG_RESET_END == rstMsg ? WMTRSTRET_SUCCESS : WMTRSTRET_FAIL; + } + mtk_wcn_stp_coredump_start_ctrl(0); + mtk_wcn_stp_set_wmt_evt_err_trg_assert(0); +rstDone: + if (osal_test_and_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state)) + WMT_WARN_FUNC("[whole chip reset] retval = %d\n", retval); + + return retval; +} + +MTK_WCN_BOOL wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +{ + + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_DEV_WMT pWmtDev = &gDevWmt; + + if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { + WMT_DBG_FUNC("reg ok!\n"); + pWmtDev->rFdrvCb.fDrvRst[eType] = pCb; + bRet = MTK_WCN_BOOL_TRUE; + } else { + WMT_WARN_FUNC("reg fail!\n"); + } + + return bRet; +} + +MTK_WCN_BOOL wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_DEV_WMT pWmtDev = &gDevWmt; + + if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { + WMT_DBG_FUNC("unreg ok!\n"); + pWmtDev->rFdrvCb.fDrvRst[eType] = NULL; + bRet = MTK_WCN_BOOL_TRUE; + } else { + WMT_WARN_FUNC("unreg fail!\n"); + } + + return bRet; +} + +UINT32 wmt_lib_dbg_level_set(UINT32 level) +{ + gWmtDbgLvl = level > WMT_LOG_LOUD ? WMT_LOG_LOUD : level; + return 0; +} + +INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value) +{ + return mtk_wcn_stp_set_wmt_last_close(value); +} + +INT32 wmt_lib_notify_stp_sleep(void) +{ + INT32 iRet = 0x0; + + iRet = wmt_lib_psm_lock_aquire(); + if (iRet) { + WMT_ERR_FUNC("--->lock psm_lock failed, iRet=%d\n", iRet); + return iRet; + } + + iRet = mtk_wcn_stp_notify_sleep_for_thermal(); + wmt_lib_psm_lock_release(); + + return iRet; +} + +VOID wmt_lib_set_patch_num(UINT32 num) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + pWmtDev->patchNum = num; +} + +VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + if (pPatchinfo) + pWmtDev->pWmtPatchInfo = pPatchinfo; + +} + +INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp) +{ + if (pWmtDev) { + pWmtDev->pCurOP = pOp; + WMT_DBG_FUNC("pOp=0x%p\n", pOp); + return 0; + } + WMT_ERR_FUNC("Invalid pointer\n"); + return -1; +} + +P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev) +{ + if (pWmtDev) + return pWmtDev->pCurOP; + + WMT_ERR_FUNC("Invalid pointer\n"); + return NULL; +} + +UINT8 *wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, UINT8 *buf, UINT32 len) +{ + UINT8 *pAddr = NULL; + UINT32 sublen1 = 0; + UINT32 sublen2 = 0; + P_CONSYS_EMI_ADDR_INFO p_consys_info; + + p_consys_info = wmt_plat_get_emi_phy_add(); + osal_assert(p_consys_info); + + if (section == 0) { + pAddr = wmt_plat_get_emi_virt_add(0x0); + if (len > 1024) + len = 1024; + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); + osal_memcpy(&buf[0], pAddr, len); + } + } else { + if (offset >= 0x7fff) + offset = 0x0; + + if (offset + len > 32768) { + pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get part1 EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("part1 vir addr(0x%p)\n", pAddr); + sublen1 = 0x7fff - offset; + osal_memcpy(&buf[0], pAddr, sublen1); + } + pAddr = wmt_plat_get_emi_virt_add(p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get part2 EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("part2 vir addr(0x%p)\n", pAddr); + sublen2 = len - sublen1; + osal_memcpy(&buf[sublen1], pAddr, sublen2); + } + } else { + pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); + osal_memcpy(&buf[0], pAddr, len); + } + } + } + + return 0; +} + +INT32 wmt_lib_poll_cpupcr(UINT32 count, UINT16 sleep, UINT16 toAee) +{ + ENUM_STP_FW_ISSUE_TYPE issue_type; + + issue_type = STP_DBG_PROC_TEST; + + stp_dbg_poll_cpupcr(count, sleep, 1); + + if (toAee) { + stp_dbg_set_fw_info("STP ProcTest", osal_strlen("STP ProcTest"), issue_type); + osal_dbg_assert_aee("[SOC_CONSYS]ProcTest", + "**[WCN_ISSUE_INFO]STP Tx Timeout**\n Polling CPUPCR for FW debug usage\n"); + } else { + WMT_INFO_FUNC("wmt_lib:do not pass cpupcr to AEE\n"); + } + return 0; +} + +UINT8 *wmt_lib_get_cpupcr_xml_format(UINT32 *len) +{ + PUINT8 temp; + UINT32 i = 0; + + osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE); + temp = g_cpupcr_buf; + stp_dbg_cpupcr_infor_format(&temp, len); + + pr_debug("print xml buffer,len(%d):\n\n", *len); + for (i = 0; i < *len; i++) + pr_cont("%c", g_cpupcr_buf[i]); + + return &g_cpupcr_buf[0]; +} + +UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en) +{ + return stp_dbg_set_host_assert_info(type, reason, en); +} + +INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl) +{ + wmt_plat_thermal_ctrl_cb_reg(thermal_ctrl); + return 0; +} + +INT8 wmt_lib_co_clock_get(void) +{ + if (gDevWmt.rWmtGenConf.cfgExist) + return gDevWmt.rWmtGenConf.co_clock_flag; + else + return -1; +} + +#if CFG_WMT_PS_SUPPORT +UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en) +{ + WMT_WARN_FUNC("%s quick sleep mode\n", en ? "enable" : "disable"); + g_quick_sleep_ctrl = en; + return 0; +} +#endif + +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_lib_jtag_flag_set(UINT32 en) +{ + return wmt_plat_jtag_flag_ctrl(en); +} +#endif + +UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver) +{ + return stp_dbg_set_wifiver(wifiver); +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h new file mode 100644 index 0000000000000..b1b5285638f96 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/stp_exp.h @@ -0,0 +1,252 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _STP_EXP_H_ +#define _STP_EXP_H_ + +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_stp_exp.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define ANT_TASK_INDX (7) +#if CFG_WMT_LTE_COEX_HANDLING +#define COEX_TASK_INDX (8) +#define MTKSTP_MAX_TASK_NUM (9) +#else +#define MTKSTP_MAX_TASK_NUM (8) +#endif + +#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ + +#define STP_EXP_HID_API_EXPORT 0 + +#else + +#define STP_EXP_HID_API_EXPORT 1 + +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +typedef void (*MTK_WCN_STP_EVENT_CB) (void); +typedef INT32 (*MTK_WCN_STP_IF_TX) (const UINT8 *data, const UINT32 size, UINT32 *written_size); +/* export for HIF driver */ +typedef void (*MTK_WCN_STP_IF_RX) (const UINT8 *data, INT32 size); + +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX = 1, + STP_BTIF_IF_TX = 2, + STP_MAX_IF_TX +} ENUM_STP_TX_IF_TYPE; +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_receive_data(UINT8 *buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* Is STP ready? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:ready, FALSE:not ready +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +extern int mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); + +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_tx_event_cb +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* func +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_tx_event_cb(int type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_event_cb +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* func +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_event_cb(int type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_tx +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_rx +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern int mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#else +extern INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); +extern INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); +extern INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); +extern MTK_WCN_BOOL _mtk_wcn_stp_is_rxqueue_empty(UINT8 type); +extern MTK_WCN_BOOL _mtk_wcn_stp_is_ready(void); +extern INT32 _mtk_wcn_stp_parser_data(UINT8 *buffer, UINT32 length); +extern void _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); +extern INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); +extern INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); +extern INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); +extern INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); +extern INT32 _mtk_wcn_stp_coredump_start_get(VOID); + +#endif + +#endif /* _WMT_EXP_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h new file mode 100644 index 0000000000000..6d10c3ff26590 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt.h @@ -0,0 +1,19 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _MTKWMT_H_ +#define _MTKWMT_H_ +#include "wmt_core.h" + +#endif /*_MTKWMT_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h new file mode 100644 index 0000000000000..06238e07879fe --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_exp.h @@ -0,0 +1,329 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_EXP_H_ +#define _WMT_EXP_H_ + +#include +#include "osal.h" +#include "wmt_plat.h" +#include "wmt_stp_exp.h" +/* not to reference to internal wmt */ +/* #include "wmt_core.h" */ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#ifndef DFT_TAG +#define DFT_TAG "[WMT-DFT]" +#endif + +#define WMT_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_LOUD) \ + osal_dbg_print(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_INFO_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_INFO) \ + osal_dbg_print(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_WARN_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_WARN) \ + osal_warn_print(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_ERR_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_ERR) \ + osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ +} while (0) +#define WMT_DBG_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_DBG) \ + osal_dbg_print(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_TRC_FUNC(f) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_DBG) \ + osal_dbg_print(DFT_TAG "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +extern UINT32 gWmtDbgLvl; +#endif +extern OSAL_BIT_OP_VAR gBtWifiGpsState; +extern OSAL_BIT_OP_VAR gGpsFmState; +extern UINT32 gWifiProbed; +extern MTK_WCN_BOOL g_pwr_off_flag; +extern UINT32 g_IsNeedDoChipReset; +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#define WMT_LOG_LOUD 4 +#define WMT_LOG_DBG 3 +#define WMT_LOG_INFO 2 +#define WMT_LOG_WARN 1 +#define WMT_LOG_ERR 0 +#endif +#define CFG_CORE_INTERNAL_TXRX 0 /*just do TX/RX in host side */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_STP = 5, + WMTDRV_TYPE_LPBK = 6, + WMTDRV_TYPE_COREDUMP = 7, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +/* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ +/* TODO: how do we extend for new chip and newer revision? */ +/* TODO: This way is hard to extend */ +typedef enum _ENUM_WMTHWVER_TYPE_T { + WMTHWVER_E1 = 0x0, + WMTHWVER_E2 = 0x1, + WMTHWVER_E3 = 0x2, + WMTHWVER_E4 = 0x3, + WMTHWVER_E5 = 0x4, + WMTHWVER_E6 = 0x5, + WMTHWVER_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +typedef enum _ENUM_WMTDSNS_TYPE_T { + WMTDSNS_FM_DISABLE = 0, + WMTDSNS_FM_ENABLE = 1, + WMTDSNS_FM_GPS_DISABLE = 2, + WMTDSNS_FM_GPS_ENABLE = 3, + WMTDSNS_MAX +} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; + +typedef enum _ENUM_WMTTHERM_TYPE_T { + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY = 3, + WMTMSG_TYPE_HW_FUNC_ON = 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + VOID *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client + can't touch this buffer after this function return. */ + UINT32 /* Buffer size in unit of byte */ +); + +typedef enum _SDIO_PS_OP { + OWN_SET = 0, + OWN_CLR = 1, + OWN_STATE = 2, +} SDIO_PS_OP; + +typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); + +typedef enum _ENUM_WMTCHIN_TYPE_T { + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_MAX, + +} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; + +#endif + +typedef enum _ENUM_WMTRSTMSG_TYPE_T { + WMTRSTMSG_RESET_START = 0x0, + WMTRSTMSG_RESET_END = 0x1, + WMTRSTMSG_RESET_END_FAIL = 0x2, + WMTRSTMSG_RESET_MAX, + WMTRSTMSG_RESET_INVALID = 0xff +} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; + +typedef enum _ENUM_BT_GPS_ONOFF_STATE_T { + WMT_BT_ON = 0, + WMT_GPS_ON = 1, + WMT_WIFI_ON = 2, + WMT_FM_ON = 3, + WMT_BT_GPS_STATE_MAX, + WMT_BT_GPS_STATE_INVALID = 0xff +} ENUM_BT_GPS_ONOFF_STATE_T, *P_ENUM_BT_GPS_ONOFF_STATE_T; + +#if 1 /* moved from wmt_core.h */ +typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM; + +typedef enum { + WMT_SDIO_FUNC_STP = 0, + WMT_SDIO_FUNC_WIFI = 1, + WMT_SDIO_FUNC_MAX +} WMT_SDIO_FUNC_TYPE; +#endif + +typedef INT32(*wmt_wlan_probe_cb) (VOID); +typedef INT32(*wmt_wlan_remove_cb) (VOID); +typedef INT32(*wmt_wlan_bus_cnt_get_cb) (VOID); +typedef INT32(*wmt_wlan_bus_cnt_clr_cb) (VOID); + +typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { + wmt_wlan_probe_cb wlan_probe_cb; + wmt_wlan_remove_cb wlan_remove_cb; + wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; + wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; +} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; + +#ifdef CONFIG_MTK_COMBO_ANT +typedef enum _ENUM_WMT_ANT_RAM_CTRL_T { + WMT_ANT_RAM_GET_STATUS = 0, + WMT_ANT_RAM_DOWNLOAD = WMT_ANT_RAM_GET_STATUS + 1, + WMT_ANT_RAM_CTRL_MAX +} ENUM_WMT_ANT_RAM_CTRL, *P_ENUM_WMT_ANT_RAM_CTRL; + +typedef enum _ENUM_WMT_ANT_RAM_SEQ_T { + WMT_ANT_RAM_START_PKT = 1, + WMT_ANT_RAM_CONTINUE_PKT = WMT_ANT_RAM_START_PKT + 1, + WMT_ANT_RAM_END_PKT = WMT_ANT_RAM_CONTINUE_PKT + 1, + WMT_ANT_RAM_SEQ_MAX +} ENUM_WMT_ANT_RAM_SEQ, *P_ENUM_WMT_ANT_RAM_SEQ; + +typedef enum _ENUM_WMT_ANT_RAM_STATUS_T { + WMT_ANT_RAM_NOT_EXIST = 0, + WMT_ANT_RAM_EXIST = WMT_ANT_RAM_NOT_EXIST + 1, + WMT_ANT_RAM_DOWN_OK = WMT_ANT_RAM_EXIST + 1, + WMT_ANT_RAM_DOWN_FAIL = WMT_ANT_RAM_DOWN_OK + 1, + WMT_ANT_RAM_PARA_ERR = WMT_ANT_RAM_DOWN_FAIL + 1, + WMT_ANT_RAM_OP_ERR = WMT_ANT_RAM_PARA_ERR + 1, + WMT_ANT_RAM_MAX +} ENUM_WMT_ANT_RAM_STATUS, *P_ENUM_WMT_ANT_RAM_STATUS; +#endif + +extern INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); +extern INT32 mtk_wcn_wmt_wlan_unreg(VOID); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern wmt_wlan_probe_cb mtk_wcn_wlan_probe; +extern wmt_wlan_remove_cb mtk_wcn_wlan_remove; +extern wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt; +extern wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*subsystem function ctrl APIs*/ +extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); + +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +#define WMT_EXP_HID_API_EXPORT 0 + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); + +extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); + +extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); + +extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); + +extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); + +extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); + +extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); +/* +return value: +enable/disable thermal sensor function: true(1)/false(0) +read thermal sensor function: thermal value + +*/ +extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); + +extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); + +#else +#define WMT_EXP_HID_API_EXPORT 1 +#endif + +#ifdef CONFIG_MTK_COMBO_ANT +extern ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, + UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq); +#endif +extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ +extern VOID wmt_lib_ps_irq_cb(VOID); + +extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type); + +extern INT32 mtk_wcn_wmt_system_state_reset(VOID); +extern MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value); +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +extern VOID mtk_wcn_wmt_exp_init(VOID); +extern VOID mtk_wcn_wmt_exp_deinit(VOID); +#endif +extern INT8 mtk_wcn_wmt_co_clock_flag_get(VOID); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_EXP_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h new file mode 100644 index 0000000000000..075496cac54f9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/include/wmt_plat.h @@ -0,0 +1,295 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_PLAT_H_ +#define _WMT_PLAT_H_ +#include "osal_typedef.h" +#include "stp_exp.h" +#include + +/* #include "mtk_wcn_consys_hw.h" */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if 1 /* moved from wmt_exp.h */ +#ifndef DFT_TAG +#define DFT_TAG "[WMT-DFT]" +#endif + +#define WMT_PLAT_LOG_LOUD 4 +#define WMT_PLAT_LOG_DBG 3 +#define WMT_PLAT_LOG_INFO 2 +#define WMT_PLAT_LOG_WARN 1 +#define WMT_PLAT_LOG_ERR 0 + +extern UINT32 wmtPlatLogLvl; + +#define WMT_PLAT_LOUD_FUNC(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_LOUD) \ + pr_debug(DFT_TAG "[L]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_PLAT_INFO_FUNC(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_INFO) \ + pr_debug(DFT_TAG "[I]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_PLAT_WARN_FUNC(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_WARN) \ + pr_warn(DFT_TAG "[W]%s:" fmt, __func__ , ##arg); \ +} while (0) +#define WMT_PLAT_ERR_FUNC(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_ERR) \ + pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__ , __LINE__, ##arg); \ +} while (0) +#define WMT_PLAT_DBG_FUNC(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_DBG) \ + pr_debug(DFT_TAG "[D]%s:" fmt, __func__ , ##arg); \ +} while (0) + +#endif + +#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_exp.h */ + +#define CFG_WMT_DUMP_INT_STATUS 0 +#define CONSYS_ENALBE_SET_JTAG 1 + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_FUNC_STATE_ { + FUNC_ON = 0, + FUNC_OFF = 1, + FUNC_RST = 2, + FUNC_STAT = 3, + FUNC_CTRL_MAX, +} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE; + +typedef enum _ENUM_PIN_ID_ { + PIN_BGF_EINT = 0, + PIN_I2S_GRP = 1, + PIN_GPS_SYNC = 2, + PIN_GPS_LNA = 3, +#if CFG_WMT_LTE_COEX_HANDLING + PIN_TDM_REQ = 4, +#endif + PIN_ID_MAX +} ENUM_PIN_ID, *P_ENUM_PIN_ID; + +typedef enum _ENUM_PIN_STATE_ { + PIN_STA_INIT = 0, + PIN_STA_OUT_L = 1, + PIN_STA_OUT_H = 2, + PIN_STA_IN_L = 3, + PIN_STA_MUX = 4, + PIN_STA_EINT_EN = 5, + PIN_STA_EINT_DIS = 6, + PIN_STA_DEINIT = 7, + PIN_STA_SHOW = 8, + PIN_STA_MAX +} ENUM_PIN_STATE, *P_ENUM_PIN_STATE; + +typedef enum _CMB_IF_TYPE_ { + CMB_IF_UART = 0, + CMB_IF_WIFI_SDIO = 1, + CMB_IF_BGF_SDIO = 2, + CMB_IF_BGWF_SDIO = 3, + CMB_IF_TYPE_MAX +} CMB_IF_TYPE, *P_CMB_IF_TYPE; + +typedef INT32(*fp_set_pin) (ENUM_PIN_STATE); + +typedef enum _ENUM_WL_OP_ { + WL_OP_GET = 0, + WL_OP_PUT = 1, + WL_OP_MAX +} ENUM_WL_OP, *P_ENUM_WL_OP; + +typedef enum _ENUM_PALDO_TYPE_ { + BT_PALDO = 0, + WIFI_PALDO = 1, + FM_PALDO = 2, + GPS_PALDO = 3, + PMIC_CHIPID_PALDO = 4, + WIFI_5G_PALDO = 5, + PALDO_TYPE_MAX +} ENUM_PALDO_TYPE, *P_ENUM_PALDO_TYPE; + +typedef enum _ENUM_PALDO_OP_ { + PALDO_OFF = 0, + PALDO_ON = 1, + PALDO_OP_MAX +} ENUM_PALDO_OP, *P_ENUM_PALDO_OP; + +typedef enum _ENUM_HOST_DUMP_STATE_T { + STP_HOST_DUMP_NOT_START = 0, + STP_HOST_DUMP_GET = 1, + STP_HOST_DUMP_GET_DONE = 2, + STP_HOST_DUMP_END = 3, + STP_HOST_DUMP_MAX +} ENUM_HOST_DUMP_STATE, *P_ENUM_HOST_DUMP_STATE_T; + +typedef enum _ENUM_FORCE_TRG_ASSERT_T { + STP_FORCE_TRG_ASSERT_EMI = 0, + STP_FORCE_TRG_ASSERT_DEBUG_PIN = 1, + STP_FORCE_TRG_ASSERT_MAX = 2 +} ENUM_FORCE_TRG_ASSERT_T, *P_ENUM_FORCE_TRG_ASSERT_T; + +typedef enum _ENUM_CHIP_DUMP_STATE_T { + STP_CHIP_DUMP_NOT_START = 0, + STP_CHIP_DUMP_PUT = 1, + STP_CHIP_DUMP_PUT_DONE = 2, + STP_CHIP_DUMP_END = 3, + STP_CHIP_DUMP_MAX +} ENUM_CHIP_DUMP_STATE, *P_ENUM_CHIP_DUMP_STATE_T; + +typedef struct _EMI_CTRL_STATE_OFFSET_ { + UINT32 emi_apmem_ctrl_state; + UINT32 emi_apmem_ctrl_host_sync_state; + UINT32 emi_apmem_ctrl_host_sync_num; + UINT32 emi_apmem_ctrl_chip_sync_state; + UINT32 emi_apmem_ctrl_chip_sync_num; + UINT32 emi_apmem_ctrl_chip_sync_addr; + UINT32 emi_apmem_ctrl_chip_sync_len; + UINT32 emi_apmem_ctrl_chip_print_buff_start; + UINT32 emi_apmem_ctrl_chip_print_buff_len; + UINT32 emi_apmem_ctrl_chip_print_buff_idx; + UINT32 emi_apmem_ctrl_chip_int_status; + UINT32 emi_apmem_ctrl_chip_paded_dump_end; + UINT32 emi_apmem_ctrl_host_outband_assert_w1; + UINT32 emi_apmem_ctrl_chip_page_dump_num; +} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET; + +typedef struct _BGF_IRQ_BALANCE_ { + UINT32 counter; + unsigned long flags; + spinlock_t lock; +} BGF_IRQ_BALANCE, *P_BGF_IRQ_BALANCE; + +typedef struct _CONSYS_EMI_ADDR_INFO_ { + UINT32 emi_phy_addr; + UINT32 paged_trace_off; + UINT32 paged_dump_off; + UINT32 full_dump_off; + P_EMI_CTRL_STATE_OFFSET p_ecso; +} CONSYS_EMI_ADDR_INFO, *P_CONSYS_EMI_ADDR_INFO; + +typedef struct _GPIO_TDM_REQ_INFO_ { + UINT32 ant_sel_index; + UINT32 gpio_number; + UINT32 cr_address; +} GPIO_TDM_REQ_INFO, *P_GPIO_TDM_REQ_INFO; + +typedef VOID(*irq_cb) (VOID); +typedef INT32(*device_audio_if_cb) (CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); +typedef VOID(*func_ctrl_cb) (UINT32 on, UINT32 type); +typedef long (*thermal_query_ctrl_cb) (VOID); +typedef INT32(*deep_idle_ctrl_cb) (UINT32); + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern UINT32 gWmtDbgLvl; +extern struct device *wmt_dev; +#ifdef CFG_WMT_READ_EFUSE_VCN33 +extern INT32 wmt_set_pmic_voltage(UINT32 level); +#endif +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 wmt_plat_init(UINT32 co_clock_type); + +INT32 wmt_plat_deinit(VOID); + +INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state); + +INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); + +INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); + +INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId); + +INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb); +VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb); +VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl); +VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl); +VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl); + +INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo); +UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset); +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en); +#endif +#if CFG_WMT_DUMP_INT_STATUS +VOID wmt_plat_BGF_irq_dump_status(VOID); +MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID); +#endif +P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID); +UINT32 wmt_plat_read_cpupcr(VOID); +UINT32 wmt_plat_read_dmaregs(UINT32); +INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state); +UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type); +INT32 wmt_plat_update_host_sync_num(VOID); +INT32 wmt_plat_get_dump_info(UINT32 offset); +UINT32 wmt_plat_get_soc_chipid(VOID); +INT32 wmt_plat_set_dbg_mode(UINT32 flag); +VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf); +#if CFG_WMT_LTE_COEX_HANDLING +INT32 wmt_plat_get_tdm_antsel_index(VOID); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_PLAT_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile new file mode 100644 index 0000000000000..9052071189386 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/Makefile @@ -0,0 +1,6 @@ +ifeq ($(CONFIG_MTK_COMBO), y) + +obj-y += pub/ +obj-y += pri/ + +endif \ No newline at end of file diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h new file mode 100644 index 0000000000000..95d1ab02a9fa4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/bgw_desense.h @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef __BGW_DESENSE_H_ +#define __BGW_DESENSE_H_ + +#ifdef MSG +#undef MSG +#endif + +#ifdef ERR +#undef ERR +#endif + +#define PFX1 "[BWG] " +#define MSG(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) +#define ERR(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__ , ##arg) + +#ifdef NETLINK_TEST +#undef NETLINK_TEST +#endif + +#define NETLINK_TEST 17 + +#ifdef MAX_NL_MSG_LEN +#undef MAX_NL_MSG_LEN +#endif + +#define MAX_NL_MSG_LEN 1024 + + +#ifdef ON +#undef ON +#endif +#ifdef OFF +#undef OFF +#endif +#ifdef ACK +#undef ACK +#endif + +#define ON 1 +#define OFF 0 +#define ACK 2 + +/* +used send command to native process + +parameter: command could be macro ON: enable co-exist; OFF: disable co-exist; +ACK: after get native process init message send ACK + +*/ +extern void send_command_to_daemon(const int command); + +/* +before use kernel socket, please call init socket first +return value: 0: ok; -1: fail +*/ +extern int bgw_init_socket(void); + +extern void bgw_destroy_netlink_kernel(void); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h new file mode 100644 index 0000000000000..493a4dd16f23f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal.h @@ -0,0 +1,348 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _OSAL_H_ +#define _OSAL_H_ + +#include +#include +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define OS_BIT_OPS_SUPPORT 1 + +#define _osal_inline_ inline + +#define MAX_THREAD_NAME_LEN 16 +#define MAX_WAKE_LOCK_NAME_LEN 16 +#define OSAL_OP_BUF_SIZE 64 + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) +#define OSAL_OP_DATA_SIZE 8 +#else +#define OSAL_OP_DATA_SIZE 32 +#endif + +#define DBG_LOG_STR_SIZE 256 + +#define osal_sizeof(x) sizeof(x) + +#define osal_array_size(x) (sizeof(x)/sizeof(x[0])) + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#define WMT_OP_BIT(x) (0x1UL << x) +#define WMT_OP_HIF_BIT WMT_OP_BIT(0) + +#define RB_SIZE(prb) ((prb)->size) +#define RB_MASK(prb) (RB_SIZE(prb) - 1) +#define RB_COUNT(prb) ((prb)->write - (prb)->read) +#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) +#define RB_EMPTY(prb) ((prb)->write == (prb)->read) + +#define RB_INIT(prb, qsize) \ +do { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ +} while (0) + +#define RB_PUT(prb, value) \ +do { \ + if (!RB_FULL(prb)) { \ + (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \ + ++((prb)->write); \ + } \ + else { \ + osal_assert(!RB_FULL(prb)); \ + } \ +} while (0) + +#define RB_GET(prb, value) \ +do { \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \ + ++((prb)->read); \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + osal_assert(!RB_EMPTY(prb)); \ + } \ +} while (0) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef VOID(*P_TIMEOUT_HANDLER) (unsigned long); +typedef INT32(*P_COND) (VOID *); + +typedef struct _OSAL_TIMER_ { + struct timer_list timer; + P_TIMEOUT_HANDLER timeoutHandler; + unsigned long timeroutHandlerData; +} OSAL_TIMER, *P_OSAL_TIMER; + +typedef struct _OSAL_UNSLEEPABLE_LOCK_ { + spinlock_t lock; + unsigned long flag; +} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; + +typedef struct _OSAL_SLEEPABLE_LOCK_ { + struct mutex lock; +} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; + +typedef struct _OSAL_SIGNAL_ { + struct completion comp; + UINT32 timeoutValue; +} OSAL_SIGNAL, *P_OSAL_SIGNAL; + +typedef struct _OSAL_EVENT_ { + wait_queue_head_t waitQueue; +/* VOID *pWaitQueueData; */ + UINT32 timeoutValue; + INT32 waitFlag; + +} OSAL_EVENT, *P_OSAL_EVENT; + +typedef struct _OSAL_THREAD_ { + struct task_struct *pThread; + VOID *pThreadFunc; + VOID *pThreadData; + char threadName[MAX_THREAD_NAME_LEN]; +} OSAL_THREAD, *P_OSAL_THREAD; + +typedef struct _OSAL_FIFO_ { + /*fifo definition */ + VOID *pFifoBody; + spinlock_t fifoSpinlock; + /*fifo operations */ + INT32 (*FifoInit)(struct _OSAL_FIFO_ *pFifo, UINT8 *buf, UINT32); + INT32 (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoReset)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoSz)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoLen)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); + INT32 (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const VOID *buf, UINT32 len); + INT32 (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, void *buf, UINT32 len); +} OSAL_FIFO, *P_OSAL_FIFO; + +typedef struct firmware osal_firmware; + +typedef struct _OSAL_OP_DAT { + UINT32 opId; /* Event ID */ + UINT32 u4InfoBit; /* Reserved */ + SIZE_T au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */ +} OSAL_OP_DAT, *P_OSAL_OP_DAT; + +typedef struct _OSAL_LXOP_ { + OSAL_OP_DAT op; + OSAL_SIGNAL signal; + INT32 result; +} OSAL_OP, *P_OSAL_OP; + +typedef struct _OSAL_LXOP_Q { + OSAL_SLEEPABLE_LOCK sLock; + UINT32 write; + UINT32 read; + UINT32 size; + P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; +} OSAL_OP_Q, *P_OSAL_OP_Q; + +typedef struct _OSAL_WAKE_LOCK_ { + #ifdef CONFIG_PM_WAKELOCKS + struct wakeup_source wake_lock; + #else + struct wake_lock wake_lock; + #endif + UINT8 name[MAX_WAKE_LOCK_NAME_LEN]; +} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK; +#if 1 +typedef struct _OSAL_BIT_OP_VAR_ { + unsigned long data; + OSAL_UNSLEEPABLE_LOCK opLock; +} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; +#else +#define OSAL_BIT_OP_VAR unsigned long +#define P_OSAL_BIT_OP_VAR unsigned long * + +#endif +typedef UINT32(*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern UINT32 osal_strlen(const char *str); +extern INT32 osal_strcmp(const char *dst, const char *src); +extern INT32 osal_strncmp(const char *dst, const char *src, UINT32 len); +extern char *osal_strcpy(char *dst, const char *src); +extern char *osal_strncpy(char *dst, const char *src, UINT32 len); +extern char *osal_strcat(char *dst, const char *src); +extern char *osal_strncat(char *dst, const char *src, UINT32 len); +extern char *osal_strchr(const char *str, UINT8 c); +extern char *osal_strsep(char **str, const char *c); +extern int osal_strtol(const char *str, UINT32 adecimal, long *res); +extern INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...); +extern char *osal_strstr(char *str1, const char *str2); + +extern INT32 osal_err_print(const char *str, ...); +extern INT32 osal_dbg_print(const char *str, ...); +extern INT32 osal_warn_print(const char *str, ...); + +extern INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line); +extern INT32 osal_sprintf(char *str, const char *format, ...); +extern VOID *osal_malloc(UINT32 size); +extern VOID osal_free(const VOID *dst); +extern VOID *osal_memset(VOID *buf, INT32 i, UINT32 len); +extern VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len); +extern INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len); + +extern INT32 osal_sleep_ms(UINT32 ms); +extern INT32 osal_udelay(UINT32 us); +extern INT32 osal_timer_create(P_OSAL_TIMER); +extern INT32 osal_timer_start(P_OSAL_TIMER, UINT32); +extern INT32 osal_timer_stop(P_OSAL_TIMER); +extern INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer); +extern INT32 osal_timer_modify(P_OSAL_TIMER, UINT32); +extern INT32 osal_timer_delete(P_OSAL_TIMER); + +extern INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size); +extern VOID osal_fifo_deinit(P_OSAL_FIFO pFifo); +extern INT32 osal_fifo_reset(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); +extern UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size); +extern UINT32 osal_fifo_len(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo); +extern UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo); + +extern INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK plock); +extern INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); } +#else +extern INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK); +#endif +extern INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +extern INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +extern INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); } +#else +extern INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK); +#endif +extern INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +extern INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +extern INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK); + +extern INT32 osal_signal_init(P_OSAL_SIGNAL); +extern INT32 osal_wait_for_signal(P_OSAL_SIGNAL); +extern INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL); +extern INT32 osal_raise_signal(P_OSAL_SIGNAL); +extern INT32 osal_signal_deinit(P_OSAL_SIGNAL); + +extern INT32 osal_event_init(P_OSAL_EVENT); +extern INT32 osal_wait_for_event(P_OSAL_EVENT, P_COND, void *); +extern INT32 osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, void *); +extern INT32 osal_trigger_event(P_OSAL_EVENT); + +extern INT32 osal_event_deinit(P_OSAL_EVENT); + +extern INT32 osal_thread_create(P_OSAL_THREAD); +extern INT32 osal_thread_run(P_OSAL_THREAD); +extern INT32 osal_thread_should_stop(P_OSAL_THREAD); +extern INT32 osal_thread_stop(P_OSAL_THREAD); +/*extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ +extern INT32 osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); +/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ +extern INT32 osal_thread_destroy(P_OSAL_THREAD); + +extern INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); +extern INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData); + +extern INT32 osal_dbg_assert_aee(const char *module, const char *detail_description); +extern INT32 osal_gettimeofday(PINT32 sec, PINT32 usec); +extern INT32 osal_printtimeofday(const PUINT8 prefix); + +extern VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, UINT32 len, UINT32 limit); + +extern UINT32 osal_op_get_id(P_OSAL_OP pOp); +extern MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); +extern VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result); +extern VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result); +extern UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length); +extern VOID osal_thread_show_stack(P_OSAL_THREAD pThread); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#define osal_assert(condition) \ +do { \ + if (!(condition)) \ + osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition); \ +} while (0) + +#endif /* _OSAL_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h new file mode 100644 index 0000000000000..b3a9c57e062dd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/osal_typedef.h @@ -0,0 +1,90 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _OSAL_TYPEDEF_H_ +#define _OSAL_TYPEDEF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_EARLYSUSPEND +#include +#else +#include +#endif +#include +#include +#ifdef WMT_PLAT_ALPS +#include +#endif +#include +#ifdef CONFIG_PM_WAKELOCKS +#include +#else +#include +#endif +#include + +#ifndef _TYPEDEFS_H /*fix redifine */ +typedef char INT8; +#endif + +typedef void VOID, *PVOID, **PPVOID; +typedef char *PINT8, **PPINT8; +typedef short INT16, *PINT16, **PPINT16; +typedef int INT32, *PINT32, **PPINT32; +typedef long long INT64, *PINT64, **PPINT64; + +typedef unsigned char UINT8, *PUINT8, **PPUINT8; +typedef unsigned short UINT16, *PUINT16, **PPUINT16; +typedef unsigned int UINT32, *PUINT32, **PPUINT32; +typedef unsigned long long UINT64, *PUINT64, **PPUINT64; + +typedef size_t SIZE_T; + +typedef int MTK_WCN_BOOL; +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) +#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) +#endif + +#endif /*_OSAL_TYPEDEF_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h new file mode 100644 index 0000000000000..17be778484c17 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/include/wmt_idc.h @@ -0,0 +1,97 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WMT_IDC_H_ +#define _WMT_IDC_H_ + +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_stp_exp.h" + +#if CFG_WMT_LTE_COEX_HANDLING + +#include "wmt_stp_exp.h" +#include "conn_md_exp.h" + +#define LTE_IDC_BUFFER_MAX_SIZE 1024 +/*comment from firmware owner,max pckage num is 5,but should not happened*/ +#define WMT_IDC_RX_MAX_LEN 384 +#define LTE_MSG_ID_OFFSET 0x30 + +typedef enum { + WMT_IDC_TX_OPCODE_MIN = 0, + WMT_IDC_TX_OPCODE_LTE_PARA = 0x0a, + WMT_IDC_TX_OPCODE_LTE_FREQ = 0x0b, + WMT_IDC_TX_OPCODE_WIFI_MAX_POWER = 0x0c, + WMT_IDC_TX_OPCODE_DEBUG_MONITOR = 0x0e, + WMT_IDC_TX_OPCODE_SPLIT_FILTER = 0x0f, + WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS = 0x16, + WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION = 0x17, + WMT_IDC_TX_OPCODE_LTE_INDICATION = 0x20, + WMT_IDC_TX_OPCODE_MAX +} WMT_IDC_TX_OPCODE; + +typedef enum { + WMT_IDC_RX_OPCODE_BTWF_DEF_PARA = 0x0, + WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN = 0x1, + /* WMT_IDC_RX_OPCODE_TDM_REQ = 0x10, */ + WMT_IDC_RX_OPCODE_DEBUG_MONITOR = 0x02, + WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE = 0x03, + WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND = 0x04, + WMT_IDC_RX_OPCODE_UART_PIN_SEL = 0x05, + WMT_IDC_RX_OPCODE_MAX +} WMT_IDC_RX_OPCODE; + +#if (CFG_WMT_LTE_ENABLE_MSGID_MAPPING == 0) +typedef enum { + IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN, + IPC_L4C_MSG_ID_END, + IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN, + /* below are EL1 IPC messages sent from AP */ + IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND, + IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND, + IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND, + IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND, + IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND, + + /* below are EL1 messages sent to AP */ + IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, + IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, + IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, + IPC_MSG_ID_EL1_LTE_TX_IND, + IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND, + IPC_MSG_ID_EL1_PIN_TYPE_IND, + IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND, + IPC_MSG_ID_EL1_DUMMY13_IND, + IPC_MSG_ID_EL1_DUMMY14_IND, + IPC_MSG_ID_EL1_DUMMY15_IND, + IPC_EL1_MSG_ID_END, +} IPC_MSG_ID_CODE; +#endif + +typedef struct _MTK_WCN_WMT_IDC_INFO_ { + ipc_ilm_t iit; + CONN_MD_BRIDGE_OPS ops; + UINT8 buffer[LTE_IDC_BUFFER_MAX_SIZE]; +} MTK_WCN_WMT_IDC_INFO, *P_MTK_WCN_WMT_IDC_INFO; + +extern INT32 wmt_idc_init(VOID); +extern INT32 wmt_idc_deinit(VOID); +extern INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm); +extern INT32 wmt_idc_msg_to_lte_handing(VOID); +extern UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len); + +#endif /* endif CFG_WMT_LTE_COEX_HANDLING */ + +#endif /* _WMT_IDC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile new file mode 100644 index 0000000000000..ff0f0b0aefda7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/Makefile @@ -0,0 +1,21 @@ +ifeq ($(CONFIG_MTK_COMBO), y) + +ccflags-y += \ + -I$(src)/../../linux/include \ + -I$(src)/../../linux/pri/include \ + -I$(src)/../../core/include \ + -I$(src)/../../include \ + -I$(src)/../include \ + -I$(src)/../../../common_detect \ + -I$(srctree)/drivers/misc/mediatek/btif/common/inc \ + -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach + +ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 + +obj-y += stp_btif.o \ + stp_dbg.o \ + stp_exp.o \ + wmt_dev.o \ + wmt_exp.o + +endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h new file mode 100644 index 0000000000000..3730fbba69289 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_btif.h @@ -0,0 +1,31 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _STP_BTIF_H_ +#define _STP_BTIF_H_ + +#include "osal_typedef.h" +#include "mtk_btif_exp.h" + +extern INT32 mtk_wcn_consys_stp_btif_open(VOID); +extern INT32 mtk_wcn_consys_stp_btif_close(VOID); +extern INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb); +extern INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len); +extern INT32 mtk_wcn_consys_stp_btif_wakeup(VOID); +extern INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag); +extern INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode); +extern INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag); +extern MTK_WCN_BOOL mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h new file mode 100644 index 0000000000000..de5684a168537 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/stp_dbg.h @@ -0,0 +1,316 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _STP_DEBUG_H_ +#define _STP_DEBUG_H_ + +#include +#include "osal.h" + +#define CONFIG_LOG_STP_INTERNAL + +#if 1 /* #ifndef CONFIG_LOG_STP_INTERNAL */ +#define STP_PKT_SZ 16 +#define STP_DMP_SZ 2048 +#define STP_PKT_NO 2048 + +#define STP_DBG_LOG_ENTRY_NUM 60 +#define STP_DBG_LOG_ENTRY_SZ 64 + +#else + +#define STP_PKT_SZ 16 +#define STP_DMP_SZ 16 +#define STP_PKT_NO 16 + +#define STP_DBG_LOG_ENTRY_NUM 28 +#define STP_DBG_LOG_ENTRY_SZ 64 + +#endif + +typedef enum { + STP_DBG_EN = 0, + STP_DBG_PKT = 1, + STP_DBG_DR = 2, + STP_DBG_FW_ASSERT = 3, + STP_DBG_FW_LOG = 4, + STP_DBG_FW_DMP = 5, + STP_DBG_MAX +} STP_DBG_OP_T; + +typedef enum { + STP_DBG_PKT_FIL_ALL = 0, + STP_DBG_PKT_FIL_BT = 1, + STP_DBG_PKT_FIL_GPS = 2, + STP_DBG_PKT_FIL_FM = 3, + STP_DBG_PKT_FIL_WMT = 4, + STP_DBG_PKT_FIL_MAX +} STP_DBG_PKT_FIL_T; + +static char *const gStpDbgType[] = { + "< BT>", + "< FM>", + "", + "", + "", + "", + "", + "", + "" +}; + +typedef enum { + STP_DBG_DR_MAX = 0, +} STP_DBG_DR_FIL_T; + +typedef enum { + STP_DBG_FW_MAX = 0, +} STP_DBG_FW_FIL_T; + +typedef enum { + PKT_DIR_RX = 0, + PKT_DIR_TX +} STP_DBG_PKT_DIR_T; + +/*simple log system ++*/ + +typedef struct { + /*type: 0. pkt trace 1. fw info + * 2. assert info 3. trace32 dump . + * -1. linked to the the previous + */ + int id; + int len; + char buffer[STP_DBG_LOG_ENTRY_SZ]; +} MTKSTP_LOG_ENTRY_T; + +typedef struct log_sys { + MTKSTP_LOG_ENTRY_T queue[STP_DBG_LOG_ENTRY_NUM]; + unsigned int size; + unsigned int in; + unsigned int out; + spinlock_t lock; +} MTKSTP_LOG_SYS_T; +/*--*/ + +typedef struct stp_dbg_pkt_hdr { + /* packet information */ + unsigned int sec; + unsigned int usec; + unsigned int dbg_type; + unsigned int dmy; + unsigned int no; + unsigned int dir; + + /* packet content */ + unsigned int type; + unsigned int len; + unsigned int ack; + unsigned int seq; + unsigned int chs; + unsigned int crc; +} STP_DBG_HDR_T; + +typedef struct stp_dbg_pkt { + struct stp_dbg_pkt_hdr hdr; + unsigned char raw[STP_DMP_SZ]; +} STP_PACKET_T; + +typedef struct mtkstp_dbg_t { + /*log_sys */ + int pkt_trace_no; + void *btm; + int is_enable; + MTKSTP_LOG_SYS_T *logsys; +} MTKSTP_DBG_T; + +/* extern void aed_combo_exception(const int *, int, const int *, int, const char *); */ + +#define STP_CORE_DUMP_TIMEOUT (5*60*1000) /* default 5minutes */ +#define STP_OJB_NAME_SZ 20 +#define STP_CORE_DUMP_INFO_SZ 500 +#define STP_CORE_DUMP_INIT_SIZE 1 +typedef enum wcn_compress_algorithm_t { + GZIP = 0, + BZIP2 = 1, + RAR = 2, + LMA = 3, + MAX +} WCN_COMPRESS_ALG_T; + +typedef INT32 (*COMPRESS_HANDLER) (void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, + INT32 finish); +typedef struct wcn_compressor_t { + /* current object name */ + UINT8 name[STP_OJB_NAME_SZ + 1]; + + /* buffer for raw data, named L1 */ + PUINT8 L1_buf; + INT32 L1_buf_sz; + INT32 L1_pos; + + /* target buffer, named L2 */ + PUINT8 L2_buf; + INT32 L2_buf_sz; + INT32 L2_pos; + + /* compress state */ + UINT8 f_done; + UINT16 reserved; + UINT32 uncomp_size; + UINT32 crc32; + + /* compress algorithm */ + UINT8 f_compress_en; + WCN_COMPRESS_ALG_T compress_type; + void *worker; + COMPRESS_HANDLER handler; +} WCN_COMPRESSOR_T, *P_WCN_COMPRESSOR_T; + +P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz); +INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T compressor); +INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T compressor, PUINT8 buf, INT32 len, INT32 finish); +INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T compressor, PUINT8 *pbuf, PINT32 len); +INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T compressor, UINT8 enable, WCN_COMPRESS_ALG_T type); + +typedef enum core_dump_state_t { + CORE_DUMP_INIT = 0, + CORE_DUMP_DOING, + CORE_DUMP_TIMEOUT, + CORE_DUMP_DONE, + CORE_DUMP_MAX +} CORE_DUMP_STA; + +typedef struct core_dump_t { + /* compress dump data and buffered */ + P_WCN_COMPRESSOR_T compressor; + + /* timer for monitor timeout */ + OSAL_TIMER dmp_timer; + UINT32 timeout; + + OSAL_SLEEPABLE_LOCK dmp_lock; + + /* state machine for core dump flow */ + CORE_DUMP_STA sm; + + /* dump info */ + INT8 info[STP_CORE_DUMP_INFO_SZ + 1]; +} WCN_CORE_DUMP_T, *P_WCN_CORE_DUMP_T; + +typedef enum _ENUM_STP_FW_ISSUE_TYPE_ { + STP_FW_ISSUE_TYPE_INVALID = 0x0, + STP_FW_ASSERT_ISSUE = 0x1, + STP_FW_NOACK_ISSUE = 0x2, + STP_FW_WARM_RST_ISSUE = 0x3, + STP_DBG_PROC_TEST = 0x4, + STP_HOST_TRIGGER_FW_ASSERT = 0x5, + STP_HOST_TRIGGER_ASSERT_TIMEOUT = 0x6, + STP_FW_ISSUE_TYPE_MAX +} ENUM_STP_FW_ISSUE_TYPE, *P_ENUM_STP_FW_ISSUE_TYPE; + +/* this was added for support dmareg's issue */ +typedef enum _ENUM_DMA_ISSUE_TYPE_ { + CONNSYS_CLK_GATE_STATUS = 0x00, + CONSYS_EMI_STATUS, + SYSRAM1, + SYSRAM2, + SYSRAM3, + DMA_REGS_MAX +} ENUM_DMA_ISSUE_TYPE; +#define STP_PATCH_TIME_SIZE 12 +#define STP_DBG_CPUPCR_NUM 512 +#define STP_DBG_DMAREGS_NUM 16 +#define STP_PATCH_BRANCH_SZIE 8 +#define STP_ASSERT_INFO_SIZE 64 +#define STP_DBG_ROM_VER_SIZE 4 +#define STP_ASSERT_TYPE_SIZE 32 + +typedef struct stp_dbg_host_assert_t { + UINT32 drv_type; + UINT32 reason; + UINT32 assert_from_host; +} STP_DBG_HOST_ASSERT_T, *P_STP_DBG_HOST_ASSERT_T; + +typedef struct stp_dbg_cpupcr_t { + UINT32 chipId; + UINT8 romVer[STP_DBG_ROM_VER_SIZE]; + UINT8 patchVer[STP_PATCH_TIME_SIZE]; + UINT8 branchVer[STP_PATCH_BRANCH_SZIE]; + UINT32 wifiVer; + UINT32 count; + UINT32 stop_flag; + UINT32 buffer[STP_DBG_CPUPCR_NUM]; + UINT8 assert_info[STP_ASSERT_INFO_SIZE]; + UINT32 fwTaskId; + UINT32 fwRrq; + UINT32 fwIsr; + STP_DBG_HOST_ASSERT_T host_assert_info; + UINT8 assert_type[STP_ASSERT_TYPE_SIZE]; + ENUM_STP_FW_ISSUE_TYPE issue_type; + OSAL_SLEEPABLE_LOCK lock; +} STP_DBG_CPUPCR_T, *P_STP_DBG_CPUPCR_T; + +typedef struct stp_dbg_dmaregs_t { + UINT32 count; + UINT32 dmaIssue[DMA_REGS_MAX][STP_DBG_DMAREGS_NUM]; + OSAL_SLEEPABLE_LOCK lock; +} STP_DBG_DMAREGS_T, *P_STP_DBG_DMAREGS_T; + +typedef enum _ENUM_ASSERT_INFO_PARSER_TYPE_ { + STP_DBG_ASSERT_INFO = 0x0, + STP_DBG_FW_TASK_ID = 0x1, + STP_DBG_FW_ISR = 0x2, + STP_DBG_FW_IRQ = 0x3, + STP_DBG_ASSERT_TYPE = 0x4, + STP_DBG_PARSER_TYPE_MAX +} ENUM_ASSERT_INFO_PARSER_TYPE, *P_ENUM_ASSERT_INFO_PARSER_TYPE; + +P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout); +INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp); +INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len); +INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 len); +INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout); +INT32 wcn_core_dump_timeout(void); +INT32 wcn_wmtd_timeout_collect_ftrace(void); + +extern INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout); +extern INT32 wcn_core_dump_deinit_gcoredump(VOID); +extern INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL is_coredump_timeout); +extern int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg); +extern int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg); +extern MTKSTP_DBG_T *stp_dbg_init(void *); +extern int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg); +extern int stp_dbg_dmp_out_ex(char *buf, int *len); +extern int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len); +extern int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg); +extern char stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len); + +extern INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd); +extern INT32 _stp_btm_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len); +extern int +stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, + int dbg_type, int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body); +extern int stp_dbg_log_ctrl(unsigned int on); +extern INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); +extern INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep); +extern INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en); +extern INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, + PUINT8 pPatchBrh); +extern INT32 stp_dbg_set_wifiver(UINT32 wifiver); +extern INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 len); +extern INT32 stp_dbg_set_fw_info(PUINT8 assert_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type); +extern INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en); +extern UINT32 stp_dbg_get_host_trigger_assert(VOID); +#endif /* end of _STP_DEBUG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h new file mode 100644 index 0000000000000..5788eb355549a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/include/wmt_dev.h @@ -0,0 +1,71 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#ifndef _WMT_DEV_H_ +#define _WMT_DEV_H_ + +#include "osal.h" + +#define STP_UART_FULL 0x01 +#define STP_UART_MAND 0x02 +#define STP_BTIF_FULL 0x03 +#define STP_SDIO 0x04 + +#define CFG_WMT_DBG_SUPPORT 1 /* support wmt_dbg or not */ +#define CFG_WMT_PROC_FOR_AEE 1 + +extern VOID wmt_dev_rx_event_cb(VOID); +extern INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent); +extern INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf); +extern INT32 wmt_dev_patch_put(osal_firmware **ppPatch); +extern VOID wmt_dev_patch_info_free(VOID); +extern VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd); +extern MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID); + +#if CFG_WMT_DBG_SUPPORT +typedef struct _COEX_BUF { + UINT8 buffer[128]; + INT32 availSize; +} COEX_BUF, *P_COEX_BUF; + +typedef enum _ENUM_CMD_TYPE_T { + WMTDRV_CMD_ASSERT = 0, + WMTDRV_CMD_EXCEPTION = 1, + WMTDRV_CMD_COEXDBG_00 = 2, + WMTDRV_CMD_COEXDBG_01 = 3, + WMTDRV_CMD_COEXDBG_02 = 4, + WMTDRV_CMD_COEXDBG_03 = 5, + WMTDRV_CMD_COEXDBG_04 = 6, + WMTDRV_CMD_COEXDBG_05 = 7, + WMTDRV_CMD_COEXDBG_06 = 8, + WMTDRV_CMD_COEXDBG_07 = 9, + WMTDRV_CMD_COEXDBG_08 = 10, + WMTDRV_CMD_COEXDBG_09 = 11, + WMTDRV_CMD_COEXDBG_10 = 12, + WMTDRV_CMD_COEXDBG_11 = 13, + WMTDRV_CMD_COEXDBG_12 = 14, + WMTDRV_CMD_COEXDBG_13 = 15, + WMTDRV_CMD_COEXDBG_14 = 16, + WMTDRV_CMD_COEXDBG_15 = 17, + WMTDRV_CMD_NOACK_TEST = 18, + WMTDRV_CMD_WARNRST_TEST = 19, + WMTDRV_CMD_FWTRACE_TEST = 20, + WMTDRV_CMD_MAX +} ENUM_WMTDRV_CMD_T, *P_ENUM_WMTDRV_CMD_T; + +#endif + +typedef INT32(*WMT_DEV_DBG_FUNC) (INT32 par1, INT32 par2, INT32 par3); + +#endif /*_WMT_DEV_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c new file mode 100644 index 0000000000000..76debb4674f9c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_btif.c @@ -0,0 +1,279 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*file: stp_btif, mainly control stp & btif interaction*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[STP-BTIF]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_exp.h" +#include "stp_exp.h" +#include "stp_btif.h" + +#include +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define BTIF_OWNER_NAME "CONSYS_STP" + +#define STP_MAX_PACKAGE_ALLOWED (2000) + +#define STP_BTIF_TX_RTY_LMT (10) +#define STP_BTIF_TX_RTY_DLY (5) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +unsigned long stpBtifId = 0; +unsigned long *pBtifRef = &stpBtifId; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_consys_stp_btif_open(VOID) +{ + INT32 iRet = -1; + + iRet = mtk_wcn_btif_open(BTIF_OWNER_NAME, pBtifRef); + if (iRet) { + WMT_WARN_FUNC("STP open btif fail(%d)\n", iRet); + return -1; + } + WMT_DBG_FUNC("STP open bitf OK\n"); + + mtk_wcn_stp_register_if_tx(STP_BTIF_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_consys_stp_btif_tx); + + return 0; +} + +INT32 mtk_wcn_consys_stp_btif_close(VOID) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_close(stpBtifId); + if (iRet) { + WMT_WARN_FUNC("STP close btif fail(%d)\n", iRet); + iRet = -2; + } else { + stpBtifId = 0; + WMT_DBG_FUNC("STP close btif OK\n"); + } + } + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference\n!"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_rx_cb_register(stpBtifId, rx_cb); + if (iRet) { + WMT_WARN_FUNC("STP register rxcb to btif fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("STP register rxcb to btif OK\n"); + } + } + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_tx(const UINT8 *pBuf, const UINT32 len, UINT32 *written_len) +{ + INT32 retry_left = STP_BTIF_TX_RTY_LMT; + INT32 wr_count = 0; + INT32 written = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + return -1; + } + + if (len == 0) { + *written_len = 0; + WMT_INFO_FUNC("special case for STP-CORE,pbuf(%p)\n", pBuf); + return 0; + } + + *written_len = 0; + + if (len > STP_MAX_PACKAGE_ALLOWED) { + WMT_WARN_FUNC("abnormal pacage length,len(%d),pid[%d/%s]\n", len, current->pid, current->comm); + return -2; + } + wr_count = mtk_wcn_btif_write(stpBtifId, pBuf, len); + + if (wr_count < 0) { + WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)\n", wr_count); + *written_len = 0; + return -3; + } + if (wr_count == len) { + /*perfect case */ + *written_len = wr_count; + return wr_count; + } + + while ((retry_left--) && (wr_count < len)) { + osal_sleep_ms(STP_BTIF_TX_RTY_DLY); + written = mtk_wcn_btif_write(stpBtifId, pBuf + wr_count, len - wr_count); + if (written < 0) { + WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)when do recovered\n", written); + break; + } + wr_count += written; + } + + if (wr_count == len) { + WMT_INFO_FUNC("recovered,len(%d),retry_left(%d)\n", len, retry_left); + /*recovered case */ + *written_len = wr_count; + return wr_count; + } + + WMT_ERR_FUNC("stp btif write fail,len(%d),written(%d),retry_left(%d),pid[%d/%s]\n", + len, wr_count, retry_left, current->pid, current->comm); + *written_len = 0; + return -wr_count; +} + +INT32 mtk_wcn_consys_stp_btif_rx(UINT8 *pBuf, UINT32 len) +{ + return 0; +} + +INT32 mtk_wcn_consys_stp_btif_wakeup(VOID) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_wakeup_consys(stpBtifId); + if (iRet) { + WMT_WARN_FUNC("STP btif wakeup consys fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("STP btif wakeup consys ok\n"); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + mtk_wcn_btif_dpidle_ctrl(stpBtifId, en_flag); + WMT_DBG_FUNC("stp btif dpidle ctrl done,en_flag(%d)\n", en_flag); + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_loopback_ctrl(stpBtifId, mode); + if (iRet) { + WMT_WARN_FUNC("STP btif lpbk ctrl fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_INFO_FUNC("stp btif lpbk ctrl ok,mode(%d)\n", mode); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_dbg_ctrl(stpBtifId, flag); + if (iRet) { + WMT_WARN_FUNC("STP btif log dbg ctrl fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_INFO_FUNC("stp btif log dbg ctrl ok,flag(%d)\n", flag); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const UINT8 *str, UINT32 len) +{ + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + return -1; + } else { + return (INT32) mtk_wcn_btif_parser_wmt_evt(stpBtifId, str, len); + } +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c new file mode 100644 index 0000000000000..fd8e9a97a0b82 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_dbg.c @@ -0,0 +1,2060 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ +#include /* GFP_KERNEL */ +#include /* init_timer, add_time, del_timer_sync */ +#include /* gettimeofday */ +#include +#include /* kzalloc */ +#include /* task's status */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "osal_typedef.h" +#include "stp_dbg.h" +/* #include "stp_btm.h" */ +#include "btm_core.h" +#include "wmt_plat.h" + +#define PFX_STP_DBG "[STPDbg]" +#define STP_DBG_LOG_LOUD 4 +#define STP_DBG_LOG_DBG 3 +#define STP_DBG_LOG_INFO 2 +#define STP_DBG_LOG_WARN 1 +#define STP_DBG_LOG_ERR 0 + +unsigned int gStpDbgDbgLevel = STP_DBG_LOG_INFO; +unsigned int gStpDbgLogOut = 0; + +#define STP_DBG_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \ + pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_DBG_DBG_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ + pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_DBG_INFO_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \ + pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_DBG_WARN_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \ + pr_warn(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_DBG_ERR_FUNC(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \ + pr_err(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \ +} while (0) +#define STP_DBG_TRC_FUNC(f) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ + pr_debug(PFX_STP_DBG "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +MTKSTP_DBG_T *g_stp_dbg = NULL; + +#define STP_DBG_FAMILY_NAME "STP_DBG" +#define MAX_BIND_PROCESS (4) +#ifdef WMT_PLAT_ALPS +#define STP_DBG_AEE_EXP_API (1) +#else +#define STP_DBG_AEE_EXP_API (0) +#endif +enum { + __STP_DBG_ATTR_INVALID, + STP_DBG_ATTR_MSG, + __STP_DBG_ATTR_MAX, +}; +#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1) + +enum { + __STP_DBG_COMMAND_INVALID, + STP_DBG_COMMAND_BIND, + STP_DBG_COMMAND_RESET, + __STP_DBG_COMMAND_MAX, +}; +#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1) + +static struct genl_family stp_dbg_gnl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = STP_DBG_FAMILY_NAME, + .version = 1, + .maxattr = STP_DBG_ATTR_MAX, +}; + +static void stp_dbg_nl_init(void); +static void stp_dbg_nl_deinit(void); +static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info); +static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info); + +/* attribute policy */ +static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = { + [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING}, +}; + +/* operation definition */ +#if 0 +static struct genl_ops stp_dbg_gnl_ops_bind = { + .cmd = STP_DBG_COMMAND_BIND, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_bind, + .dumpit = NULL, +}; + +static struct genl_ops stp_dbg_gnl_ops_reset = { + .cmd = STP_DBG_COMMAND_RESET, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_reset, + .dumpit = NULL, +}; +#endif +static struct genl_ops stp_dbg_gnl_ops_array[] = { + { + .cmd = STP_DBG_COMMAND_BIND, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_bind, + .dumpit = NULL, + }, + { + .cmd = STP_DBG_COMMAND_RESET, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_reset, + .dumpit = NULL, + }, +}; + +#if 0 +#define E2S(x) #x +static char *dmaRegsStr[] = { + E2S(CONNSYS_CLK_GATE_STATUS), + E2S(CONSYS_EMI_STATUS), + E2S(SYSRAM1), + E2S(SYSRAM2), + E2S(SYSRAM3) +}; +#endif +static unsigned int stp_dbg_seqnum; +static int num_bind_process; +static pid_t bind_pid[MAX_BIND_PROCESS]; + +static P_WCN_CORE_DUMP_T g_core_dump; + +static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr; + +/* just show in log at present */ +static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs; + +/* core_dump_timeout_handler - handler of coredump timeout + * @ data - core dump object's pointer + * + * No return value + */ +static void core_dump_timeout_handler(unsigned long data) +{ + P_WCN_CORE_DUMP_T dmp = (P_WCN_CORE_DUMP_T) data; + + STP_DBG_INFO_FUNC(" start\n"); + + stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm); + + STP_DBG_INFO_FUNC(" end\n"); + + if (dmp) + dmp->sm = CORE_DUMP_TIMEOUT; +} + +/* wcn_core_dump_init - create core dump sys + * @ timeout - core dump time out value + * + * Return object pointer if success, else NULL + */ +P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 packet_num, UINT32 timeout) +{ +#define KBYTES (1024*sizeof(char)) +#define L1_BUF_SIZE (32*KBYTES) + + P_WCN_CORE_DUMP_T core_dmp = NULL; + + core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T)); + if (!core_dmp) { + STP_DBG_ERR_FUNC("alloc mem failed!\n"); + goto fail; + } + + osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T)); + + core_dmp->compressor = wcn_compressor_init("core_dump_compressor", L1_BUF_SIZE, 18*packet_num*KBYTES); + if (!core_dmp->compressor) { + STP_DBG_ERR_FUNC("create compressor failed!\n"); + goto fail; + } + wcn_compressor_reset(core_dmp->compressor, 1, GZIP); + + core_dmp->dmp_timer.timeoutHandler = core_dump_timeout_handler; + core_dmp->dmp_timer.timeroutHandlerData = (unsigned long)core_dmp; + osal_timer_create(&core_dmp->dmp_timer); + core_dmp->timeout = timeout; + + osal_sleepable_lock_init(&core_dmp->dmp_lock); + + core_dmp->sm = CORE_DUMP_INIT; + STP_DBG_INFO_FUNC("create coredump object OK!\n"); + + return core_dmp; + +fail: + if (core_dmp && core_dmp->compressor) { + wcn_compressor_deinit(core_dmp->compressor); + core_dmp->compressor = NULL; + } + if (core_dmp) + osal_free(core_dmp); + + return NULL; +} +INT32 wcn_core_dump_init_gcoredump(UINT32 packet_num, UINT32 timeout) +{ + INT32 Ret = 0; + + g_core_dump = wcn_core_dump_init(packet_num, timeout); + if (g_core_dump == NULL) + Ret = -1; + return Ret; +} + +/* wcn_core_dump_deinit - destroy core dump object + * @ dmp - pointer of object + * + * Retunr 0 if success, else error code + */ +INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp) +{ + if (dmp && dmp->compressor) { + wcn_compressor_deinit(dmp->compressor); + dmp->compressor = NULL; + } + + if (dmp) { + osal_sleepable_lock_deinit(&dmp->dmp_lock); + osal_timer_stop(&dmp->dmp_timer); + osal_free(dmp); + } + + return 0; +} + +INT32 wcn_core_dump_deinit_gcoredump(VOID) +{ + wcn_core_dump_deinit(g_core_dump); + return 0; +} + +static INT32 wcn_core_dump_check_end(PUINT8 buf, INT32 len) +{ + if (strnstr(buf, "coredump end", len)) + return 1; + else + return 0; +} + +/* wcn_core_dump_in - add a packet to compressor buffer + * @ dmp - pointer of object + * @ buf - input buffer + * @ len - data length + * + * Retunr 0 if success; return 1 if find end string; else error code + */ +INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) +{ + INT32 ret = 0; + INT32 tmp; + +#define INFO_HEAD ";SOC_CONSYS FW CORE, " + + if ((!dmp) || (!buf)) { + STP_DBG_ERR_FUNC("invalid pointer!\n"); + return -1; + } + + ret = osal_lock_sleepable_lock(&dmp->dmp_lock); + if (ret) { + STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); + return ret; + } + + switch (dmp->sm) { + case CORE_DUMP_INIT: + wcn_compressor_reset(dmp->compressor, 1, GZIP); + osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); + + /* first package, copy to info buffer */ + osal_strcpy(&dmp->info[0], INFO_HEAD); + + if (NULL == (strnstr(buf, "", 32))) { + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...", + osal_strlen("Fw warm reset exception...")); + dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] = '\0'; + } else { + char *pStr = buf; + char *pDtr = NULL; + + pDtr = osal_strchr(pStr, '-'); + if (NULL != pDtr) { + tmp = pDtr - pStr; + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); + dmp->info[osal_strlen(dmp->info) + 1] = '\0'; + } else { + tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD); + tmp = (len > tmp) ? tmp : len; + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp); + dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0'; + } + + } + /* show coredump start info on UI */ + /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */ +#if STP_DBG_AEE_EXP_API + aee_kernel_dal_show("SOC_CONSYS coredump start ....\n"); +#endif + /* parsing data, and check end srting */ + ret = wcn_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_INFO_FUNC("core dump end!\n"); + dmp->sm = CORE_DUMP_DONE; + wcn_compressor_in(dmp->compressor, buf, len, 0); + } else { + dmp->sm = CORE_DUMP_DOING; + wcn_compressor_in(dmp->compressor, buf, len, 0); + } + break; + + case CORE_DUMP_DOING: + /* parsing data, and check end srting */ + ret = wcn_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_INFO_FUNC("core dump end!\n"); + dmp->sm = CORE_DUMP_DONE; + wcn_compressor_in(dmp->compressor, buf, len, 0); + } else { + dmp->sm = CORE_DUMP_DOING; + wcn_compressor_in(dmp->compressor, buf, len, 0); + } + break; + + case CORE_DUMP_DONE: + wcn_compressor_reset(dmp->compressor, 1, GZIP); + osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); + wcn_compressor_in(dmp->compressor, buf, len, 0); + dmp->sm = CORE_DUMP_DOING; + break; + + case CORE_DUMP_TIMEOUT: + break; + default: + break; + } + + osal_unlock_sleepable_lock(&dmp->dmp_lock); + + return ret; +} + +/* wcn_core_dump_out - get compressed data from compressor buffer + * @ dmp - pointer of object + * @ pbuf - target buffer's pointer + * @ len - data length + * + * Retunr 0 if success; else error code + */ +INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 plen) +{ + INT32 ret = 0; + + if ((!dmp) || (!pbuf) || (!plen)) { + STP_DBG_ERR_FUNC("invalid pointer!\n"); + return -1; + } + + ret = osal_lock_sleepable_lock(&dmp->dmp_lock); + if (ret) { + STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret); + return ret; + } + + ret = wcn_compressor_out(dmp->compressor, pbuf, plen); + + osal_unlock_sleepable_lock(&dmp->dmp_lock); + + return ret; +} + +/* wcn_core_dump_reset - reset core dump sys + * @ dmp - pointer of object + * @ timeout - core dump time out value + * + * Retunr 0 if success, else error code + */ +INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout) +{ + if (!dmp) { + STP_DBG_ERR_FUNC("invalid pointer!\n"); + return -1; + } + + dmp->sm = CORE_DUMP_INIT; + dmp->timeout = timeout; + osal_timer_stop(&dmp->dmp_timer); + wcn_compressor_reset(dmp->compressor, 1, GZIP); + osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1); + + wcn_core_dump_deinit(dmp); + g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); + + return 0; +} + +/* wcn_wmtd_timeout_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE + * + * Retunr 0 if success + */ +#define WMTD_TIMEOUT_INFO_HEAD "Wait wmtd complation timeout ,just collect SYS_FTRACE to DB" +INT32 wcn_wmtd_timeout_collect_ftrace(void) +{ + PUINT8 pbuf; + INT32 len; + + pbuf = "Wait wmtd complation timeout"; + len = osal_strlen("Wait wmtd complation timeout"); + osal_strcpy(&g_core_dump->info[0], WMTD_TIMEOUT_INFO_HEAD); +#ifdef WMT_PLAT_ALPS + aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); +#endif + return 0; +} +/* wcn_psm_flag_trigger_collect_ftrace - wmtd timeout ,this func can collect SYS_FTRACE + * + * Retunr 0 if success + */ +#define PSM_ABNORMAL_FLAG_INFO_HEAD "Abnormal PSM flag be set ,just collect SYS_FTRACE to DB" +INT32 wcn_psm_flag_trigger_collect_ftrace(void) +{ + PUINT8 pbuf; + INT32 len; + + pbuf = "Abnormal PSM flag be set"; + len = osal_strlen("Abnormal PSM flag be set"); + osal_strcpy(&g_core_dump->info[0], PSM_ABNORMAL_FLAG_INFO_HEAD); +#ifdef WMT_PLAT_ALPS + aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); +#endif + return 0; +} +#if BTIF_RXD_BE_BLOCKED_DETECT +MTK_WCN_BOOL is_btif_rxd_be_blocked(void) +{ + MTK_WCN_BOOL flag = MTK_WCN_BOOL_FALSE; + + if (mtk_btif_rxd_be_blocked_flag_get()) + flag = MTK_WCN_BOOL_TRUE; + return flag; +} +/* wcn_btif_rxd_blocked_collect_ftrace - btif rxd be blocked,this func can collect SYS_FTRACE + * + * Retunr 0 if success + */ +#define BTIF_RXD_BLOCKED_INFO_HEAD "Btif_rxd thread be blocked too long,just collect SYS_FTRACE to DB" +INT32 wcn_btif_rxd_blocked_collect_ftrace(void) +{ + PUINT8 pbuf; + INT32 len; + + pbuf = "Btif_rxd thread be blocked too long"; + len = osal_strlen("Btif_rxd thread be blocked too long"); + osal_strcpy(&g_core_dump->info[0], BTIF_RXD_BLOCKED_INFO_HEAD); +#ifdef WMT_PLAT_ALPS + aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); +#endif + return 0; +} +#endif +/* wcn_core_dump_timeout - wait for FW assert info timeout ,this func can collect SYS_FTRACE + * + * Retunr 0 if success + */ +#define TIMEOUT_INFO_HEAD "Trigger assert timeout ,just collect SYS_FTRACE to DB" +INT32 wcn_core_dump_timeout(void) +{ + PUINT8 pbuf; + INT32 len; + + pbuf = "Trigger assert timeout"; + len = osal_strlen("Trigger assert timeout"); + osal_strcpy(&g_core_dump->info[0], TIMEOUT_INFO_HEAD); +#ifdef WMT_PLAT_ALPS + aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); +#endif + return 0; +} + +#define ENABLE_F_TRACE 0 +/* wcn_core_dump_flush - Fulsh dump data and reset core dump sys + * + * Retunr 0 if success, else error code + */ +INT32 wcn_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout) +{ + PUINT8 pbuf = NULL; + INT32 len = 0; + + if (!g_core_dump) { + STP_DBG_ERR_FUNC("invalid pointer!\n"); + return -1; + } + + wcn_core_dump_out(g_core_dump, &pbuf, &len); + STP_DBG_INFO_FUNC("buf 0x%zx, len %d\n", (SIZE_T) pbuf, len); +#ifdef WMT_PLAT_ALPS + /* show coredump end info on UI */ + /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */ +#if STP_DBG_AEE_EXP_API + if (coredump_is_timeout) + aee_kernel_dal_show("++ SOC_CONSYS coredump tiemout ,pass received coredump to AEE ++\n"); + else + aee_kernel_dal_show("++ SOC_CONSYS coredump get successfully ++\n"); + /* call AEE driver API */ +#if ENABLE_F_TRACE + aed_combo_exception_api(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info, DB_OPT_FTRACE); +#else + aed_combo_exception(NULL, 0, (const int *)pbuf, len, (const char *)g_core_dump->info); +#endif + +#endif + +#endif // WMT_PLAT_ALPS + + /* reset */ + wcn_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT); + + return 0; +} + +static INT32 wcn_gzip_compressor(void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, + INT32 finish) +{ + INT32 ret = 0; + z_stream *stream = NULL; + INT32 tmp = *out_sz; + + STP_DBG_INFO_FUNC("need to compressor :buf 0x%zx, size %d\n", (SIZE_T) in_buf, in_sz); + STP_DBG_INFO_FUNC("before compressor,avalible buf: 0x%zx, size %d\n", (SIZE_T) out_buf, tmp); + + stream = (z_stream *) worker; + if (!stream) { + STP_DBG_ERR_FUNC("invalid workspace!\n"); + return -1; + } + + if (in_sz > 0) { +#if 0 + ret = zlib_deflateReset(stream); + if (ret != Z_OK) { + STP_DBG_ERR_FUNC("reset failed!\n"); + return -2; + } +#endif + + stream->next_in = in_buf; + stream->avail_in = in_sz; + stream->next_out = out_buf; + stream->avail_out = tmp; + + zlib_deflate(stream, Z_FULL_FLUSH); + + if (finish) { + while (1) { + int val = zlib_deflate(stream, Z_FINISH); + + if (val == Z_OK) + continue; + else if (val == Z_STREAM_END) + break; + STP_DBG_ERR_FUNC("finish operation failed %d\n", val); + return -3; + } + } + + *out_sz = tmp - stream->avail_out; + } + + STP_DBG_INFO_FUNC("after compressor,avalible buf: 0x%zx, compress rate %d -> %d\n", (SIZE_T) out_buf, in_sz, + *out_sz); + + return ret; +} + +/* wcn_compressor_init - create a compressor and do init + * @ name - compressor's name + * @ L1_buf_sz - L1 buffer size + * @ L2_buf_sz - L2 buffer size + * + * Retunr object's pointer if success, else NULL + */ +P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz) +{ + z_stream *pstream = NULL; + P_WCN_COMPRESSOR_T compress = NULL; + + compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T)); + if (!compress) { + STP_DBG_ERR_FUNC("alloc compressor failed!\n"); + goto fail; + } + + osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T)); + osal_memcpy(compress->name, name, STP_OJB_NAME_SZ); + + compress->f_compress_en = 0; + compress->compress_type = GZIP; + + if (compress->compress_type == GZIP) { + compress->worker = osal_malloc(sizeof(z_stream)); + if (!compress->worker) { + STP_DBG_ERR_FUNC("alloc stream failed!\n"); + goto fail; + } + pstream = (z_stream *) compress->worker; + + pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); + if (!pstream->workspace) { + STP_DBG_ERR_FUNC("alloc workspace failed!\n"); + goto fail; + } + zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, + DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); + } + + compress->handler = wcn_gzip_compressor; + compress->L1_buf_sz = L1_buf_sz; + compress->L2_buf_sz = L2_buf_sz; + compress->L1_pos = 0; + compress->L2_pos = 0; + compress->uncomp_size = 0; + compress->crc32 = 0xffffffffUL; + + compress->L1_buf = osal_malloc(compress->L1_buf_sz); + if (!compress->L1_buf) { + STP_DBG_ERR_FUNC("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz); + goto fail; + } + + compress->L2_buf = osal_malloc(compress->L2_buf_sz); + if (!compress->L2_buf) { + STP_DBG_ERR_FUNC("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz); + goto fail; + } + + STP_DBG_INFO_FUNC("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz); + return compress; + +fail: + if (compress) { + if (compress->L2_buf) { + osal_free(compress->L2_buf); + compress->L2_buf = NULL; + } + + if (compress->L1_buf) { + osal_free(compress->L1_buf); + compress->L1_buf = NULL; + } + + if (compress->worker) { + pstream = (z_stream *) compress->worker; + if ((compress->compress_type == GZIP) && pstream->workspace) { + zlib_deflateEnd(pstream); + osal_free(pstream->workspace); + } + osal_free(compress->worker); + compress->worker = NULL; + } + + if (compress->worker) { + osal_free(compress->worker); + compress->worker = NULL; + } + + osal_free(compress); + compress = NULL; + } + + STP_DBG_ERR_FUNC("init failed!\n"); + + return NULL; +} + +/* wcn_compressor_deinit - distroy a compressor + * @ cprs - compressor's pointer + * + * Retunr 0 if success, else NULL + */ +INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T cprs) +{ + z_stream *pstream = NULL; + + if (cprs) { + if (cprs->L2_buf) { + osal_free(cprs->L2_buf); + cprs->L2_buf = NULL; + } + + if (cprs->L1_buf) { + osal_free(cprs->L1_buf); + cprs->L1_buf = NULL; + } + + if (cprs->worker) { + pstream = (z_stream *) cprs->worker; + if ((cprs->compress_type == GZIP) && pstream->workspace) { + zlib_deflateEnd(pstream); + osal_free(pstream->workspace); + } + osal_free(cprs->worker); + cprs->worker = NULL; + } + + cprs->handler = NULL; + + osal_free(cprs); + } + + STP_DBG_INFO_FUNC("destroy OK\n"); + + return 0; +} + +/* wcn_compressor_in - put in a raw data, and compress L1 buffer if need + * @ cprs - compressor's pointer + * @ buf - raw data buffer + * @ len - raw data length + * @ finish - core dump finish or not, 1: finished; 0: not finish + * + * Retunr 0 if success, else NULL + */ +INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, INT32 finish) +{ + INT32 tmp_len = 0; + INT32 ret = 0; + + if (!cprs) { + STP_DBG_ERR_FUNC("invalid para!\n"); + return -1; + } + + cprs->uncomp_size += len; + + /* check L1 buf valid space */ + if (len > (cprs->L1_buf_sz - cprs->L1_pos)) { + STP_DBG_INFO_FUNC("L1 buffer full\n"); + + if (cprs->f_compress_en && cprs->handler) { + /* need compress */ + /* compress L1 buffer, and put result to L2 buffer */ + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + ret = + cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], + &tmp_len, finish); + if (!ret) { + cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); + cprs->L2_pos += tmp_len; + if (cprs->L2_pos > cprs->L2_buf_sz) + STP_DBG_ERR_FUNC("coredump size too large(%d), L2 buf overflow\n", + cprs->L2_pos); + + if (finish) { + /* Add 8 byte suffix + === + 32 bits UNCOMPRESS SIZE + 32 bits CRC + */ + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; + cprs->L2_pos += 8; + } + STP_DBG_INFO_FUNC("compress OK!\n"); + } else + STP_DBG_ERR_FUNC("compress error!\n"); + } else { + /* no need compress */ + /* Flush L1 buffer to L2 buffer */ + STP_DBG_INFO_FUNC("No need do compress, Put to L2 buf\n"); + + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; + osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); + cprs->L2_pos += tmp_len; + } + + /* reset L1 buf pos */ + cprs->L1_pos = 0; + + /* put curren data to L1 buf */ + if (len > cprs->L1_buf_sz) { + STP_DBG_ERR_FUNC("len=%d, too long err!\n", len); + } else { + STP_DBG_INFO_FUNC("L1 Flushed, and Put %d bytes to L1 buf\n", len); + osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); + cprs->L1_pos += len; + } + } else { + /* put to L1 buffer */ + STP_DBG_INFO_FUNC("Put %d bytes to L1 buf\n", len); + + osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); + cprs->L1_pos += len; + } + + return ret; +} + +/* wcn_compressor_out - get the result data from L2 buffer + * @ cprs - compressor's pointer + * @ pbuf - point to L2 buffer + * @ plen - out len + * + * Retunr 0 if success, else NULL + */ +INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T cprs, PUINT8 *pbuf, PINT32 plen) +{ + INT32 ret = 0; + INT32 tmp_len = 0; + + if ((!cprs) || (!pbuf) || (!plen)) { + STP_DBG_ERR_FUNC("invalid para!\n"); + return -1; + } + /* check if there's L1 data need flush to L2 buffer */ + if (cprs->L1_pos > 0) { + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + + if (cprs->f_compress_en && cprs->handler) { + /* need compress */ + ret = + cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], + &tmp_len, 1); + + if (!ret) { + cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); + cprs->L2_pos += tmp_len; + + /* Add 8 byte suffix + === + 32 bits UNCOMPRESS SIZE + 32 bits CRC + */ + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; + cprs->L2_pos += 8; + + STP_DBG_INFO_FUNC("compress OK!\n"); + } else { + STP_DBG_ERR_FUNC("compress error!\n"); + } + } else { + /* no need compress */ + tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; + osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); + cprs->L2_pos += tmp_len; + } + + cprs->L1_pos = 0; + } + + *pbuf = cprs->L2_buf; + *plen = cprs->L2_pos; + + STP_DBG_INFO_FUNC("0x%zx, len %d\n", (SIZE_T)*pbuf, *plen); + + return 0; +} + +/* wcn_compressor_reset - reset compressor + * @ cprs - compressor's pointer + * @ enable - enable/disable compress + * @ type - compress algorithm + * + * Retunr 0 if success, else NULL + */ +INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type) +{ + if (!cprs) { + STP_DBG_ERR_FUNC("invalid para!\n"); + return -1; + } + + cprs->f_compress_en = enable; + /* cprs->f_compress_en = 0; // disable compress for test */ + cprs->compress_type = type; + cprs->L1_pos = 0; + cprs->L2_pos = 0; + cprs->uncomp_size = 0; + cprs->crc32 = 0xffffffffUL; + + /* zlib_deflateEnd((z_stream*)cprs->worker); */ + + STP_DBG_INFO_FUNC("OK! compress algorithm %d\n", type); + + return 0; +} + +static void stp_dbg_dump_data(unsigned char *pBuf, char *title, int len) +{ + int k = 0; + + pr_debug(" %s-len:%d\n", title, len); + + for (k = 0; k < len; k++) { + if (k % 16 == 0 && k != 0) + pr_cont("\n "); + pr_cont("0x%02x ", pBuf[k]); + } + pr_debug("--end\n"); +} + +static int _stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) +{ + + unsigned long flags; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + stp_dbg->pkt_trace_no = 0; + stp_dbg->is_enable = 1; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +static int _stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) +{ + + unsigned long flags; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + stp_dbg->pkt_trace_no = 0; + memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); + stp_dbg->is_enable = 0; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +static int _stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) +{ + unsigned long flags; + STP_DBG_HDR_T *pHdr = NULL; + char *pBuf = NULL; + unsigned int length = 0; + unsigned int internalFlag = stp_dbg->logsys->size < STP_DBG_LOG_ENTRY_NUM; + /* #ifdef CONFIG_LOG_STP_INTERNAL */ + /* Here we record log in this circle buffer, if buffer is full , + select to overlap earlier log, logic should be okay */ + internalFlag = 1; + /* #endif */ + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + + if (internalFlag) { + stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0; + stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len; + memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), + 0, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); + memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), + buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); + + stp_dbg->logsys->size++; + stp_dbg->logsys->size = + (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ? STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size; + + if (0 != gStpDbgLogOut) { + pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]); + pBuf = (char *)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) + sizeof(STP_DBG_HDR_T); + length = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T); + pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", + pHdr->sec, + pHdr->usec, + pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", + gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); + if (0 < length) + stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", length); + } + stp_dbg->logsys->in = + (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1); + STP_DBG_DBG_FUNC("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in); + } else { + STP_DBG_WARN_FUNC("logsys FULL!\n"); + } + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +int stp_gdb_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg) +{ + int retval = 0; +/* #ifndef CONFIG_LOG_STP_INTERNAL */ + + if (stp_dbg->btm != NULL) + retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm); +/* #endif */ + + return retval; +} + +int stp_dbg_log_ctrl(unsigned int on) +{ + if (on != 0) { + gStpDbgLogOut = 1; + pr_debug("STP-DBG: enable pkt log dump out.\n"); + } else { + gStpDbgLogOut = 0; + pr_debug("STP-DBG: disable pkt log dump out.\n"); + } + return 0; +} + +int stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len) +{ + return _stp_dbg_dmp_in(stp_dbg, buf, len); +} + +int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg) +{ +#define MAX_DMP_NUM 80 + unsigned long flags; + char *pBuf = NULL; + int len = 0; + STP_DBG_HDR_T *pHdr = NULL; + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + /* Not to dequeue from loging system */ + inIndex = stp_dbg->logsys->in; + dumpSize = stp_dbg->logsys->size; + if (STP_DBG_LOG_ENTRY_NUM == dumpSize) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM; + + if (dumpSize > MAX_DMP_NUM) { + + outIndex += (dumpSize - MAX_DMP_NUM); + outIndex %= STP_DBG_LOG_ENTRY_NUM; + dumpSize = MAX_DMP_NUM; + + } + STP_DBG_INFO_FUNC("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + while (dumpSize > 0) { + pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[outIndex].buffer[0]); + pBuf = &(stp_dbg->logsys->queue[outIndex].buffer[0]) + sizeof(STP_DBG_HDR_T); + len = stp_dbg->logsys->queue[outIndex].len - sizeof(STP_DBG_HDR_T); + len = len > STP_PKT_SZ ? STP_PKT_SZ : len; + pr_debug("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", + pHdr->sec, + pHdr->usec, + pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", + gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); + + if (0 < len) + stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len); + outIndex = (outIndex >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (outIndex + 1); + dumpSize--; + + } + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +int stp_dbg_dmp_out_ex(char *buf, int *len) +{ + return stp_dbg_dmp_out(g_stp_dbg, buf, len); +} + +int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len) +{ + + unsigned long flags; + int remaining = 0; + *len = 0; + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + + if (stp_dbg->logsys->size > 0) { + memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]), + stp_dbg->logsys->queue[stp_dbg->logsys->out].len); + + (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len; + stp_dbg->logsys->out = + (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->out + 1); + stp_dbg->logsys->size--; + + STP_DBG_DBG_FUNC("logsys size = %d, out = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->out); + } else { + STP_DBG_LOUD_FUNC("logsys EMPTY!\n"); + } + + remaining = (stp_dbg->logsys->size == 0) ? (0) : (1); + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return remaining; +} + +static int stp_dbg_fill_hdr(struct stp_dbg_pkt_hdr *hdr, int type, int ack, int seq, int crc, int dir, int len, + int dbg_type) +{ + + struct timeval now; + + if (!hdr) { + STP_DBG_ERR_FUNC("function invalid\n"); + return -EINVAL; + } + do_gettimeofday(&now); + hdr->dbg_type = dbg_type; + hdr->ack = ack; + hdr->seq = seq; + hdr->sec = now.tv_sec; + hdr->usec = now.tv_usec; + hdr->crc = crc; + hdr->dir = dir; /* rx */ + hdr->dmy = 0xffffffff; + hdr->len = len; + hdr->type = type; + return 0; + +} + +static int stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, struct stp_dbg_pkt_hdr *hdr, const unsigned char *body) +{ + /* fix the frame size large issues. */ + static struct stp_dbg_pkt stp_pkt; + uint32_t hdr_sz = sizeof(struct stp_dbg_pkt_hdr); + uint32_t body_sz = 0; + + BUG_ON(!stp_dbg); + + if (hdr->dbg_type == STP_DBG_PKT) + body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ); + else + body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ); + + hdr->no = stp_dbg->pkt_trace_no++; + memcpy((uint8_t *) &stp_pkt.hdr, (uint8_t *) hdr, hdr_sz); + if (body != NULL) + memcpy((uint8_t *) &stp_pkt.raw[0], body, body_sz); + + _stp_dbg_dmp_in(stp_dbg, (char *)&stp_pkt, hdr_sz + body_sz); + /* Only FW DMP MSG should inform BTM-CORE to dump packet to native process */ + if (hdr->dbg_type == STP_DBG_FW_DMP) + stp_gdb_notify_btm_dmp_wq(stp_dbg); + + return 0; +} + +int stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, int dbg_type, + int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body) +{ + + struct stp_dbg_pkt_hdr hdr; + + if (stp_dbg->is_enable == 0) { + /*dbg is disable,and not to log */ + } else { + hdr.no = 0; + hdr.chs = 0; + stp_dbg_fill_hdr(&hdr, + (int)type, (int)ack_no, (int)seq_no, (int)crc, (int)dir, (int)len, (int)dbg_type); + + stp_dbg_add_pkt(stp_dbg, &hdr, body); + } + + return 0; +} + +int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) +{ + return _stp_dbg_enable(stp_dbg); +} + +int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) +{ + return _stp_dbg_disable(stp_dbg); +} + +static void stp_dbg_nl_init(void) +{ +#if 0 + if (genl_register_family(&stp_dbg_gnl_family) != 0) { + STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); + } else { + if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0) + STP_DBG_ERR_FUNC("%s(): BIND operation registration fail\n", __func__); + + if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0) + STP_DBG_ERR_FUNC("%s(): RESET operation registration fail\n", __func__); + + } +#endif + if (genl_register_family_with_ops(&stp_dbg_gnl_family, stp_dbg_gnl_ops_array) != 0) + STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__); +} + +static void stp_dbg_nl_deinit(void) +{ + genl_unregister_family(&stp_dbg_gnl_family); +} + +static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *na; + char *mydata; + + if (info == NULL) + goto out; + + STP_DBG_INFO_FUNC("%s():->\n", __func__); + + na = info->attrs[STP_DBG_ATTR_MSG]; + + if (na) + mydata = (char *)nla_data(na); + + if (num_bind_process < MAX_BIND_PROCESS) { + bind_pid[num_bind_process] = info->snd_portid; + num_bind_process++; + STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_portid); + } else { + STP_DBG_ERR_FUNC("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS); + } + +out: + return 0; +} + +static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info) +{ + STP_DBG_ERR_FUNC("%s(): should not be invoked\n", __func__); + + return 0; +} + +INT8 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len) +{ + struct sk_buff *skb = NULL; + void *msg_head = NULL; + int rc = -1; + int i; + + if (num_bind_process == 0) { + /* no listening process */ + STP_DBG_ERR_FUNC("%s(): the process is not invoked\n", __func__); + return 0; + } + + for (i = 0; i < num_bind_process; i++) { + skb = genlmsg_new(2048, GFP_KERNEL); + + if (skb) { + msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd); + if (msg_head == NULL) { + nlmsg_free(skb); + STP_DBG_ERR_FUNC("%s(): genlmsg_put fail...\n", __func__); + return -1; + } + + rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg); + if (rc != 0) { + nlmsg_free(skb); + STP_DBG_ERR_FUNC("%s(): nla_put_string fail...%d\n", __func__, rc); + return -1; + } + + /* finalize the message */ + genlmsg_end(skb, msg_head); + + /* sending message */ + rc = genlmsg_unicast(&init_net, skb, bind_pid[i]); + if (rc != 0) { + STP_DBG_ERR_FUNC("%s(): genlmsg_unicast fail...\n", __func__); + return -1; + } + } else { + STP_DBG_ERR_FUNC("%s(): genlmsg_new fail...\n", __func__); + return -1; + } + } + + return 0; +} + +INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd) +{ + INT32 ret = 0; + + /* buffered to compressor */ + ret = wcn_core_dump_in(g_core_dump, aucMsg, len); + if (ret == 1) + wcn_core_dump_flush(0, MTK_WCN_BOOL_FALSE); + + return ret; +} + +UINT8 *_stp_dbg_id_to_task(UINT32 id) +{ + UINT8 *taskStr[] = { + "Task_WMT", + "Task_BT", + "Task_Wifi", + "Task_Tst", + "Task_FM", + "Task_Idle", + "Task_DrvStp", + "Task_DrvBtif", + "Task_NatBt" + }; + return taskStr[id]; +} + +INT32 _stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type) +{ + char *pStr = NULL; + char *pDtr = NULL; + char *pTemp = NULL; + char *pTemp2 = NULL; + char tempBuf[64] = { 0 }; + UINT32 len = 0; + long res; + INT32 ret; + + PUINT8 parser_sub_string[] = { + " ", + "id=", + "isr=", + "irq=", + "rc=" + }; + + if (!str) { + STP_DBG_ERR_FUNC("NULL string source\n"); + return -1; + } + + if (!g_stp_dbg_cpupcr) { + STP_DBG_ERR_FUNC("NULL pointer\n"); + return -2; + } + + pStr = str; + STP_DBG_DBG_FUNC("source infor:%s\n", pStr); + switch (type) { + case STP_DBG_ASSERT_INFO: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (NULL != pDtr) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ' '); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + len = pTemp - pDtr; + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@")); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len); + g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_'; + + pTemp = osal_strchr(pDtr, '#'); + pTemp += 1; + + pTemp2 = osal_strchr(pTemp, ' '); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp, pTemp2 - pTemp); + g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0'; + STP_DBG_INFO_FUNC("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]); + break; + case STP_DBG_FW_TASK_ID: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (NULL != pDtr) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ' '); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; + + STP_DBG_INFO_FUNC("fw task id :%x\n", (UINT32)res); + break; + case STP_DBG_FW_ISR: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (NULL != pDtr) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_ERR_FUNC("get fw isr id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwIsr = (UINT32)res; + + STP_DBG_INFO_FUNC("fw isr str:%x\n", (UINT32)res); + break; + case STP_DBG_FW_IRQ: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (NULL != pDtr) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_ERR_FUNC("get fw irq id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwRrq = (UINT32)res; + + STP_DBG_INFO_FUNC("fw irq value:%x\n", (UINT32)res); + break; + case STP_DBG_ASSERT_TYPE: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (NULL != pDtr) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + + if (0 == osal_memcmp(tempBuf, "*", len)) + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert", osal_strlen("general assert")); + if (0 == osal_memcmp(tempBuf, "Watch Dog Timeout", len)) + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt")); + if (0 == osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL"))) { + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len); + + pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL("); + if (NULL != pDtr) { + pDtr += osal_strlen("RB_FULL("); + pTemp = osal_strchr(pDtr, ')'); + } else { + STP_DBG_ERR_FUNC("parser str is NULL,substring(RB_FULL()\n"); + return -4; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_ERR_FUNC("get fw task id fail(%d)\n", ret); + return -5; + } + g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; + + STP_DBG_INFO_FUNC("update fw task id :%x\n", (UINT32)res); + } + + STP_DBG_INFO_FUNC("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type); + break; + default: + STP_DBG_ERR_FUNC("unknown parser type\n"); + break; + } + + return 0; +} + +P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID) +{ + P_STP_DBG_CPUPCR_T pSdCpupcr = NULL; + + pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T)); + if (!pSdCpupcr) { + STP_DBG_ERR_FUNC("stp dbg cpupcr allocate memory fail!\n"); + return NULL; + } + + osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T)); + + osal_sleepable_lock_init(&pSdCpupcr->lock); + + return pSdCpupcr; +} + +P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID) +{ + P_STP_DBG_DMAREGS_T pDmaRegs = NULL; + + pDmaRegs = (P_STP_DBG_DMAREGS_T) osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T)); + if (!pDmaRegs) { + STP_DBG_ERR_FUNC("stp dbg dmareg allocate memory fail!\n"); + return NULL; + } + + osal_memset(pDmaRegs, 0, osal_sizeof(STP_DBG_DMAREGS_T)); + + osal_sleepable_lock_init(&pDmaRegs->lock); + + return pDmaRegs; +} + +VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr) +{ + if (pCpupcr) { + osal_sleepable_lock_deinit(&pCpupcr->lock); + osal_free(pCpupcr); + pCpupcr = NULL; + } +} + +VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs) +{ + if (pDmaRegs) { + osal_sleepable_lock_deinit(&pDmaRegs->lock); + osal_free(pDmaRegs); + pDmaRegs = NULL; + } +} + +INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd) +{ + INT32 i = 0; + + if (!g_stp_dbg_cpupcr) { + STP_DBG_ERR_FUNC("NULL reference pointer\n"); + return -1; + } + + if (!cmd) { + if (g_stp_dbg_cpupcr->count + times > STP_DBG_CPUPCR_NUM) + times = STP_DBG_CPUPCR_NUM - g_stp_dbg_cpupcr->count; + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + for (i = 0; i < times; i++) { + STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); + /* osal_memcpy( + * &g_stp_dbg_cpupcr->buffer[i], + * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), + * osal_sizeof(UINT32)); + */ + g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count + i] = wmt_plat_read_cpupcr(); + osal_sleep_ms(sleep); + } + g_stp_dbg_cpupcr->count += times; + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_INFO_FUNC("stp-dbg: for proc test polling cpupcr\n"); + if (times > STP_DBG_CPUPCR_NUM) + times = STP_DBG_CPUPCR_NUM; + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->count = 0; + for (i = 0; i < times; i++) { + STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n", i, wmt_plat_read_cpupcr()); + /* osal_memcpy( + * &g_stp_dbg_cpupcr->buffer[i], + * (UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)), + * osal_sizeof(UINT32)); + */ + g_stp_dbg_cpupcr->buffer[i] = wmt_plat_read_cpupcr(); + osal_sleep_ms(sleep); + } + g_stp_dbg_cpupcr->count = times; + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + } + return 0; +} + +INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep) +{ +#if 0 + INT32 i = 0; + + if (!g_stp_dbg_dmaregs) { + STP_DBG_ERR_FUNC("NULL reference pointer\n"); + return -1; + } + + osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock); + + if (g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM) { + if (g_stp_dbg_dmaregs->count > STP_DBG_DMAREGS_NUM) { + STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count:%d must less than STP_DBG_DMAREGS_NUM:%d\n", + g_stp_dbg_dmaregs->count, STP_DBG_DMAREGS_NUM); + g_stp_dbg_dmaregs->count = 0; + STP_DBG_ERR_FUNC("g_stp_dbg_dmaregs->count be set default value 0\n"); + } + times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count; + } + if (times > STP_DBG_DMAREGS_NUM) { + STP_DBG_ERR_FUNC("times overflow, set default value:0\n"); + times = 0; + } + STP_DBG_WARN_FUNC("---------Now Polling DMA relative Regs -------------\n"); + for (i = 0; i < times; i++) { + INT32 k = 0; + + for (; k < DMA_REGS_MAX; k++) { + STP_DBG_WARN_FUNC("times:%d,i:%d reg: %s, regs:%08x\n", times, i, dmaRegsStr[k], + wmt_plat_read_dmaregs(k)); + /* g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] = wmt_plat_read_dmaregs(k); */ + } + osal_sleep_ms(sleep); + } + STP_DBG_WARN_FUNC("---------Polling DMA relative Regs End-------------\n"); + g_stp_dbg_dmaregs->count += times; + + osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock); +#else + return 0; +#endif +} + +INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en) +{ + + STP_DBG_INFO_FUNC("%s polling cpupcr\n", en == 0 ? "start" : "stop"); + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->stop_flag = en; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + return 0; +} + +INT32 stp_dbg_set_version_info(UINT32 chipid, UINT8 *pRomVer, UINT8 *pPatchVer, UINT8 *pPatchBrh) +{ + if (g_stp_dbg_cpupcr) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->chipId = chipid; + + if (pRomVer) + osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2); + if (pPatchVer) + osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8); + if (pPatchBrh) + osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4); + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_ERR_FUNC("NULL pointer\n"); + return -1; + } + STP_DBG_INFO_FUNC("chipid(0x%x),romver(%s),patchver(%s),branchver(%s)\n", g_stp_dbg_cpupcr->chipId, + &g_stp_dbg_cpupcr->romVer[0], &g_stp_dbg_cpupcr->patchVer[0], &g_stp_dbg_cpupcr->branchVer[0]); + return 0; +} +INT32 stp_dbg_set_wifiver(UINT32 wifiver) +{ + if (g_stp_dbg_cpupcr) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->wifiVer = wifiver; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_ERR_FUNC("NULL pointer\n"); + return -1; + } + STP_DBG_INFO_FUNC("wifiver(%x)\n", g_stp_dbg_cpupcr->wifiVer); + return 0; +} + +INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en) +{ + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en; + g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type; + g_stp_dbg_cpupcr->host_assert_info.reason = reason; + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + return 0; +} + +UINT32 stp_dbg_get_host_trigger_assert(VOID) +{ + return g_stp_dbg_cpupcr->host_assert_info.assert_from_host; +} + +INT32 stp_dbg_set_fw_info(UINT8 *issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type) +{ + ENUM_ASSERT_INFO_PARSER_TYPE type_index; + PUINT8 tempbuf = NULL; + UINT32 i = 0; + INT32 iRet = 0; + + if (NULL == issue_info) { + STP_DBG_ERR_FUNC("null issue infor\n"); + return -1; + } + STP_DBG_INFO_FUNC("issue type(%d)\n", issue_type); + g_stp_dbg_cpupcr->issue_type = issue_type; + osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE); + + /*print patch version when assert happened */ + STP_DBG_INFO_FUNC("=======================================\n"); + STP_DBG_INFO_FUNC("[consys patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer); + STP_DBG_INFO_FUNC("[consys patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer); + STP_DBG_INFO_FUNC("=======================================\n"); + + if ((STP_FW_ASSERT_ISSUE == issue_type) || + (STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { + if ((STP_FW_ASSERT_ISSUE == issue_type) || (STP_HOST_TRIGGER_FW_ASSERT == issue_type)) { + tempbuf = osal_malloc(len + 1); + if (!tempbuf) + return -2; + + osal_memcpy(&tempbuf[0], issue_info, len); + + for (i = 0; i < len; i++) { + if (tempbuf[i] == '\0') + tempbuf[i] = '?'; + } + + tempbuf[len] = '\0'; + + for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX; type_index++) + iRet += _stp_dbg_parser_assert_str(&tempbuf[0], type_index); + + if (iRet) + STP_DBG_ERR_FUNC("passert assert infor fail(%d)\n", iRet); + + } + if ((STP_HOST_TRIGGER_FW_ASSERT == issue_type) || (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type)) { + switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) { + case 0: + STP_DBG_INFO_FUNC("BT trigger assert\n"); + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + if (31 != g_stp_dbg_cpupcr->host_assert_info.reason) + /*BT firmware trigger assert */ + { + g_stp_dbg_cpupcr->fwTaskId = 1; + + } else + /*BT stack trigger assert */ + { + g_stp_dbg_cpupcr->fwTaskId = 8; + } + + g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; + /* g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; */ + /* g_stp_dbg_cpupcr->host_assert_info.reason = 0; */ + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + break; + case 4: + STP_DBG_INFO_FUNC("WMT trigger assert\n"); + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + if (STP_HOST_TRIGGER_ASSERT_TIMEOUT == issue_type) + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + + if ((38 == g_stp_dbg_cpupcr->host_assert_info.reason) || + (39 == g_stp_dbg_cpupcr->host_assert_info.reason) || + (40 == g_stp_dbg_cpupcr->host_assert_info.reason)) + g_stp_dbg_cpupcr->fwTaskId = 6; /* HOST schedule reason trigger */ + else + g_stp_dbg_cpupcr->fwTaskId = 0; /* Must be firmware reason */ + g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + break; + default: + break; + } + + } + osal_free(tempbuf); + } else if (STP_FW_NOACK_ISSUE == issue_type) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = 6; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else if (STP_DBG_PROC_TEST == issue_type) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = 0; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else if (STP_FW_WARM_RST_ISSUE == issue_type) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = 0; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_ERR_FUNC("invalid issue type(%d)\n", issue_type); + return -3; + } + + return iRet; +} + +INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 str_len) +{ + UINT32 len = 0; + UINT32 i = 0; + + if (!g_stp_dbg_cpupcr) { + STP_DBG_ERR_FUNC("NULL pointer\n"); + return -1; + } + + /*format common information about issue */ + len = osal_sprintf(*buf, "
\n\t"); + len += osal_sprintf(*buf + len, "\n\t\tMT%x\n\t\n\t", g_stp_dbg_cpupcr->chipId); + len += osal_sprintf(*buf + len, "\n\t\t"); + len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->romVer); + if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", strlen("ALPS")))) + len += osal_sprintf(*buf + len, "Internal Dev\n\t\t", g_stp_dbg_cpupcr->branchVer); + else + len += osal_sprintf(*buf + len, "W%sMP\n\t\t", g_stp_dbg_cpupcr->branchVer); + + len += osal_sprintf(*buf + len, "%s\n\t\t", g_stp_dbg_cpupcr->patchVer); + + if (0 == g_stp_dbg_cpupcr->wifiVer) + len += osal_sprintf(*buf + len, "NULL\n\t"); + else + len += osal_sprintf(*buf + len, "0x%X.%X\n\t", + (UINT8)((g_stp_dbg_cpupcr->wifiVer & 0xFF00)>>8), (UINT8)(g_stp_dbg_cpupcr->wifiVer & 0xFF)); + + len += osal_sprintf(*buf + len, "\n\t"); + + /*format issue information: no ack, assert */ + len += osal_sprintf(*buf + len, "\n\t\t\n\t\t\t"); + if ((STP_FW_NOACK_ISSUE == g_stp_dbg_cpupcr->issue_type) || + (STP_DBG_PROC_TEST == g_stp_dbg_cpupcr->issue_type) || + (STP_FW_WARM_RST_ISSUE == g_stp_dbg_cpupcr->issue_type)) { + len += + osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", + g_stp_dbg_cpupcr->assert_info); + len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); + len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t"); + len += + osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", + _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); + len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); + len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + } else if ((STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) || + (STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || + (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { + len += + osal_sprintf(*buf + len, "%s\n\t\t\n\t\t\n\t\t\t", + g_stp_dbg_cpupcr->assert_info); + len += osal_sprintf(*buf + len, "%s\n\t\t\n\t\n\t", g_stp_dbg_cpupcr->assert_type); + len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t"); + len += + osal_sprintf(*buf + len, "\n\t\t\t%s\n\t\t\t", + _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); + if (32 == g_stp_dbg_cpupcr->host_assert_info.reason || 33 == g_stp_dbg_cpupcr->host_assert_info.reason + || 34 == g_stp_dbg_cpupcr->host_assert_info.reason + || 35 == g_stp_dbg_cpupcr->host_assert_info.reason + || 36 == g_stp_dbg_cpupcr->host_assert_info.reason + || 37 == g_stp_dbg_cpupcr->host_assert_info.reason + || 38 == g_stp_dbg_cpupcr->host_assert_info.reason + || 39 == g_stp_dbg_cpupcr->host_assert_info.reason + || 40 == g_stp_dbg_cpupcr->host_assert_info.reason) { + /*handling wmt turn on/off bt cmd has ack but no evt issue */ + /*one of both the irqx and irs is nULL, then use task to find MOF */ + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + } else { + len += osal_sprintf(*buf + len, "IRQ_0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); + } + len += osal_sprintf(*buf + len, "0x%x\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); + + if (STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) { + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + } + + if ((STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type) || + (STP_HOST_TRIGGER_ASSERT_TIMEOUT == g_stp_dbg_cpupcr->issue_type)) { + len += + osal_sprintf(*buf + len, "%d\n\t\t\t", + g_stp_dbg_cpupcr->host_assert_info.drv_type); + len += + osal_sprintf(*buf + len, "%d\n\t\t\t", + g_stp_dbg_cpupcr->host_assert_info.reason); + } + } else { + len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\t\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n\t"); + len += osal_sprintf(*buf + len, "\n\t\tNULL\n\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t"); + len += osal_sprintf(*buf + len, "\n\t\t\tNULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\t"); + } + + len += osal_sprintf(*buf + len, ""); + STP_DBG_INFO_FUNC("stp-dbg:sub len1 for debug(%d)\n", len); + + if (!g_stp_dbg_cpupcr->count) + len += osal_sprintf(*buf + len, "NULL"); + else { + for (i = 0; i < g_stp_dbg_cpupcr->count; i++) + len += osal_sprintf(*buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]); + } + STP_DBG_INFO_FUNC("stp-dbg:sub len2 for debug(%d)\n", len); + len += osal_sprintf(*buf + len, "\n\t\t\t"); + len += osal_sprintf(*buf + len, "NULL\n\t\t\n\t\n
\n"); + STP_DBG_INFO_FUNC("buffer len[%d]\n", len); + /* STP_DBG_INFO_FUNC("Format infor:\n%s\n",*buf); */ + *str_len = len; + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM); + g_stp_dbg_cpupcr->count = 0; + g_stp_dbg_cpupcr->host_assert_info.reason = 0; + g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + return 0; + +} + +MTKSTP_DBG_T *stp_dbg_init(void *btm_half) +{ + + MTKSTP_DBG_T *stp_dbg = NULL; + + STP_DBG_INFO_FUNC("stp-dbg init\n"); + + stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL); + if (stp_dbg == NULL) + goto ERR_EXIT1; + if (IS_ERR(stp_dbg)) { + STP_DBG_ERR_FUNC("-ENOMEM\n"); + goto ERR_EXIT1; + } + + stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T)); + if (stp_dbg->logsys == NULL) + goto ERR_EXIT2; + if (IS_ERR(stp_dbg->logsys)) { + STP_DBG_ERR_FUNC("-ENOMEM stp_gdb->logsys\n"); + goto ERR_EXIT2; + } + memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); + spin_lock_init(&(stp_dbg->logsys->lock)); + stp_dbg->pkt_trace_no = 0; + stp_dbg->is_enable = 0; + g_stp_dbg = stp_dbg; + + if (btm_half != NULL) + stp_dbg->btm = btm_half; + else + stp_dbg->btm = NULL; + + + /* bind to netlink */ + stp_dbg_nl_init(); + g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_INIT_SIZE, STP_CORE_DUMP_TIMEOUT); + g_stp_dbg_cpupcr = stp_dbg_cpupcr_init(); + g_stp_dbg_dmaregs = stp_dbg_dmaregs_init(); + + return stp_dbg; + +ERR_EXIT2: + kfree(stp_dbg); + return NULL; + +ERR_EXIT1: + kfree(stp_dbg); + return NULL; +} + +int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg) +{ + + STP_DBG_INFO_FUNC("stp-dbg deinit\n"); + + wcn_core_dump_deinit(g_core_dump); + + stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr); + stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs); + /* unbind with netlink */ + stp_dbg_nl_deinit(); + + if (stp_dbg->logsys) + vfree(stp_dbg->logsys); + + kfree(stp_dbg); + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c new file mode 100644 index 0000000000000..f7f4aff010d4a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/stp_exp.c @@ -0,0 +1,279 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* udelay() */ + +#include + + +#include "osal_typedef.h" +#include "stp_core.h" +#include "stp_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static MTK_WCN_STP_IF_TX stp_uart_if_tx; +static MTK_WCN_STP_IF_TX stp_sdio_if_tx; +static MTK_WCN_STP_IF_TX stp_btif_if_tx; +static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX; +static MTK_WCN_STP_IF_RX stp_if_rx; +static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; +static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size) +{ + if (stp_if_rx == 0x0) + return -1; + + (*stp_if_rx) (data, size); + return 0; +} + +static INT32 mtk_wcn_sys_if_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) +{ + + if (STP_UART_IF_TX == g_stp_if_type) + return stp_uart_if_tx != NULL ? (*stp_uart_if_tx) (data, size, written_size) : -1; + else if (STP_SDIO_IF_TX == g_stp_if_type) + return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx) (data, size, written_size) : -1; + else if (STP_BTIF_IF_TX == g_stp_if_type) + return stp_btif_if_tx != NULL ? (*stp_btif_if_tx) (data, size, written_size) : -1; + /*if (g_stp_if_type >= STP_MAX_IF_TX) *//* George: remove ALWAYS TRUE condition */ + return -1; +} + +static INT32 mtk_wcn_sys_event_set(UINT8 function_type) +{ + if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0)) { + (*event_callback_tbl[function_type]) (); + } else { + /* FIXME: error handling */ + pr_err("[%s] STP set event fail. It seems the function is not active.\n", __func__); + } + + return 0; +} + +static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace) +{ + int type = 0; + + for (type = 0; type < MTKSTP_MAX_TASK_NUM; type++) { + if (tx_event_callback_tbl[type]) + tx_event_callback_tbl[type] (); + } + + return 0; +} + +static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op) +{ + + /* op == FUNCTION_ACTIVE, to check if funciton[type] is active ? */ + if (!(type < MTKSTP_MAX_TASK_NUM)) + return STATUS_FUNCTION_INVALID; + + if (op == OP_FUNCTION_ACTIVE) { + if (event_callback_tbl[type] != 0x0) + return STATUS_FUNCTION_ACTIVE; + else + return STATUS_FUNCTION_INACTIVE; + + } + /* you can define more operation here ..., to queury function's status/information */ + + return STATUS_OP_INVALID; +} + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +#else +INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +#endif +{ + stp_if_rx = func; + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); +#endif + +VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type) +{ + static const char * const ifType[] = { + "UART", + "SDIO", + "BTIF", + "UNKNOWN" + }; + g_stp_if_type = stp_if_type; + pr_debug("[%s] set STP_IF_TX to %s.\n", __func__, ifType[stp_if_type]); +} + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +#else +INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +#endif +{ + if (STP_UART_IF_TX == stp_if) { + stp_uart_if_tx = func; + } else if (STP_SDIO_IF_TX == stp_if) { + stp_sdio_if_tx = func; + } else if (STP_BTIF_IF_TX == stp_if) { + stp_btif_if_tx = func; + } else { + pr_debug("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); + return -1; + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#else +INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#endif +{ + if (type < MTKSTP_MAX_TASK_NUM) { + event_callback_tbl[type] = func; + + /*clear rx queue */ + pr_debug("Flush type = %d Rx Queue\n", type); + mtk_wcn_stp_flush_rx_queue(type); + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#else +INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#endif +{ + if (type < MTKSTP_MAX_TASK_NUM) + tx_event_callback_tbl[type] = func; + else + BUG_ON(0); + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); +#endif + +INT32 stp_drv_init(VOID) +{ + INT32 ret = 0; + + mtkstp_callback cb = { + .cb_if_tx = mtk_wcn_sys_if_tx, + .cb_event_set = mtk_wcn_sys_event_set, + .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume, + .cb_check_funciton_status = mtk_wcn_sys_check_function_status + }; + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + MTK_WCN_STP_EXP_CB_INFO stpExpCb = { + .stp_send_data_cb = _mtk_wcn_stp_send_data, + .stp_send_data_raw_cb = _mtk_wcn_stp_send_data_raw, + .stp_parser_data_cb = _mtk_wcn_stp_parser_data, + .stp_receive_data_cb = _mtk_wcn_stp_receive_data, + .stp_is_rxqueue_empty_cb = _mtk_wcn_stp_is_rxqueue_empty, + .stp_is_ready_cb = _mtk_wcn_stp_is_ready, + .stp_set_bluez_cb = _mtk_wcn_stp_set_bluez, + .stp_if_tx_cb = _mtk_wcn_stp_register_if_tx, + .stp_if_rx_cb = _mtk_wcn_stp_register_if_rx, + .stp_reg_event_cb = _mtk_wcn_stp_register_event_cb, + .stp_reg_tx_event_cb = _mtk_wcn_stp_register_tx_event_cb, + .stp_coredump_start_get_cb = _mtk_wcn_stp_coredump_start_get, + }; +#endif + + ret = mtk_wcn_stp_init(&cb); +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_stp_exp_cb_reg(&stpExpCb); +#endif + return ret; +} + +VOID stp_drv_exit(VOID) +{ + mtk_wcn_stp_deinit(); + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_stp_exp_cb_unreg(); +#endif + +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c new file mode 100644 index 0000000000000..f70c88796f091 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_dev.c @@ -0,0 +1,2566 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief brief description + + Detailed descriptions here. + +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DEV]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_dev.h" +#include "wmt_core.h" +#include "wmt_exp.h" +#include "wmt_lib.h" +#include "wmt_conf.h" +#include "psm_core.h" +#include "stp_core.h" +#include "stp_exp.h" +#include "bgw_desense.h" +#include +#include "wmt_idc.h" +#ifdef CONFIG_COMPAT +#include +#endif +#if WMT_CREATE_NODE_DYNAMIC +#include +#endif +#define BUF_LEN_MAX 384 +#include +#ifdef CONFIG_COMPAT +#define COMPAT_WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, compat_uptr_t) +#define COMPAT_WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, compat_uptr_t) +#define COMPAT_WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, compat_uptr_t) +#define COMPAT_WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, compat_uptr_t) +#define COMPAT_WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, compat_uptr_t) +#endif + +#define WMT_IOC_MAGIC 0xa0 +#define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, char*) +#define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC, 5, int) +#define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC, 6, int) +#define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC, 7, int) +#define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, char*) +#define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC, 12, int) +#define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC, 13, int) +#define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC, 14, int) +#define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, char*) +#define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*) +#define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*) +#define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int) +#define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int) +#define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int) +#define WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, char*) +#define WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, char*) +#define WMT_IOCTL_FW_DBGLOG_CTRL _IOR(WMT_IOC_MAGIC, 29, int) +#define WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, char*) + +#define MTK_WMT_VERSION "SOC Consys WMT Driver - v1.0" +#define MTK_WMT_DATE "2013/01/20" +#define WMT_DEV_MAJOR 190 /* never used number */ +#define WMT_DEV_NUM 1 +#define WMT_DEV_INIT_TO_MS (2 * 1000) +#define DYNAMIC_DUMP_BUF 109 + +#if CFG_WMT_DBG_SUPPORT +#define WMT_DBG_PROCNAME "driver/wmt_dbg" +#endif + +#define WMT_DRIVER_NAME "mtk_stp_wmt" + +P_OSAL_EVENT gpRxEvent = NULL; + +UINT32 u4RxFlag = 0x0; +static atomic_t gRxCount = ATOMIC_INIT(0); + +/* Linux UINT8 device */ +static int gWmtMajor = WMT_DEV_MAJOR; +static struct cdev gWmtCdev; +static atomic_t gWmtRefCnt = ATOMIC_INIT(0); +/* WMT driver information */ +static UINT8 gLpbkBuf[1024+5] = { 0 }; + +static UINT32 gLpbkBufLog; /* George LPBK debug */ +static INT32 gWmtInitDone; +static wait_queue_head_t gWmtInitWq; + +P_WMT_PATCH_INFO pPatchInfo = NULL; +UINT32 pAtchNum = 0; + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MT_ENG_BUILD)) +#define WMT_EMI_DEBUG_BUF_SIZE (8*1024) +#else +#define WMT_EMI_DEBUG_BUF_SIZE (32*1024) +#endif + +static UINT8 gEmiBuf[WMT_EMI_DEBUG_BUF_SIZE]; +UINT8 *buf_emi; + +#if CFG_WMT_PROC_FOR_AEE +static struct proc_dir_entry *gWmtAeeEntry; +#define WMT_AEE_PROCNAME "driver/wmt_aee" +#define WMT_PROC_AEE_SIZE 3072 +static UINT32 g_buf_len; +static UINT8 *pBuf; +#endif + +#if WMT_CREATE_NODE_DYNAMIC +struct class *wmt_class = NULL; +struct device *wmt_dev = NULL; +#endif + +#if CFG_WMT_DBG_SUPPORT +static struct proc_dir_entry *gWmtDbgEntry; +COEX_BUF gCoexBuf; + +static INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd); +static INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3); + +#if CFG_CORE_INTERNAL_TXRX +static INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3); +#endif +static INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3); +#if CONSYS_ENALBE_SET_JTAG +static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3); +#endif +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3); +#endif +#endif +static void wmt_dbg_fwinfor_print_buff(UINT32 len) +{ + UINT32 i = 0; + UINT32 idx = 0; + + for (i = 0; i < len; i++) { + buf_emi[idx] = gEmiBuf[i]; + if (gEmiBuf[i] == '\n') { + pr_cont("%s", buf_emi); + osal_memset(buf_emi, 0, BUF_LEN_MAX); + idx = 0; + } else { + idx++; + } + if (idx == BUF_LEN_MAX-1) { + buf_emi[idx] = '\0'; + pr_cont("%s", buf_emi); + osal_memset(buf_emi, 0, BUF_LEN_MAX); + idx = 0; + } + } +} + +/*LCM on/off ctrl for wmt varabile*/ +static struct work_struct gPwrOnOffWork; +UINT32 g_es_lr_flag_for_quick_sleep = 1; /* for ctrl quick sleep flag */ +UINT32 g_es_lr_flag_for_lpbk_onoff = 0; /* for ctrl lpbk on off */ +OSAL_SLEEPABLE_LOCK g_es_lr_lock; + +#ifdef CONFIG_EARLYSUSPEND + +static void wmt_dev_early_suspend(struct early_suspend *h) +{ + osal_lock_sleepable_lock(&g_es_lr_lock); + g_es_lr_flag_for_quick_sleep = 1; + g_es_lr_flag_for_lpbk_onoff = 0; + osal_unlock_sleepable_lock(&g_es_lr_lock); + + WMT_WARN_FUNC("@@@@@@@@@@wmt enter early suspend@@@@@@@@@@@@@@\n"); + + schedule_work(&gPwrOnOffWork); +} + +static void wmt_dev_late_resume(struct early_suspend *h) +{ + osal_lock_sleepable_lock(&g_es_lr_lock); + g_es_lr_flag_for_quick_sleep = 0; + g_es_lr_flag_for_lpbk_onoff = 1; + osal_unlock_sleepable_lock(&g_es_lr_lock); + + WMT_WARN_FUNC("@@@@@@@@@@wmt enter late resume@@@@@@@@@@@@@@\n"); + + schedule_work(&gPwrOnOffWork); + +} + +struct early_suspend wmt_early_suspend_handler = { + .suspend = wmt_dev_early_suspend, + .resume = wmt_dev_late_resume, +}; + +#else + +static struct notifier_block wmt_fb_notifier; +static int wmt_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + struct fb_event *evdata = data; + INT32 blank; + + WMT_DBG_FUNC("wmt_fb_notifier_callback\n"); + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + blank = *(INT32 *)evdata->data; + WMT_DBG_FUNC("fb_notify(blank=%d)\n", blank); + + switch (blank) { + case FB_BLANK_UNBLANK: + osal_lock_sleepable_lock(&g_es_lr_lock); + g_es_lr_flag_for_quick_sleep = 0; + g_es_lr_flag_for_lpbk_onoff = 1; + osal_unlock_sleepable_lock(&g_es_lr_lock); + WMT_WARN_FUNC("@@@@@@@@@@wmt enter UNBLANK @@@@@@@@@@@@@@\n"); + schedule_work(&gPwrOnOffWork); + break; + case FB_BLANK_POWERDOWN: + osal_lock_sleepable_lock(&g_es_lr_lock); + g_es_lr_flag_for_quick_sleep = 1; + g_es_lr_flag_for_lpbk_onoff = 0; + osal_unlock_sleepable_lock(&g_es_lr_lock); + WMT_WARN_FUNC("@@@@@@@@@@wmt enter early POWERDOWN @@@@@@@@@@@@@@\n"); + schedule_work(&gPwrOnOffWork); + break; + default: + break; + } + return 0; +} +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static void wmt_pwr_on_off_handler(struct work_struct *work) +{ + INT32 retryCounter = 1; + + WMT_DBG_FUNC("wmt_pwr_on_off_handler start to run\n"); + + osal_lock_sleepable_lock(&g_es_lr_lock); + + if (g_es_lr_flag_for_lpbk_onoff) { + do { + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK)) { + WMT_WARN_FUNC("WMT turn on LPBK fail, retrying, retryCounter left:%d!\n", retryCounter); + retryCounter--; + osal_sleep_ms(1000); + } else { + WMT_INFO_FUNC("WMT turn on LPBK suceed\n"); + break; + } + } while (retryCounter > 0); + } else { + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK)) + WMT_WARN_FUNC("WMT turn off LPBK fail\n"); + else + WMT_DBG_FUNC("WMT turn off LPBK suceed\n"); + + } + + osal_unlock_sleepable_lock(&g_es_lr_lock); + +} + + +MTK_WCN_BOOL wmt_dev_get_early_suspend_state(void) +{ + MTK_WCN_BOOL bRet = (0 == g_es_lr_flag_for_quick_sleep) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; + /* WMT_INFO_FUNC("bRet:%d\n", bRet); */ + return bRet; +} + +#if CFG_WMT_DBG_SUPPORT + +static const WMT_DEV_DBG_FUNC wmt_dev_dbg_func[] = { + [0] = wmt_dbg_psm_ctrl, + [1] = wmt_dbg_quick_sleep_ctrl, + [2] = wmt_dbg_dsns_ctrl, + [3] = wmt_dbg_hwver_get, + [4] = wmt_dbg_assert_test, + [5] = wmt_dbg_inband_rst, + [6] = wmt_dbg_chip_rst, + [7] = wmt_dbg_func_ctrl, + [8] = wmt_dbg_raed_chipid, + [9] = wmt_dbg_wmt_dbg_level, + [0xa] = wmt_dbg_stp_dbg_level, + [0xb] = wmt_dbg_reg_read, + [0xc] = wmt_dbg_reg_write, + [0xd] = wmt_dbg_coex_test, + [0xe] = wmt_dbg_rst_ctrl, + [0xf] = wmt_dbg_ut_test, + [0x10] = wmt_dbg_efuse_read, + [0x11] = wmt_dbg_efuse_write, + [0x12] = wmt_dbg_sdio_ctrl, + [0x13] = wmt_dbg_stp_dbg_ctrl, + [0x14] = wmt_dbg_stp_dbg_log_ctrl, + [0x15] = wmt_dbg_wmt_assert_ctrl, + [0x16] = wmt_dbg_fwinfor_from_emi, + [0x17] = wmt_dbg_set_mcu_clock, + [0x18] = wmt_dbg_poll_cpupcr, + [0x19] = wmt_dbg_jtag_flag_ctrl, +#if CFG_WMT_LTE_COEX_HANDLING + [0x20] = wmt_dbg_lte_coex_test, +#endif +}; + +INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +#if CFG_WMT_PS_SUPPORT + if (0 == par2) { + wmt_lib_ps_ctrl(0); + WMT_INFO_FUNC("disable PSM\n"); + } else { + par2 = (1 > par2 || 20000 < par2) ? STP_PSM_IDLE_TIME_SLEEP : par2; + wmt_lib_ps_set_idle_time(par2); + wmt_lib_ps_ctrl(1); + WMT_WARN_FUNC("enable PSM, idle to sleep time = %d ms\n", par2); + } +#else + WMT_INFO_FUNC("WMT PS not supported\n"); +#endif + return 0; +} + +INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +#if CFG_WMT_PS_SUPPORT + UINT32 en_flag = par2; + + wmt_lib_quick_sleep_ctrl(en_flag); +#else + WMT_WARN_FUNC("WMT PS not supported\n"); +#endif + return 0; +} + +INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (WMTDSNS_FM_DISABLE <= par2 && WMTDSNS_MAX > par2) { + WMT_INFO_FUNC("DSNS type (%d)\n", par2); + mtk_wcn_wmt_dsns_ctrl(par2); + } else { + WMT_WARN_FUNC("invalid DSNS type\n"); + } + return 0; +} + +INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("query chip version\n"); + mtk_wcn_wmt_hwver_get(); + return 0; +} + +INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3) +{ + if (0 == par3) { + /* par2 = 0: send assert command */ + /* par2 != 0: send exception command */ + return wmt_dbg_cmd_test_api(0 == par2 ? 0 : 1); + } else if (1 == par3) { + /* send noack command */ + return wmt_dbg_cmd_test_api(18); + } else if (2 == par3) { + /* warn reset test */ + return wmt_dbg_cmd_test_api(19); + } else if (3 == par3) { + /* firmware trace test */ + return wmt_dbg_cmd_test_api(20); + } + { + INT32 sec = 8; + INT32 times = 0; + + times = par3; + do { + WMT_INFO_FUNC("Send Assert Command per 8 secs!!\n"); + wmt_dbg_cmd_test_api(0); + osal_sleep_ms(sec * 1000); + } while (--times); + } + return 0; +} + +INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd) +{ + + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = WMT_OPID_CMD_TEST; + + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*this test command should be run with usb cable connected, so no host awake is needed */ + /* wmt_lib_host_awake_get(); */ + switch (cmd) { + case WMTDRV_CMD_ASSERT: + pOp->op.au4OpData[0] = 0; + break; + case WMTDRV_CMD_EXCEPTION: + pOp->op.au4OpData[0] = 1; + break; + case WMTDRV_CMD_NOACK_TEST: + pOp->op.au4OpData[0] = 3; + break; + case WMTDRV_CMD_WARNRST_TEST: + pOp->op.au4OpData[0] = 4; + break; + case WMTDRV_CMD_FWTRACE_TEST: + pOp->op.au4OpData[0] = 5; + break; + default: + if (WMTDRV_CMD_COEXDBG_00 <= cmd && WMTDRV_CMD_COEXDBG_15 >= cmd) { + pOp->op.au4OpData[0] = 2; + pOp->op.au4OpData[1] = cmd - 2; + } else { + pOp->op.au4OpData[0] = 0xff; + pOp->op.au4OpData[1] = 0xff; + } + pOp->op.au4OpData[2] = (SIZE_T) gCoexBuf.buffer; + pOp->op.au4OpData[3] = osal_sizeof(gCoexBuf.buffer); + break; + } + WMT_INFO_FUNC("CMD_TEST, opid(%d), par(%d, %d)\n", pOp->op.opId, pOp->op.au4OpData[0], pOp->op.au4OpData[1]); + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if ((cmd != WMTDRV_CMD_ASSERT) && + (cmd != WMTDRV_CMD_EXCEPTION) && + (cmd != WMTDRV_CMD_NOACK_TEST) && (cmd != WMTDRV_CMD_WARNRST_TEST) && (cmd != WMTDRV_CMD_FWTRACE_TEST)) { + if (MTK_WCN_BOOL_FALSE == bRet) { + gCoexBuf.availSize = 0; + } else { + gCoexBuf.availSize = pOp->op.au4OpData[3]; + WMT_INFO_FUNC("gCoexBuf.availSize = %d\n", gCoexBuf.availSize); + } + } + /* wmt_lib_host_awake_put(); */ + WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", + pOp->op.opId, + pOp->op.au4OpData[0], + pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + return 0; +} + +INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3) +{ + if (0 == par2) { + WMT_INFO_FUNC("inband reset test!!\n"); + mtk_wcn_stp_inband_reset(); + } else { + WMT_INFO_FUNC("STP context reset in host side!!\n"); + mtk_wcn_stp_flush_context(); + } + + return 0; +} + +INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3) +{ + if (0 == par2) { + if (mtk_wcn_stp_is_ready()) { + WMT_INFO_FUNC("whole chip reset test\n"); + wmt_lib_cmb_rst(WMTRSTSRC_RESET_TEST); + } else { + WMT_INFO_FUNC("STP not ready , not to launch whole chip reset test\n"); + } + } else if (1 == par2) { + WMT_INFO_FUNC("chip hardware reset test\n"); + wmt_lib_hw_rst(); + } else { + WMT_INFO_FUNC("chip software reset test\n"); + wmt_lib_sw_rst(1); + } + return 0; +} + +INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (WMTDRV_TYPE_WMT > par2 || WMTDRV_TYPE_LPBK == par2) { + if (0 == par3) { + WMT_INFO_FUNC("function off test, type(%d)\n", par2); + mtk_wcn_wmt_func_off(par2); + } else { + WMT_INFO_FUNC("function on test, type(%d)\n", par2); + mtk_wcn_wmt_func_on(par2); + } + } else { + WMT_INFO_FUNC("function ctrl test, invalid type(%d)\n", par2); + } + return 0; +} + +INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("chip version = %d\n", wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER)); + return 0; +} + +INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3) +{ + par2 = (WMT_LOG_ERR <= par2 && WMT_LOG_LOUD >= par2) ? par2 : WMT_LOG_INFO; + wmt_lib_dbg_level_set(par2); + WMT_INFO_FUNC("set wmt log level to %d\n", par2); + return 0; +} + +INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3) +{ + par2 = (0 <= par2 && 4 >= par2) ? par2 : 2; + mtk_wcn_stp_dbg_level(par2); + WMT_INFO_FUNC("set stp log level to %d\n", par2); + return 0; + +} + +INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->register address */ + /* par3-->register mask */ + UINT32 value = 0x0; + UINT32 iRet = -1; +#if 0 + DISABLE_PSM_MONITOR(); + iRet = wmt_core_reg_rw_raw(0, par2, &value, par3); + ENABLE_PSM_MONITOR(); +#endif + iRet = wmt_lib_reg_rw(0, par2, &value, par3); + WMT_INFO_FUNC("read combo chip register (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", + par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); + return 0; +} + +INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->register address */ + /* par3-->value to set */ + UINT32 iRet = -1; +#if 0 + DISABLE_PSM_MONITOR(); + iRet = wmt_core_reg_rw_raw(1, par2, &par3, 0xffffffff); + ENABLE_PSM_MONITOR(); +#endif + iRet = wmt_lib_reg_rw(1, par2, &par3, 0xffffffff); + WMT_INFO_FUNC("write combo chip register (0x%08x) with value (0x%08x) %s\n", + par2, par3, iRet != 0 ? "failed" : "succeed"); + return 0; +} + +INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->efuse address */ + /* par3-->register mask */ + UINT32 value = 0x0; + UINT32 iRet = -1; + + iRet = wmt_lib_efuse_rw(0, par2, &value, par3); + WMT_INFO_FUNC("read combo chip efuse (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", + par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); + return 0; +} + +INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->efuse address */ + /* par3-->value to set */ + UINT32 iRet = -1; + + iRet = wmt_lib_efuse_rw(1, par2, &par3, 0xffffffff); + WMT_INFO_FUNC("write combo chip efuse (0x%08x) with value (0x%08x) %s\n", + par2, par3, iRet != 0 ? "failed" : "succeed"); + return 0; +} + +INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +/*remove sdio card detect/remove control because of btif is used*/ +#if 0 + INT32 iRet = -1; + + iRet = wmt_lib_sdio_ctrl(0 != par2 ? 1 : 0); + WMT_INFO_FUNC("ctrl SDIO function %s\n", 0 == iRet ? "succeed" : "failed"); +#endif + return 0; +} + +INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (1 < par2) { + mtk_wcn_stp_dbg_dump_package(); + return 0; + } + WMT_INFO_FUNC("%s stp debug function\n", 0 == par2 ? "disable" : "enable"); + if (0 == par2) + mtk_wcn_stp_dbg_disable(); + else if (1 == par2) + mtk_wcn_stp_dbg_enable(); + + return 0; +} + +INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + mtk_wcn_stp_dbg_log_ctrl(0 != par2 ? 1 : 0); + return 0; +} + +INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + mtk_wcn_stp_coredump_flag_ctrl(0 != par2 ? 1 : 0); + return 0; +} + +INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 offset = 0; + UINT32 len = 0; + UINT32 *pAddr = NULL; + UINT32 cur_idx_pagedtrace; + static UINT32 prev_idx_pagedtrace; + MTK_WCN_BOOL isBreak = MTK_WCN_BOOL_TRUE; + + offset = par2; + len = par3; + + buf_emi = kmalloc(sizeof(UINT8) * BUF_LEN_MAX, GFP_KERNEL); + if (!buf_emi) { + WMT_ERR_FUNC("buf kmalloc memory fail\n"); + return 0; + } + osal_memset(buf_emi, 0, BUF_LEN_MAX); + osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); + wmt_lib_get_fwinfor_from_emi(0, offset, &gEmiBuf[0], 0x100); + + if (offset == 1) { + do { + pAddr = (PUINT32) wmt_plat_get_emi_virt_add(0x24); + cur_idx_pagedtrace = *pAddr; + + if (cur_idx_pagedtrace > prev_idx_pagedtrace) { + len = cur_idx_pagedtrace - prev_idx_pagedtrace; + wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); + wmt_dbg_fwinfor_print_buff(len); + prev_idx_pagedtrace = cur_idx_pagedtrace; + } + + if (cur_idx_pagedtrace < prev_idx_pagedtrace) { + if (prev_idx_pagedtrace >= 0x8000) { + pr_debug("++ prev_idx_pagedtrace invalid ...++\n\\n"); + prev_idx_pagedtrace = 0x8000 - 1; + continue; + } + + len = 0x8000 - prev_idx_pagedtrace - 1; + wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); + pr_debug("\n\n -- CONNSYS paged trace ascii output (cont...) --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + + len = cur_idx_pagedtrace; + wmt_lib_get_fwinfor_from_emi(1, 0x0, &gEmiBuf[0], len); + pr_debug("\n\n -- CONNSYS paged trace ascii output (end) --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + prev_idx_pagedtrace = cur_idx_pagedtrace; + } + msleep(100); + } while (isBreak); + } + + pr_debug("\n\n -- control word --\n\n"); + wmt_dbg_fwinfor_print_buff(256); + if (len > 1024 * 4) + len = 1024 * 4; + + WMT_WARN_FUNC("get fw infor from emi at offset(0x%x),len(0x%x)\n", offset, len); + osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); + wmt_lib_get_fwinfor_from_emi(1, offset, &gEmiBuf[0], len); + + pr_debug("\n\n -- paged trace hex output --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + pr_debug("\n\n -- paged trace ascii output --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + kfree(buf_emi); + return 0; +} + +INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("coexistance test cmd!!\n"); + return wmt_dbg_cmd_test_api(par2 + WMTDRV_CMD_COEXDBG_00); +} + +INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("%s audo rst\n", 0 == par2 ? "disable" : "enable"); + mtk_wcn_stp_set_auto_rst(0 == par2 ? 0 : 1); + return 0; +} + +INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3) +{ + + INT32 i = 0; + INT32 j = 0; + INT32 iRet = 0; + + i = 20; + while ((i--) > 0) { + WMT_INFO_FUNC("#### UT WMT and STP Function On/Off .... %d\n", i); + j = 10; + while ((j--) > 0) { + WMT_INFO_FUNC("#### BT On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### GPS On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### FM On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### WIFI On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### BT Off .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### GPS Off ....(%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### FM Off .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### WIFI Off ....(%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + } + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + } + if (iRet == MTK_WCN_BOOL_FALSE) + WMT_INFO_FUNC("#### UT FAIL!!\n"); + else + WMT_INFO_FUNC("#### UT PASS!!\n"); + + return iRet; +} + +#if CFG_CORE_INTERNAL_TXRX + +struct lpbk_package { + long payload_length; + unsigned char out_payload[2048]; + unsigned char in_payload[2048]; +}; + +static INT32 wmt_internal_loopback(INT32 count, INT32 max) +{ + int ret = 0; + int loop; + int offset; + struct lpbk_package lpbk_buffer; + P_OSAL_OP pOp; + P_OSAL_SIGNAL pSignal = NULL; + + for (loop = 0; loop < count; loop++) { + /* <1> init buffer */ + osal_memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package)); + lpbk_buffer.payload_length = max; + for (offset = 0; offset < max; offset++) + lpbk_buffer.out_payload[offset] = (offset + 1) /*for test use: begin from 1 */ & 0xFF; + + + memcpy(&gLpbkBuf[0], &lpbk_buffer.out_payload[0], max); + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + ret = -1; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_LPBK; + pOp->op.au4OpData[0] = lpbk_buffer.payload_length; /* packet length */ + pOp->op.au4OpData[1] = (UINT32) &gLpbkBuf[0]; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + ret = -2; + } + + ret = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == ret) { + WMT_WARN_FUNC("OPID(%d) type(%d)fail\n", pOp->op.opId, pOp->op.au4OpData[0]); + ret = -3; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + memcpy(&lpbk_buffer.in_payload[0], &gLpbkBuf[0], max); + + ret = pOp->op.au4OpData[0]; + /*<3> compare result */ + if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) { + WMT_INFO_FUNC("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __func__); + ret = -4; + break; + } + WMT_ERR_FUNC("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld)\n", __func__, loop, + lpbk_buffer.payload_length); + + } + + if (loop != count) + WMT_ERR_FUNC("fail at loop(%d) buf_length(%d)\n", loop, max); + + + return ret; +} + +INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 count; + UINT32 length; + + count = par1; + length = par2; + + WMT_INFO_FUNC("count[%d],length[%d]\n", count, length); + + wmt_core_lpbk_do_stp_init(); + + wmt_internal_loopback(count, length); + + wmt_core_lpbk_do_stp_deinit(); + return 0; +} +#endif + +static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3) +{ + int ret = 0; + P_OSAL_OP pOp; + P_OSAL_SIGNAL pSignal = NULL; + UINT32 kind = 0; + + kind = par2; + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_SET_MCU_CLK; + pOp->op.au4OpData[0] = kind; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + WMT_INFO_FUNC("OPID(%d) kind(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) kind(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return -2; + } + + ret = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == ret) { + WMT_WARN_FUNC("OPID(%d) kind(%d)fail(%d)\n", pOp->op.opId, pOp->op.au4OpData[0], ret); + return -3; + } + WMT_INFO_FUNC("OPID(%d) kind(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return ret; +} + +static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 count = 0; + UINT16 sleep = 0; + UINT16 toAee = 0; + + count = par2; + sleep = (par3 & 0xF0) >> 4; + toAee = (par3 & 0x0F); + + WMT_INFO_FUNC("polling count[%d],polling sleep[%d],toaee[%d]\n", count, sleep, toAee); + wmt_lib_poll_cpupcr(count, sleep, toAee); + + return 0; +} + +#if CONSYS_ENALBE_SET_JTAG +static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 en_flag = par2; + + wmt_lib_jtag_flag_set(en_flag); + return 0; +} +#endif + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_dbg_lte_to_wmt_test(UINT32 opcode, UINT32 msg_len) +{ + ipc_ilm_t ilm; + local_para_struct *p_buf_str; + INT32 i = 0; + INT32 iRet = -1; + + WMT_INFO_FUNC("opcode(0x%02x),msg_len(%d)\n", opcode, msg_len); + p_buf_str = osal_malloc(osal_sizeof(local_para_struct) + msg_len); + if (NULL == p_buf_str) { + WMT_ERR_FUNC("kmalloc for local para ptr structure failed.\n"); + return -1; + } + p_buf_str->msg_len = msg_len; + for (i = 0; i < msg_len; i++) + p_buf_str->data[i] = i; + + ilm.local_para_ptr = p_buf_str; + ilm.msg_id = opcode; + + iRet = wmt_lib_handle_idc_msg(&ilm); + osal_free(p_buf_str); + return iRet; + +} + +static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3) +{ + UINT8 *local_buffer = NULL; + UINT32 handle_len; + INT32 iRet = -1; + static UINT8 wmt_to_lte_test_evt1[] = { 0x02, 0x16, 0x0d, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0xa, 0xb + }; + static UINT8 wmt_to_lte_test_evt2[] = { 0x02, 0x16, 0x09, 0x00, + 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + static UINT8 wmt_to_lte_test_evt3[] = { 0x02, 0x16, 0x02, 0x00, + 0x02, 0xff + }; + static UINT8 wmt_to_lte_test_evt4[] = { 0x02, 0x16, 0x0d, 0x00, + 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0xa, 0xb + }; + + local_buffer = kmalloc(512, GFP_KERNEL); + if (!local_buffer) { + WMT_ERR_FUNC("local_buffer kmalloc memory fail\n"); + return 0; + } + + if (par2 == 1) { + handle_len = + wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt1)) { + WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", + handle_len, osal_sizeof(wmt_to_lte_test_evt1)); + } else { + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + } + if (par2 == 2) { + osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], + &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); + + handle_len = + wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], + osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)) { + WMT_ERR_FUNC("par2=2,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", + handle_len, osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)); + } else { + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + } + if (par2 == 3) { + osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], + &wmt_to_lte_test_evt2[0], osal_sizeof(wmt_to_lte_test_evt2)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)], + &wmt_to_lte_test_evt3[0], osal_sizeof(wmt_to_lte_test_evt3)); + + handle_len = wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)); + if (handle_len != + osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)) { + WMT_ERR_FUNC("par2=3,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", handle_len, + osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)); + } else { + WMT_INFO_FUNC("par3=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + } + if (par2 == 4) { + handle_len = + wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt4[0], osal_sizeof(wmt_to_lte_test_evt4)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt4)) { + WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%d)\n", + handle_len, osal_sizeof(wmt_to_lte_test_evt4)); + } else { + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + } + if (par2 == 5) { + if (par3 >= 1024) + par3 = 1024; + + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND test result(%d)\n", iRet); + } + if (par2 == 6) { + if (par3 >= 1024) + par3 = 1024; + + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND test result(%d)\n", iRet); + } + if (par2 == 7) { + if (par3 >= 1024) + par3 = 1024; + + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND test result(%d)\n", iRet); + } + if (par2 == 8) { + if (par3 >= 1024) + par3 = 1024; + + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_TX_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_TX_IND test result(%d)\n", iRet); + } + if (par2 == 9) { + if (par3 > 0) + wmt_core_set_flag_for_test(1); + else + wmt_core_set_flag_for_test(0); + } + return 0; + kfree(local_buffer); +} +#endif + +static ssize_t wmt_dev_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + + INT32 retval = 0; + INT32 i_ret = 0; + PINT8 warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; + + if (*f_pos > 0) { + retval = 0; + } else { + /*len = sprintf(page, "%d\n", g_psm_enable); */ + if (gCoexBuf.availSize <= 0) { + WMT_INFO_FUNC("no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"); + retval = osal_strlen(warn_msg) + 1; + if (count < retval) + retval = count; + + i_ret = copy_to_user(buf, warn_msg, retval); + if (i_ret) { + WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + } else { + INT32 i = 0; + INT32 len = 0; + INT8 msg_info[128]; + INT32 max_num = 0; + /*we do not check page buffer, because there are only + * 100 bytes in g_coex_buf, no reason page buffer is not + * enough, a bomb is placed here on unexpected condition + */ + + WMT_INFO_FUNC("%d bytes available\n", gCoexBuf.availSize); + max_num = ((osal_sizeof(msg_info) > count ? osal_sizeof(msg_info) : count) - 1) / 5; + + if (max_num > gCoexBuf.availSize) + max_num = gCoexBuf.availSize; + else + WMT_INFO_FUNC("round to %d bytes due to local buffer size limitation\n", max_num); + + + for (i = 0; i < max_num; i++) + len += osal_sprintf(msg_info + len, "0x%02x ", gCoexBuf.buffer[i]); + + + len += osal_sprintf(msg_info + len, "\n"); + retval = len; + + i_ret = copy_to_user(buf, msg_info, retval); + if (i_ret) { + WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + + } + } + gCoexBuf.availSize = 0; +err_exit: + + return retval; +} + +static ssize_t wmt_dev_dbg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) +{ + INT8 buf[256]; + PINT8 pBuf; + ssize_t len = count; + INT32 x = 0, y = 0, z = 0; + PINT8 pToken = NULL; + PINT8 pDelimiter = " \t"; + long res; + INT32 ret; + + WMT_INFO_FUNC("write parameter len = %d\n\r", (INT32) len); + if (len >= osal_sizeof(buf)) { + WMT_ERR_FUNC("input handling fail!\n"); + len = osal_sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf, buffer, len)) + return -EFAULT; + + buf[len] = '\0'; + WMT_INFO_FUNC("write parameter data = %s\n\r", buf); + + pBuf = buf; + pToken = osal_strsep(&pBuf, pDelimiter); + + if (pToken != NULL) { + ret = osal_strtol(pToken, 16, &res); + if (ret) { + WMT_ERR_FUNC("get x fail(%d)\n", ret); + x = 0; + } + x = res; + } else { + x = 0; + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + ret = osal_strtol(pToken, 16, &res); + if (ret) { + WMT_ERR_FUNC("get y fail(%d)\n", ret); + y = 0; + } + y = res; + WMT_INFO_FUNC("y = 0x%08x\n\r", y); + } else { + y = 3000; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + y = 0x80000000; + + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + ret = osal_strtol(pToken, 16, &res); + if (ret) { + WMT_ERR_FUNC("get z fail(%d)\n", ret); + z = 0; + } + z = res; + } else { + z = 10; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + z = 0xffffffff; + + } + + WMT_WARN_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); + + if (osal_array_size(wmt_dev_dbg_func) > x && NULL != wmt_dev_dbg_func[x]) + (*wmt_dev_dbg_func[x]) (x, y, z); + else + WMT_WARN_FUNC("no handler defined for command id(0x%08x)\n\r", x); + + return len; +} + +INT32 wmt_dev_dbg_setup(VOID) +{ + static const struct file_operations wmt_dbg_fops = { + .owner = THIS_MODULE, + .read = wmt_dev_dbg_read, + .write = wmt_dev_dbg_write, + }; + gWmtDbgEntry = proc_create(WMT_DBG_PROCNAME, 0664, NULL, &wmt_dbg_fops); + if (gWmtDbgEntry == NULL) { + WMT_ERR_FUNC("Unable to create /proc entry\n\r"); + return -1; + } + return 0; +} + +INT32 wmt_dev_dbg_remove(VOID) +{ + if (NULL != gWmtDbgEntry) + remove_proc_entry(WMT_DBG_PROCNAME, NULL); + +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_deinit(); +#endif + return 0; +} +#endif + +#if CFG_WMT_PROC_FOR_AEE + +static ssize_t wmt_dev_proc_for_aee_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = 0; + UINT32 len = 0; + + WMT_INFO_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos); + + if (0 == *f_pos) { + pBuf = wmt_lib_get_cpupcr_xml_format(&len); + g_buf_len = len; + WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len); + } + + if (g_buf_len >= count) { + + retval = copy_to_user(buf, pBuf, count); + if (retval) { + WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + + *f_pos += count; + g_buf_len -= count; + pBuf += count; + WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); + + retval = count; + } else if (0 != g_buf_len) { + + retval = copy_to_user(buf, pBuf, g_buf_len); + if (retval) { + WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + + *f_pos += g_buf_len; + len = g_buf_len; + g_buf_len = 0; + pBuf += len; + retval = len; + WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); + } else { + WMT_INFO_FUNC("wmt_dev: no data available for aee\n"); + retval = 0; + } +err_exit: + return retval; +} + +static ssize_t wmt_dev_proc_for_aee_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + WMT_TRC_FUNC(); + return 0; +} + +INT32 wmt_dev_proc_for_aee_setup(VOID) +{ + static const struct file_operations wmt_aee_fops = { + .owner = THIS_MODULE, + .read = wmt_dev_proc_for_aee_read, + .write = wmt_dev_proc_for_aee_write, + }; + + gWmtDbgEntry = proc_create(WMT_AEE_PROCNAME, 0664, NULL, &wmt_aee_fops); + if (gWmtDbgEntry == NULL) { + WMT_ERR_FUNC("Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + +INT32 wmt_dev_proc_for_aee_remove(VOID) +{ + if (NULL != gWmtAeeEntry) + remove_proc_entry(WMT_AEE_PROCNAME, NULL); + + return 0; +} +#endif + +VOID wmt_dev_rx_event_cb(VOID) +{ + u4RxFlag = 1; + atomic_inc(&gRxCount); + if (NULL != gpRxEvent) { + /* u4RxFlag = 1; */ + /* atomic_inc(&gRxCount); */ + wake_up_interruptible(&gpRxEvent->waitQueue); + } else { + /* WMT_ERR_FUNC("null gpRxEvent, flush rx!\n"); */ + /* wmt_lib_flush_rx(); */ + } +} + +INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent) +{ + + UINT32 ms = pEvent->timeoutValue; + long lRet = 0; + + gpRxEvent = pEvent; + if (0 != ms) + lRet = wait_event_interruptible_timeout(gpRxEvent->waitQueue, 0 != u4RxFlag, msecs_to_jiffies(ms)); + else + lRet = wait_event_interruptible(gpRxEvent->waitQueue, u4RxFlag != 0); + + u4RxFlag = 0; +/* gpRxEvent = NULL; */ + if (atomic_dec_return(&gRxCount)) { + WMT_ERR_FUNC("gRxCount != 0 (%d), reset it!\n", atomic_read(&gRxCount)); + atomic_set(&gRxCount, 0); + } + + return lRet; +} + +INT32 wmt_dev_read_file(PUINT8 pName, const PPUINT8 ppBufPtr, INT32 offset, INT32 padSzBuf) +{ + INT32 iRet = -1; + struct file *fd; + /* ssize_t iRet; */ + INT32 file_len; + INT32 read_len; + PVOID pBuf; + mm_segment_t fs; + + /* struct cred *cred = get_task_cred(current); */ + //const struct cred *cred = get_current_cred(); + + if (!ppBufPtr) { + WMT_ERR_FUNC("invalid ppBufptr!\n"); + return -1; + } + *ppBufPtr = NULL; + + fd = filp_open(pName, O_RDONLY, 0); + if (IS_ERR(fd)) { + WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); + return -2; + } + + if(fd->f_op == NULL) { + printk(KERN_ERR "invalid file op \r\n"); + return -3; + } + +#if 0 + if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { + WMT_ERR_FUNC("failed to open or read!(0x%p, %d, %d, %d)\n", fd, PTR_ERR(fd), cred->fsuid, cred->fsgid); + if (IS_ERR(fd)) + WMT_ERR_FUNC("error code:%d\n", PTR_ERR(fd)); + return -1; + } +#endif + file_len = fd->f_path.dentry->d_inode->i_size; + file_len = fd->f_op->llseek(fd, 0, 2); + fd->f_op->llseek(fd, 0, 0); + pBuf = vmalloc((file_len + BCNT_PATCH_BUF_HEADROOM + 3) & ~0x3UL); + if (!pBuf) { + WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32) ((file_len + 3) & ~0x3UL)); + goto read_file_done; + } + + do { + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + WMT_ERR_FUNC("failed to seek!!\n"); + goto read_file_done; + } + } else { + fd->f_pos = offset; + } + } + + fs=get_fs(); + read_len = vfs_read(fd, pBuf + padSzBuf, file_len, &fd->f_pos); + set_fs(fs); + if (read_len != file_len) + WMT_WARN_FUNC("read abnormal: read_len(%d), file_len(%d)\n", read_len, file_len); + + } while (false); + + iRet = 0; + *ppBufPtr = pBuf; + +read_file_done: + if (iRet) { + if (pBuf) + vfree(pBuf); + + } + + filp_close(fd, NULL); + + return (iRet) ? iRet : read_len; +} + +/* TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. */ +INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf) +{ + INT32 iRet = -1; + osal_firmware *pfw; + uid_t orig_uid; + gid_t orig_gid; + + /* struct cred *cred = get_task_cred(current); */ + struct cred *cred = (struct cred *)get_current_cred(); + + mm_segment_t orig_fs = get_fs(); + + if (*ppPatch) { + WMT_WARN_FUNC("f/w patch already exists\n"); + if ((*ppPatch)->data) + vfree((*ppPatch)->data); + + kfree(*ppPatch); + *ppPatch = NULL; + } + + if (!osal_strlen(pPatchName)) { + WMT_ERR_FUNC("empty f/w name\n"); + osal_assert((osal_strlen(pPatchName) > 0)); + return -1; + } + + pfw = kzalloc(sizeof(osal_firmware), /*GFP_KERNEL */ GFP_ATOMIC); + if (!pfw) { + WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(osal_firmware)); + return -2; + } + + orig_uid = cred->fsuid.val; + orig_gid = cred->fsgid.val; + cred->fsuid.val = cred->fsgid.val = 0; + + set_fs(get_ds()); + + /* load patch file from fs */ + iRet = wmt_dev_read_file(pPatchName, (const PPUINT8)&pfw->data, 0, padSzBuf); + set_fs(orig_fs); + + cred->fsuid.val = orig_uid; + cred->fsgid.val = orig_gid; + + + if (iRet > 0) { + pfw->size = iRet; + *ppPatch = pfw; + WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName, pfw->data); + return 0; + } + kfree(pfw); + *ppPatch = NULL; + WMT_ERR_FUNC("load file (%s) fail, iRet(%d)\n", pPatchName, iRet); + return -1; +} + +INT32 wmt_dev_patch_put(osal_firmware **ppPatch) +{ + if (NULL != *ppPatch) { + if ((*ppPatch)->data) + vfree((*ppPatch)->data); + + kfree(*ppPatch); + *ppPatch = NULL; + } + return 0; +} + +VOID wmt_dev_patch_info_free(VOID) +{ + + kfree(pPatchInfo); + pPatchInfo = NULL; + +} + +MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName) +{ + struct file *fd = NULL; + /* ssize_t iRet; */ + INT32 fileLen = -1; + const struct cred *cred = get_current_cred(); + + if (pFileName == NULL) { + WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) { + WMT_ERR_FUNC("invalid file name(%s)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + /* struct cred *cred = get_task_cred(current); */ + + fd = filp_open(pFileName, O_RDONLY, 0); + if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) { + WMT_ERR_FUNC("failed to open or read(%s)!(0x%p, %d, %d)\n", pFileName, fd, cred->fsuid, cred->fsgid); + return MTK_WCN_BOOL_FALSE; + } + fileLen = fd->f_path.dentry->d_inode->i_size; + filp_close(fd, NULL); + fd = NULL; + if (fileLen <= 0) { + WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName, fileLen); + return MTK_WCN_BOOL_FALSE; + } + WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName, fileLen); + return true; + +} + +/* static unsigned long count_last_access_sdio = 0; */ +static unsigned long count_last_access_btif; +static unsigned long jiffies_last_poll; + +#if 0 +static INT32 wmt_dev_tra_sdio_update(void) +{ + count_last_access_sdio += 1; + /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */ + + return 0; +} +#endif + +extern INT32 wmt_dev_tra_bitf_update(void) +{ + count_last_access_btif += 1; + /* WMT_INFO_FUNC("jiffies_last_access_btif: jiffies = %ul\n", jiffies); */ + + return 0; +} + +static UINT32 wmt_dev_tra_ahb_poll(void) +{ +#define TIME_THRESHOLD_TO_TEMP_QUERY 3000 +#define COUNT_THRESHOLD_TO_TEMP_QUERY 200 + + unsigned long ahb_during_count = 0; + unsigned long poll_during_time = 0; + + /* if (jiffies > jiffies_last_poll) */ + if (time_after(jiffies, jiffies_last_poll)) + poll_during_time = jiffies - jiffies_last_poll; + else + poll_during_time = 0xffffffff; + + + WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %lu\n", jiffies_to_msecs(0xffffffff)); + + if (jiffies_to_msecs(poll_during_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { + WMT_DBG_FUNC("**poll_during_time = %lu < %lu, not to query\n", + jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY); + return -1; + } + /* ahb_during_count = count_last_access_sdio; */ + if (NULL == mtk_wcn_wlan_bus_tx_cnt) { + WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt null pointer\n"); + return -1; + } + ahb_during_count = (*mtk_wcn_wlan_bus_tx_cnt) (); + + if (ahb_during_count < COUNT_THRESHOLD_TO_TEMP_QUERY) { + WMT_DBG_FUNC("**ahb_during_count = %lu < %lu, not to query\n", + ahb_during_count, COUNT_THRESHOLD_TO_TEMP_QUERY); + return -2; + } + + if (NULL == mtk_wcn_wlan_bus_tx_cnt_clr) { + WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt_clr null pointer\n"); + return -3; + } + (*mtk_wcn_wlan_bus_tx_cnt_clr) (); + /* count_last_access_sdio = 0; */ + jiffies_last_poll = jiffies; + + WMT_INFO_FUNC("**poll_during_time = %lu > %lu, ahb_during_count = %lu > %lu, query\n", + jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY, + jiffies_to_msecs(ahb_during_count), COUNT_THRESHOLD_TO_TEMP_QUERY); + + return 0; +} + +long wmt_dev_tm_temp_query(void) +{ +#define HISTORY_NUM 5 +#define TEMP_THRESHOLD 65 +#define REFRESH_TIME 300 /* sec */ + + static INT32 temp_table[HISTORY_NUM] = { 99 }; /* not query yet. */ + static INT32 idx_temp_table; + static struct timeval query_time, now_time; + + INT8 query_cond = 0; + INT32 current_temp = 0; + INT32 index = 0; + long return_temp = 0; + /* Query condition 1: */ + /* If we have the high temperature records on the past, we continue to query/monitor */ + /* the real temperature until cooling */ + for (index = 0; index < HISTORY_NUM; index++) { + if (temp_table[index] >= TEMP_THRESHOLD) { + query_cond = 1; + WMT_DBG_FUNC("temperature table is still initial value, we should query temp temperature..\n"); + } + } + + do_gettimeofday(&now_time); +#if 1 + /* Query condition 2: */ + /* Moniter the ahb bus activity to decide if we have the need to query temperature. */ + if (!query_cond) { + if (wmt_dev_tra_ahb_poll() == 0) { + query_cond = 1; + WMT_INFO_FUNC("ahb traffic , we must query temperature..\n"); + } else { + WMT_DBG_FUNC("ahb idle traffic ....\n"); + } + + /* only WIFI tx power might make temperature varies largely */ +#if 0 + if (!query_cond) { + last_access_time = wmt_dev_tra_uart_poll(); + if (jiffies_to_msecs(last_access_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { + query_cond = 1; + WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n"); + } else { + WMT_DBG_FUNC("uart still idle traffic , we don't query temp temperature..\n"); + } + } +#endif + } +#endif + /* Query condition 3: */ + /* If the query time exceeds the a certain of period, refresh temp table. */ + /* */ + if (!query_cond) { + /* time overflow, we refresh temp table again for simplicity! */ + if ((now_time.tv_sec < query_time.tv_sec) || + ((now_time.tv_sec > query_time.tv_sec) && (now_time.tv_sec - query_time.tv_sec) > REFRESH_TIME)) { + query_cond = 1; + + WMT_INFO_FUNC("It is long time (> %d sec) not to query, we must query temp temperature..\n", + REFRESH_TIME); + for (index = 0; index < HISTORY_NUM; index++) + temp_table[index] = 99; + + } + } + + if (query_cond) { + /* update the temperature record */ + mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE); + current_temp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ); + mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE); + idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; + temp_table[idx_temp_table] = current_temp; + do_gettimeofday(&query_time); + + WMT_INFO_FUNC("[Thermal] current_temp = 0x%x\n", (current_temp & 0xFF)); + } else { + current_temp = temp_table[idx_temp_table]; + idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM; + temp_table[idx_temp_table] = current_temp; + } + + /* */ + /* Dump information */ + /* */ + WMT_DBG_FUNC("[Thermal] idx_temp_table = %d\n", idx_temp_table); + WMT_DBG_FUNC("[Thermal] now.time = %d, query.time = %d, REFRESH_TIME = %d\n", now_time.tv_sec, + query_time.tv_sec, REFRESH_TIME); + + WMT_DBG_FUNC("[0] = %d, [1] = %d, [2] = %d, [3] = %d, [4] = %d\n----\n", + temp_table[0], temp_table[1], temp_table[2], temp_table[3], temp_table[4]); + + return_temp = ((current_temp & 0x80) == 0x0) ? current_temp : (-1) * (current_temp & 0x7f); + + return return_temp; +} + +ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 iRet = 0; + UINT8 wrBuf[NAME_MAX + 1] = { 0 }; + INT32 copySize = (count < NAME_MAX) ? count : NAME_MAX; + + WMT_LOUD_FUNC("count:%d copySize:%d\n", count, copySize); + + if (copySize > 0) { + if (copy_from_user(wrBuf, buf, copySize)) { + iRet = -EFAULT; + goto write_done; + } + iRet = copySize; + wrBuf[NAME_MAX] = '\0'; + + if (!strncasecmp(wrBuf, "ok", NAME_MAX)) { + WMT_DBG_FUNC("resp str ok\n"); + /* pWmtDevCtx->cmd_result = 0; */ + wmt_lib_trigger_cmd_signal(0); + } else { + WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf); + /* pWmtDevCtx->cmd_result = -1; */ + wmt_lib_trigger_cmd_signal(-1); + } + /* complete(&pWmtDevCtx->cmd_comp); */ + + } + +write_done: + return iRet; +} + +ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 iRet = 0; + PUINT8 pCmd = NULL; + UINT32 cmdLen = 0; + + pCmd = wmt_lib_get_cmd(); + + if (pCmd != NULL) { + cmdLen = osal_strlen(pCmd) < NAME_MAX ? osal_strlen(pCmd) : NAME_MAX; + WMT_DBG_FUNC("cmd str(%s)\n", pCmd); + if (copy_to_user(buf, pCmd, cmdLen)) + iRet = -EFAULT; + else + iRet = cmdLen; + + } +#if 0 + if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { + iRet = osal_strlen(localBuf) < NAME_MAX ? osal_strlen(localBuf) : NAME_MAX; + /* we got something from STP driver */ + WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf); + if (copy_to_user(buf, localBuf, iRet)) { + iRet = -EFAULT; + goto read_done; + } + } +#endif + return iRet; +} + +unsigned int WMT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event(); + + poll_wait(filp, &pEvent->waitQueue, wait); + /* empty let select sleep */ + if (MTK_WCN_BOOL_TRUE == wmt_lib_get_cmd_status()) + mask |= POLLIN | POLLRDNORM; /* readable */ + +#if 0 + if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) + mask |= POLLIN | POLLRDNORM; /* readable */ + +#endif + mask |= POLLOUT | POLLWRNORM; /* writable */ + return mask; +} + +/* INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) */ +long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + + INT32 iRet = 0; + UINT8 *pBuffer = NULL; + + WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); + switch (cmd) { + case WMT_IOCTL_SET_PATCH_NAME: /* patch location */ + { + + pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); + if (!pBuffer) { + WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); + return 0; + } + if (copy_from_user(pBuffer, (void *)arg, NAME_MAX)) { + iRet = -EFAULT; + kfree(pBuffer); + break; + } + pBuffer[NAME_MAX] = '\0'; + wmt_lib_set_patch_name(pBuffer); + kfree(pBuffer); + } + break; + + case WMT_IOCTL_SET_STP_MODE: /* stp/hif/fm mode */ + + /* set hif conf */ + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal = NULL; + P_WMT_HIF_CONF pHif = NULL; + + iRet = wmt_lib_set_hif(arg); + if (0 != iRet) { + WMT_INFO_FUNC("wmt_lib_set_hif fail\n"); + break; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_INFO_FUNC("get_free_lxop fail\n"); + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_HIF_CONF; + + pHif = wmt_lib_get_hif(); + + osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF)); + pOp->op.u4InfoBit = WMT_OP_HIF_BIT; + pSignal->timeoutValue = 0; + + bRet = wmt_lib_put_act_op(pOp); + WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d)\n", bRet); + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + } while (0); + + break; + + case WMT_IOCTL_FUNC_ONOFF_CTRL: /* test turn on/off func */ + + do { + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + if (arg & 0x80000000) + bRet = mtk_wcn_wmt_func_on(arg & 0xF); + else + bRet = mtk_wcn_wmt_func_off(arg & 0xF); + + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + } while (0); + + break; + + case WMT_IOCTL_LPBK_POWER_CTRL: + /*switch Loopback function on/off + arg: bit0 = 1:turn loopback function on + bit0 = 0:turn loopback function off + */ + do { + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + if (arg & 0x01) + bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); + else + bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); + + iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0; + } while (0); + + break; + + case WMT_IOCTL_LPBK_TEST: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 u4Wait; + /* UINT8 lpbk_buf[1024] = {0}; */ + UINT32 effectiveLen = 0; + P_OSAL_SIGNAL pSignal = NULL; + + if (copy_from_user(&effectiveLen, (void *)arg, sizeof(effectiveLen))) { + iRet = -EFAULT; + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + break; + } + if (effectiveLen > sizeof(gLpbkBuf)) { + iRet = -EFAULT; + WMT_ERR_FUNC("length is too long\n"); + break; + } + WMT_DBG_FUNC("len = %d\n", effectiveLen); + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + u4Wait = 2000; + if (copy_from_user(&gLpbkBuf[0], (void *)arg + sizeof(unsigned long), effectiveLen)) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_LPBK; + pOp->op.au4OpData[0] = effectiveLen; /* packet length */ + pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; /* packet buffer pointer */ + memcpy(&gLpbkBufLog, &gLpbkBuf[((effectiveLen >= 4) ? effectiveLen - 4 : 0)], 4); + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", + pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n", + pOp->op.opId, pOp->op.au4OpData[0], gLpbkBufLog); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + if (copy_to_user((void *)arg + sizeof(SIZE_T) + sizeof(UINT8[2048]), gLpbkBuf, iRet)) { + iRet = -EFAULT; + break; + } + + } while (0); + + break; + + case WMT_IOCTL_ADIE_LPBK_TEST: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal = NULL; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_ADIE_LPBK_TEST; + pOp->op.au4OpData[0] = 0; + pOp->op.au4OpData[1] = (SIZE_T) &gLpbkBuf[0]; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d)abort\n", pOp->op.opId); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + if (copy_to_user((void *)arg + sizeof(SIZE_T), gLpbkBuf, iRet)) { + iRet = -EFAULT; + break; + } + + } while (0); + + break; + + case 10: + { + pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); + if (!pBuffer) { + WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); + return 0; + } + wmt_lib_host_awake_get(); + mtk_wcn_stp_coredump_start_ctrl(1); + osal_strcpy(pBuffer, "MT662x f/w coredump start-"); + if (copy_from_user + (pBuffer + osal_strlen(pBuffer), (void *)arg, NAME_MAX - osal_strlen(pBuffer))) { + /* osal_strcpy(pBuffer, "MT662x f/w assert core dump start"); */ + WMT_ERR_FUNC("copy assert string failed\n"); + } + pBuffer[NAME_MAX] = '\0'; + osal_dbg_assert_aee(pBuffer, pBuffer); + kfree(pBuffer); + } + break; + case 11: + { + osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); + wmt_lib_host_awake_put(); + } + break; + + case WMT_IOCTL_GET_CHIP_INFO: + { + if (0 == arg) + return wmt_lib_get_icinfo(WMTCHIN_CHIPID); + else if (1 == arg) + return wmt_lib_get_icinfo(WMTCHIN_HWVER); + else if (2 == arg) + return wmt_lib_get_icinfo(WMTCHIN_FWVER); + + } + break; + + case WMT_IOCTL_SET_LAUNCHER_KILL:{ + if (1 == arg) { + WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n"); + wmt_lib_set_stp_wmt_last_close(1); + } else { + wmt_lib_set_stp_wmt_last_close(0); + } + + } + break; + + case WMT_IOCTL_SET_PATCH_NUM:{ + pAtchNum = arg; + WMT_DBG_FUNC(" get patch num from launcher = %d\n", pAtchNum); + wmt_lib_set_patch_num(pAtchNum); + pPatchInfo = kcalloc(pAtchNum, sizeof(WMT_PATCH_INFO), GFP_ATOMIC); + if (!pPatchInfo) { + WMT_ERR_FUNC("allocate memory fail!\n"); + break; + } + } + break; + + case WMT_IOCTL_SET_PATCH_INFO:{ + WMT_PATCH_INFO wMtPatchInfo; + P_WMT_PATCH_INFO pTemp = NULL; + UINT32 dWloadSeq; + static UINT32 counter; + + if (!pPatchInfo) { + WMT_ERR_FUNC("NULL patch info pointer\n"); + break; + } + + if (copy_from_user(&wMtPatchInfo, (void *)arg, sizeof(WMT_PATCH_INFO))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + dWloadSeq = wMtPatchInfo.dowloadSeq; + WMT_DBG_FUNC( + "patch dl seq %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n", + dWloadSeq, wMtPatchInfo.patchName, + wMtPatchInfo.addRess[0], + wMtPatchInfo.addRess[1], + wMtPatchInfo.addRess[2], + wMtPatchInfo.addRess[3]); + osal_memcpy(pPatchInfo + dWloadSeq - 1, &wMtPatchInfo, sizeof(WMT_PATCH_INFO)); + pTemp = pPatchInfo + dWloadSeq - 1; + if (++counter == pAtchNum) { + wmt_lib_set_patch_info(pPatchInfo); + counter = 0; + } + } + break; + + case WMT_IOCTL_WMT_COREDUMP_CTRL: + mtk_wcn_stp_coredump_flag_ctrl(arg); + break; + case WMT_IOCTL_WMT_QUERY_CHIPID: + { + iRet = mtk_wcn_wmt_chipid_query(); + WMT_WARN_FUNC("chipid = 0x%x\n", iRet); + } + break; + case WMT_IOCTL_SEND_BGW_DS_CMD: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT8 desense_buf[14] = { 0 }; + UINT32 effectiveLen = 14; + P_OSAL_SIGNAL pSignal = NULL; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + if (copy_from_user(&desense_buf[0], (void *)arg, effectiveLen)) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_BGW_DS; + pOp->op.au4OpData[0] = effectiveLen; /* packet length */ + pOp->op.au4OpData[1] = (SIZE_T) &desense_buf[0]; /* packet buffer pointer */ + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,opid(%d) abort\n", pOp->op.opId); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + + } while (0); + + break; + case WMT_IOCTL_FW_DBGLOG_CTRL: + { + iRet = wmt_plat_set_dbg_mode(arg); + if (iRet == 0) + wmt_dbg_fwinfor_from_emi(0, 1, 0); + } + break; + case WMT_IOCTL_DYNAMIC_DUMP_CTRL: + { + UINT32 i = 0, j = 0, k = 0; + UINT8 *pBuf = NULL; + UINT32 int_buf[10]; + char Buffer[10][11]; + + pBuf = kmalloc(DYNAMIC_DUMP_BUF + 1, GFP_KERNEL); + if (!pBuf) { + WMT_ERR_FUNC("pBuf kmalloc memory fail\n"); + return 0; + } + if (copy_from_user(pBuf, (void *)arg, DYNAMIC_DUMP_BUF)) { + iRet = -EFAULT; + kfree(pBuf); + break; + } + pBuf[DYNAMIC_DUMP_BUF] = '\0'; + WMT_INFO_FUNC("get dynamic dump data from property(%s)\n", pBuf); + memset(Buffer, 0, 10*11); + for (i = 0; i < DYNAMIC_DUMP_BUF; i++) { + if (pBuf[i] == '/') { + k = 0; + j++; + } else { + Buffer[j][k] = pBuf[i]; + k++; + } + } + for (j = 0; j < 10; j++) { + iRet = kstrtou32(Buffer[j], 0, &int_buf[j]); + if (iRet) { + WMT_ERR_FUNC("string convert fail(%d)\n", iRet); + break; + } + WMT_INFO_FUNC("dynamic dump data buf[%d]:(0x%x)\n", j, int_buf[j]); + } + wmt_plat_set_dynamic_dumpmem(int_buf); + kfree(pBuf); + } + break; + default: + iRet = -EINVAL; + WMT_WARN_FUNC("unknown cmd (%d)\n", cmd); + break; + } + + return iRet; +} +#ifdef CONFIG_COMPAT +long WMT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + WMT_INFO_FUNC("cmd[0x%x]\n", cmd); + switch (cmd) { + case COMPAT_WMT_IOCTL_SET_PATCH_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_NAME, (unsigned long)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_LPBK_TEST: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_LPBK_TEST, (unsigned long)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_SET_PATCH_INFO: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_INFO, (unsigned long)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_PORT_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_PORT_NAME, (unsigned long)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_WMT_CFG_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_WMT_CFG_NAME, (unsigned long)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SEND_BGW_DS_CMD, (unsigned long)compat_ptr(arg)); + break; + default: { + ret = WMT_unlocked_ioctl(filp, cmd, arg); + break; + } + } + return ret; +} +#endif +static int WMT_open(struct inode *inode, struct file *file) +{ + long ret; + + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + ret = wait_event_timeout(gWmtInitWq, gWmtInitDone != 0, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); + if (!ret) { + WMT_WARN_FUNC("wait_event_timeout (%d)ms,(%d)jiffies,return -EIO\n", + WMT_DEV_INIT_TO_MS, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); + return -EIO; + } + + if (atomic_inc_return(&gWmtRefCnt) == 1) + WMT_INFO_FUNC("1st call\n"); + + return 0; +} + +static int WMT_close(struct inode *inode, struct file *file) +{ + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + if (atomic_dec_return(&gWmtRefCnt) == 0) + WMT_INFO_FUNC("last call\n"); + + return 0; +} + +const struct file_operations gWmtFops = { + .open = WMT_open, + .release = WMT_close, + .read = WMT_read, + .write = WMT_write, +/* .ioctl = WMT_ioctl, */ + .unlocked_ioctl = WMT_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = WMT_compat_ioctl, +#endif + .poll = WMT_poll, +}; + +void wmt_dev_bgw_desense_init(VOID) +{ + bgw_init_socket(); +} + +void wmt_dev_bgw_desense_deinit(VOID) +{ + bgw_destroy_netlink_kernel(); +} + +void wmt_dev_send_cmd_to_daemon(UINT32 cmd) +{ + send_command_to_daemon(cmd); +} + +static int WMT_init(void) +{ + dev_t devID = MKDEV(gWmtMajor, 0); + INT32 cdevErr = -1; + INT32 ret = -1; + + WMT_INFO_FUNC("WMT Version= %s DATE=%s\n", MTK_WMT_VERSION, MTK_WMT_DATE); + /* Prepare a UINT8 device */ + /*static allocate chrdev */ + gWmtInitDone = 0; + init_waitqueue_head((wait_queue_head_t *) &gWmtInitWq); + stp_drv_init(); + + ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME); + if (ret) { + WMT_ERR_FUNC("fail to register chrdev\n"); + return ret; + } + cdev_init(&gWmtCdev, &gWmtFops); + gWmtCdev.owner = THIS_MODULE; + cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM); + if (cdevErr) { + WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); + goto error; + } + WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor); +#if WMT_CREATE_NODE_DYNAMIC + wmt_class = class_create(THIS_MODULE, "stpwmt"); + if (IS_ERR(wmt_class)) + goto error; + wmt_dev = device_create(wmt_class, NULL, devID, NULL, "stpwmt"); + if (IS_ERR(wmt_dev)) + goto error; +#endif + +#if 0 + pWmtDevCtx = wmt_drv_create(); + if (!pWmtDevCtx) { + WMT_ERR_FUNC("wmt_drv_create() fails\n"); + goto error; + } + ret = wmt_drv_init(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret); + goto error; + } + WMT_INFO_FUNC("stp_btmcb_reg\n"); + wmt_cdev_btmcb_reg(); + ret = wmt_drv_start(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret); + goto error; + } +#endif + ret = wmt_lib_init(); + if (ret) { + WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret); + goto error; + } +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_setup(); +#endif + +#if CFG_WMT_PROC_FOR_AEE + wmt_dev_proc_for_aee_setup(); +#endif + + WMT_INFO_FUNC("wmt_dev register thermal cb\n"); + wmt_lib_register_thermal_ctrl_cb(wmt_dev_tm_temp_query); + wmt_dev_bgw_desense_init(); + gWmtInitDone = 1; + wake_up(&gWmtInitWq); + osal_sleepable_lock_init(&g_es_lr_lock); + INIT_WORK(&gPwrOnOffWork, wmt_pwr_on_off_handler); +#ifdef CONFIG_EARLYSUSPEND + register_early_suspend(&wmt_early_suspend_handler); + WMT_INFO_FUNC("register_early_suspend finished\n"); +#else + wmt_fb_notifier.notifier_call = wmt_fb_notifier_callback; + ret = fb_register_client(&wmt_fb_notifier); + if (ret) + WMT_ERR_FUNC("wmt register fb_notifier failed! ret(%d)\n", ret); + else + WMT_INFO_FUNC("wmt register fb_notifier OK!\n"); +#endif + WMT_INFO_FUNC("success\n"); + return 0; + +error: + wmt_lib_deinit(); +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); +#endif +#if WMT_CREATE_NODE_DYNAMIC + if (!(IS_ERR(wmt_dev))) + device_destroy(wmt_class, devID); + if (!(IS_ERR(wmt_class))) { + class_destroy(wmt_class); + wmt_class = NULL; + } +#endif + + if (cdevErr == 0) + cdev_del(&gWmtCdev); + + if (ret == 0) { + unregister_chrdev_region(devID, WMT_DEV_NUM); + gWmtMajor = -1; + } + + WMT_ERR_FUNC("fail\n"); + + return -1; +} + +static void WMT_exit(void) +{ + dev_t dev = MKDEV(gWmtMajor, 0); + + osal_sleepable_lock_deinit(&g_es_lr_lock); +#ifdef CONFIG_EARLYSUSPEND + unregister_early_suspend(&wmt_early_suspend_handler); + WMT_INFO_FUNC("unregister_early_suspend finished\n"); +#else + fb_unregister_client(&wmt_fb_notifier); +#endif + + wmt_dev_bgw_desense_deinit(); + + wmt_lib_register_thermal_ctrl_cb(NULL); + + wmt_lib_deinit(); + +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); +#endif + +#if CFG_WMT_PROC_FOR_AEE + wmt_dev_proc_for_aee_remove(); +#endif +#if WMT_CREATE_NODE_DYNAMIC + if (wmt_dev) { + device_destroy(wmt_class, dev); + wmt_dev = NULL; + } + if (wmt_class) { + class_destroy(wmt_class); + wmt_class = NULL; + } +#endif + cdev_del(&gWmtCdev); + unregister_chrdev_region(dev, WMT_DEV_NUM); + gWmtMajor = -1; + + stp_drv_exit(); + + WMT_INFO_FUNC("done\n"); +} + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + +int mtk_wcn_soc_common_drv_init(void) +{ + return WMT_init(); + +} +EXPORT_SYMBOL(mtk_wcn_soc_common_drv_init); +void mtk_wcn_soc_common_drv_exit(void) +{ + return WMT_exit(); +} +EXPORT_SYMBOL(mtk_wcn_soc_common_drv_exit); + +#else +module_init(WMT_init); +module_exit(WMT_exit); +#endif +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MediaTek Inc WCN"); +MODULE_DESCRIPTION("MTK WCN combo driver for WMT function"); + +module_param(gWmtMajor, uint, 0); diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c new file mode 100644 index 0000000000000..9f2192d9a3e54 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pri/wmt_exp.c @@ -0,0 +1,610 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-EXP]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" + +#include +#include + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +wmt_wlan_probe_cb mtk_wcn_wlan_probe = NULL; +wmt_wlan_remove_cb mtk_wcn_wlan_remove = NULL; +wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt = NULL; +wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr = NULL; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +OSAL_BIT_OP_VAR gBtWifiGpsState; +OSAL_BIT_OP_VAR gGpsFmState; +UINT32 gWifiProbed = 0; +UINT32 gWmtDbgLvl = WMT_LOG_DBG; +MTK_WCN_BOOL g_pwr_off_flag = MTK_WCN_BOOL_TRUE; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = opId; + pOp->op.au4OpData[0] = type; + if (WMTDRV_TYPE_WIFI == type) + pSignal->timeoutValue = 4000; + /*donot block system server/init/netd from longer than 5s, in case of ANR happens*/ + else + pSignal->timeoutValue = (WMT_OPID_FUNC_ON == pOp->op.opId) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + + /*do not check return value, we will do this either way */ + wmt_lib_host_awake_get(); + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + wmt_lib_host_awake_put(); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + wmt_lib_host_awake_put(); + + if (MTK_WCN_BOOL_FALSE == bRet) + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); + else + WMT_WARN_FUNC("OPID(%d) type(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return bRet; +} + +#if WMT_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) +#else +MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) +#endif +{ + MTK_WCN_BOOL ret; + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday("############ BT OFF ====>"); + + ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF); + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday("############ BT OFF <===="); + + return ret; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_func_off); +#endif + +#if WMT_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) +#else +MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) +#endif +{ + MTK_WCN_BOOL ret; + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday("############ BT ON ====>"); + + ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON); + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday(" ############BT ON <===="); + + return ret; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_func_on); +#endif + +VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type) +{ + if (on) + mtk_wcn_wmt_func_on(type); + else + mtk_wcn_wmt_func_off(type); +} + +/* +return value: +enable/disable thermal sensor function: true(1)/false(0) +read thermal sensor function:thermal value + +*/ +#if WMT_EXP_HID_API_EXPORT +INT8 _mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) +#else +INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) +#endif +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /*parameter validation check */ + if (WMTTHERM_MAX < eType || WMTTHERM_ENABLE > eType) { + WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not */ + bRet = wmt_lib_is_therm_ctrl_support(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_ERR_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_THERM_CTRL; + /*parameter fill */ + pOpData->au4OpData[0] = eType; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); + /*0xFF means read error occurs */ + /*will return to function driver */ + pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE; + } else { + WMT_INFO_FUNC("OPID(%d) type(%d) return(%d) ok\n\n", + pOpData->opId, pOpData->au4OpData[0], pOpData->au4OpData[1]); + } + /*return value will be put to lxop->op.au4OpData[1] */ + WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08x)\n", eType, pOpData->au4OpData[1]); + return (INT8) pOpData->au4OpData[1]; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); +#endif + +#if WMT_EXP_HID_API_EXPORT +ENUM_WMTHWVER_TYPE_T _mtk_wcn_wmt_hwver_get(VOID) +#else +ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) +#endif +{ + /* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ + /* TODO: how do we extend for new chip and newer revision? */ + /* TODO: This way is hard to extend */ + return wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER); +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); +#endif + +#if WMT_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) +#else +MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) +#endif +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + if (WMTDSNS_MAX <= eType) { + WMT_ERR_FUNC("invalid desense control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not */ + bRet = wmt_lib_is_dsns_ctrl_support(); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_ERR_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_DSNS; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*parameter fill */ + if ((WMTDSNS_FM_DISABLE <= eType) && (WMTDSNS_FM_GPS_ENABLE >= eType)) { + pOpData->au4OpData[0] = WMTDRV_TYPE_FM; + pOpData->au4OpData[1] = eType; + } + + WMT_INFO_FUNC("OPID(%d) type(%d) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (MTK_WCN_BOOL_FALSE == bRet) + WMT_WARN_FUNC("OPID(%d) type(%d) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); + else + WMT_INFO_FUNC("OPID(%d) type(%d) ok\n\n", pOpData->opId, pOpData->au4OpData[0]); + + return bRet; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); +#endif + +#if WMT_EXP_HID_API_EXPORT +INT32 _mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +#else +INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +#endif +{ + return (INT32) wmt_lib_msgcb_reg(eType, pCb); +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); +#endif + +#if WMT_EXP_HID_API_EXPORT +INT32 _mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +#else +INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +#endif +{ + return (INT32) wmt_lib_msgcb_unreg(eType); +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); +#endif + +#if WMT_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) +#else +INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) +#endif +{ + wmt_lib_ps_set_sdio_psop(own_cb); + return 0; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); +#endif + +#if WMT_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_wmt_sdio_host_awake(VOID) +#else +INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) +#endif +{ + wmt_lib_ps_irq_cb(); + return 0; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); +#endif + +#if WMT_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) +#else +MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) +#endif +{ + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + wmt_lib_set_host_assert_info(type, reason, 1); + + pSignal = &pOp->signal; + + pOp->op.opId = WMT_OPID_CMD_TEST; + + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*this test command should be run with usb cable connected, so no host awake is needed */ + /* wmt_lib_host_awake_get(); */ + pOp->op.au4OpData[0] = 0; + + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,assert flow abort\n"); + wmt_lib_put_op_to_free_queue(pOp); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + /* wmt_lib_host_awake_put(); */ + WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%d, %d), ret(%d), result(%s)\n", + pOp->op.opId, + pOp->op.au4OpData[0], + pOp->op.au4OpData[1], bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + return bRet; +} +#if !WMT_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_wmt_assert); +#endif + +INT8 mtk_wcn_wmt_co_clock_flag_get(void) +{ + return wmt_lib_co_clock_get(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_co_clock_flag_get); + +INT32 mtk_wcn_wmt_system_state_reset(void) +{ + osal_memset(&gBtWifiGpsState, 0, osal_sizeof(gBtWifiGpsState)); + osal_memset(&gGpsFmState, 0, osal_sizeof(gGpsFmState)); + + return 0; +} + +INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo) +{ + INT32 iRet = -1; + + if (!pWmtWlanCbInfo) { + WMT_ERR_FUNC("wlan cb info in null!\n"); + return -1; + } + + WMT_INFO_FUNC("wmt wlan cb register\n"); + mtk_wcn_wlan_probe = pWmtWlanCbInfo->wlan_probe_cb; + mtk_wcn_wlan_remove = pWmtWlanCbInfo->wlan_remove_cb; + mtk_wcn_wlan_bus_tx_cnt = pWmtWlanCbInfo->wlan_bus_cnt_get_cb; + mtk_wcn_wlan_bus_tx_cnt_clr = pWmtWlanCbInfo->wlan_bus_cnt_clr_cb; + + if (gWifiProbed) { + WMT_INFO_FUNC("wlan has been done power on,call probe directly\n"); + iRet = (*mtk_wcn_wlan_probe) (); + if (!iRet) { + WMT_INFO_FUNC("call wlan probe OK when do wlan register to wmt\n"); + gWifiProbed = 0; + } else { + WMT_ERR_FUNC("call wlan probe fail(%d) when do wlan register to wmt\n", iRet); + return -2; + } + } + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_wlan_reg); + +INT32 mtk_wcn_wmt_wlan_unreg(void) +{ + WMT_INFO_FUNC("wmt wlan cb unregister\n"); + mtk_wcn_wlan_probe = NULL; + mtk_wcn_wlan_remove = NULL; + mtk_wcn_wlan_bus_tx_cnt = NULL; + mtk_wcn_wlan_bus_tx_cnt_clr = NULL; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_wlan_unreg); + +MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value) +{ + g_pwr_off_flag = value; + if (g_pwr_off_flag) + WMT_DBG_FUNC("enable connsys power off flag\n"); + else + WMT_INFO_FUNC("disable connsys power off, maybe need trigger coredump!\n"); + return g_pwr_off_flag; +} +EXPORT_SYMBOL(mtk_wcn_set_connsys_power_off_flag); + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +VOID mtk_wcn_wmt_exp_init(void) +{ + MTK_WCN_WMT_EXP_CB_INFO wmtExpCb = { + + .wmt_func_on_cb = _mtk_wcn_wmt_func_on, + .wmt_func_off_cb = _mtk_wcn_wmt_func_off, + .wmt_therm_ctrl_cb = _mtk_wcn_wmt_therm_ctrl, + .wmt_hwver_get_cb = _mtk_wcn_wmt_hwver_get, + .wmt_dsns_ctrl_cb = _mtk_wcn_wmt_dsns_ctrl, + .wmt_msgcb_reg_cb = _mtk_wcn_wmt_msgcb_reg, + .wmt_msgcb_unreg_cb = _mtk_wcn_wmt_msgcb_unreg, + .wmt_sdio_op_reg_cb = _mtk_wcn_stp_wmt_sdio_op_reg, + .wmt_sdio_host_awake_cb = _mtk_wcn_stp_wmt_sdio_host_awake, + .wmt_assert_cb = _mtk_wcn_wmt_assert + }; + + mtk_wcn_wmt_exp_cb_reg(&wmtExpCb); +} + +VOID mtk_wcn_wmt_exp_deinit(void) +{ + mtk_wcn_wmt_exp_cb_unreg(); +} +#ifdef CONFIG_MTK_COMBO_ANT +/* + ctrlId: get ram code status opId or ram code download opId + pBuf: pointer to ANT ram code + length: total length of ANT ram code +*/ +ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, + UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq) +{ + ENUM_WMT_ANT_RAM_STATUS eRet = 0; + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + /*1. parameter validation check */ + /*for WMT_ANT_RAM_GET_STATUS, ignore pBuf and length */ + /*for WMT_ANT_RAM_DOWNLOAD, + pBuf must not be NULL, kernel space memory pointer + length must be large than 0 */ + + if ((WMT_ANT_RAM_GET_STATUS > ctrlId) || (WMT_ANT_RAM_CTRL_MAX <= ctrlId)) { + WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); + eRet = WMT_ANT_RAM_PARA_ERR; + return eRet; + } + + if ((WMT_ANT_RAM_DOWNLOAD == ctrlId) && + ((NULL == pBuf) || + (0 >= length) || + (1000 < length) || (seq >= WMT_ANT_RAM_SEQ_MAX) || (seq < WMT_ANT_RAM_START_PKT))) { + eRet = WMT_ANT_RAM_PARA_ERR; + WMT_ERR_FUNC + ("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x),seq(%d) .\n", + ctrlId, pBuf, length, seq); + return eRet; + } + /*get WMT opId */ + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = + (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD; + + pOp->op.opId = + (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? WMT_OPID_ANT_RAM_DOWN : WMT_OPID_ANT_RAM_STA_GET; + pOp->op.au4OpData[0] = (size_t) pBuf; + pOp->op.au4OpData[1] = length; + pOp->op.au4OpData[2] = seq; + + + /*disable PSM monitor */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return MTK_WCN_BOOL_FALSE; + } + /*wakeup wmtd thread */ + bRet = wmt_lib_put_act_op(pOp); + + /*enable PSM monitor */ + ENABLE_PSM_MONITOR(); + + WMT_DBG_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n", + pOp->op.opId, + bRet, + pOp->op.au4OpData[2], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + /*check return value and return result */ + if (MTK_WCN_BOOL_FALSE == bRet) { + eRet = WMT_ANT_RAM_OP_ERR; + } else { + eRet = (WMT_ANT_RAM_DOWNLOAD == ctrlId) ? + WMT_ANT_RAM_DOWN_OK : + ((1 == pOp->op.au4OpData[2]) ? WMT_ANT_RAM_EXIST : WMT_ANT_RAM_NOT_EXIST); + } + + return eRet; + +} +EXPORT_SYMBOL(mtk_wcn_wmt_ant_ram_ctrl); +#endif + +#endif +VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value) +{ + wmt_lib_soc_set_wifiver(Value); +} +EXPORT_SYMBOL(mtk_wcn_wmt_set_wifi_ver); diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile new file mode 100644 index 0000000000000..eb37baf87b025 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/Makefile @@ -0,0 +1,27 @@ +ifeq ($(CONFIG_MTK_COMBO), y) + +ccflags-y += \ + -I$(src)/../../linux/include \ + -I$(src)/../../linux/pri/include \ + -I$(src)/../../core/include \ + -I$(src)/../../include \ + -I$(src)/../include \ + -I$(src)/../../../common_detect \ + -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach \ + -DMTK_BT_HCI=1 + +ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 + +ifeq ($(CONFIG_MTK_TC1_FEATURE), y) + ccflags-y += -DCFG_TC1_FEATURE=1 +else + ccflags-y += -DCFG_TC1_FEATURE=0 +endif + +obj-y += osal.o \ + bgw_desense.o \ + wmt_idc.o +obj-$(CONFIG_MTK_COMBO_BT) += stp_chrdev_bt.o +obj-$(CONFIG_MTK_COMBO_WIFI) += wmt_chrdev_wifi.o + +endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c new file mode 100644 index 0000000000000..11e45aa130872 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/bgw_desense.c @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "bgw_desense.h" + +static struct sock *g_nl_sk; +/* static struct sockaddr_nl src_addr, des_addr; */ +/* static struct iovec iov; */ +static int pid; +/* static struct msghdr msg; */ + +void bgw_destroy_netlink_kernel(void) +{ + if (g_nl_sk != NULL) { + /* sock_release(g_nl_sk->sk_socket); */ + netlink_kernel_release(g_nl_sk); + MSG("release socket\n"); + return; + } + ERR("no socket yet\n"); +} + +void send_command_to_daemon(const int command /*struct sk_buff *skb */) +{ +/* + struct iphdr *iph; + struct ethhdr *ehdr; + */ + struct nlmsghdr *nlh; + struct sk_buff *nl_skb; + int res; + + MSG("here we will send command to native daemon\n"); +/* if(skb == NULL) + { + ERR("invalid sk_buff\n"); + return; + } +*/ + if (!g_nl_sk) { + ERR("invalid socket\n"); + return; + } + if (pid == 0) { + ERR("invalid native process pid\n"); + return; + } + /*alloc data buffer for sending to native */ + /*malloc data space at least 1500 bytes, which is ethernet data length */ + nl_skb = alloc_skb(NLMSG_SPACE(MAX_NL_MSG_LEN), GFP_ATOMIC); + if (nl_skb == NULL) { + ERR("malloc skb error\n"); + return; + } + MSG("malloc data space done\n"); + /* + ehdr = eth_hdr(skb); + iph = ip_hdr(skb); + */ + +/* nlh = NLMSG_PUT(nl_skb, 0, 0, 0, NLMSG_SPACE(1500)-sizeof(struct nlmsghdr)); */ + nlh = nlmsg_put(nl_skb, 0, 0, 0, MAX_NL_MSG_LEN, 0); + if (nlh == NULL) { + MSG("nlh is NULL\n"); + kfree_skb(nl_skb); + return; + } + NETLINK_CB(nl_skb).portid = 0; + +/* memcpy(NLMSG_DATA(nlh), ACK, 5); */ + *(char *)NLMSG_DATA(nlh) = command; + res = netlink_unicast(g_nl_sk, nl_skb, pid, MSG_DONTWAIT); + if (res == 0) { + MSG("send to user space process error\n"); + return; + } + ERR("send to user space process done, data length = %d\n", res); +} + +static void nl_data_handler(struct sk_buff *__skb) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int i; + int len; + char str[128]; + + MSG("we got netlink message\n"); + len = NLMSG_SPACE(MAX_NL_MSG_LEN); + skb = skb_get(__skb); + if (skb == NULL) + ERR("skb_get return NULL"); + if (skb->len >= NLMSG_SPACE(0)) { /*presume there is 5byte payload at leaset */ + MSG("length is enough\n"); + nlh = nlmsg_hdr(skb); /* point to data which include in skb */ + memcpy(str, NLMSG_DATA(nlh), sizeof(str)); + for (i = 0; i < 3; i++) + MSG("str[%d = %c]", i, str[i]); + MSG("str[0] = %d, str[1] = %d, str[2] = %d\n", str[0], str[1], str[2]); + if (str[0] == 'B' && str[1] == 'G' && str[2] == 'W') { + MSG("got native daemon init command, record it's pid\n"); + pid = nlh->nlmsg_pid; /*record the native process PID */ + MSG("native daemon pid is %d\n", pid); + } else { + ERR("this is not BGW message, ignore it\n"); + return; + } + } else { + ERR("not engouth data length\n"); + return; + } + + kfree_skb(skb); + + send_command_to_daemon(ACK); +} + +int bgw_init_socket(void) +{ + struct netlink_kernel_cfg cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.input = nl_data_handler; + + g_nl_sk = __netlink_kernel_create(&init_net, NETLINK_TEST, THIS_MODULE, &cfg); + + if (g_nl_sk == NULL) { + ERR("netlink_kernel_create error\n"); + return -1; + } + MSG("netlink_kernel_create ok\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c new file mode 100644 index 0000000000000..4ebbd51c0259a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/osal.c @@ -0,0 +1,1210 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "osal.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ +static UINT16 const crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*string operations*/ +_osal_inline_ UINT32 osal_strlen(const char *str) +{ + return strlen(str); +} + +_osal_inline_ INT32 osal_strcmp(const char *dst, const char *src) +{ + return strcmp(dst, src); +} + +_osal_inline_ INT32 osal_strncmp(const char *dst, const char *src, UINT32 len) +{ + return strncmp(dst, src, len); +} + +_osal_inline_ char *osal_strcpy(char *dst, const char *src) +{ + return strcpy(dst, src); +} + +_osal_inline_ char *osal_strncpy(char *dst, const char *src, UINT32 len) +{ + return strncpy(dst, src, len); +} + +_osal_inline_ char *osal_strcat(char *dst, const char *src) +{ + return strcat(dst, src); +} + +_osal_inline_ char *osal_strncat(char *dst, const char *src, UINT32 len) +{ + return strncat(dst, src, len); +} + +_osal_inline_ char *osal_strchr(const char *str, UINT8 c) +{ + return strchr(str, c); +} + +_osal_inline_ char *osal_strsep(char **str, const char *c) +{ + return strsep(str, c); +} + +_osal_inline_ int osal_strtol(const char *str, UINT32 adecimal, long *res) +{ + return kstrtol(str, adecimal, res); +} + +_osal_inline_ char *osal_strstr(char *str1, const char *str2) +{ + return strstr(str1, str2); +} + +INT32 osal_snprintf(char *buf, UINT32 len, const char *fmt, ...) +{ + INT32 iRet = 0; + va_list args; + + /*va_start(args, fmt); */ + va_start(args, fmt); + /*iRet = snprintf(buf, len, fmt, args); */ + iRet = vsnprintf(buf, len, fmt, args); + va_end(args); + + return iRet; +} + +INT32 osal_err_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_err("%s", tempString); + + return 0; +} + +INT32 osal_dbg_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_debug("%s", tempString); + + return 0; +} + +INT32 osal_warn_print(const char *str, ...) +{ + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_warn("%s", tempString); + + return 0; +} + +INT32 osal_dbg_assert(INT32 expr, const char *file, INT32 line) +{ + if (!expr) { + pr_warn("%s (%d)\n", file, line); + /*BUG_ON(!expr); */ +#ifdef CFG_COMMON_GPIO_DBG_PIN +/* package this part */ + mt_set_gpio_out(GPIO70, GPIO_OUT_ZERO); + pr_warn("toggle GPIO70\n"); + udelay(10); + mt_set_gpio_out(GPIO70, GPIO_OUT_ONE); +#endif + return 1; + } + return 0; + +} + +INT32 osal_dbg_assert_aee(const char *module, const char *detail_description) +{ + osal_err_print("[WMT-ASSERT]" "[E][Module]:%s, [INFO]%s\n", module, detail_description); + +#ifdef WMT_PLAT_ALPS + /* aee_kernel_warning(module,detail_description); */ + aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_WCN_ISSUE_INFO, module, detail_description); +#endif + return 0; +} + +INT32 osal_sprintf(char *str, const char *format, ...) +{ + INT32 iRet = 0; + va_list args; + + va_start(args, format); + iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); + va_end(args); + + return iRet; +} + +_osal_inline_ VOID *osal_malloc(UINT32 size) +{ + return vmalloc(size); +} + +_osal_inline_ VOID osal_free(const VOID *dst) +{ + vfree(dst); +} + +_osal_inline_ VOID *osal_memset(VOID *buf, INT32 i, UINT32 len) +{ + return memset(buf, i, len); +} + +_osal_inline_ VOID *osal_memcpy(VOID *dst, const VOID *src, UINT32 len) +{ +#ifdef CONFIG_MTK_WCN_ARM64 + char *tmp; + const char *s; + size_t i; + + tmp = dst; + s = src; + for (i = 0; i < len; i++) + tmp[i] = s[i]; + + return dst; + +#else + return memcpy(dst, src, len); +#endif +} + +_osal_inline_ INT32 osal_memcmp(const VOID *buf1, const VOID *buf2, UINT32 len) +{ + return memcmp(buf1, buf2, len); +} + +_osal_inline_ UINT16 osal_crc16(const UINT8 *buffer, const UINT32 length) +{ + UINT16 crc = 0; + UINT32 i = 0; + + /* FIXME: Add STP checksum feature */ + crc = 0; + for (i = 0; i < length; i++, buffer++) + crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; + + return crc; +} + +_osal_inline_ VOID osal_thread_show_stack(P_OSAL_THREAD pThread) +{ + return show_stack(pThread->pThread, NULL); +} + +/* + *OSAL layer Thread Opeartion related APIs + * + * +*/ +_osal_inline_ INT32 osal_thread_create(P_OSAL_THREAD pThread) +{ + pThread->pThread = kthread_create(pThread->pThreadFunc, pThread->pThreadData, pThread->threadName); + if (NULL == pThread->pThread) + return -1; + + return 0; +} + +_osal_inline_ INT32 osal_thread_run(P_OSAL_THREAD pThread) +{ + if (pThread->pThread) { + wake_up_process(pThread->pThread); + return 0; + } else { + return -1; + } +} + +_osal_inline_ INT32 osal_thread_stop(P_OSAL_THREAD pThread) +{ + INT32 iRet; + + if ((pThread) && (pThread->pThread)) { + iRet = kthread_stop(pThread->pThread); + /* pThread->pThread = NULL; */ + return iRet; + } + return -1; +} + +_osal_inline_ INT32 osal_thread_should_stop(P_OSAL_THREAD pThread) +{ + if ((pThread) && (pThread->pThread)) + return kthread_should_stop(); + else + return 1; + +} + +_osal_inline_ INT32 +osal_thread_wait_for_event(P_OSAL_THREAD pThread, P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker) +{ + /* P_DEV_WMT pDevWmt;*/ + + if ((pThread) && (pThread->pThread) && (pEvent) && (pChecker)) { + /* pDevWmt = (P_DEV_WMT)(pThread->pThreadData);*/ + return wait_event_interruptible(pEvent->waitQueue, (/*!RB_EMPTY(&pDevWmt->rActiveOpQ) || */ + osal_thread_should_stop(pThread) + || (*pChecker) (pThread))); + } + return -1; +} + +_osal_inline_ INT32 osal_thread_destroy(P_OSAL_THREAD pThread) +{ + if (pThread && (pThread->pThread)) { + kthread_stop(pThread->pThread); + pThread->pThread = NULL; + } + return 0; +} + +/* + *OSAL layer Signal Opeartion related APIs + *initialization + *wait for signal + *wait for signal timerout + *raise signal + *destroy a signal + * +*/ + +_osal_inline_ INT32 osal_signal_init(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + init_completion(&pSignal->comp); + return 0; + } else { + return -1; + } +} + +_osal_inline_ INT32 osal_wait_for_signal(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + wait_for_completion_interruptible(&pSignal->comp); + return 0; + } else { + return -1; + } +} + +_osal_inline_ INT32 osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal) +{ + /* return wait_for_completion_interruptible_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); */ + /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. + * Avoid using *interruptible" version in order to complete our jobs, such + * as function off gracefully. + */ + return wait_for_completion_timeout(&pSignal->comp, msecs_to_jiffies(pSignal->timeoutValue)); +} + +_osal_inline_ INT32 osal_raise_signal(P_OSAL_SIGNAL pSignal) +{ + /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ + complete(&pSignal->comp); + return 0; +} + +_osal_inline_ INT32 osal_signal_deinit(P_OSAL_SIGNAL pSignal) +{ + /* TODO:[FixMe][GeorgeKuo]: DO sanity check here!!! */ + pSignal->timeoutValue = 0; + return 0; +} + +/* + *OSAL layer Event Opeartion related APIs + *initialization + *wait for signal + *wait for signal timerout + *raise signal + *destroy a signal + * +*/ + +INT32 osal_event_init(P_OSAL_EVENT pEvent) +{ + init_waitqueue_head(&pEvent->waitQueue); + + return 0; +} + +INT32 osal_wait_for_event(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) +{ + return wait_event_interruptible(pEvent->waitQueue, condition(cond_pa)); +} + +INT32 osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, INT32(*condition) (PVOID), void *cond_pa) +{ + return wait_event_interruptible_timeout(pEvent->waitQueue, condition(cond_pa), + msecs_to_jiffies(pEvent->timeoutValue)); +} + +INT32 osal_trigger_event(P_OSAL_EVENT pEvent) +{ + INT32 ret = 0; + + wake_up_interruptible(&pEvent->waitQueue); + return ret; +} + +INT32 osal_event_deinit(P_OSAL_EVENT pEvent) +{ + return 0; +} + +_osal_inline_ long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) +{ + UINT32 ms = pEvent->timeoutValue; + + if (ms != 0) { + return wait_event_interruptible_timeout(pEvent->waitQueue, test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + } else { + return wait_event_interruptible(pEvent->waitQueue, test_bit(bitOffset, pState)); + } + +} + +_osal_inline_ long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, unsigned long *pState, UINT32 bitOffset) +{ + UINT32 ms = pEvent->timeoutValue; + + if (ms != 0) { + return wait_event_interruptible_timeout(pEvent->waitQueue, !test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + } else { + return wait_event_interruptible(pEvent->waitQueue, !test_bit(bitOffset, pState)); + } + +} + +/* + *bit test and set/clear operations APIs + * + * +*/ +#if OS_BIT_OPS_SUPPORT +#define osal_bit_op_lock(x) +#define osal_bit_op_unlock(x) +#else + +_osal_inline_ INT32 osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} + +_osal_inline_ INT32 osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} +#endif +_osal_inline_ INT32 osal_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +_osal_inline_ INT32 osal_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +_osal_inline_ INT32 osal_test_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + +_osal_inline_ INT32 osal_test_and_clear_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; + +} + +_osal_inline_ INT32 osal_test_and_set_bit(UINT32 bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + UINT32 iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + +/* + *tiemr operations APIs + *create + *stop + * modify + *create + *delete + * +*/ + +INT32 osal_timer_create(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + init_timer(timer); + timer->function = pTimer->timeoutHandler; + timer->data = (unsigned long)pTimer->timeroutHandlerData; + return 0; +} + +INT32 osal_timer_start(P_OSAL_TIMER pTimer, UINT32 ms) +{ + + struct timer_list *timer = &pTimer->timer; + + timer->expires = jiffies + (ms / (1000 / HZ)); + add_timer(timer); + return 0; +} + +INT32 osal_timer_stop(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + del_timer(timer); + return 0; +} + +INT32 osal_timer_stop_sync(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + del_timer_sync(timer); + return 0; +} + +INT32 osal_timer_modify(P_OSAL_TIMER pTimer, UINT32 ms) +{ + + mod_timer(&pTimer->timer, jiffies + (ms) / (1000 / HZ)); + return 0; +} + +INT32 _osal_fifo_init(OSAL_FIFO *pFifo, UINT8 *buf, UINT32 size) +{ + struct kfifo *fifo = NULL; + INT32 ret = -1; + + if (!pFifo) { + pr_err("pFifo must be !NULL\n"); + return -1; + } + if (pFifo->pFifoBody) { + pr_err("pFifo->pFifoBody must be NULL\n"); + pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", pFifo, pFifo->pFifoBody); + return -1; + } + fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (!buf) { + /*fifo's buffer is not ready, we allocate automatically */ + ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC); + } else { + if (is_power_of_2(size)) { + kfifo_init(fifo, buf, size); + ret = 0; + } else { + kfifo_free(fifo); + fifo = NULL; + ret = -1; + } + } + + pFifo->pFifoBody = fifo; + return (ret < 0) ? (-1) : (0); +} + +INT32 _osal_fifo_deinit(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_free(fifo); + + return 0; +} + +INT32 _osal_fifo_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_size(fifo); + + return ret; +} + +/*returns unused bytes in fifo*/ +INT32 _osal_fifo_avail_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_avail(fifo); + + return ret; +} + +/*returns used bytes in fifo*/ +INT32 _osal_fifo_len(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_len(fifo); + + return ret; +} + +INT32 _osal_fifo_is_empty(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_empty(fifo); + + return ret; +} + +INT32 _osal_fifo_is_full(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_full(fifo); + + return ret; +} + +INT32 _osal_fifo_data_in(OSAL_FIFO *pFifo, const VOID *buf, UINT32 len) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) { + ret = kfifo_in(fifo, buf, len); + } else { + pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", + __func__, len, _osal_fifo_avail_size(pFifo), buf); + + ret = 0; + } + + return ret; +} + +INT32 _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, UINT32 len) +{ + struct kfifo *fifo = NULL; + INT32 ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_len(pFifo))) { + ret = kfifo_out(fifo, buf, len); + } else { + pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", + __func__, len, _osal_fifo_len(pFifo), buf); + + ret = 0; + } + + return ret; +} + +INT32 _osal_fifo_reset(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_reset(fifo); + + return 0; +} + +INT32 osal_fifo_init(P_OSAL_FIFO pFifo, UINT8 *buffer, UINT32 size) +{ + if (!pFifo) { + pr_err("%s:pFifo = NULL, error\n", __func__); + return -1; + } + + pFifo->FifoInit = _osal_fifo_init; + pFifo->FifoDeInit = _osal_fifo_deinit; + pFifo->FifoSz = _osal_fifo_size; + pFifo->FifoAvailSz = _osal_fifo_avail_size; + pFifo->FifoLen = _osal_fifo_len; + pFifo->FifoIsEmpty = _osal_fifo_is_empty; + pFifo->FifoIsFull = _osal_fifo_is_full; + pFifo->FifoDataIn = _osal_fifo_data_in; + pFifo->FifoDataOut = _osal_fifo_data_out; + pFifo->FifoReset = _osal_fifo_reset; + + if (NULL != pFifo->pFifoBody) { + pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__); + pFifo->FifoDeInit(pFifo->pFifoBody); + pFifo->pFifoBody = NULL; + } + + pFifo->FifoInit(pFifo, buffer, size); + + return 0; +} + +VOID osal_fifo_deinit(P_OSAL_FIFO pFifo) +{ + if (pFifo) + pFifo->FifoDeInit(pFifo); + else { + pr_err("%s:pFifo = NULL, error\n", __func__); + return; + } + kfree(pFifo->pFifoBody); +} + +INT32 osal_fifo_reset(P_OSAL_FIFO pFifo) +{ + INT32 ret = -1; + + if (pFifo) { + ret = pFifo->FifoReset(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = -1; + } + return ret; +} + +UINT32 osal_fifo_in(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataIn(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_out(P_OSAL_FIFO pFifo, PUINT8 buffer, UINT32 size) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataOut(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_len(P_OSAL_FIFO pFifo) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoLen(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_sz(P_OSAL_FIFO pFifo) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_avail(P_OSAL_FIFO pFifo) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoAvailSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_is_empty(P_OSAL_FIFO pFifo) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsEmpty(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +UINT32 osal_fifo_is_full(P_OSAL_FIFO pFifo) +{ + UINT32 ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsFull(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + return ret; +} + +INT32 osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + #ifdef CONFIG_PM_WAKELOCKS + wakeup_source_init(&pLock->wake_lock, pLock->name); + #else + wake_lock_init(&pLock->wake_lock, WAKE_LOCK_SUSPEND, pLock->name); + #endif + return 0; +} + +INT32 osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + #ifdef CONFIG_PM_WAKELOCKS + wakeup_source_trash(&pLock->wake_lock); + #else + wake_lock_destroy(&pLock->wake_lock); + #endif + return 0; +} + +INT32 osal_wake_lock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + #ifdef CONFIG_PM_WAKELOCKS + __pm_stay_awake(&pLock->wake_lock); + #else + wake_lock(&pLock->wake_lock); + #endif + + return 0; +} + +INT32 osal_wake_unlock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + #ifdef CONFIG_PM_WAKELOCKS + __pm_relax(&pLock->wake_lock); + #else + wake_unlock(&pLock->wake_lock); + #endif + + return 0; + +} + +INT32 osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock) +{ + INT32 count = 0; + + if (!pLock) + return -1; + + #ifdef CONFIG_PM_WAKELOCKS + count = pLock->wake_lock.active; + #else + count = wake_lock_active(&pLock->wake_lock); + #endif + return count; +} + +/* + *sleepable lock operations APIs + *init + *lock + *unlock + *destroy + * +*/ + +#if !defined(CONFIG_PROVE_LOCKING) +INT32 osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_init(&(pUSL->lock)); + return 0; +} +#endif + +INT32 osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_irqsave(&(pUSL->lock), pUSL->flag); + return 0; +} + +INT32 osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); + return 0; +} + +INT32 osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + return 0; +} + +/* + *unsleepable operations APIs + *init + *lock + *unlock + *destroy + + * +*/ + +#if !defined(CONFIG_PROVE_LOCKING) +INT32 osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_init(&pSL->lock); + return 0; +} +#endif + +INT32 osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + return mutex_lock_killable(&pSL->lock); +} + +INT32 osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_unlock(&pSL->lock); + return 0; +} + +INT32 osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_destroy(&pSL->lock); + return 0; +} + +INT32 osal_sleep_ms(UINT32 ms) +{ + msleep(ms); + return 0; +} + +INT32 osal_udelay(UINT32 us) +{ + udelay(us); + return 0; +} + +INT32 osal_gettimeofday(PINT32 sec, PINT32 usec) +{ + INT32 ret = 0; + struct timeval now; + + do_gettimeofday(&now); + + if (sec != NULL) + *sec = now.tv_sec; + else + ret = -1; + + if (usec != NULL) + *usec = now.tv_usec; + else + ret = -1; + + return ret; +} + +INT32 osal_printtimeofday(const PUINT8 prefix) +{ + INT32 ret; + INT32 sec; + INT32 usec; + + ret = osal_gettimeofday(&sec, &usec); + ret += osal_dbg_print("%s>sec=%d, usec=%d\n", prefix, sec, usec); + + return ret; +} + +VOID osal_buffer_dump(const UINT8 *buf, const UINT8 *title, const UINT32 len, const UINT32 limit) +{ + INT32 k; + UINT32 dump_len; + + pr_warn("start of dump>[%s] len=%d, limit=%d,", title, len, limit); + + dump_len = ((0 != limit) && (len > limit)) ? limit : len; +#if 0 + if (limit != 0) + len = (len > limit) ? (limit) : (len); + +#endif + + for (k = 0; k < dump_len; k++) { + if ((k != 0) && (k % 16 == 0)) + pr_cont("\n"); + pr_cont("0x%02x ", buf[k]); + } + pr_warn("op.opId : 0xFFFFFFFF; +} + +MTK_WCN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) +{ + return (pOp && pOp->signal.timeoutValue) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} + +VOID osal_op_raise_signal(P_OSAL_OP pOp, INT32 result) +{ + if (pOp) { + pOp->result = result; + osal_raise_signal(&pOp->signal); + } +} + +VOID osal_set_op_result(P_OSAL_OP pOp, INT32 result) +{ + if (pOp) + pOp->result = result; + +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c new file mode 100644 index 0000000000000..190fa3944d801 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/stp_chrdev_bt.c @@ -0,0 +1,899 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WMT_CREATE_NODE_DYNAMIC +#include +#endif +#include + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#ifdef MTK_BT_HCI +#define MTK_BT_DEBUG 0 +#include +#include +#endif + + +#define BT_DRIVER_NAME "mtk_stp_BT_chrdev" +#define BT_DEV_MAJOR 192 /* Never used number */ + +#define PFX "[MTK-BT] " +#define BT_LOG_DBG 3 +#define BT_LOG_INFO 2 +#define BT_LOG_WARN 1 +#define BT_LOG_ERR 0 + +#define COMBO_IOC_MAGIC 0xb0 +#define COMBO_IOCTL_FW_ASSERT _IOWR(COMBO_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_BT_IC_HW_VER _IOWR(COMBO_IOC_MAGIC, 1, void*) +#define COMBO_IOCTL_BT_IC_FW_VER _IOWR(COMBO_IOC_MAGIC, 2, void*) +#define COMBO_IOC_BT_HWVER _IOWR(COMBO_IOC_MAGIC, 3, void*) + +static UINT32 gDbgLevel = BT_LOG_INFO; + +#define BT_DBG_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_DBG) \ + pr_debug(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_INFO_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_INFO) \ + pr_warn(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_WARN_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_WARN) \ + pr_err(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_ERR_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_ERR) \ + pr_err(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) + +#define VERSION "1.0" + +#ifdef MTK_BT_HCI + +#define NUM_REASSEMBLY 32 +struct mtk_hci { + struct hci_dev *hdev; + struct work_struct work; + struct sk_buff_head txq; + struct sk_buff *reassembly[NUM_REASSEMBLY]; +}; + +static struct mtk_hci mtk_hci; + +#endif + +#if WMT_CREATE_NODE_DYNAMIC +struct class *stpbt_class = NULL; +struct device *stpbt_dev = NULL; +#endif + +static INT32 BT_devs = 1; /* Device count */ +static INT32 BT_major = BT_DEV_MAJOR; /* Dynamic allocation */ +module_param(BT_major, uint, 0); +static struct cdev BT_cdev; + +#define BT_BUFFER_SIZE 2048 +static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer of read() */ +static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer of write() */ + +static struct semaphore wr_mtx, rd_mtx; +/* Wait queue for poll and read */ +static wait_queue_head_t inq; +static DECLARE_WAIT_QUEUE_HEAD(BT_wq); +static INT32 flag; +/* Reset flag for whole chip reset senario */ +static volatile INT32 rstflag; + +#ifdef MTK_BT_HCI +static int hci_reassembly(struct hci_dev *hdev, int type, void *data, + int count, __u8 index) +{ + int len = 0; + int hlen = 0; + int offset = 0; + int remain = count; + struct sk_buff *skb; + struct bt_skb_cb *scb; + u16 opcode = 0; + unsigned char *pdata = data; + + struct mtk_hci *info = NULL; + struct hci_event_hdr *ehdr = NULL; + struct hci_ev_cmd_complete *ev = NULL; + struct hci_rp_read_local_ext_features *ext = NULL; + + info = hci_get_drvdata(hdev); + if ( NULL == info ) { + printk(KERN_ERR "mtk_bt_hci: invalid info point\n"); + return 0; + } + + if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || + index >= NUM_REASSEMBLY) + return -EILSEQ; + + skb = info->reassembly[index]; + + if (!skb) { + switch (type) { + case HCI_ACLDATA_PKT: + len = HCI_MAX_FRAME_SIZE; + hlen = HCI_ACL_HDR_SIZE; + break; + case HCI_EVENT_PKT: + len = HCI_MAX_EVENT_SIZE; + hlen = HCI_EVENT_HDR_SIZE; + break; + case HCI_SCODATA_PKT: + len = HCI_MAX_SCO_SIZE; + hlen = HCI_SCO_HDR_SIZE; + break; + } + + skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + scb = (void *) skb->cb; + scb->expect = hlen; + scb->pkt_type = type; + + info->reassembly[index] = skb; + } + + while (count) { + scb = (void *) skb->cb; + len = min_t(uint, scb->expect, count); + + /* + * Workaround for MT7623+MT6625 BT: the max page in response of cmd READ_LOCAL_EXT_FEATURES + * should be 1, instead of 2, so changing it to 1 here + */ + + if (HCI_EVENT_PKT == type) + { + ehdr = (void *)pdata; + offset = sizeof(struct hci_event_hdr); + if ( HCI_EV_CMD_COMPLETE == ehdr->evt) + { + ev = (struct hci_ev_cmd_complete *)&pdata[offset]; + + offset += sizeof(struct hci_ev_cmd_complete); + + opcode = __le16_to_cpu(ev->opcode); + if(HCI_OP_READ_LOCAL_EXT_FEATURES == opcode) { + ext = (struct hci_rp_read_local_ext_features *) &pdata[offset]; + if( !ext->status && ext->max_page >= 2) { + pr_info("%s: this workaround is applied for mediatek BT\n", __func__); + ext->max_page = 1; + } + } + + } + } + + memcpy(skb_put(skb, len), data, len); + + count -= len; + data += len; + scb->expect -= len; + remain = count; + + switch (type) { + case HCI_EVENT_PKT: + if (skb->len == HCI_EVENT_HDR_SIZE) { + struct hci_event_hdr *h = hci_event_hdr(skb); + + scb->expect = h->plen; + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + info->reassembly[index] = NULL; + return -ENOMEM; + } + } + + break; + + case HCI_ACLDATA_PKT: + if (skb->len == HCI_ACL_HDR_SIZE) { + struct hci_acl_hdr *h = hci_acl_hdr(skb); + + scb->expect = __le16_to_cpu(h->dlen); + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + info->reassembly[index] = NULL; + return -ENOMEM; + } + } + break; + + case HCI_SCODATA_PKT: + if (skb->len == HCI_SCO_HDR_SIZE) { + struct hci_sco_hdr *h = hci_sco_hdr(skb); + + scb->expect = h->dlen; + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + info->reassembly[index] = NULL; + return -ENOMEM; + } + } + break; + } + + if (scb->expect == 0) { + /* Complete frame */ + + bt_cb(skb)->pkt_type = type; + hci_recv_frame(hdev, skb); + + info->reassembly[index] = NULL; + return remain; + } + } + + return remain; +} + +int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) +{ + int rem = 0; + + if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) + return -EILSEQ; + + while (count) { + rem = hci_reassembly(hdev, type, data, count, type - 1); + if (rem < 0) + return rem; + + data += (count - rem); + count = rem; + } + + return rem; +} +#endif + +#ifdef MTK_BT_HCI +void +hex_dump(char *prefix, char *p, int len) +{ + int i; + + pr_err("%s ", prefix); + for (i = 0; i < len; i++) + pr_err("%02x ", (*p++ & 0xff)); + pr_err("\n"); +} + +static int +mtk_bt_hci_open(struct hci_dev *hdev) +{ + int err = 0; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + err = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); + if (err != MTK_WCN_BOOL_TRUE) { + pr_err("%s func on failed with %d\n", __func__, err); + return -ENODEV; + } + + set_bit(HCI_RUNNING, &hdev->flags); + + mtk_wcn_stp_set_bluez(1); + + return 0; +} + +static int +mtk_bt_hci_close(struct hci_dev *hdev) +{ + int err = 0; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + mtk_wcn_stp_set_bluez(0); + + clear_bit(HCI_RUNNING, &hdev->flags); + + err = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + if (err != MTK_WCN_BOOL_TRUE) { + pr_err("%s func off failed with %d\n", __func__, err); + return -EIO; + } + + return 0; +} + +static void +mtk_bt_hci_work(struct work_struct *work) +{ + int err; + struct sk_buff *skb; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + while ((skb = skb_dequeue(&mtk_hci.txq))) { + skb_push(skb, 1); + skb->data[0] = bt_cb(skb)->pkt_type; + +#if MTK_BT_DEBUG == 1 + hex_dump(">>", skb->data, skb->len); +#endif + + err = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX); + if (err < 0) { + pr_err("%s err=%d\n", __func__, err); + mtk_hci.hdev->stat.err_tx++; + skb_queue_head(&mtk_hci.txq, skb); + break; + } + + mtk_hci.hdev->stat.byte_tx += skb->len; + kfree_skb(skb); + } +} + +static int +mtk_bt_hci_send(struct hci_dev *hdev, struct sk_buff *skb) +{ +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + if (mtk_hci.hdev && !test_bit(HCI_RUNNING, &mtk_hci.hdev->flags)) + return -EBUSY; + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + mtk_hci.hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + mtk_hci.hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + mtk_hci.hdev->stat.sco_tx++; + break; + + default: + return -EILSEQ; + } + + skb_queue_tail(&mtk_hci.txq, skb); + schedule_work(&mtk_hci.work); + + return 0; +} + +static int +mtk_bt_hci_flush(struct hci_dev *hdev) +{ + pr_err("%s: todo\n", __func__); + + return 0; +} + +static void +mtk_bt_hci_receive(const PUINT8 data, INT32 size) +{ + int err; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); + hex_dump("<<", data, size); +#endif + + err = hci_recv_fragment(mtk_hci.hdev, data[0], (void *)&data[1], size - 1); + if (err < 0) + pr_err("%s: hci_recv_fragment failed with %d\n", __func__, err); + + if (mtk_hci.hdev) + mtk_hci.hdev->stat.byte_rx += size - 1; +} + +static void +mtk_bt_hci_notify(struct hci_dev *hdev, unsigned int evt) +{ + static const char * const notify_str[] = { + "null", + "HCI_NOTIFY_CONN_ADD", + "HCI_NOTIFY_CONN_DEL", + "HCI_NOTIFY_VOICE_SETTING" + }; + + if (evt > HCI_NOTIFY_VOICE_SETTING) + pr_info("%s event=0x%x\n", __func__, evt); + else + pr_info("%s event(%d)=%s\n", __func__, evt, notify_str[evt]); +} +#endif + +#ifdef MTK_BT_HCI + +int mtk_bt_hci_init(void) +{ + INT32 hci_err = 0; + + mtk_hci.hdev = hci_alloc_dev(); + if (!(mtk_hci.hdev)) { + mtk_hci.hdev = NULL; + BT_ERR_FUNC("%s hci_alloc_dev failed\n", __func__); + return -ENOMEM; + } + + mtk_hci.hdev->bus = HCI_SDIO; + mtk_hci.hdev->open = mtk_bt_hci_open; + mtk_hci.hdev->close = mtk_bt_hci_close; + mtk_hci.hdev->send = mtk_bt_hci_send; + mtk_hci.hdev->flush = mtk_bt_hci_flush; + mtk_hci.hdev->notify = mtk_bt_hci_notify; + SET_HCIDEV_DEV(mtk_hci.hdev, stpbt_dev); + + hci_set_drvdata(mtk_hci.hdev, &mtk_hci); + + mtk_wcn_stp_register_if_rx(mtk_bt_hci_receive); + + hci_err = hci_register_dev(mtk_hci.hdev); + if (hci_err) { + BT_ERR_FUNC("%s hci_register_dev failed with %d\n", __func__, hci_err); + hci_free_dev(mtk_hci.hdev); + mtk_hci.hdev = NULL; + return hci_err; + } + + skb_queue_head_init(&mtk_hci.txq); + INIT_WORK(&mtk_hci.work, mtk_bt_hci_work); + + return 0; +} +#endif + + +static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz) +{ + /* + Handle whole chip reset messages + */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + memcpy((PINT8)&rst_msg, (PINT8)buf, sz); + BT_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, + dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) + && (type == WMTMSG_TYPE_RESET)) { + if (rst_msg == WMTRSTMSG_RESET_START) { + BT_INFO_FUNC("BT reset start!\n"); + rstflag = 1; + wake_up_interruptible(&inq); + + } else if (rst_msg == WMTRSTMSG_RESET_END) { + BT_INFO_FUNC("BT reset end!\n"); + rstflag = 2; + wake_up_interruptible(&inq); + } + } + } else { + /* Invalid message format */ + BT_WARN_FUNC("Invalid message format!\n"); + } +} + +VOID BT_event_cb(VOID) +{ + BT_DBG_FUNC("BT_event_cb()\n"); + + flag = 1; + + /* + * Finally, wake up any reader blocked in poll or read + */ + wake_up_interruptible(&inq); + wake_up(&BT_wq); +} + +unsigned int BT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + +/* down(&wr_mtx); */ + /* + * The buffer is circular; it is considered full + * if "wp" is right behind "rp". "left" is 0 if the + * buffer is empty, and it is "1" if it is completely full. + */ + if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) { + poll_wait(filp, &inq, wait); + + if (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) || rstflag) + /* BT Rx queue has valid data, or whole chip reset occurs */ + mask |= POLLIN | POLLRDNORM; /* Readable */ + } else { + mask |= POLLIN | POLLRDNORM; /* Readable */ + } + + /* Do we need condition here? */ + mask |= POLLOUT | POLLWRNORM; /* Writable */ +/* up(&wr_mtx); */ + return mask; +} + +ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = 0; + INT32 write_size; + INT32 written = 0; + + down(&wr_mtx); + + BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + BT_INFO_FUNC("%s: detect whole chip reset start\n", __func__); + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); + } + goto OUT; + } + + if (count > 0) { + if (count < BT_BUFFER_SIZE) { + write_size = count; + } else { + write_size = BT_BUFFER_SIZE; + BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); + } + + if (copy_from_user(&o_buf[0], &buf[0], write_size)) { + retval = -EFAULT; + goto OUT; + } + + written = mtk_wcn_stp_send_data(&o_buf[0], write_size, BT_TASK_INDX); + if (0 == written) { + retval = -ENOSPC; + /* No space is available, native program should not call BT_write with no delay */ + BT_ERR_FUNC + ("Packet length %zd, sent length %d, retval = %d\n", + count, written, retval); + } else { + retval = written; + } + + } else { + retval = -EFAULT; + BT_ERR_FUNC("Packet length %zd is not allowed, retval = %d\n", count, retval); + } + +OUT: + up(&wr_mtx); + return retval; +} + +ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + static int chip_reset_count; + INT32 retval = 0; + + down(&rd_mtx); + + BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + if ((chip_reset_count%500) == 0) + BT_INFO_FUNC("%s: detect whole chip reset start, %d\n", __func__, chip_reset_count); + chip_reset_count++; + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); + chip_reset_count = 0; + } + goto OUT; + } + + if (count > BT_BUFFER_SIZE) { + count = BT_BUFFER_SIZE; + BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); + } + + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + + while (retval == 0) { /* Got nothing, wait for STP's signal */ + /* + * If nonblocking mode, return directly. + * O_NONBLOCK is specified during open() + */ + if (filp->f_flags & O_NONBLOCK) { + BT_DBG_FUNC("Non-blocking BT_read\n"); + retval = -EAGAIN; + goto OUT; + } + + BT_DBG_FUNC("%s: wait_event 1\n", __func__); + wait_event(BT_wq, flag != 0); + BT_DBG_FUNC("%s: wait_event 2\n", __func__); + flag = 0; + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + BT_DBG_FUNC("%s: mtk_wcn_stp_receive_data returns %d\n", __func__, retval); + } + + /* Got something from STP driver */ + if (copy_to_user(buf, i_buf, retval)) { + retval = -EFAULT; + goto OUT; + } + +OUT: + up(&rd_mtx); + BT_DBG_FUNC("%s: retval = %d\n", __func__, retval); + return retval; +} + +/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ +long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + INT32 retval = 0; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; + ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; + + BT_DBG_FUNC("%s: cmd: 0x%x\n", __func__, cmd); + + switch (cmd) { + case COMBO_IOC_BT_HWVER: + /* Get combo HW version */ + hw_ver_sym = mtk_wcn_wmt_hwver_get(); + BT_INFO_FUNC("%s: HW version = %d, sizeof(hw_ver_sym) = %zd\n", + __func__, hw_ver_sym, sizeof(hw_ver_sym)); + if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) + retval = -EFAULT; + break; + + case COMBO_IOCTL_FW_ASSERT: + /* Trigger FW assert for debug */ + BT_INFO_FUNC("%s: Host trigger FW assert......, reason:%lu\n", __func__, arg); + bRet = mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, arg); + if (bRet == MTK_WCN_BOOL_TRUE) { + BT_INFO_FUNC("Host trigger FW assert succeed\n"); + retval = 0; + } else { + BT_ERR_FUNC("Host trigger FW assert Failed\n"); + retval = (-EBUSY); + } + break; + case COMBO_IOCTL_BT_IC_HW_VER: + retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); + break; + case COMBO_IOCTL_BT_IC_FW_VER: + retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); + break; + default: + retval = -EFAULT; + BT_ERR_FUNC("Unknown cmd (%d)\n", cmd); + break; + } + + return retval; +} + +long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return BT_unlocked_ioctl(filp, cmd, arg); +} + +static int BT_open(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); + + /* Turn on BT */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -ENODEV; + } + + BT_INFO_FUNC("WMT turn on BT OK!\n"); + rstflag = 0; + + if (mtk_wcn_stp_is_ready()) { + + mtk_wcn_stp_set_bluez(0); + + BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); + BT_INFO_FUNC("STP is ready!\n"); + + BT_DBG_FUNC("Register BT event callback!\n"); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); + } else { + BT_ERR_FUNC("STP is not ready\n"); + mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + return -ENODEV; + } + + BT_DBG_FUNC("Register BT reset callback!\n"); + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); + + /* init_MUTEX(&wr_mtx); */ + sema_init(&wr_mtx, 1); + /* init_MUTEX(&rd_mtx); */ + sema_init(&rd_mtx, 1); + BT_INFO_FUNC("%s: finish\n", __func__); + + return 0; +} + +static int BT_close(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); + rstflag = 0; + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { + BT_ERR_FUNC("WMT turn off BT fail!\n"); + return -EIO; /* Mostly, native program will not check this return value. */ + } + + BT_INFO_FUNC("WMT turn off BT OK!\n"); + + return 0; +} + +const struct file_operations BT_fops = { + .open = BT_open, + .release = BT_close, + .read = BT_read, + .write = BT_write, + /* .ioctl = BT_ioctl, */ + .unlocked_ioctl = BT_unlocked_ioctl, + .compat_ioctl = BT_compat_ioctl, + .poll = BT_poll +}; + + + +static int BT_init(void) +{ + dev_t dev = MKDEV(BT_major, 0); + INT32 alloc_ret = 0; + INT32 cdev_err = 0; + + /* Static allocate char device */ + alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME); + if (alloc_ret) { + BT_ERR_FUNC("%s: Failed to register char device\n", __func__); + return alloc_ret; + } + + cdev_init(&BT_cdev, &BT_fops); + BT_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&BT_cdev, dev, BT_devs); + if (cdev_err) + goto error; + +#if WMT_CREATE_NODE_DYNAMIC + stpbt_class = class_create(THIS_MODULE, "stpbt"); + if (IS_ERR(stpbt_class)) + goto error; + stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt"); + if (IS_ERR(stpbt_dev)) + goto error; +#endif + + BT_INFO_FUNC("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major); + + /* Init wait queue */ + init_waitqueue_head(&(inq)); + +#ifdef MTK_BT_HCI + mtk_bt_hci_init(); +#endif + + return 0; + +error: +#if WMT_CREATE_NODE_DYNAMIC + if (!IS_ERR(stpbt_dev)) + device_destroy(stpbt_class, dev); + if (!IS_ERR(stpbt_class)) { + class_destroy(stpbt_class); + stpbt_class = NULL; + } +#endif + if (cdev_err == 0) + cdev_del(&BT_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, BT_devs); + + return -1; +} + +static void BT_exit(void) +{ + dev_t dev = MKDEV(BT_major, 0); + +#if WMT_CREATE_NODE_DYNAMIC + if (stpbt_dev) { + device_destroy(stpbt_class, dev); + stpbt_dev = NULL; + } + if (stpbt_class) { + class_destroy(stpbt_class); + stpbt_class = NULL; + } +#endif + + cdev_del(&BT_cdev); + unregister_chrdev_region(dev, BT_devs); + + BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); +} + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + +int mtk_wcn_stpbt_drv_init(void) +{ + return BT_init(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init); + +void mtk_wcn_stpbt_drv_exit(void) +{ + return BT_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit); + +#else + +module_init(BT_init); +module_exit(BT_exit); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c new file mode 100644 index 0000000000000..c43bec5f74522 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_chrdev_wifi.c @@ -0,0 +1,668 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wmt_exp.h" +#include "stp_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#define WIFI_DRIVER_NAME "mtk_wmt_WIFI_chrdev" +#define WIFI_DEV_MAJOR 153 + +#define PFX "[MTK-WIFI] " +#define WIFI_LOG_DBG 3 +#define WIFI_LOG_INFO 2 +#define WIFI_LOG_WARN 1 +#define WIFI_LOG_ERR 0 + +UINT32 gDbgLevel = WIFI_LOG_DBG; + +#define WIFI_DBG_FUNC(fmt, arg...)\ + do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) +#define WIFI_INFO_FUNC(fmt, arg...)\ + do {if (gDbgLevel >= WIFI_LOG_INFO) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) +#define WIFI_WARN_FUNC(fmt, arg...)\ + do {if (gDbgLevel >= WIFI_LOG_WARN) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) +#define WIFI_ERR_FUNC(fmt, arg...)\ + do {if (gDbgLevel >= WIFI_LOG_ERR) printk(PFX "%s: " fmt, __func__ , ##arg); } while (0) +#define WIFI_TRC_FUNC(f)\ + do {if (gDbgLevel >= WIFI_LOG_DBG) printk(PFX "<%s> <%d>\n", __func__, __LINE__); } while (0) + +#define VERSION "1.0" + +#define WLAN_IFACE_NAME "wlan0" +#if CFG_TC1_FEATURE +#define LEGACY_IFACE_NAME "legacy0" +#endif + +enum { + WLAN_MODE_HALT, + WLAN_MODE_AP, + WLAN_MODE_STA_P2P, + WLAN_MODE_MAX +}; +static INT32 wlan_mode = WLAN_MODE_HALT; +static INT32 powered; +static INT8 *ifname = WLAN_IFACE_NAME; +#if CFG_TC1_FEATURE +volatile INT32 wlan_if_changed = 0; +EXPORT_SYMBOL(wlan_if_changed); +#endif + +typedef enum _ENUM_RESET_STATUS_T { + RESET_FAIL, + RESET_SUCCESS +} ENUM_RESET_STATUS_T; + +/* + * enable = 1, mode = 0 => init P2P network + * enable = 1, mode = 1 => init Soft AP network + * enable = 0 => uninit P2P/AP network + */ +typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { + UINT32 u4Enable; + UINT32 u4Mode; +} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; +typedef INT32(*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); + +static set_p2p_mode pf_set_p2p_mode; +VOID register_set_p2p_mode_handler(set_p2p_mode handler) +{ + WIFI_INFO_FUNC("(pid %d) register set p2p mode handler %p\n", current->pid, handler); + pf_set_p2p_mode = handler; +} +EXPORT_SYMBOL(register_set_p2p_mode_handler); + +/* For dynamical debug level setting */ +/* copy of debug.h in wlan driver */ +#define DBG_CLASS_ERROR BIT(0) +#define DBG_CLASS_WARN BIT(1) +#define DBG_CLASS_STATE BIT(2) +#define DBG_CLASS_EVENT BIT(3) +#define DBG_CLASS_TRACE BIT(4) +#define DBG_CLASS_INFO BIT(5) +#define DBG_CLASS_LOUD BIT(6) +#define DBG_CLASS_TEMP BIT(7) +#define DBG_CLASS_MASK BITS(0, 7) + +typedef enum _ENUM_DBG_MODULE_T { + DBG_INIT_IDX = 0, /* For driver initial */ + DBG_HAL_IDX, /* For HAL(HW) Layer */ + DBG_INTR_IDX, /* For Interrupt */ + DBG_REQ_IDX, + DBG_TX_IDX, + DBG_RX_IDX, + DBG_RFTEST_IDX, /* For RF test mode */ + DBG_EMU_IDX, /* Developer specific */ + + DBG_SW1_IDX, /* Developer specific */ + DBG_SW2_IDX, /* Developer specific */ + DBG_SW3_IDX, /* Developer specific */ + DBG_SW4_IDX, /* Developer specific */ + + DBG_HEM_IDX, /* HEM */ + DBG_AIS_IDX, /* AIS */ + DBG_RLM_IDX, /* RLM */ + DBG_MEM_IDX, /* RLM */ + DBG_CNM_IDX, /* CNM */ + DBG_RSN_IDX, /* RSN */ + DBG_BSS_IDX, /* BSS */ + DBG_SCN_IDX, /* SCN */ + DBG_SAA_IDX, /* SAA */ + DBG_AAA_IDX, /* AAA */ + DBG_P2P_IDX, /* P2P */ + DBG_QM_IDX, /* QUE_MGT */ + DBG_SEC_IDX, /* SEC */ + DBG_BOW_IDX, /* BOW */ + DBG_WAPI_IDX, /* WAPI */ + DBG_ROAMING_IDX, /* ROAMING */ + + DBG_MODULE_NUM /* Notice the XLOG check */ +} ENUM_DBG_MODULE_T; +/* end */ +typedef VOID(*set_dbg_level) (UINT8 modules[DBG_MODULE_NUM]); + +UINT8 wlan_dbg_level[DBG_MODULE_NUM]; +static set_dbg_level pf_set_dbg_level; +VOID register_set_dbg_level_handler(set_dbg_level handler) +{ + pf_set_dbg_level = handler; +} +EXPORT_SYMBOL(register_set_dbg_level_handler); + +static INT32 WIFI_devs = 1; +static INT32 WIFI_major = WIFI_DEV_MAJOR; +module_param(WIFI_major, uint, 0); +static struct cdev WIFI_cdev; +volatile INT32 retflag = 0; +static struct semaphore wr_mtx; + +#define WMT_CHECK_DO_CHIP_RESET() \ +do { \ + if (g_IsNeedDoChipReset) { \ + g_IsNeedDoChipReset = 0; \ + WIFI_ERR_FUNC("Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ + mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); \ + } \ +} while (0) + +/******************************************************************* + * WHOLE CHIP RESET PROCEDURE: + * + * WMTRSTMSG_RESET_START callback + * -> wlanRemove + * -> WMTRSTMSG_RESET_END callback + * + ******************************************************************* +*/ +/*-----------------------------------------------------------------*/ +/* + * Receiving RESET_START message + */ +/*-----------------------------------------------------------------*/ +INT32 wifi_reset_start(VOID) +{ + struct net_device *netdev = NULL; + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; + + down(&wr_mtx); + + if (powered == 1) { + netdev = dev_get_by_name(&init_net, ifname); + if (netdev == NULL) { + WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); + } else { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + + if (pf_set_p2p_mode) { + if (pf_set_p2p_mode(netdev, p2pmode) != 0) + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + else + WIFI_INFO_FUNC("Turn off p2p/ap mode"); + } + dev_put(netdev); + netdev = NULL; + } + } else { + /* WIFI is off before whole chip reset, do nothing */ + } + + return 0; +} +EXPORT_SYMBOL(wifi_reset_start); + +/*-----------------------------------------------------------------*/ +/* + * Receiving RESET_END/RESET_END_FAIL message + */ +/*-----------------------------------------------------------------*/ +INT32 wifi_reset_end(ENUM_RESET_STATUS_T status) +{ + struct net_device *netdev = NULL; + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; + INT32 wait_cnt = 0; + INT32 ret = -1; + + if (status == RESET_FAIL) { + /* whole chip reset fail, donot recover WIFI */ + ret = 0; + up(&wr_mtx); + } else if (status == RESET_SUCCESS) { + WIFI_WARN_FUNC("WIFI state recovering...\n"); + + if (powered == 1) { + /* WIFI is on before whole chip reset, reopen it now */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + goto done; + } else { + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + } + + if (pf_set_p2p_mode == NULL) { + WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + while (netdev == NULL && wait_cnt < 10) { + WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); + msleep(300); + wait_cnt++; + netdev = dev_get_by_name(&init_net, ifname); + } + if (wait_cnt >= 10) { + WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); + goto done; + } + + if (wlan_mode == WLAN_MODE_STA_P2P) { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_P2P); + ret = 0; + } + } else if (wlan_mode == WLAN_MODE_AP) { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 1; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_AP); + ret = 0; + } + } +done: + if (netdev != NULL) + dev_put(netdev); + } else { + /* WIFI is off before whole chip reset, do nothing */ + ret = 0; + } + up(&wr_mtx); + } + + return ret; +} +EXPORT_SYMBOL(wifi_reset_end); + +static int WIFI_open(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static int WIFI_close(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + retflag = 0; + + return 0; +} + +ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = -EIO; + INT8 local[12] = { 0 }; + struct net_device *netdev = NULL; + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; + INT32 wait_cnt = 0; + + down(&wr_mtx); + if (count <= 0) { + WIFI_ERR_FUNC("WIFI_write invalid param\n"); + goto done; + } + + if (0 == copy_from_user(local, buf, (count > sizeof(local)) ? sizeof(local) : count)) { + local[11] = 0; + WIFI_INFO_FUNC("WIFI_write %s\n", local); + + if (local[0] == '0') { + if (powered == 0) { + WIFI_INFO_FUNC("WIFI is already power off!\n"); + retval = count; + wlan_mode = WLAN_MODE_HALT; + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + if (netdev == NULL) { + WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); + } else { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + + if (pf_set_p2p_mode) { + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + } else { + WIFI_INFO_FUNC("Turn off p2p/ap mode"); + wlan_mode = WLAN_MODE_HALT; + } + } + dev_put(netdev); + netdev = NULL; + } + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI)) { + WIFI_ERR_FUNC("WMT turn off WIFI fail!\n"); + WMT_CHECK_DO_CHIP_RESET(); + } else { + WIFI_INFO_FUNC("WMT turn off WIFI OK!\n"); + powered = 0; + retval = count; + wlan_mode = WLAN_MODE_HALT; +#if CFG_TC1_FEATURE + ifname = WLAN_IFACE_NAME; + wlan_if_changed = 0; +#endif + } + } else if (local[0] == '1') { + if (powered == 1) { + WIFI_INFO_FUNC("WIFI is already power on!\n"); + retval = count; + goto done; + } + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + WMT_CHECK_DO_CHIP_RESET(); + } else { + powered = 1; + retval = count; + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + wlan_mode = WLAN_MODE_HALT; + } + } else if (local[0] == 'D') { + INT32 k = 0; + /* + * 0: no debug + * 1: common debug output + * 2: more detials + * 3: verbose + */ + switch (local[1]) { + case '0': + for (k = 0; k < DBG_MODULE_NUM; k++) + wlan_dbg_level[k] = 0; + if (pf_set_dbg_level) + pf_set_dbg_level(wlan_dbg_level); + break; + case '1': + for (k = 0; k < DBG_MODULE_NUM; k++) { + wlan_dbg_level[k] = DBG_CLASS_ERROR | + DBG_CLASS_WARN | + DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; + } + wlan_dbg_level[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); + wlan_dbg_level[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); + wlan_dbg_level[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO); + wlan_dbg_level[DBG_INTR_IDX] = 0; + wlan_dbg_level[DBG_MEM_IDX] = 0; + if (pf_set_dbg_level) + pf_set_dbg_level(wlan_dbg_level); + break; + case '2': + for (k = 0; k < DBG_MODULE_NUM; k++) { + wlan_dbg_level[k] = DBG_CLASS_ERROR | + DBG_CLASS_WARN | + DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO; + } + wlan_dbg_level[DBG_INTR_IDX] = 0; + wlan_dbg_level[DBG_MEM_IDX] = 0; + if (pf_set_dbg_level) + pf_set_dbg_level(wlan_dbg_level); + break; + case '3': + for (k = 0; k < DBG_MODULE_NUM; k++) { + wlan_dbg_level[k] = DBG_CLASS_ERROR | + DBG_CLASS_WARN | + DBG_CLASS_STATE | + DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO | DBG_CLASS_LOUD; + } + if (pf_set_dbg_level) + pf_set_dbg_level(wlan_dbg_level); + break; + default: + break; + } + } else if (local[0] == 'S' || local[0] == 'P' || local[0] == 'A') { + if (powered == 0) { + /* If WIFI is off, turn on WIFI first */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) { + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + WMT_CHECK_DO_CHIP_RESET(); + goto done; + } else { + powered = 1; + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + wlan_mode = WLAN_MODE_HALT; + } + } + + if (pf_set_p2p_mode == NULL) { + WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + while (netdev == NULL && wait_cnt < 10) { + WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); + msleep(300); + wait_cnt++; + netdev = dev_get_by_name(&init_net, ifname); + } + if (wait_cnt >= 10) { + WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); + goto done; + } + + if ((wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'S' || local[0] == 'P')) || + (wlan_mode == WLAN_MODE_AP && (local[0] == 'A'))) { + WIFI_INFO_FUNC("WIFI is already in mode %d!\n", wlan_mode); + retval = count; + goto done; + } + + if ((wlan_mode == WLAN_MODE_AP && (local[0] == 'S' || local[0] == 'P')) || + (wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'A'))) { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + goto done; + } + } + + if (local[0] == 'S' || local[0] == 'P') { +#if CFG_TC1_FEATURE + /* Restore NIC name to wlan0 */ + rtnl_lock(); + if (strcmp(ifname, WLAN_IFACE_NAME) != 0) { + if (dev_change_name(netdev, WLAN_IFACE_NAME) != 0) { + WIFI_ERR_FUNC("netdev name change to %s fail\n", WLAN_IFACE_NAME); + rtnl_unlock(); + goto done; + } else { + WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, + WLAN_IFACE_NAME); + ifname = WLAN_IFACE_NAME; + wlan_if_changed = 0; + } + } + rtnl_unlock(); +#endif + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_STA_P2P); + wlan_mode = WLAN_MODE_STA_P2P; + retval = count; + } + } else if (local[0] == 'A') { +#if CFG_TC1_FEATURE + /* Change NIC name to legacy0, since wlan0 is used for AP */ + rtnl_lock(); + if (strcmp(ifname, LEGACY_IFACE_NAME) != 0) { + if (dev_change_name(netdev, LEGACY_IFACE_NAME) != 0) { + WIFI_ERR_FUNC("netdev name change to %s fail\n", LEGACY_IFACE_NAME); + rtnl_unlock(); + goto done; + } else { + WIFI_INFO_FUNC("netdev name changed %s --> %s\n", ifname, + LEGACY_IFACE_NAME); + ifname = LEGACY_IFACE_NAME; + wlan_if_changed = 1; + } + } + rtnl_unlock(); +#endif + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 1; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_AP); + wlan_mode = WLAN_MODE_AP; + retval = count; + } + } + dev_put(netdev); + netdev = NULL; + } + } +done: + if (netdev != NULL) + dev_put(netdev); + + up(&wr_mtx); + return retval; +} + +const struct file_operations WIFI_fops = { + .open = WIFI_open, + .release = WIFI_close, + .write = WIFI_write, +}; + +#if WMT_CREATE_NODE_DYNAMIC +struct class *wmtwifi_class = NULL; +#endif + +static int WIFI_init(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + INT32 alloc_ret = 0; + INT32 cdev_err = 0; +#if WMT_CREATE_NODE_DYNAMIC + struct device *wmtwifi_dev = NULL; +#endif + + /* static allocate chrdev */ + alloc_ret = register_chrdev_region(dev, 1, WIFI_DRIVER_NAME); + if (alloc_ret) { + WIFI_ERR_FUNC("Fail to register chrdev\n"); + return alloc_ret; + } + + cdev_init(&WIFI_cdev, &WIFI_fops); + WIFI_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs); + if (cdev_err) + goto error; + +#if WMT_CREATE_NODE_DYNAMIC /* mknod replace */ + wmtwifi_class = class_create(THIS_MODULE, "wmtWifi"); + if (IS_ERR(wmtwifi_class)) + goto error; + wmtwifi_dev = device_create(wmtwifi_class, NULL, dev, NULL, "wmtWifi"); + if (wmtwifi_dev == NULL) + goto error; + if (IS_ERR(wmtwifi_dev)) + goto error; +#endif + + sema_init(&wr_mtx, 1); + + WIFI_INFO_FUNC("%s driver(major %d) installed.\n", WIFI_DRIVER_NAME, WIFI_major); + retflag = 0; + wlan_mode = WLAN_MODE_HALT; + pf_set_p2p_mode = NULL; + + return 0; + +error: +#if WMT_CREATE_NODE_DYNAMIC + if (!IS_ERR(wmtwifi_dev)) + device_destroy(wmtwifi_class, dev); + if (!IS_ERR(wmtwifi_class)) { + class_destroy(wmtwifi_class); + wmtwifi_class = NULL; + } +#endif + + if (cdev_err == 0) + cdev_del(&WIFI_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, WIFI_devs); + + return -1; +} + +static void WIFI_exit(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + + retflag = 0; + +#if WMT_CREATE_NODE_DYNAMIC + device_destroy(wmtwifi_class, dev); + class_destroy(wmtwifi_class); + wmtwifi_class = NULL; +#endif + + cdev_del(&WIFI_cdev); + unregister_chrdev_region(dev, WIFI_devs); + + WIFI_INFO_FUNC("%s driver removed.\n", WIFI_DRIVER_NAME); +} + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + +INT32 mtk_wcn_wmt_wifi_init(VOID) +{ + return WIFI_init(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_wifi_init); + +VOID mtk_wcn_wmt_wifi_exit(VOID) +{ + return WIFI_exit(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_wifi_exit); + +#else + +module_init(WIFI_init); +module_exit(WIFI_exit); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c new file mode 100644 index 0000000000000..641e516f603d4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/linux/pub/wmt_idc.c @@ -0,0 +1,307 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include "osal_typedef.h" +#include "wmt_idc.h" +#include "wmt_lib.h" + +#if CFG_WMT_LTE_COEX_HANDLING + +MTK_WCN_WMT_IDC_INFO gWmtIdcInfo; + +INT32 wmt_idc_init(VOID) +{ + INT32 iRet; + + osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); + gWmtIdcInfo.iit.src_mod_id = AP_MOD_WMT; + gWmtIdcInfo.iit.dest_mod_id = MD_MOD_EL1; + gWmtIdcInfo.iit.sap_id = 0; + gWmtIdcInfo.ops.rx_cb = wmt_idc_msg_from_lte_handing; + + iRet = mtk_conn_md_bridge_reg(gWmtIdcInfo.iit.src_mod_id, &gWmtIdcInfo.ops); + if (iRet) { + WMT_ERR_FUNC("mtk_conn_md_bridge_reg fail(%d)\n", iRet); + return -1; + } + /* mtk_wcn_stp_flush_rx_queue(COEX_TASK_INDX); */ + return 0; + +} + +INT32 wmt_idc_deinit(VOID) +{ + INT32 iRet; + + iRet = mtk_conn_md_bridge_unreg(gWmtIdcInfo.iit.src_mod_id); + if (iRet) + WMT_ERR_FUNC("mtk_conn_md_bridge_unreg fail(%d)\n", iRet); + + osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); + + return 0; +} + +INT32 wmt_idc_msg_from_lte_handing(ipc_ilm_t *ilm) +{ + MTK_WCN_BOOL bRet; + + if (NULL == ilm) { + WMT_ERR_FUNC("NULL pointer\n"); + return -1; + } + if (mtk_wcn_stp_is_ready()) { + bRet = wmt_lib_handle_idc_msg(ilm); + if (MTK_WCN_BOOL_FALSE == bRet) { + WMT_ERR_FUNC("wmt handing idc msg fail\n"); + return -2; + } + } else { + WMT_INFO_FUNC("Received LTE msg,but STP is not ready,drop it!\n"); + } + return 0; +} + +VOID wmt_idc_dump_debug_msg(UINT8 *str, UINT8 *p_buf, UINT32 buf_len) +{ + UINT32 idx = 0; + + WMT_DBG_FUNC("%s:, length:%d\n", str, buf_len); + + WMT_DBG_FUNC("ASCII output:\n"); + + for (idx = 0; idx < buf_len;) { + WMT_DBG_FUNC("%c", p_buf[idx]); + idx++; + if (0 == idx % 16) + WMT_DBG_FUNC("\n"); + } + + WMT_DBG_FUNC("HEX output:\n"); + + for (idx = 0; idx < buf_len;) { + WMT_DBG_FUNC("%02x ", p_buf[idx]); + idx++; + if (0 == idx % 16) + WMT_DBG_FUNC("\n"); + } +} + +INT32 wmt_idc_msg_to_lte_handing(VOID) +{ + UINT32 readlen = 0; + local_para_struct *p_lps = NULL; + UINT8 *p_data = NULL; + UINT8 opcode = 0; + UINT16 msg_len = 0; + UINT32 handle_len = 0; +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; +#endif + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); + if (readlen == 0) { + osal_sleep_ms(5); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], LTE_IDC_BUFFER_MAX_SIZE, COEX_TASK_INDX); + } + + if (readlen > 0) { + WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); + wmt_idc_dump_debug_msg("WMT->LTE from STP buffer", &gWmtIdcInfo.buffer[0], readlen); + p_data = &gWmtIdcInfo.buffer[0]; + + while (handle_len < readlen) { + p_data += 2; /*omit direction & opcode 2 bytes */ + osal_memcpy(&msg_len, p_data, 2); + msg_len -= 1; /*flag byte */ + WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); + + p_data += 2; /*length: 2 bytes */ + + /*how to handle flag(msg type) need to Scott comment */ + /************************************************/ + + if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) + /*do not need transfer to LTE */ + { + p_data += 1; /*flag : 1 byte */ + /*need to handle these debug message */ + wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); + } else + /*need to transfer to LTE */ + { + p_lps = + (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + + osal_sizeof(UINT8) * msg_len); + if (NULL == p_lps) { + WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); + return -1; + } + + p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); + + opcode = *p_data; + WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); + + p_data += 1; /*flag : 1 byte */ + osal_memcpy(p_lps->data, p_data, msg_len); + + gWmtIdcInfo.iit.local_para_ptr = p_lps; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + switch (opcode) { + case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; + break; + case WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND; + break; + case WMT_IDC_RX_OPCODE_UART_PIN_SEL: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_PIN_TYPE_IND; + break; + /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ + /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ + /* break; */ + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); + break; + } + if (MTK_WCN_BOOL_FALSE == unknown_msgid) { + /*handling flag value in wmt cmd */ + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + } +#else + if (opcode >= LTE_MSG_ID_OFFSET) { + gWmtIdcInfo.iit.msg_id = opcode + IPC_EL1_MSG_ID_BEGIN - LTE_MSG_ID_OFFSET + 1; + /*handling flag value in wmt cmd */ + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + WMT_DBG_FUNC("CONN->LTE: (0x%x->0x%x)\n", opcode, gWmtIdcInfo.iit.msg_id); + } else { + WMT_ERR_FUNC("opcode(%d)from connsys fw is out of range,drop it!\n", opcode); + } +#endif + osal_free(p_lps); + } + + p_data += msg_len; /*point to next package header */ + + handle_len += (msg_len + 5); + } + + } else { + WMT_ERR_FUNC("there is no coex data in stp buffer\n"); + } + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + + return 0; +} + +UINT32 wmt_idc_msg_to_lte_handing_for_test(UINT8 *p_buf, UINT32 len) +{ + UINT32 readlen = len; + local_para_struct *p_lps = NULL; + UINT8 *p_data = NULL; + UINT8 opcode = 0; + UINT16 msg_len = 0; + UINT32 handle_len = 0; + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; + + osal_memcpy(&gWmtIdcInfo.buffer[0], p_buf, len); + + if (readlen > 0) { + WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); + p_data = &gWmtIdcInfo.buffer[0]; + + while (handle_len < readlen) { + p_data += 2; /*omit direction & opcode 2 bytes */ + osal_memcpy(&msg_len, p_data, 2); + msg_len -= 1; /*flag byte */ + WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); + + p_data += 2; /*length: 2 bytes */ + + /*how to handle flag(msg type) need to Scott comment */ + /************************************************/ + + if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) + /*do not need transfer to LTE */ + { + p_data += 1; /*flag : 1 byte */ + /*need to handle these debug message */ + wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); + } else + /*need to transfer to LTE */ + { + p_lps = + (local_para_struct *) osal_malloc(osal_sizeof(local_para_struct) + + osal_sizeof(UINT8) * msg_len); + if (NULL == p_lps) { + WMT_ERR_FUNC("allocate local_para_struct memory fail\n"); + return -1; + } + + p_lps->msg_len = msg_len + osal_sizeof(local_para_struct); + + opcode = *p_data; + WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); + + p_data += 1; /*flag : 1 byte */ + osal_memcpy(p_lps->data, p_data, msg_len); + + gWmtIdcInfo.iit.local_para_ptr = p_lps; + + switch (opcode) { + case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; + break; + /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ + /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ + /* break; */ + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); + break; + } + if (MTK_WCN_BOOL_FALSE == unknown_msgid) { + /*handling flag value in wmt cmd */ + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + } + osal_free(p_lps); + } + + p_data += msg_len; /*point to next package header */ + + handle_len += (msg_len + 5); + } + + } else { + WMT_ERR_FUNC("there is no coex data in stp buffer\n"); + } + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + + return handle_len; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile new file mode 100644 index 0000000000000..c201e8291b8ef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/Makefile @@ -0,0 +1,25 @@ +# WMT HAL driver for MT7623 + +ccflags-y += \ + -I$(src)/include \ + -I$(src)/../linux/include \ + -I$(src)/../include \ + -I$(src)/../../common_detect + + ifeq ($(CONFIG_MTK_CLKMGR),y) + ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach + endif + #ifeq ($(CONFIG_MTK_EMI_MPU),y) + ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach + #endif + +subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + subdir-ccflags-y += -DWMT_IDC_SUPPORT=1 +else + subdir-ccflags-y += -DWMT_IDC_SUPPORT=0 +endif + +obj-y += mtk_wcn_consys_hw.o +obj-y += wmt_plat_alps.o diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h new file mode 100644 index 0000000000000..94d6af9d0b3ea --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/include/mtk_wcn_consys_hw.h @@ -0,0 +1,287 @@ +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_WCN_CONSYS_HW_H_ +#define _MTK_WCN_CONSYS_HW_H_ + +#include +/*#include */ +#include "wmt_plat.h" + +/*device tree mode*/ +#ifdef CONFIG_OF +/* #if 1 */ +#include +#include +#include +#include +#endif + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_PMIC_CTRL_UPMU 1 +#define CONSYS_EMI_MPU_SETTING 0 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 0 +#if defined(CONFIG_MTK_LEGACY) +#define CONFIG_MTK_PMIC_LEGACY 0 +#endif +#define CONFIG_RESET_CONTROL 1 +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x7623 +/*tag end*/ + +#ifdef CONFIG_OF + +struct CONSYS_BASE_ADDRESS { + SIZE_T mcu_base; + SIZE_T ap_rgu_base; + SIZE_T topckgen_base; + SIZE_T spm_base; +}; + +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000800 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000310 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000280 +#define CONSYS_PWR_CONN_ACK_OFFSET 0x0000060c +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000610 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +/*AXI bus*/ + +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x0228 +#endif + +#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile UINT32*)(REG)) |= ((UINT32)(BITVAL))) +#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile UINT32*)(REG)) &= ~((UINT32)(BITVAL))) +#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ + UINT32 val = (*(volatile UINT32*)(REG)); \ + val &= ~((UINT32)(BITVAL)); \ + val |= ((UINT32)(KEY)); \ + (*(volatile UINT32*)(REG)) = val;\ +} +#define CONSYS_REG_READ(addr) (*((volatile UINT32*)(addr))) +#if CONSYS_USE_PLATFORM_WRITE +#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) +#else +#define CONSYS_REG_WRITE(addr, data) (*((volatile UINT32*)(addr)) = (UINT32)(data)) +#endif + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 237 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x00000280) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x0000060c) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000610) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) +#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) +#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) +#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) +#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) +#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) +#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x0220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x0228) +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14) | (0x1<<15)) /* bit 13, 14, 15 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define KBYTE (1024*sizeof(char)) +#define CONSYS_EMI_AP_PHY_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_MEM_SIZE (343*KBYTE) /*coredump space , 343K is enough */ +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + 0x1310) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 16) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 17) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) +#define CONSYS_PAGED_DUMP_SIZE (32*KBYTE) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + +/*force fw assert pattern*/ +#define EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1 (0x19b30bb1) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_EMI_CTRL_STATE_OFFSET_ { + EXP_APMEM_CTRL_STATE = 0x0, + EXP_APMEM_CTRL_HOST_SYNC_STATE = 0x4, + EXP_APMEM_CTRL_HOST_SYNC_NUM = 0x8, + EXP_APMEM_CTRL_CHIP_SYNC_STATE = 0xc, + EXP_APMEM_CTRL_CHIP_SYNC_NUM = 0x10, + EXP_APMEM_CTRL_CHIP_SYNC_ADDR = 0x14, + EXP_APMEM_CTRL_CHIP_SYNC_LEN = 0x18, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START = 0x1c, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN = 0x20, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX = 0x24, + EXP_APMEM_CTRL_CHIP_INT_STATUS = 0x28, + EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END = 0x2c, + EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 = 0x30, + EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP = 0x48, + EXP_APMEM_CTRL_MAX +} ENUM_EMI_CTRL_STATE_OFFSET, *P_ENUM_EMI_CTRL_STATE_OFFSET; + +#if CONSYS_BT_WIFI_SHARE_V33 +typedef struct _BT_WIFI_V33_STATUS_ { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +} BT_WIFI_V33_STATUS; + +#endif + +typedef enum _CONSYS_GPS_CO_CLOCK_TYPE_ { + GPS_TCXO_TYPE = 0, + GPS_CO_TSX_TYPE = 1, + GPS_CO_DCXO_TYPE = 2, + GPS_CO_VCTCXO_TYPE = 3, + GPS_CO_CLOCK_TYPE_MAX +} CONSYS_GPS_CO_CLOCK_TYPE, *P_CONSYS_GPS_CO_CLOCK_TYPE; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern struct CONSYS_BASE_ADDRESS conn_reg; +#if CONSYS_BT_WIFI_SHARE_V33 +extern BT_WIFI_V33_STATUS gBtWifiV33; +#endif +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +extern INT32 mtk_wcn_consys_hw_init(VOID); +extern INT32 mtk_wcn_consys_hw_deinit(VOID); +extern INT32 mtk_wcn_consys_hw_pwr_off(VOID); +extern INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type); +extern INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type); +extern INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable); +extern INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable); +extern INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable); +extern INT32 mtk_wcn_consys_hw_state_show(VOID); +extern UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset); +#if CONSYS_ENALBE_SET_JTAG +extern UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en); +#endif +extern UINT32 mtk_wcn_consys_soc_chipid(VOID); +#if !defined(CONFIG_MTK_GPIO_LEGACY) +extern struct pinctrl *mtk_wcn_consys_get_pinctrl(VOID); +#endif +extern INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 buf); +#endif /* _MTK_WCN_CMB_HW_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c new file mode 100644 index 0000000000000..191f7312f8978 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/mtk_wcn_consys_hw.c @@ -0,0 +1,737 @@ +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include "osal_typedef.h" +#include "mtk_wcn_consys_hw.h" +#include +#include +#include +#if CONSYS_EMI_MPU_SETTING +#include +#endif + +#include +#ifdef CONFIG_MTK_HIBERNATION +#include +#endif + +#include + +#if CONSYS_CLOCK_BUF_CTRL +#include +#endif + +#include +#include + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 mtk_wmt_probe(struct platform_device *pdev); +static INT32 mtk_wmt_remove(struct platform_device *pdev); + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +struct CONSYS_BASE_ADDRESS conn_reg; +static phys_addr_t gConEmiPhyBase; +static UINT8 __iomem *pEmibaseaddr; +static struct clk *clk_infra_conn_main; /*ctrl infra_connmcu_bus clk */ +static struct platform_device *my_pdev; +static struct reset_control *rstc; +static struct regulator *reg_VCN18; +static struct regulator *reg_VCN28; +static struct regulator *reg_VCN33_BT; +static struct regulator *reg_VCN33_WIFI; +static struct pinctrl *consys_pinctrl; +static struct pinctrl *mt6625_spi_pinctrl; +static struct pinctrl_state *mt6625_spi_default; +static struct regmap *pmic_regmap; +#define DYNAMIC_DUMP_GROUP_NUM 5 + +static const struct of_device_id apwmt_of_ids[] = { + {.compatible = "mediatek,mt7623-consys",} +}; +MODULE_DEVICE_TABLE(of, apwmt_of_ids); + +static struct platform_driver mtk_wmt_dev_drv = { + .probe = mtk_wmt_probe, + .remove = mtk_wmt_remove, + .driver = { + .name = "mt7623consys", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(apwmt_of_ids), + }, +}; + +static INT32 mtk_wmt_probe(struct platform_device *pdev) +{ + int ret = 0; + struct device_node *node = NULL; + + pm_runtime_enable(&pdev->dev); + my_pdev = pdev; + mt6625_spi_pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(mt6625_spi_pinctrl)) { + ret = PTR_ERR(mt6625_spi_pinctrl); + WMT_PLAT_ERR_FUNC("Wmt cannot find pinctrl!\n"); + goto set_pin_exit; + } + mt6625_spi_default = pinctrl_lookup_state(mt6625_spi_pinctrl, "consys_pins_default"); + if (IS_ERR(mt6625_spi_default)) { + ret = PTR_ERR(mt6625_spi_default); + WMT_PLAT_ERR_FUNC("Wmt Cannot find pinctrl default!\n"); + goto set_pin_exit; + } + pinctrl_select_state(mt6625_spi_pinctrl, mt6625_spi_default); +set_pin_exit: + + node = of_parse_phandle(pdev->dev.of_node, "mediatek,pwrap-regmap", 0); + if (node) { + pmic_regmap = pwrap_node_to_regmap(node); + if (IS_ERR(pmic_regmap)) + goto set_pmic_wrap_exit; + } else { + WMT_PLAT_ERR_FUNC("Pwrap node has not register regmap.\n"); + goto set_pmic_wrap_exit; + } +set_pmic_wrap_exit: + + clk_infra_conn_main = devm_clk_get(&pdev->dev, "consysbus"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_ERR_FUNC("sean debug [CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_DBG_FUNC("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); + + reg_VCN18 = devm_regulator_get(&pdev->dev, "vcn18"); + if (IS_ERR(reg_VCN18)) { + ret = PTR_ERR(reg_VCN18); + WMT_PLAT_ERR_FUNC("Regulator_get VCN_1V8 fail, ret=%d\n", ret); + } + reg_VCN28 = devm_regulator_get(&pdev->dev, "vcn28"); + if (IS_ERR(reg_VCN28)) { + ret = PTR_ERR(reg_VCN28); + WMT_PLAT_ERR_FUNC("Regulator_get VCN_2V8 fail, ret=%d\n", ret); + } + reg_VCN33_BT = devm_regulator_get(&pdev->dev, "vcn33_bt"); + if (IS_ERR(reg_VCN33_BT)) { + ret = PTR_ERR(reg_VCN33_BT); + WMT_PLAT_ERR_FUNC("Regulator_get VCN33_BT fail, ret=%d\n", ret); + } + reg_VCN33_WIFI = devm_regulator_get(&pdev->dev, "vcn33_wifi"); + if (IS_ERR(reg_VCN33_WIFI)) { + ret = PTR_ERR(reg_VCN33_WIFI); + WMT_PLAT_ERR_FUNC("Regulator_get VCN33_WIFI fail, ret=%d\n", ret); + } + + rstc = devm_reset_control_get(&pdev->dev, "connsys"); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + WMT_PLAT_ERR_FUNC("CanNot get consys reset. ret=%d\n", ret); + return PTR_ERR(rstc); + } + + consys_pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(consys_pinctrl)) { + ret = PTR_ERR(consys_pinctrl); + WMT_PLAT_ERR_FUNC("CanNot find consys pinctrl. ret=%d\n", ret); + return PTR_ERR(consys_pinctrl); + } + return 0; +} + +static INT32 mtk_wmt_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +VOID mtk_wcn_consys_power_on(VOID) +{ + INT32 iRet = -1; +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + iRet = pm_runtime_get_sync(&my_pdev->dev); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + if (iRet) + WMT_PLAT_ERR_FUNC("pm_runtime_get_sync() fail(%d)\n", iRet); + else + WMT_PLAT_INFO_FUNC("pm_runtime_get_sync() CONSYS ok\n"); + + iRet = device_init_wakeup(&my_pdev->dev, true); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + if (iRet) + WMT_PLAT_ERR_FUNC("device_init_wakeup(true) fail.\n"); + else + WMT_PLAT_INFO_FUNC("device_init_wakeup(true) CONSYS ok\n"); +} + +VOID mtk_wcn_consys_power_off(VOID) +{ + INT32 iRet = -1; + + iRet = pm_runtime_put_sync(&my_pdev->dev); + if (iRet) + WMT_PLAT_ERR_FUNC("pm_runtime_put_sync() fail.\n"); + else + WMT_PLAT_INFO_FUNC("pm_runtime_put_sync() CONSYS ok\n"); + + iRet = device_init_wakeup(&my_pdev->dev, false); + if (iRet) + WMT_PLAT_ERR_FUNC("device_init_wakeup(false) fail.\n"); + else + WMT_PLAT_INFO_FUNC("device_init_wakeup(false) CONSYS ok\n"); +} + +INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_type) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + + WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),start\n", on); + if (on) { + WMT_PLAT_DBG_FUNC("++\n"); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ + if (reg_VCN18) { +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + regulator_set_voltage(reg_VCN18, 1800000, 1800000); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_ERR_FUNC("enable VCN18 fail\n"); + else + WMT_PLAT_DBG_FUNC("enable VCN18 ok\n"); + } + udelay(150); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + if (co_clock_type) { + /*step0,clk buf ctrl */ + WMT_PLAT_INFO_FUNC("co clock type(%d),turn on clk buf\n", co_clock_type); +#if CONSYS_CLOCK_BUF_CTRL + clk_buf_ctrl(CLK_BUF_CONN, 1); +#endif + /*if co-clock mode: */ + /*2.set VCN28 to SW control mode (with PMIC_WRAP API) */ + /*turn on VCN28 LDO only when FMSYS is activated" */ + regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ + } else { + /*if NOT co-clock: */ + /*2.1.switch VCN28 to HW control mode (with PMIC_WRAP API) */ + regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x1 << 14);/*V28*/ + /*2.2.turn on VCN28 LDO (with PMIC_WRAP API)" */ + /*fix vcn28 not balance warning */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_ERR_FUNC("enable VCN_2V8 fail!\n"); + else + WMT_PLAT_DBG_FUNC("enable VCN_2V8 ok\n"); + } + } + + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + reset_control_reset(rstc); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + mtk_wcn_consys_power_on(); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + /*11.26M is ready now, delay 10us for mem_pd de-assert */ + udelay(10); + /*enable AP bus clock : connmcu_bus_pd API: enable_clock() ++?? */ + clk_prepare_enable(clk_infra_conn_main); +printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__); + WMT_PLAT_DBG_FUNC("[CCF]enable clk_infra_conn_main\n"); + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET) - 0xf6d; + + if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { + WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + if ((consysHwChipId == 0x8163) || (consysHwChipId == 0x8127) || (consysHwChipId == 0x7623)) { + WMT_PLAT_INFO_FUNC("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + + WMT_PLAT_ERR_FUNC("Read CONSYS chipId(0x%08x)", consysHwChipId); + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) + WMT_PLAT_ERR_FUNC("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + + msleep(40); + + } else { + + clk_disable_unprepare(clk_infra_conn_main); + WMT_PLAT_DBG_FUNC("[CCF] clk_disable_unprepare(clk_infra_conn_main) calling\n"); + mtk_wcn_consys_power_off(); + + if (co_clock_type) { + /*VCN28 has been turned off by GPS OR FM */ +#if CONSYS_CLOCK_BUF_CTRL + clk_buf_ctrl(CLK_BUF_CONN, 0); +#endif + } else { + regmap_update_bits(pmic_regmap, 0x41C, 0x1 << 14, 0x0 << 14);/*V28*/ + /*turn off VCN28 LDO (with PMIC_WRAP API)" */ + if (reg_VCN28) { + if (regulator_disable(reg_VCN28)) + WMT_PLAT_ERR_FUNC("disable VCN_2V8 fail!\n"); + else + WMT_PLAT_DBG_FUNC("disable VCN_2V8 ok\n"); + } + } + + /*AP power off MT6625L VCN_1V8 LDO */ + regulator_set_mode(reg_VCN18, REGULATOR_MODE_STANDBY); + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_ERR_FUNC("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_DBG_FUNC("disable VCN_1V8 ok\n"); + } + + } + WMT_PLAT_DBG_FUNC("CONSYS-HW-REG-CTRL(0x%08x),finish\n", on); + return 0; +} + +INT32 mtk_wcn_consys_hw_gpio_ctrl(UINT32 on) +{ + INT32 iRet = 0; + + WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), start\n", on); + + if (on) { + + /* TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok */ + /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); */ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ registered and disabled\n"); + + } else { + + /* set bgf eint/all eint to deinit state, namely input low state */ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); + WMT_PLAT_DBG_FUNC("CONSYS-HW, BGF IRQ unregistered and disabled\n"); + /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); */ + } + WMT_PLAT_DBG_FUNC("CONSYS-HW-GPIO-CTRL(0x%08x), finish\n", on); + return iRet; + +} + +INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, start\n"); + + iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); + iRet += mtk_wcn_consys_hw_gpio_ctrl(1); + + WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-ON, finish(%d)\n", iRet); + return iRet; +} + +INT32 mtk_wcn_consys_hw_pwr_off(VOID) +{ + INT32 iRet = 0; + + WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, start\n"); + + iRet += mtk_wcn_consys_hw_reg_ctrl(0, 0); + iRet += mtk_wcn_consys_hw_gpio_ctrl(0); + + WMT_PLAT_INFO_FUNC("CONSYS-HW-PWR-OFF, finish(%d)\n", iRet); + return iRet; +} + +INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst start, eirq should be disabled before this step\n"); + + /*1. do whole hw power off flow */ + iRet += mtk_wcn_consys_hw_reg_ctrl(0, co_clock_type); + + /*2. do whole hw power on flow */ + iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); + + WMT_PLAT_INFO_FUNC("CONSYS-HW, hw_rst finish, eirq should be enabled after this step\n"); + return iRet; +} + +#if CONSYS_BT_WIFI_SHARE_V33 +INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) +{ + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (1 == gBtWifiV33.counter) { + gBtWifiV33.counter++; + WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (2 == gBtWifiV33.counter) { + WMT_PLAT_DBG_FUNC("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6323_POWER_LDO_VCN33, VOL_3300, "wcn_drv"); + upmu_set_vcn33_on_ctrl_bt(1); +#endif + WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (1 == gBtWifiV33.counter) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + upmu_set_vcn33_on_ctrl_bt(0); + hwPowerDown(MT6323_POWER_LDO_VCN33, "wcn_drv"); +#endif + WMT_PLAT_INFO_FUNC("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (2 == gBtWifiV33.counter) { + gBtWifiV33.counter--; + WMT_PLAT_DBG_FUNC("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_DBG_FUNC("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ + return 0; +} + +INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) +{ + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); + return 0; +} + +#else +INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) +{ + + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_ERR_FUNC("WMT do BT PMIC on fail!\n"); + } + regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x1 << 5);/*BT*/ + WMT_PLAT_INFO_FUNC("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ + regmap_update_bits(pmic_regmap, 0x416, 0x1 << 5, 0x0 << 5);/*BT*/ + if (reg_VCN33_BT) + if (regulator_disable(reg_VCN33_BT)) + WMT_PLAT_ERR_FUNC("WMT do BT PMIC off fail!\n"); + WMT_PLAT_INFO_FUNC("WMT do BT PMIC off\n"); + } + + return 0; + +} + +INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) +{ + + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC on fail!\n"); + else + WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on !\n"); + } + regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x1 << 14);/*WIFI*/ + WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ + regmap_update_bits(pmic_regmap, 0x418, 0x1 << 14, 0x0 << 14);/*WIFI*/ + if (reg_VCN33_WIFI) + if (regulator_disable(reg_VCN33_WIFI)) + WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC off fail!\n"); + WMT_PLAT_INFO_FUNC("WMT do WIFI PMIC off\n"); + } + + return 0; +} + +#endif +INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) +{ + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_INFO_FUNC("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + if (regulator_disable(reg_VCN28)) + WMT_PLAT_ERR_FUNC("WMT do VCN28 PMIC off fail!\n"); + WMT_PLAT_INFO_FUNC("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } + return 0; +} + +INT32 mtk_wcn_consys_hw_state_show(VOID) +{ + return 0; +} + +INT32 mtk_wcn_consys_hw_restore(struct device *device) +{ + UINT32 addrPhy = 0; + + if (gConEmiPhyBase) { + +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); + +#if 0 + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, + gConEmiPhyBase + SZ_1M, + 5, + SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); + + +#else + WMT_PLAT_WARN_FUNC("not define platform config\n"); +#endif + +#endif + /*consys to ap emi remapping register:10001310, cal remapping address */ + addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + +#if 1 + pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); +#else + pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); +#endif + if (pEmibaseaddr) { + WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); + memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); + } + } else { + WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); + } + + return 0; +} + +/*Reserved memory by device tree!*/ +int reserve_memory_consys_fn(struct reserved_mem *rmem) +{ + WMT_PLAT_WARN_FUNC(" name: %s, base: 0x%llx, size: 0x%llx\n", rmem->name, + (unsigned long long)rmem->base, (unsigned long long)rmem->size); + gConEmiPhyBase = rmem->base; + return 0; +} + +RESERVEDMEM_OF_DECLARE(reserve_memory_test, "mediatek,consys-reserve-memory", reserve_memory_consys_fn); + + +INT32 mtk_wcn_consys_hw_init(void) +{ + + INT32 iRet = -1; + UINT32 addrPhy = 0; + INT32 i = 0; + struct device_node *node = NULL; + + node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, i); + WMT_PLAT_DBG_FUNC("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + i++; + + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, i); + WMT_PLAT_DBG_FUNC("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + i++; + } else { + WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + if (gConEmiPhyBase) { +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_INFO_FUNC("setting MPU for EMI share memory\n"); + +#if 0 + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, + gConEmiPhyBase + SZ_1M, + 5, + SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#else + WMT_PLAT_WARN_FUNC("not define platform config\n"); +#endif + +#endif + WMT_PLAT_DBG_FUNC("get consys start phy address(0x%zx)\n", (SIZE_T) gConEmiPhyBase); + + /*consys to ap emi remapping register:10001310, cal remapping address */ + addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_INFO_FUNC("CONSYS_EMI_MAPPING dump(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + +#if 1 + pEmibaseaddr = ioremap_nocache(gConEmiPhyBase + CONSYS_EMI_AP_PHY_OFFSET, CONSYS_EMI_MEM_SIZE); +#else + pEmibaseaddr = ioremap_nocache(CONSYS_EMI_AP_PHY_BASE, CONSYS_EMI_MEM_SIZE); +#endif + /* pEmibaseaddr = ioremap_nocache(0x80090400,270*KBYTE); */ + if (pEmibaseaddr) { + WMT_PLAT_INFO_FUNC("EMI mapping OK(0x%p)\n", pEmibaseaddr); + memset_io(pEmibaseaddr, 0, CONSYS_EMI_MEM_SIZE); + iRet = 0; + } else { + WMT_PLAT_ERR_FUNC("EMI mapping fail\n"); + } + } else { + WMT_PLAT_ERR_FUNC("consys emi memory address gConEmiPhyBase invalid\n"); + } +#ifdef CONFIG_MTK_HIBERNATION + WMT_PLAT_INFO_FUNC("register connsys restore cb for complying with IPOH function\n"); + register_swsusp_restore_noirq_func(ID_M_CONNSYS, mtk_wcn_consys_hw_restore, NULL); +#endif + iRet = platform_driver_register(&mtk_wmt_dev_drv); + if (iRet) + WMT_PLAT_ERR_FUNC("WMT platform driver registered failed(%d)\n", iRet); + return iRet; +} + +INT32 mtk_wcn_consys_hw_deinit(void) +{ + if (pEmibaseaddr) { + iounmap(pEmibaseaddr); + pEmibaseaddr = NULL; + } +#ifdef CONFIG_MTK_HIBERNATION + unregister_swsusp_restore_noirq_func(ID_M_CONNSYS); +#endif + + platform_driver_unregister(&mtk_wmt_dev_drv); + return 0; +} + +UINT8 *mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset) +{ + UINT8 *p_virtual_addr = NULL; + + if (!pEmibaseaddr) { + WMT_PLAT_ERR_FUNC("EMI base address is NULL\n"); + return NULL; + } + WMT_PLAT_DBG_FUNC("ctrl_state_offset(%08x)\n", ctrl_state_offset); + p_virtual_addr = pEmibaseaddr + ctrl_state_offset; + + return p_virtual_addr; +} + +UINT32 mtk_wcn_consys_soc_chipid(void) +{ + return PLATFORM_SOC_CHIP; +} + +struct pinctrl *mtk_wcn_consys_get_pinctrl() +{ + return consys_pinctrl; +} +INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 str_buf) +{ + PUINT8 vir_addr = NULL; + + vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP); + if (!vir_addr) { + WMT_PLAT_ERR_FUNC("get vir address fail\n"); + return -2; + } + memcpy(vir_addr, str_buf, DYNAMIC_DUMP_GROUP_NUM*8); + WMT_PLAT_INFO_FUNC("dynamic dump register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c new file mode 100644 index 0000000000000..3a3be8308f6af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/conn_soc/mt7623/wmt_plat_alps.c @@ -0,0 +1,1071 @@ +/*! \file + \brief Declaration of library functions + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-PLAT]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include + +/* ALPS header files */ +/*#include */ +/*#include */ +#if defined(CONFIG_MTK_GPIO_LEGACY) +#include +#endif +#include + +/* MTK_WCN_COMBO header files */ +#include "osal_typedef.h" +#include "mtk_wcn_consys_hw.h" +#include "stp_dbg.h" + +#define CFG_WMT_WAKELOCK_SUPPORT 1 + +#ifdef CONFIG_MTK_MT6306_SUPPORT +#define MTK_WCN_MT6306_IS_READY 1 +#else +#define MTK_WCN_MT6306_IS_READY 0 +#endif + +#if MTK_WCN_MT6306_IS_READY +#include + +#ifdef GPIO_GPS_LNA_PIN +#undef GPIO_GPS_LNA_PIN +#endif + +#define GPIO_GPS_LNA_PIN GPIO7 +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static VOID wmt_plat_bgf_eirq_cb(VOID); + +static INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state); + +static INT32 wmt_plat_dump_pin_conf(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +UINT32 gCoClockFlag = 0; +BGF_IRQ_BALANCE gbgfIrqBle; +UINT32 wmtPlatLogLvl = WMT_PLAT_LOG_DBG; +#if CONSYS_BT_WIFI_SHARE_V33 +BT_WIFI_V33_STATUS gBtWifiV33; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if CFG_WMT_WAKELOCK_SUPPORT +static struct mutex gOsSLock; +#ifdef CONFIG_PM_WAKELOCKS +static struct wakeup_source wmtWakeLock; +#else +static struct wake_lock wmtWakeLock; +#endif +#endif + +irq_cb wmt_plat_bgf_irq_cb = NULL; +device_audio_if_cb wmt_plat_audio_if_cb = NULL; +func_ctrl_cb wmt_plat_func_ctrl_cb = NULL; +thermal_query_ctrl_cb wmt_plat_thermal_query_ctrl_cb = NULL; +deep_idle_ctrl_cb wmt_plat_deep_idle_ctrl_cb = NULL; + +static const fp_set_pin gfp_set_pin_table[] = { + [PIN_BGF_EINT] = wmt_plat_bgf_eint_ctrl, + [PIN_I2S_GRP] = wmt_plat_i2s_ctrl, + [PIN_GPS_SYNC] = wmt_plat_gps_sync_ctrl, + [PIN_GPS_LNA] = wmt_plat_gps_lna_ctrl, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*! + * \brief audio control callback function for CMB_STUB on ALPS + * + * A platform function required for dynamic binding with CMB_STUB on ALPS. + * + * \param state desired audio interface state to use + * \param flag audio interface control options + * + * \retval 0 operation success + * \retval -1 invalid parameters + * \retval < 0 error for operation fail + */ +INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + INT32 iRet = 0; + UINT32 pinShare = 0; + + /* input sanity check */ + if ((CMB_STUB_AIF_MAX <= state) + || (CMB_STUB_AIF_CTRL_MAX <= ctrl)) { + return -1; + } + + iRet = 0; + + /* set host side first */ + switch (state) { + case CMB_STUB_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + break; + + case CMB_STUB_AIF_1: + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + break; + + case CMB_STUB_AIF_2: + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + case CMB_STUB_AIF_3: + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + default: + /* FIXME: move to cust folder? */ + WMT_PLAT_ERR_FUNC("invalid state [%d]\n", state); + iRet = -1; + break; + } + + if (CMB_STUB_AIF_CTRL_EN == ctrl) { + WMT_PLAT_INFO_FUNC("call chip aif setting\n"); + /* need to control chip side GPIO */ + if (NULL != wmt_plat_audio_if_cb) { + iRet += (*wmt_plat_audio_if_cb) (state, (pinShare) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); + } else { + WMT_PLAT_WARN_FUNC("wmt_plat_audio_if_cb is not registered\n"); + iRet -= 1; + } + + } else { + WMT_PLAT_INFO_FUNC("skip chip aif setting\n"); + } + + return iRet; + +} + +static VOID wmt_plat_func_ctrl(UINT32 type, UINT32 on) +{ + if (wmt_plat_func_ctrl_cb) + (*wmt_plat_func_ctrl_cb) (on, type); +} + +static long wmt_plat_thermal_ctrl(VOID) +{ + long temp = 0; + + if (wmt_plat_thermal_query_ctrl_cb) + temp = (*wmt_plat_thermal_query_ctrl_cb) (); + + return temp; +} + +static INT32 wmt_plat_deep_idle_ctrl(UINT32 dpilde_ctrl) +{ + INT32 iRet = -1; + + if (wmt_plat_deep_idle_ctrl_cb) + iRet = (*wmt_plat_deep_idle_ctrl_cb) (dpilde_ctrl); + + return iRet; +} + +static VOID wmt_plat_bgf_eirq_cb(VOID) +{ +#if CFG_WMT_PS_SUPPORT +/* #error "need to disable EINT here" */ + /* wmt_lib_ps_irq_cb(); */ + if (NULL != wmt_plat_bgf_irq_cb) + (*(wmt_plat_bgf_irq_cb)) (); + else + WMT_PLAT_WARN_FUNC("WMT-PLAT: wmt_plat_bgf_irq_cb not registered\n"); +#else + return; +#endif + +} + +irqreturn_t wmt_plat_bgf_irq_isr(INT32 i, VOID *arg) +{ +#if CFG_WMT_PS_SUPPORT + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + wmt_plat_bgf_eirq_cb(); +#else + WMT_PLAT_INFO_FUNC("skip irq handing because psm is disable"); +#endif + return IRQ_HANDLED; +} + +VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb) +{ + wmt_plat_bgf_irq_cb = bgf_irq_cb; +} +EXPORT_SYMBOL(wmt_plat_irq_cb_reg); + +VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb) +{ + wmt_plat_audio_if_cb = aif_ctrl_cb; +} +EXPORT_SYMBOL(wmt_plat_aif_cb_reg); + +VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl) +{ + wmt_plat_func_ctrl_cb = subsys_func_ctrl; +} +EXPORT_SYMBOL(wmt_plat_func_ctrl_cb_reg); + +VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl) +{ + wmt_plat_thermal_query_ctrl_cb = thermal_query_ctrl; +} +EXPORT_SYMBOL(wmt_plat_thermal_ctrl_cb_reg); + +VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl) +{ + wmt_plat_deep_idle_ctrl_cb = deep_idle_ctrl; +} +EXPORT_SYMBOL(wmt_plat_deep_idle_ctrl_cb_reg); + +UINT32 wmt_plat_soc_co_clock_flag_get(VOID) +{ + return gCoClockFlag; +} + +static UINT32 wmt_plat_soc_co_clock_flag_set(UINT32 flag) +{ + gCoClockFlag = flag; + return 0; +} + +INT32 wmt_plat_init(UINT32 co_clock_type) +{ + CMB_STUB_CB stub_cb; + INT32 iret; + /*init wmt function ctrl wakelock if wake lock is supported by host platform */ + + wmt_plat_soc_co_clock_flag_set(co_clock_type); + + stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; + stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; + stub_cb.thermal_query_cb = wmt_plat_thermal_ctrl; + stub_cb.deep_idle_ctrl_cb = wmt_plat_deep_idle_ctrl; + stub_cb.size = sizeof(stub_cb); + + /* register to cmb_stub */ + iret = mtk_wcn_cmb_stub_reg(&stub_cb); +#ifdef CFG_WMT_WAKELOCK_SUPPORT +#ifdef CONFIG_PM_WAKELOCKS + wakeup_source_init(&wmtWakeLock, "wmtFuncCtrl"); +#else + wake_lock_init(&wmtWakeLock, WAKE_LOCK_SUSPEND, "wmtFuncCtrl"); +#endif + mutex_init(&gOsSLock); +#endif + +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + + iret += mtk_wcn_consys_hw_init(); + + spin_lock_init(&gbgfIrqBle.lock); + WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} +EXPORT_SYMBOL(wmt_plat_init); + +INT32 wmt_plat_deinit(VOID) +{ + INT32 iret = 0; + /* 2. unreg to cmb_stub */ + iret = mtk_wcn_cmb_stub_unreg(); +printk(KERN_ALERT "DEBUG: Passed %s %d now calling wmt wakelock deinit\n",__FUNCTION__,__LINE__); + /*3. wmt wakelock deinit */ +#ifdef CFG_WMT_WAKELOCK_SUPPORT +#ifdef CONFIG_PM_WAKELOCKS +printk(KERN_ALERT "DEBUG: Passed %s %d now calling wakeup_source_trash\n",__FUNCTION__,__LINE__); + wakeup_source_trash(&wmtWakeLock); +#else +printk(KERN_ALERT "DEBUG: Passed %s %d now calling wake lock destroy %d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); +//destroy calls wakeup_source_trash with &lock->ws +printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock:%d\n",__FUNCTION__,__LINE__,(int)&wmtWakeLock); +printk(KERN_ALERT "DEBUG: Passed %s %d now wmtWakeLock->ws: %d\n",__FUNCTION__,__LINE__,(int)&(wmtWakeLock.ws)); + wake_lock_destroy(&wmtWakeLock); +#endif +printk(KERN_ALERT "DEBUG: Passed %s %d now calling mutex_destroy\n",__FUNCTION__,__LINE__); + mutex_destroy(&gOsSLock); + WMT_PLAT_DBG_FUNC("destroy wmtWakeLock\n"); +#endif +printk(KERN_ALERT "DEBUG: Passed %s %d now calling consys hw deinit\n",__FUNCTION__,__LINE__); + + iret += mtk_wcn_consys_hw_deinit(); + + WMT_PLAT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} +EXPORT_SYMBOL(wmt_plat_deinit); + +static INT32 wmt_plat_dump_pin_conf(VOID) +{ + WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration start<=\n"); +#if defined(CONFIG_MTK_GPIO_LEGACY) + +#ifdef GPIO_COMBO_BGF_EINT_PIN + WMT_PLAT_DBG_FUNC("BGF_EINT(GPIO%d)\n", GPIO_COMBO_BGF_EINT_PIN); +#else + WMT_PLAT_DBG_FUNC("BGF_EINT(not defined)\n"); +#endif + +#ifdef CUST_EINT_COMBO_BGF_NUM + WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(%d)\n", CUST_EINT_COMBO_BGF_NUM); +#else + WMT_PLAT_DBG_FUNC("BGF_EINT_NUM(not defined)\n"); +#endif + +#ifdef GPIO_COMBO_URXD_PIN + WMT_PLAT_DBG_FUNC("UART_RX(GPIO%d)\n", GPIO_COMBO_URXD_PIN); +#else + WMT_PLAT_DBG_FUNC("UART_RX(not defined)\n"); +#endif +#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) +#ifdef GPIO_COMBO_I2S_CK_PIN + WMT_PLAT_DBG_FUNC("I2S_CK(GPIO%d)\n", GPIO_COMBO_I2S_CK_PIN); +#else + WMT_PLAT_DBG_FUNC("I2S_CK(not defined)\n"); +#endif +#ifdef GPIO_COMBO_I2S_WS_PIN + WMT_PLAT_DBG_FUNC("I2S_WS(GPIO%d)\n", GPIO_COMBO_I2S_WS_PIN); +#else + WMT_PLAT_DBG_FUNC("I2S_WS(not defined)\n"); +#endif +#ifdef GPIO_COMBO_I2S_DAT_PIN + WMT_PLAT_DBG_FUNC("I2S_DAT(GPIO%d)\n", GPIO_COMBO_I2S_DAT_PIN); +#else + WMT_PLAT_DBG_FUNC("I2S_DAT(not defined)\n"); +#endif +#else /* FM_ANALOG_INPUT || FM_ANALOG_OUTPUT */ + WMT_PLAT_DBG_FUNC("FM digital mode is not set, no need for I2S GPIOs\n"); +#endif +#ifdef GPIO_GPS_SYNC_PIN + WMT_PLAT_DBG_FUNC("GPS_SYNC(GPIO%d)\n", GPIO_GPS_SYNC_PIN); +#else + WMT_PLAT_DBG_FUNC("GPS_SYNC(not defined)\n"); +#endif + +#ifdef GPIO_GPS_LNA_PIN + WMT_PLAT_INFO_FUNC("GPS_LNA(GPIO%d)\n", GPIO_GPS_LNA_PIN); +#else + WMT_PLAT_INFO_FUNC("GPS_LNA(not defined)\n"); +#endif + +#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ +#endif + WMT_PLAT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration emds<=\n"); + return 0; +} + +INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state) +{ + INT32 ret = -1; + + switch (state) { + case FUNC_ON: + /* TODO:[ChangeFeature][George] always output this or by request throuth /proc or sysfs? */ + wmt_plat_dump_pin_conf(); + ret = mtk_wcn_consys_hw_pwr_on(gCoClockFlag); + break; + + case FUNC_OFF: + ret = mtk_wcn_consys_hw_pwr_off(); + break; + + case FUNC_RST: + ret = mtk_wcn_consys_hw_rst(gCoClockFlag); + break; + case FUNC_STAT: + ret = mtk_wcn_consys_hw_state_show(); + break; + default: + WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) in pwr_ctrl\n", state); + break; + } + + return ret; +} +EXPORT_SYMBOL(wmt_plat_pwr_ctrl); + +INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) +{ +#ifdef CONFIG_OF + struct device_node *node; + unsigned int irq_info[3] = { 0, 0, 0 }; +#endif + INT32 iret = -EINVAL; + static INT32 bgf_irq_num = -1; + static UINT32 bgf_irq_flag; + /* TODO: [ChangeFeature][GeorgeKuo]: use another function to handle this, as done in gpio_ctrls */ + + if ((PIN_STA_INIT != state) + && (PIN_STA_DEINIT != state) + && (PIN_STA_EINT_EN != state) + && (PIN_STA_EINT_DIS != state)) { + WMT_PLAT_WARN_FUNC("WMT-PLAT:invalid PIN_STATE(%d) in eirq_ctrl for PIN(%d)\n", state, id); + return -1; + } + + switch (id) { + case PIN_BGF_EINT: + + if (PIN_STA_INIT == state) { +#ifdef CONFIG_OF + node = of_find_compatible_node(NULL, NULL, "mediatek,mt7623-consys"); + if (node) { + bgf_irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_ERR_FUNC("get irq flags from DTS fail!!\n"); + return iret; + } + bgf_irq_flag = irq_info[2]; + WMT_PLAT_INFO_FUNC("get irq id(%d) and irq trigger flag(%d) from DT\n", bgf_irq_num, + bgf_irq_flag); + } else { + WMT_PLAT_ERR_FUNC("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#else + bgf_irq_num = MT_CONN2AP_BTIF_WAKEUP_IRQ_ID; + bgf_irq_flag = IRQF_TRIGGER_LOW; +#endif + iret = request_irq(bgf_irq_num, wmt_plat_bgf_irq_isr, bgf_irq_flag, "BTIF_WAKEUP_IRQ", NULL); + if (iret) { + WMT_PLAT_ERR_FUNC("request_irq fail,irq_no(%d),iret(%d)\n", bgf_irq_num, iret); + return iret; + } + gbgfIrqBle.counter = 1; + + } else if (PIN_STA_EINT_EN == state) { + + spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); + if (gbgfIrqBle.counter) { + WMT_PLAT_DBG_FUNC("BGF INT has been enabled,counter(%d)\n", gbgfIrqBle.counter); + } else { + enable_irq(bgf_irq_num); + gbgfIrqBle.counter++; + } + WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (en)\n"); + spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); + } else if (PIN_STA_EINT_DIS == state) { + spin_lock_irqsave(&gbgfIrqBle.lock, gbgfIrqBle.flags); + if (!gbgfIrqBle.counter) { + WMT_PLAT_INFO_FUNC("BGF INT has been disabled,counter(%d)\n", gbgfIrqBle.counter); + } else { + disable_irq_nosync(bgf_irq_num); + gbgfIrqBle.counter--; + } + WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt (dis)\n"); + spin_unlock_irqrestore(&gbgfIrqBle.lock, gbgfIrqBle.flags); + } else { + free_irq(bgf_irq_num, NULL); + /* de-init: nothing to do in ALPS, such as un-registration... */ + } + iret = 0; + break; + + default: + WMT_PLAT_WARN_FUNC("WMT-PLAT:unsupported EIRQ(PIN_ID:%d) in eirq_ctrl\n", id); + iret = -1; + break; + } + + return iret; +} +EXPORT_SYMBOL(wmt_plat_eirq_ctrl); + +INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) +{ + if ((PIN_ID_MAX > id) + && (PIN_STA_MAX > state)) { + + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + if (gfp_set_pin_table[id]) + return (*(gfp_set_pin_table[id])) (state); /* .handler */ + WMT_PLAT_WARN_FUNC("WMT-PLAT: null fp for gpio_ctrl(%d)\n", id); + return -2; + } + return -1; +} +EXPORT_SYMBOL(wmt_plat_gpio_ctrl); + +INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state) +{ +#if defined(CONFIG_MTK_GPIO_LEGACY) +#ifdef GPIO_COMBO_BGF_EINT_PIN + switch (state) { + case PIN_STA_INIT: + /*set to gpio input low, pull down enable */ + mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); + mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); + mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); + WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt init(in pd)\n"); + break; + + case PIN_STA_MUX: + mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); + mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_UP); + mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_EINT); + WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt mux (eint)\n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + mt_set_gpio_mode(GPIO_COMBO_BGF_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_COMBO_BGF_EINT_PIN, GPIO_DIR_IN); + mt_set_gpio_pull_select(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_DOWN); + mt_set_gpio_pull_enable(GPIO_COMBO_BGF_EINT_PIN, GPIO_PULL_ENABLE); + WMT_PLAT_DBG_FUNC("WMT-PLAT:BGFInt deinit(in pd)\n"); + break; + + default: + WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on BGF EINT\n", state); + break; + } +#else + WMT_PLAT_INFO_FUNC("WMT-PLAT:BGF EINT not defined\n"); +#endif +#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ +#endif + return 0; +} + +static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state) +{ +#if defined(CONFIG_MTK_GPIO_LEGACY) + +#ifdef GPIO_GPS_SYNC_PIN +#ifndef GPIO_GPS_SYNC_PIN_M_GPS_SYNC +#ifdef GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC +#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD1_GPS_SYNC +#else +#ifdef GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC +#define GPIO_GPS_SYNC_PIN_M_GPS_SYNC GPIO_GPS_SYNC_PIN_M_MD2_GPS_SYNC +#endif +#endif +#endif + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_GPS_SYNC_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_GPS_SYNC_PIN, GPIO_OUT_ZERO); + break; + + case PIN_STA_MUX: + mt_set_gpio_mode(GPIO_GPS_SYNC_PIN, GPIO_GPS_SYNC_PIN_M_GPS_SYNC); + break; + + default: + break; + } +#endif + +#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ +#endif + return 0; +} + +#if MTK_WCN_MT6306_IS_READY +/* MT6306 GPIO7 is GPIO_GPS_LNA_EN, for K2 common phone pin modification */ +static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) +{ +#ifdef GPIO_GPS_LNA_PIN + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + WMT_PLAT_ERR_FUNC("Gps LNA pin ctrl %d!\n", state); + mt6306_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); + mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); + break; + case PIN_STA_OUT_H: + WMT_PLAT_ERR_FUNC("Gps LNA pin output high!\n"); + mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); + break; + case PIN_STA_OUT_L: + WMT_PLAT_ERR_FUNC("Gps LNA pin output low!\n"); + mt6306_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); + break; + default: + WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } + return 0; +#else + WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); + return 0; +#endif +} +#else + +static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) +{ +#if !defined(CONFIG_MTK_GPIO_LEGACY) + static struct pinctrl_state *gps_lna_init; + static struct pinctrl_state *gps_lna_oh; + static struct pinctrl_state *gps_lna_ol; + static struct pinctrl *consys_pinctrl; + + WMT_PLAT_DBG_FUNC("ENTER++\n"); + consys_pinctrl = mtk_wcn_consys_get_pinctrl(); + if (NULL == consys_pinctrl) { + WMT_PLAT_ERR_FUNC("get consys pinctrl fail\n"); + return -1; + } + + gps_lna_init = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_init"); + if (NULL == gps_lna_init) { + WMT_PLAT_ERR_FUNC("Cannot find gps lna pin init state!\n"); + return -2; + } + + gps_lna_oh = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_oh"); + if (NULL == gps_lna_oh) { + WMT_PLAT_ERR_FUNC("Cannot find gps lna pin oh state!\n"); + return -3; + } + + gps_lna_ol = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_ol"); + if (NULL == gps_lna_ol) { + WMT_PLAT_ERR_FUNC("Cannot find gps lna pin ol state!\n"); + return -4; + } + + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + pinctrl_select_state(consys_pinctrl, gps_lna_init); + WMT_PLAT_INFO_FUNC("set gps lna to init\n"); + break; + case PIN_STA_OUT_H: + pinctrl_select_state(consys_pinctrl, gps_lna_oh); + WMT_PLAT_INFO_FUNC("set gps lna to oh\n"); + break; + case PIN_STA_OUT_L: + pinctrl_select_state(consys_pinctrl, gps_lna_ol); + WMT_PLAT_INFO_FUNC("set gps lna to ol\n"); + break; + + default: + WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } + return 0; +#else +#ifdef GPIO_GPS_LNA_PIN + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + mt_set_gpio_pull_enable(GPIO_GPS_LNA_PIN, GPIO_PULL_DISABLE); + mt_set_gpio_dir(GPIO_GPS_LNA_PIN, GPIO_DIR_OUT); + mt_set_gpio_mode(GPIO_GPS_LNA_PIN, GPIO_GPS_LNA_PIN_M_GPIO); + mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); + break; + case PIN_STA_OUT_H: + mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ONE); + break; + case PIN_STA_OUT_L: + mt_set_gpio_out(GPIO_GPS_LNA_PIN, GPIO_OUT_ZERO); + break; + + default: + WMT_PLAT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } + return 0; +#else + WMT_PLAT_WARN_FUNC("host gps lna pin not defined!!!\n"); + return 0; +#endif +#endif /* !defined(CONFIG_MTK_GPIO_LEGACY) */ +} +#endif + +INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state) +{ + /* TODO: [NewFeature][GeorgeKuo]: GPIO_I2Sx is changed according to different project. */ + /* TODO: provide a translation table in board_custom.h for different ALPS project customization. */ +#if defined(CONFIG_MTK_GPIO_LEGACY) + +#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) +#if defined(GPIO_COMBO_I2S_CK_PIN) + switch (state) { + case PIN_STA_INIT: + case PIN_STA_MUX: + mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_I2S0_CK); + mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_I2S0_WS); + mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_I2S0_DAT); + WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S init (I2S0 system)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + mt_set_gpio_mode(GPIO_COMBO_I2S_CK_PIN, GPIO_COMBO_I2S_CK_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_COMBO_I2S_CK_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_COMBO_I2S_CK_PIN, GPIO_OUT_ZERO); + + mt_set_gpio_mode(GPIO_COMBO_I2S_WS_PIN, GPIO_COMBO_I2S_WS_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_COMBO_I2S_WS_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_COMBO_I2S_WS_PIN, GPIO_OUT_ZERO); + + mt_set_gpio_mode(GPIO_COMBO_I2S_DAT_PIN, GPIO_COMBO_I2S_DAT_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_COMBO_I2S_DAT_PIN, GPIO_DIR_OUT); + mt_set_gpio_out(GPIO_COMBO_I2S_DAT_PIN, GPIO_OUT_ZERO); + WMT_PLAT_DBG_FUNC("WMT-PLAT:I2S deinit (out 0)\n"); + break; + default: + WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on I2S Group\n", state); + break; + } +#else + WMT_PLAT_ERR_FUNC("[MT6620]Error:FM digital mode set, but no I2S GPIOs defined\n"); +#endif +#else + WMT_PLAT_INFO_FUNC + ("[MT6620]warnning:FM digital mode is not set, no I2S GPIO settings should be modified by combo driver\n"); +#endif + +#else /* #if defined(CONFIG_MTK_GPIO_LEGACY) */ +#endif + return 0; +} + +INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId) +{ +#ifdef CFG_WMT_WAKELOCK_SUPPORT + static INT32 counter; + INT32 status; + INT32 ret = 0; + + ret = mutex_lock_killable(&gOsSLock); + if (ret) { + WMT_PLAT_ERR_FUNC("--->lock gOsSLock failed, ret=%d\n", ret); + return ret; + } + + if (WL_OP_GET == opId) + ++counter; + else if (WL_OP_PUT == opId) + --counter; + + mutex_unlock(&gOsSLock); + if (WL_OP_GET == opId && counter == 1) { + #ifdef CONFIG_PM_WAKELOCKS + __pm_stay_awake(&wmtWakeLock); + status = wmtWakeLock.active; + #else + wake_lock(&wmtWakeLock); + status = wake_lock_active(&wmtWakeLock); + #endif + WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_lock(%d), counter(%d)\n", status, counter); + + } else if (WL_OP_PUT == opId && counter == 0) { + #ifdef CONFIG_PM_WAKELOCKS + __pm_relax(&wmtWakeLock); + status = wmtWakeLock.active; + #else + wake_unlock(&wmtWakeLock); + status = wake_lock_active(&wmtWakeLock); + #endif + WMT_PLAT_DBG_FUNC("WMT-PLAT: after wake_unlock(%d), counter(%d)\n", status, counter); + } else { + #ifdef CONFIG_PM_WAKELOCKS + status = wmtWakeLock.active; + #else + status = wake_lock_active(&wmtWakeLock); + #endif + WMT_PLAT_WARN_FUNC("WMT-PLAT: wakelock status(%d), counter(%d)\n", status, counter); + } + return 0; +#else + WMT_PLAT_WARN_FUNC("WMT-PLAT: host awake function is not supported.\n"); + return 0; + +#endif +} +EXPORT_SYMBOL(wmt_plat_wake_lock_ctrl); + +INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo) +{ + INT32 iRet = 0; + + switch (ePt) { + + case BT_PALDO: + iRet = mtk_wcn_consys_hw_bt_paldo_ctrl(ePo); + break; + case WIFI_PALDO: + iRet = mtk_wcn_consys_hw_wifi_paldo_ctrl(ePo); + break; + case FM_PALDO: + case GPS_PALDO: + iRet = mtk_wcn_consys_hw_vcn28_ctrl(ePo); + break; + default: + WMT_PLAT_WARN_FUNC("WMT-PLAT:Warnning, invalid type(%d) in palod_ctrl\n", ePt); + break; + } + return iRet; +} +EXPORT_SYMBOL(wmt_plat_soc_paldo_ctrl); + +UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset) +{ + return mtk_wcn_consys_emi_virt_addr_get(offset); +} +EXPORT_SYMBOL(wmt_plat_get_emi_virt_add); + +P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} +EXPORT_SYMBOL(wmt_plat_get_emi_phy_add); + +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en) +{ + return 0; +} +EXPORT_SYMBOL(wmt_plat_jtag_flag_ctrl); +#endif + +#if CFG_WMT_DUMP_INT_STATUS +VOID wmt_plat_BGF_irq_dump_status(VOID) +{ + WMT_PLAT_INFO_FUNC("this function is null in MT8127\n"); +} +EXPORT_SYMBOL(wmt_plat_BGF_irq_dump_status); + +MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID) +{ + return MTK_WCN_BOOL_FALSE; +} +EXPORT_SYMBOL(wmt_plat_dump_BGF_irq_status); +#endif + +UINT32 wmt_plat_read_cpupcr(void) +{ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +} +EXPORT_SYMBOL(wmt_plat_read_cpupcr); + +UINT32 wmt_plat_read_dmaregs(UINT32 type) +{ + return 0; +#if 0 + switch (type) { + case CONNSYS_CLK_GATE_STATUS: + return CONSYS_REG_READ(CONNSYS_CLK_GATE_STATUS_REG); + case CONSYS_EMI_STATUS: + return CONSYS_REG_READ(CONSYS_EMI_STATUS_REG); + case SYSRAM1: + return CONSYS_REG_READ(SYSRAM1_REG); + case SYSRAM2: + return CONSYS_REG_READ(SYSRAM2_REG); + case SYSRAM3: + return CONSYS_REG_READ(SYSRAM3_REG); + default: + return 0; + } +#endif +} + +INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state) +{ + PUINT8 p_virtual_addr = NULL; + + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_STATE); + if (!p_virtual_addr) { + WMT_PLAT_ERR_FUNC("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, state); + + return 0; +} +EXPORT_SYMBOL(wmt_plat_set_host_dump_state); + +UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type) +{ + PUINT8 p_virtual_addr = NULL; + + switch (type) { + case STP_FORCE_TRG_ASSERT_EMI: + + WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); + if (!p_virtual_addr) { + WMT_PLAT_ERR_FUNC("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); + WMT_PLAT_INFO_FUNC("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); + break; + case STP_FORCE_TRG_ASSERT_DEBUG_PIN: + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_INFO_FUNC("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_INFO_FUNC("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + + break; + default: + WMT_PLAT_ERR_FUNC("unknown force trigger assert type\n"); + break; + } + + return 0; +} +EXPORT_SYMBOL(wmt_plat_force_trigger_assert); + +INT32 wmt_plat_update_host_sync_num(VOID) +{ + PUINT8 p_virtual_addr = NULL; + UINT32 sync_num = 0; + + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_NUM); + if (!p_virtual_addr) { + WMT_PLAT_ERR_FUNC("get virtual address fail\n"); + return -1; + } + + sync_num = CONSYS_REG_READ(p_virtual_addr); + CONSYS_REG_WRITE(p_virtual_addr, sync_num + 1); + + return 0; +} +EXPORT_SYMBOL(wmt_plat_update_host_sync_num); + +INT32 wmt_plat_get_dump_info(UINT32 offset) +{ + PUINT8 p_virtual_addr = NULL; + + p_virtual_addr = wmt_plat_get_emi_virt_add(offset); + if (!p_virtual_addr) { + WMT_PLAT_ERR_FUNC("get virtual address fail\n"); + return -1; + } + WMT_PLAT_INFO_FUNC("connsys_reg_read (0x%x), (0x%p), (0x%x)\n", CONSYS_REG_READ(p_virtual_addr), p_virtual_addr, + offset); + return CONSYS_REG_READ(p_virtual_addr); +} +EXPORT_SYMBOL(wmt_plat_get_dump_info); + +UINT32 wmt_plat_get_soc_chipid(void) +{ + UINT32 chipId = mtk_wcn_consys_soc_chipid(); + + WMT_PLAT_INFO_FUNC("current SOC chip:0x%x\n", chipId); + return chipId; +} +EXPORT_SYMBOL(wmt_plat_get_soc_chipid); + +#if CFG_WMT_LTE_COEX_HANDLING +INT32 wmt_plat_get_tdm_antsel_index(VOID) +{ + WMT_PLAT_INFO_FUNC("not support LTE in this platform\n"); + return 0; +} +EXPORT_SYMBOL(wmt_plat_get_tdm_antsel_index); +#endif +INT32 wmt_plat_set_dbg_mode(UINT32 flag) +{ + return -1; +} +VOID wmt_plat_set_dynamic_dumpmem(UINT32 *buf) +{ + mtk_wcn_consys_set_dynamic_dump(buf); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/Makefile b/drivers/misc/mediatek/connectivity/wlan/Makefile new file mode 100644 index 0000000000000..2961aeb073eaa --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/Makefile @@ -0,0 +1,8 @@ +ifeq ($(CONFIG_MTK_COMBO_WIFI),y) + subdir-ccflags-y += -D MTK_WCN_BUILT_IN_DRIVER +endif + +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) +#$(warning include gen2) + obj-y += gen2/ +endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile new file mode 100644 index 0000000000000..b86ab49fce3a0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/Makefile @@ -0,0 +1,237 @@ +# --------------------------------------------------- +# Compile Options +# --------------------------------------------------- +ccflags-y += -DLINUX -DMT6628 + +ccflags-y += -DCFG_SUPPORT_AGPS_ASSIST=1 +ccflags-y += -DCFG_SUPPORT_TSF_USING_BOOTTIME=1 +ccflags-y += -DCFG_P2P_LEGACY_COEX_REVISE=1 +ccflags-y += -DARP_MONITER_ENABLE=1 + +ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) + ccflags-y += -DCFG_SUPPORT_WAPI=1 +else + ccflags-y += -DCFG_SUPPORT_WAPI=0 +endif + +ifeq ($(CONFIG_MTK_WIFI_MCC_SUPPORT), y) + ccflags-y += -DCFG_SUPPORT_MCC=1 +else + ccflags-y += -DCFG_SUPPORT_MCC=0 +endif + +ifeq ($(CONFIG_HAVE_XLOG_FEATURE), y) + ccflags-y += -DCFG_SUPPORT_XLOG=1 +else + ccflags-y += -DCFG_SUPPORT_XLOG=0 +endif + +ifeq ($(CONFIG_MTK_AEE_FEATURE), y) + ccflags-y += -DCFG_SUPPORT_AEE=1 +else + ccflags-y += -DCFG_SUPPORT_AEE=0 +endif + +#ifeq ($(CONFIG_MTK_COMBO_WIFI_HIF_SDIO1), y) +# ccflags-y += -D_HIF_SDIO=1 +#endif + +ifeq ($(CONFIG_MTK_PASSPOINT_R1_SUPPORT), y) + ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=1 + ccflags-y += -DCFG_HS20_DEBUG=1 + ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=1 +else + ccflags-y += -DCFG_SUPPORT_HOTSPOT_2_0=0 + ccflags-y += -DCFG_HS20_DEBUG=0 + ccflags-y += -DCFG_ENABLE_GTK_FRAME_FILTER=0 +endif + +MTK_MET_PROFILING_SUPPORT = no +ifeq ($(MTK_MET_PROFILING_SUPPORT), yes) + ccflags-y += -DCFG_SUPPORT_MET_PROFILING=1 +else + ccflags-y += -DCFG_SUPPORT_MET_PROFILING=0 +endif + +ifeq ($(CONFIG_MTK_TC1_FEATURE), y) +ifeq ($(CONFIG_MTK_GPT_SCHEME_SUPPORT), y) + ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/gpt +else + ccflags-y += -I$(srctree)/drivers/misc/mediatek/tc1_interface/pmt +endif + ccflags-y += -DCFG_TC1_FEATURE=1 + ccflags-y += -DCFG_SUPPORT_CFG_FILE=1 +else + ccflags-y += -DCFG_TC1_FEATURE=0 +endif + +MTK_SRAM_SIZE_OPTION=0 +ifeq ($(CONFIG_ARCH_MT6755), y) + MTK_SRAM_SIZE_OPTION=2 +endif +ifeq ($(CONFIG_ARCH_MT6735), y) + MTK_SRAM_SIZE_OPTION=1 +endif +ifeq ($(CONFIG_ARCH_MT6735M), y) + MTK_SRAM_SIZE_OPTION=1 +endif +ifeq ($(CONFIG_ARCH_MT6753), y) + MTK_SRAM_SIZE_OPTION=1 +endif +ifeq ($(CONFIG_ARCH_MT6580), y) + MTK_SRAM_SIZE_OPTION=1 +endif +ifeq ($(CONFIG_ARCH_MT8163), y) + MTK_SRAM_SIZE_OPTION=1 +endif +ccflags-y += -DCFG_SRAM_SIZE_OPTION=$(MTK_SRAM_SIZE_OPTION) + +ifeq ($(strip $(TRUSTONIC_TEE_SUPPORT)),yes) +ifeq ($(strip $(MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT)),yes) + ccflags-y += -DTRUSTONIC_TEE_SUPPORT + ccflags-y += -DMTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT +endif +endif + +ccflags-y += -D_HIF_SDIO=1 + +ccflags-y += -DDBG=0 +ccflags-y += -I$(src)/os -I$(src)/os/linux/include -I$(src)/os/linux/hif/ahb/include +ccflags-y += -I$(src)/include -I$(src)/include/nic -I$(src)/include/mgmt +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/ + +MODULE_NAME := wlan_gen2 +obj-$(CONFIG_MTK_COMBO_WIFI) += $(MODULE_NAME).o +#obj-m += $(MODULE_NAME).o if CONFIG_MTK_COMBO_WIFI=m ==> obj-m means ko module, not build in obj-y + +# --------------------------------------------------- +# Directory List +# --------------------------------------------------- +COMMON_DIR := common/ +OS_DIR := os/linux/ +HIF_DIR := os/linux/hif/ahb/ +NIC_DIR := nic/ +MGMT_DIR := mgmt/ +DMA_DIR := ../../../../platform/$(call lc,$(MTK_PLATFORM))/kernel/drivers/wifi/ +PLAT_DIR := os/linux/plat/$(MTK_PLATFORM)/ +HIF_AHB_PDMA := $(HIF_DIR)$(MTK_PLATFORM)/ +#$(call lc,$(MTK_PLATFORM)) + + +# --------------------------------------------------- +# Objects List +# --------------------------------------------------- + +COMMON_OBJS := $(COMMON_DIR)dump.o \ + $(COMMON_DIR)wlan_lib.o \ + $(COMMON_DIR)wlan_oid.o \ + $(COMMON_DIR)wlan_bow.o \ + $(COMMON_DIR)debug.o + +NIC_OBJS := $(NIC_DIR)nic.o \ + $(NIC_DIR)nic_tx.o \ + $(NIC_DIR)nic_rx.o \ + $(NIC_DIR)nic_pwr_mgt.o \ + $(NIC_DIR)cmd_buf.o \ + $(NIC_DIR)que_mgt.o \ + $(NIC_DIR)nic_cmd_event.o + +OS_OBJS := $(OS_DIR)gl_init.o \ + $(OS_DIR)gl_kal.o \ + $(OS_DIR)gl_bow.o \ + $(OS_DIR)gl_wext.o \ + $(OS_DIR)gl_wext_priv.o \ + $(OS_DIR)gl_rst.o \ + $(OS_DIR)gl_cfg80211.o \ + $(OS_DIR)gl_vendor.o \ + $(OS_DIR)platform.o \ + $(OS_DIR)gl_proc.o + +MGMT_OBJS := $(MGMT_DIR)ais_fsm.o \ + $(MGMT_DIR)aaa_fsm.o \ + $(MGMT_DIR)assoc.o \ + $(MGMT_DIR)auth.o \ + $(MGMT_DIR)bss.o \ + $(MGMT_DIR)cnm.o \ + $(MGMT_DIR)cnm_timer.o \ + $(MGMT_DIR)cnm_mem.o \ + $(MGMT_DIR)hem_mbox.o \ + $(MGMT_DIR)mib.o \ + $(MGMT_DIR)privacy.o \ + $(MGMT_DIR)rate.o \ + $(MGMT_DIR)rlm.o \ + $(MGMT_DIR)rlm_domain.o \ + $(MGMT_DIR)rlm_obss.o \ + $(MGMT_DIR)rlm_protection.o \ + $(MGMT_DIR)rsn.o \ + $(MGMT_DIR)saa_fsm.o \ + $(MGMT_DIR)scan.o \ + $(MGMT_DIR)scan_fsm.o \ + $(MGMT_DIR)sec_fsm.o \ + $(MGMT_DIR)swcr.o \ + $(MGMT_DIR)swcr.o \ + $(MGMT_DIR)roaming_fsm.o \ + $(MGMT_DIR)hs20.o + +# --------------------------------------------------- +# TDLS Objects List +# --------------------------------------------------- +MGMT_OBJS += $(MGMT_DIR)tdls.o \ + $(MGMT_DIR)tdls_com.o + +# --------------------------------------------------- +# STATS Objects List +# --------------------------------------------------- +MGMT_OBJS += $(MGMT_DIR)stats.o + +# --------------------------------------------------- +# P2P Objects List +# --------------------------------------------------- + +COMMON_OBJS += $(COMMON_DIR)wlan_p2p.o + +NIC_OBJS += $(NIC_DIR)p2p_nic.o + +OS_OBJS += $(OS_DIR)gl_p2p.o \ + $(OS_DIR)gl_p2p_cfg80211.o \ + $(OS_DIR)gl_p2p_init.o \ + $(OS_DIR)gl_p2p_kal.o + +MGMT_OBJS += $(MGMT_DIR)p2p_assoc.o \ + $(MGMT_DIR)p2p_bss.o \ + $(MGMT_DIR)p2p_fsm.o \ + $(MGMT_DIR)p2p_func.o \ + $(MGMT_DIR)p2p_rlm.o \ + $(MGMT_DIR)p2p_rlm_obss.o \ + $(MGMT_DIR)p2p_scan.o \ + $(MGMT_DIR)p2p_ie.o \ + $(MGMT_DIR)p2p_state.o + + +ifeq ($(CONFIG_MTK_WAPI_SUPPORT), y) +MGMT_OBJS += $(MGMT_DIR)wapi.o +endif + +ifeq ($(WLAN_PROC), y) +OS_OBJS += gl_proc.o +endif + +#$(warning $(CONFIG_MACH_MT7623)) + +ifeq ($(CONFIG_MACH_MT7623), y) +HIF_AHB_PDMA = $(HIF_DIR)mt8127/ +endif +HIF_OBJS := $(HIF_DIR)arm.o \ + $(HIF_DIR)ahb.o \ + $(HIF_AHB_PDMA)ahb_pdma.o +ifeq ($(CONFIG_ARCH_MT6755), y) +PLAT_OBJS := $(PLAT_DIR)plat_priv.o +$(MODULE_NAME)-objs += $(PLAT_OBJS) +endif +$(MODULE_NAME)-objs += $(COMMON_OBJS) +$(MODULE_NAME)-objs += $(NIC_OBJS) +$(MODULE_NAME)-objs += $(OS_OBJS) +$(MODULE_NAME)-objs += $(HIF_OBJS) +$(MODULE_NAME)-objs += $(MGMT_OBJS) + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c new file mode 100644 index 0000000000000..e31e0b86d231e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/debug.c @@ -0,0 +1,165 @@ +#include "precomp.h" +#include "gl_kal.h" + +struct COMMAND { + UINT_8 ucCID; + BOOLEAN fgSetQuery; + BOOLEAN fgNeedResp; + UINT_8 ucCmdSeqNum; +}; + +struct SECURITY_FRAME { + UINT_16 u2EthType; + UINT_16 u2Reserved; +}; + +struct MGMT_FRAME { + UINT_16 u2FrameCtl; + UINT_16 u2DurationID; +}; + +struct TC_RES_RELEASE_ENTRY { + UINT_64 u8RelaseTime; + UINT_32 u4RelCID; + UINT_8 ucTc4RelCnt; + UINT_8 ucAvailableTc4; +}; + +struct CMD_TRACE_ENTRY { + UINT_64 u8TxTime; + COMMAND_TYPE eCmdType; + union { + struct COMMAND rCmd; + struct SECURITY_FRAME rSecFrame; + struct MGMT_FRAME rMgmtFrame; + } u; +}; + +#define TC_RELEASE_TRACE_BUF_MAX_NUM 100 +#define TXED_CMD_TRACE_BUF_MAX_NUM 100 + +static struct TC_RES_RELEASE_ENTRY *gprTcReleaseTraceBuffer; +static struct CMD_TRACE_ENTRY *gprCmdTraceEntry; +VOID wlanDebugInit(VOID) +{ + /* debug for command/tc4 resource begin */ + gprTcReleaseTraceBuffer = + kalMemAlloc(TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY), PHY_MEM_TYPE); + kalMemZero(gprTcReleaseTraceBuffer, TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); + gprCmdTraceEntry = kalMemAlloc(TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY), PHY_MEM_TYPE); + kalMemZero(gprCmdTraceEntry, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); + /* debug for command/tc4 resource end */ +} + +VOID wlanDebugUninit(VOID) +{ + /* debug for command/tc4 resource begin */ + kalMemFree(gprTcReleaseTraceBuffer, PHY_MEM_TYPE, + TC_RELEASE_TRACE_BUF_MAX_NUM * sizeof(struct TC_RES_RELEASE_ENTRY)); + kalMemFree(gprCmdTraceEntry, PHY_MEM_TYPE, TXED_CMD_TRACE_BUF_MAX_NUM * sizeof(struct CMD_TRACE_ENTRY)); + /* debug for command/tc4 resource end */ +} + +VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd) +{ + static UINT_16 u2CurEntry; + struct CMD_TRACE_ENTRY *prCurCmd = &gprCmdTraceEntry[u2CurEntry]; + + prCurCmd->u8TxTime = sched_clock(); + prCurCmd->eCmdType = prCmd->eCmdType; + if (prCmd->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + P_WLAN_MAC_MGMT_HEADER_T prMgmt = (P_WLAN_MAC_MGMT_HEADER_T)((P_MSDU_INFO_T)prCmd->prPacket)->prPacket; + + prCurCmd->u.rMgmtFrame.u2FrameCtl = prMgmt->u2FrameCtrl; + prCurCmd->u.rMgmtFrame.u2DurationID = prMgmt->u2Duration; + } else if (prCmd->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + PUINT_8 pucPkt = (PUINT_8)((struct sk_buff *)prCmd->prPacket)->data; + + prCurCmd->u.rSecFrame.u2EthType = + (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); + } else { + prCurCmd->u.rCmd.ucCID = prCmd->ucCID; + prCurCmd->u.rCmd.ucCmdSeqNum = prCmd->ucCmdSeqNum; + prCurCmd->u.rCmd.fgNeedResp = prCmd->fgNeedResp; + prCurCmd->u.rCmd.fgSetQuery = prCmd->fgSetQuery; + } + u2CurEntry++; + if (u2CurEntry == TC_RELEASE_TRACE_BUF_MAX_NUM) + u2CurEntry = 0; +} + +VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable) +{ + static UINT_16 u2CurEntry; + struct TC_RES_RELEASE_ENTRY *prCurBuf = &gprTcReleaseTraceBuffer[u2CurEntry]; + + HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &prCurBuf->u4RelCID); + prCurBuf->u8RelaseTime = sched_clock(); + prCurBuf->ucTc4RelCnt = aucTxRlsCnt[TC4_INDEX]; + prCurBuf->ucAvailableTc4 = ucAvailable; + u2CurEntry++; + if (u2CurEntry == TXED_CMD_TRACE_BUF_MAX_NUM) + u2CurEntry = 0; +} + +VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen) +{ + UINT_16 i = 0; + struct CMD_TRACE_ENTRY *prCmd = gprCmdTraceEntry; + struct TC_RES_RELEASE_ENTRY *prTcRel = gprTcReleaseTraceBuffer; + + if (pucBuf) { + int bufLen = 0; + + for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/2; i++) { + bufLen = snprintf(pucBuf, maxLen, + "%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", + i*2, prCmd[i*2].u8TxTime, prCmd[i*2].eCmdType, *(PUINT_32)(&prCmd[i*2].u.rCmd.ucCID), + i*2+1, prCmd[i*2+1].u8TxTime, prCmd[i*2+1].eCmdType, + *(PUINT_32)(&prCmd[i*2+1].u.rCmd.ucCID)); + if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) + break; + pucBuf += bufLen; + maxLen -= bufLen; + } + for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/2; i++) { + bufLen = snprintf(pucBuf, maxLen, + "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d CID %08x\n", + i*2, prTcRel[i*2].u8RelaseTime, prTcRel[i*2].ucTc4RelCnt, prTcRel[i*2].ucAvailableTc4, + prTcRel[i*2].u4RelCID, + i*2+1, prTcRel[i*2+1].u8RelaseTime, prTcRel[i*2+1].ucTc4RelCnt, + prTcRel[i*2+1].ucAvailableTc4, prTcRel[i*2+1].u4RelCID); + if (bufLen <= 0 || (UINT_32)bufLen >= maxLen) + break; + pucBuf += bufLen; + maxLen -= bufLen; + } + return; + } + for (; i < TXED_CMD_TRACE_BUF_MAX_NUM/4; i++) { + LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x; ", + i*4, prCmd[i*4].u8TxTime, prCmd[i*4].eCmdType, + *(PUINT_32)(&prCmd[i*4].u.rCmd.ucCID), + i*4+1, prCmd[i*4+1].u8TxTime, prCmd[i*4+1].eCmdType, + *(PUINT_32)(&prCmd[i*4+1].u.rCmd.ucCID)); + LOG_FUNC("%d: Time %llu, Type %d, Content %08x; %d: Time %llu, Type %d, Content %08x\n", + i*4+2, prCmd[i*4+2].u8TxTime, prCmd[i*4+2].eCmdType, + *(PUINT_32)(&prCmd[i*4+2].u.rCmd.ucCID), + i*4+3, prCmd[i*4+3].u8TxTime, prCmd[i*4+3].eCmdType, + *(PUINT_32)(&prCmd[i*4+3].u.rCmd.ucCID)); + } + for (i = 0; i < TC_RELEASE_TRACE_BUF_MAX_NUM/4; i++) { + LOG_FUNC( + "%d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x;", + i*4, prTcRel[i*4].u8RelaseTime, prTcRel[i*4].ucTc4RelCnt, + prTcRel[i*4].ucAvailableTc4, prTcRel[i*4].u4RelCID, + i*4+1, prTcRel[i*4+1].u8RelaseTime, prTcRel[i*4+1].ucTc4RelCnt, + prTcRel[i*4+1].ucAvailableTc4, prTcRel[i*4+1].u4RelCID); + LOG_FUNC( + " %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x; %d: Time %llu, Tc4Cnt %d, Free %d, CID %08x\n", + i*4+2, prTcRel[i*4+2].u8RelaseTime, prTcRel[i*4+2].ucTc4RelCnt, + prTcRel[i*4+2].ucAvailableTc4, prTcRel[i*4+2].u4RelCID, + i*4+3, prTcRel[i*4+3].u8RelaseTime, prTcRel[i*4+3].ucTc4RelCnt, + prTcRel[i*4+3].ucAvailableTc4, prTcRel[i*4+3].u4RelCID); + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c new file mode 100644 index 0000000000000..486ba239f16a5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/dump.c @@ -0,0 +1,345 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/dump.c#1 +*/ + +/*! \file "dump.c" + \brief Provide memory dump function for debugging. + + Provide memory dump function for debugging. +*/ + +/* +** Log: dump.c + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 19:58:51 GMT mtk01426 +** Init develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump a segment of memory in bytes. +* +* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. +* \param[in] u4Length Length of the memory to be dumped. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length) +{ + ASSERT(pucStartAddr); + + LOG_FUNC("DUMP8 ADDRESS: %p, Length: %u\n", pucStartAddr, u4Length); + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], pucStartAddr[8], + pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], pucStartAddr[12], pucStartAddr[13], + pucStartAddr[14], pucStartAddr[15]); + u4Length -= 16; + pucStartAddr += 16; + } else { + switch (u4Length) { + case 1: + LOG_FUNC("(%p) %02x\n", pucStartAddr, pucStartAddr[0]); + break; + case 2: + LOG_FUNC("(%p) %02x %02x\n", pucStartAddr, pucStartAddr[0], pucStartAddr[1]); + break; + case 3: + LOG_FUNC("(%p) %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2]); + break; + case 4: + LOG_FUNC("(%p) %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3]); + break; + case 5: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4]); + break; + case 6: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5]); + break; + case 7: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6]); + break; + case 8: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7]); + break; + case 9: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8]); + break; + case 10: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9]); + break; + case 11: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9], pucStartAddr[10]); + break; + case 12: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11]); + break; + case 13: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12]); + break; + case 14: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13]); + break; + case 15: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], pucStartAddr[1], pucStartAddr[2], pucStartAddr[3], + pucStartAddr[4], pucStartAddr[5], pucStartAddr[6], pucStartAddr[7], + pucStartAddr[8], pucStartAddr[9], pucStartAddr[10], pucStartAddr[11], + pucStartAddr[12], pucStartAddr[13], pucStartAddr[14]); + break; + /* + default: + break; + */ + } + u4Length = 0; + } + } + + LOG_FUNC("\n"); + +} /* end of dumpMemory8() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump a segment of memory in double words. +* +* \param[in] pucStartAddr Pointer to the starting address of the memory to be dumped. +* \param[in] u4Length Length of the memory to be dumped. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length) +{ + PUINT_8 pucAddr; + + ASSERT(pu4StartAddr); + + LOG_FUNC("DUMP32 ADDRESS: %p, Length: %u\n", pu4StartAddr, u4Length); + + if (IS_NOT_ALIGN_4((ULONG) pu4StartAddr)) { + UINT_32 u4ProtrudeLen = sizeof(UINT_32) - ((ULONG) pu4StartAddr % 4); + + u4ProtrudeLen = ((u4Length < u4ProtrudeLen) ? u4Length : u4ProtrudeLen); + LOG_FUNC("pu4StartAddr is not at DW boundary.\n"); + pucAddr = (PUINT_8) &pu4StartAddr[0]; + + switch (u4ProtrudeLen) { + case 1: + LOG_FUNC("(%p) %02x------\n", pu4StartAddr, pucAddr[0]); + break; + case 2: + LOG_FUNC("(%p) %02x%02x----\n", pu4StartAddr, pucAddr[1], pucAddr[0]); + break; + case 3: + LOG_FUNC("(%p) %02x%02x%02x--\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); + break; + default: + break; + } + + u4Length -= u4ProtrudeLen; + pu4StartAddr = (PUINT_32) ((ULONG) pu4StartAddr + u4ProtrudeLen); + } + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC("(%p) %08x %08x %08x %08x\n", + pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pu4StartAddr[3]); + pu4StartAddr += 4; + u4Length -= 16; + } else { + switch (u4Length) { + case 1: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%p) ------%02x\n", pu4StartAddr, pucAddr[0]); + break; + case 2: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%p) ----%02x%02x\n", pu4StartAddr, pucAddr[1], pucAddr[0]); + break; + case 3: + pucAddr = (PUINT_8) &pu4StartAddr[0]; + LOG_FUNC("(%p) --%02x%02x%02x\n", pu4StartAddr, pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 4: + LOG_FUNC("(%p) %08x\n", pu4StartAddr, pu4StartAddr[0]); + break; + case 5: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%p) %08x ------%02x\n", pu4StartAddr, pu4StartAddr[0], pucAddr[0]); + break; + case 6: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%p) %08x ----%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], pucAddr[1], pucAddr[0]); + break; + case 7: + pucAddr = (PUINT_8) &pu4StartAddr[1]; + LOG_FUNC("(%p) %08x --%02x%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 8: + LOG_FUNC("(%p) %08x %08x\n", pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1]); + break; + case 9: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x ------%02x\n", + pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[0]); + break; + case 10: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x ----%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pucAddr[1], pucAddr[0]); + break; + case 11: + pucAddr = (PUINT_8) &pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x --%02x%02x%02x\n", + pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pucAddr[2], pucAddr[1], pucAddr[0]); + break; + case 12: + LOG_FUNC("(%p) %08x %08x %08x\n", + pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2]); + break; + case 13: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x ------%02x\n", + pu4StartAddr, pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[0]); + break; + case 14: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x ----%02x%02x\n", + pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], pucAddr[1], pucAddr[0]); + break; + case 15: + pucAddr = (PUINT_8) &pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x --%02x%02x%02x\n", + pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], pu4StartAddr[2], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + /* + default: + break; + */ + } + u4Length = 0; + } + } + +} /* end of dumpMemory32() */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c new file mode 100644 index 0000000000000..21bd849827e17 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_bow.c @@ -0,0 +1,3442 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_bow.c#1 +*/ + +/*! \file wlan_bow.c + \brief This file contains the 802.11 PAL commands processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_bow.c + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 16 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support BOW for 5GHz band. + * + * 01 09 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * [ALPS00110632] [Rose][LCA42][Cross Feature][Bluetooth]The "KE" pops up after the device reboots automatically.(once) + * + * Fix bow link disconnected event dereference. + * + * 09 29 2011 cm.chang + * NULL + * Change the function prototype of rlmDomainGetChnlList() + * + * 07 06 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Improve BoW connection establishment speed. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 21 2011 terry.wu + * NULL + * Fix BoW KE. + * + * 06 20 2011 terry.wu + * NULL + * Add BoW Rate Limitation. + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 06 17 2011 terry.wu + * NULL + * Add BoW 11N support. + * + * 06 07 2011 cp.wu + * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction + * aware more compile options. + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 23 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add some BoW error handling. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * . + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Only reply probe response to its peer or mached SSID for BoW AP. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW SAA retry and disable disconnect event when AAA fail . + * + * 05 21 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Protect BoW connection establishment. + * + * 05 17 2011 terry.wu + * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting + * Send deauth while disconnecting BoW link. + * + * 05 17 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix wrong StaRec state of BoW . + * + * 05 06 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix BoW Multiple Physical Link connect/disconnect issue. + * + * 05 03 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix prAssocRspSwRfb casting. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 12 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add WMM IE for BOW initiator data. + * + * 04 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 28 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Simplify link disconnected routine, remove link disconnected other routine. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add new feature - multiple physical link support. + * + * 02 22 2011 wh.su + * [WCXRP00000486] [MT6620 Wi-Fi][BOW] Fixed the bow send frame but not encrypted issue + * fixed the BOW packet sending without encrypted issue. + * + * 02 21 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BOW link disconnection bug. + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting. + * + * 02 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW channel granted function. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW Activity Report structure and bug fix. + * + * 01 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW to support multiple physical link. + * + * 12 08 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support concurrent networks. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 11 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BoW timer assert issue. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix for event returnning Band. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix wrong BoW event size. + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced + * by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 chinghwa.yu + * NULL + * Fix bowResponderScanDone error when prBssDesc is NULL. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 09 14 2010 cp.wu + * NULL + * indicate correct AIS network information for PAL. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 24 2010 chinghwa.yu + * NULL + * Initialize nicActivateNetwork(prAdapter as soon as bow is starting.. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * 2) command sequence number is now increased atomically + * * 3) private data could be hold and taken use for other purpose +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "precomp.h" + +#if CFG_ENABLE_BT_OVER_WIFI + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +static UINT_32 g_u4LinkCount; +static UINT_32 g_u4Beaconing; +static BOW_TABLE_T arBowTable[CFG_BOW_PHYSICAL_LINK_NUM]; + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +const BOW_CMD_T arBowCmdTable[] = { + {BOW_CMD_ID_GET_MAC_STATUS, bowCmdGetMacStatus}, + {BOW_CMD_ID_SETUP_CONNECTION, bowCmdSetupConnection}, + {BOW_CMD_ID_DESTROY_CONNECTION, bowCmdDestroyConnection}, + {BOW_CMD_ID_SET_PTK, bowCmdSetPTK}, + {BOW_CMD_ID_READ_RSSI, bowCmdReadRSSI}, + {BOW_CMD_ID_READ_LINK_QUALITY, bowCmdReadLinkQuality}, + {BOW_CMD_ID_SHORT_RANGE_MODE, bowCmdShortRangeMode}, + {BOW_CMD_ID_GET_CHANNEL_LIST, bowCmdGetChannelList}, +}; + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCID, + IN BOOLEAN fgSetQuery, + IN BOOLEAN fgNeedResp, + IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + IN UINT_32 u4SetQueryInfoLen, IN PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_BOW_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + prCmdInfo->u4PrivateData = (UINT_32) ucSeqNumber; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dispatch command coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + WLAN_STATUS retval = WLAN_STATUS_FAILURE; + UINT_16 i; + + ASSERT(prAdapter); + + for (i = 0; i < sizeof(arBowCmdTable) / sizeof(BOW_CMD_T); i++) { + if ((arBowCmdTable[i].uCmdID == prCmd->rHeader.ucCommandId) && arBowCmdTable[i].pfCmdHandle) { + retval = arBowCmdTable[i].pfCmdHandle(prAdapter, prCmd); + break; + } + } + + return retval; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_GET_MAC_STATUS +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_AMPC_EVENT prEvent; + P_BOW_MAC_STATUS prMacStatus; + UINT_8 idx = 0; + UINT_8 ucPrimaryChannel; + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eBssSCO; + UINT_8 ucNumOfChannel = 0; /* MAX_BOW_NUMBER_OF_CHANNEL; */ + + RF_CHANNEL_INFO_T aucChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; + + ASSERT(prAdapter); + + /* 3 <1> If LinkCount != 0 -> OK (optional) */ + + eBand = BAND_2G4; + eBssSCO = CHNL_EXT_SCN; + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return WLAN_STATUS_FAILURE; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_MAC_STATUS; + prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_MAC_STATUS); + + /* fill event body */ + prMacStatus = (P_BOW_MAC_STATUS) (prEvent->aucPayload); + kalMemZero(prMacStatus, sizeof(BOW_MAC_STATUS)); + + /* 3 <2> Call CNM to decide if BOW available. */ + if (cnmBowIsPermitted(prAdapter)) + prMacStatus->ucAvailability = TRUE; + else + prMacStatus->ucAvailability = FALSE; + + memcpy(prMacStatus->aucMacAddr, prAdapter->rWifiVar.aucDeviceAddress, PARAM_MAC_ADDR_LEN); + + if (cnmPreferredChannel(prAdapter, &eBand, &ucPrimaryChannel, &eBssSCO)) { +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, "bowCmdGetMacStatus, Get preferred channel.\n"); +#endif + + prMacStatus->ucNumOfChannel = 1; + prMacStatus->arChannelList[0].ucChannelBand = eBand; + prMacStatus->arChannelList[0].ucChannelNum = ucPrimaryChannel; + } else { +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, + "bowCmdGetMacStatus, Get channel list. Current number of channel, %d.\n", ucNumOfChannel); +#endif + + rlmDomainGetChnlList(prAdapter, BAND_2G4, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_2G4, + &ucNumOfChannel, aucChannelList); + + if (ucNumOfChannel > 0) { + for (idx = 0; idx < ucNumOfChannel; idx++) { + prMacStatus->arChannelList[idx].ucChannelBand = aucChannelList[idx].eBand; + prMacStatus->arChannelList[idx].ucChannelNum = aucChannelList[idx].ucChannelNum; + } + + prMacStatus->ucNumOfChannel = ucNumOfChannel; + } + + rlmDomainGetChnlList(prAdapter, BAND_5G, FALSE, MAX_BOW_NUMBER_OF_CHANNEL_5G, + &ucNumOfChannel, aucChannelList); + + if (ucNumOfChannel > 0) { + for (idx = 0; idx < ucNumOfChannel; idx++) { + prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelBand = + aucChannelList[idx].eBand; + prMacStatus->arChannelList[prMacStatus->ucNumOfChannel + idx].ucChannelNum = + aucChannelList[idx].ucChannelNum; + } + + prMacStatus->ucNumOfChannel = prMacStatus->ucNumOfChannel + ucNumOfChannel; + + } + } + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, + "ucNumOfChannel,eBand,aucChannelList,%x,%x,%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + ucNumOfChannel, aucChannelList[0].eBand, aucChannelList[0].ucChannelNum, aucChannelList[1].ucChannelNum, + aucChannelList[2].ucChannelNum, aucChannelList[3].ucChannelNum, aucChannelList[4].ucChannelNum, + aucChannelList[5].ucChannelNum, aucChannelList[6].ucChannelNum, aucChannelList[7].ucChannelNum, + aucChannelList[8].ucChannelNum, aucChannelList[9].ucChannelNum, aucChannelList[10].ucChannelNum, + aucChannelList[11].ucChannelNum, aucChannelList[12].ucChannelNum, aucChannelList[13].ucChannelNum, + aucChannelList[14].ucChannelNum, aucChannelList[15].ucChannelNum, aucChannelList[16].ucChannelNum, + aucChannelList[17].ucChannelNum)); + + DBGLOG(BOW, TRACE, + "prMacStatus->ucNumOfChannel, eBand, %x, %x.\n", + prMacStatus->ucNumOfChannel, prMacStatus->arChannelList[0].ucChannelBand); + DBGLOG(BOW, TRACE, + "prMacStatus->arChannelList, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + prMacStatus->arChannelList[0].ucChannelNum, prMacStatus->arChannelList[1].ucChannelNum, + prMacStatus->arChannelList[2].ucChannelNum, prMacStatus->arChannelList[3].ucChannelNum, + prMacStatus->arChannelList[4].ucChannelNum, prMacStatus->arChannelList[5].ucChannelNum, + prMacStatus->arChannelList[6].ucChannelNum, prMacStatus->arChannelList[7].ucChannelNum, + prMacStatus->arChannelList[8].ucChannelNum, prMacStatus->arChannelList[9].ucChannelNum, + prMacStatus->arChannelList[10].ucChannelNum, prMacStatus->arChannelList[11].ucChannelNum, + prMacStatus->arChannelList[12].ucChannelNum, prMacStatus->arChannelList[13].ucChannelNum, + prMacStatus->arChannelList[14].ucChannelNum, prMacStatus->arChannelList[15].ucChannelNum, + prMacStatus->arChannelList[16].ucChannelNum, prMacStatus->arChannelList[17].ucChannelNum)); + + DBGLOG(BOW, TRACE, "prMacStatus->ucNumOfChannel, %x.\n", prMacStatus->ucNumOfChannel); + DBGLOG(BOW, TRACE, + "prMacStatus->arChannelList[0].ucChannelBand, %x.\n", prMacStatus->arChannelList[0].ucChannelBand); + DBGLOG(BOW, TRACE, + "prMacStatus->arChannelList[0].ucChannelNum, %x.\n", prMacStatus->arChannelList[0].ucChannelNum); + DBGLOG(BOW, TRACE, "prMacStatus->ucAvailability, %x.\n", prMacStatus->ucAvailability); + DBGLOG(BOW, TRACE, "prMacStatus->aucMacAddr, %x:%x:%x:%x:%x:%x.\n", + prMacStatus->aucMacAddr[0], + prMacStatus->aucMacAddr[1], + prMacStatus->aucMacAddr[2], + prMacStatus->aucMacAddr[3], prMacStatus->aucMacAddr[4], prMacStatus->aucMacAddr[5])); +#endif + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_MAC_STATUS))); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SETUP_CONNECTION +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_SETUP_CONNECTION prBowSetupConnection; + CMD_BT_OVER_WIFI rCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; + BOW_TABLE_T rBowTable; + + UINT_8 ucBowTableIdx = 0; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowSetupConnection = (P_BOW_SETUP_CONNECTION) &(prCmd->aucPayload[0]); + + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SETUP_CONNECTION)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); + return WLAN_STATUS_INVALID_LENGTH; + } + /* 3 <1> If ucLinkCount >= 4 -> Fail. */ + if (g_u4LinkCount >= CFG_BOW_PHYSICAL_LINK_NUM) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + /* 3 <2> Call CNM, check if BOW is available. */ + if (!cnmBowIsPermitted(prAdapter)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + /* 3 <3> Lookup BOW Table, if Peer MAC address exist and valid -> Fail. */ + if (bowCheckBowTableIfVaild(prAdapter, prBowSetupConnection->aucPeerAddress)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (EQUAL_MAC_ADDR(prBowSetupConnection->aucPeerAddress, prAdapter->rWifiVar.aucDeviceAddress)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_INVALID); + return WLAN_STATUS_NOT_ACCEPTED; + } + /* fill CMD_BT_OVER_WIFI */ + rCmdBtOverWifi.ucAction = BOW_SETUP_CMD; + rCmdBtOverWifi.ucChannelNum = prBowSetupConnection->ucChannelNum; + COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowSetupConnection->aucPeerAddress); + rCmdBtOverWifi.u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; + rCmdBtOverWifi.ucTimeoutDiscovery = prBowSetupConnection->ucTimeoutDiscovery; + rCmdBtOverWifi.ucTimeoutInactivity = prBowSetupConnection->ucTimeoutInactivity; + rCmdBtOverWifi.ucRole = prBowSetupConnection->ucRole; + rCmdBtOverWifi.PAL_Capabilities = prBowSetupConnection->ucPAL_Capabilities; + rCmdBtOverWifi.cMaxTxPower = prBowSetupConnection->cMaxTxPower; + + if (prBowSetupConnection->ucChannelNum > 14) + rCmdBtOverWifi.ucChannelBand = BAND_5G; + else + rCmdBtOverWifi.ucChannelBand = BAND_2G4; + + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowSetupConnection->aucPeerAddress); + +#if CFG_BOW_PHYSICAL_LINK_NUM > 1 + /*Channel check for supporting multiple physical link */ + if (g_u4LinkCount > 0) { + if (prBowSetupConnection->ucChannelNum != prBowFsmInfo->ucPrimaryChannel) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + } +#endif + + prBowFsmInfo->ucPrimaryChannel = prBowSetupConnection->ucChannelNum; + prBowFsmInfo->eBand = rCmdBtOverWifi.ucChannelBand; + prBowFsmInfo->u2BeaconInterval = prBowSetupConnection->u2BeaconInterval; + prBowFsmInfo->ucRole = prBowSetupConnection->ucRole; + + if (prBowSetupConnection->ucPAL_Capabilities > 0) + prBowFsmInfo->fgSupportQoS = TRUE; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowCmdSetupConnection.\n"); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Channel Number - 0x%x.\n", rCmdBtOverWifi.ucChannelNum); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Peer address - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], + rCmdBtOverWifi.rPeerAddr[1], + rCmdBtOverWifi.rPeerAddr[2], + rCmdBtOverWifi.rPeerAddr[3], rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Beacon interval - 0x%x.\n", rCmdBtOverWifi.u2BeaconInterval); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout activity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutDiscovery); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Timeout inactivity - 0x%x.\n", rCmdBtOverWifi.ucTimeoutInactivity); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Role - 0x%x.\n", rCmdBtOverWifi.ucRole); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi PAL capability - 0x%x.\n", rCmdBtOverWifi.PAL_Capabilities); + DBGLOG(BOW, EVENT, "rCmdBtOverWifi Max Tx power - 0x%x.\n", rCmdBtOverWifi.cMaxTxPower); +#endif + + /* 3 <4> Get a free BOW entry, mark as Valid, fill in Peer MAC address, LinkCount += 1, state == Starting. */ + if (!bowGetBowTableFreeEntry(prAdapter, &ucBowTableIdx)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + prBowFsmInfo->prTargetBssDesc = NULL; + + kalMemZero(&rBowTable, sizeof(BOW_TABLE_T)); + + COPY_MAC_ADDR(rBowTable.aucPeerAddress, prBowSetupConnection->aucPeerAddress); + /* owTable.eState = BOW_DEVICE_STATE_ACQUIRING_CHANNEL; */ + rBowTable.fgIsValid = TRUE; + rBowTable.ucAcquireID = prBowFsmInfo->ucSeqNumOfChReq; + /* rBowTable.ucRole = prBowSetupConnection->ucRole; */ + /* rBowTable.ucChannelNum = prBowSetupConnection->ucChannelNum; */ + bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); + + kalSetBowRole(prAdapter->prGlueInfo, rCmdBtOverWifi.ucRole, prBowSetupConnection->aucPeerAddress); + + GLUE_INC_REF_CNT(g_u4LinkCount); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); +#endif + + if (g_u4LinkCount == 1) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowStarting, cnmTimerInitTimer.\n"); + DBGLOG(BOW, EVENT, "prBowFsmInfo->u2BeaconInterval, %d.\n", prBowFsmInfo->u2BeaconInterval); +#endif + cnmTimerInitTimer(prAdapter, + &prBowFsmInfo->rStartingBeaconTimer, + (PFN_MGMT_TIMEOUT_FUNC) bowSendBeacon, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, + (PFN_MGMT_TIMEOUT_FUNC) bowChGrantedTimeout, (ULONG) NULL); + + /* Reset Global Variable */ + g_u4Beaconing = 0; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowCmdSetupConnection, g_u4LinkCount, %x.\n", g_u4LinkCount); + DBGLOG(BOW, EVENT, "kalInitBowDevice, bow0\n"); +#endif +#if CFG_BOW_SEPARATE_DATA_PATH + kalInitBowDevice(prAdapter->prGlueInfo, BOWDEVNAME); +#endif + + /*Active BoW Network */ + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); + + } + + if (rCmdBtOverWifi.ucRole == BOW_INITIATOR) { + bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, + BOW_DEVICE_STATE_ACQUIRING_CHANNEL); + bowRequestCh(prAdapter); + } else { + bowSetBowTableState(prAdapter, prBowSetupConnection->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); + bowResponderScan(prAdapter); + } + + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_DESTROY_CONNECTION +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_DESTROY_CONNECTION prBowDestroyConnection; + CMD_BT_OVER_WIFI rCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; +#if CFG_BOW_TEST + UINT_8 ucIdx; +#endif + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + /* 3 <1> If LinkCount == 0 ->Fail (Optional) */ + if (g_u4LinkCount == 0) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_DESTROY_CONNECTION)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_INVALID_LENGTH; + } + /* 3 <2> Lookup BOW table, check if is not exist (Valid and Peer MAC address) -> Fail */ + prBowDestroyConnection = (P_BOW_DESTROY_CONNECTION) &(prCmd->aucPayload[0]); + + if (!bowCheckBowTableIfVaild(prAdapter, prBowDestroyConnection->aucPeerAddress)) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowCmdDestroyConnection, bowCheckIfVaild, not accepted.\n"); +#endif + return WLAN_STATUS_NOT_ACCEPTED; + } +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "bowCmdDestroyConnection, destroy Peer address - %x:%x:%x:%x:%x:%x.\n", + prBowDestroyConnection->aucPeerAddress[0], prBowDestroyConnection->aucPeerAddress[1], + prBowDestroyConnection->aucPeerAddress[2], prBowDestroyConnection->aucPeerAddress[3], + prBowDestroyConnection->aucPeerAddress[4], prBowDestroyConnection->aucPeerAddress[5])); +#endif + + /* fill CMD_BT_OVER_WIFI */ + rCmdBtOverWifi.ucAction = 2; + COPY_MAC_ADDR(rCmdBtOverWifi.rPeerAddr, prBowDestroyConnection->aucPeerAddress); + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prBowDestroyConnection->aucPeerAddress); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "bowCmdDestroyConnection, rCmdBtOverWifi.rPeerAddr - %x:%x:%x:%x:%x:%x.\n", rCmdBtOverWifi.rPeerAddr[0], + rCmdBtOverWifi.rPeerAddr[1], rCmdBtOverWifi.rPeerAddr[2], rCmdBtOverWifi.rPeerAddr[3], + rCmdBtOverWifi.rPeerAddr[4], rCmdBtOverWifi.rPeerAddr[5]); +#endif + +#if CFG_BOW_TEST + for (ucIdx = 0; ucIdx < 11; ucIdx++) { + DBGLOG(BOW, EVENT, + "BoW receiving PAL packet delta time vs packet number -- %d ms vs %x.\n", ucIdx, + g_arBowRevPalPacketTime[ucIdx]); + } +#endif + + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, + sizeof(CMD_BT_OVER_WIFI), + (PUINT_8)&rCmdBtOverWifi, prCmd->rHeader.ucSeqNumber); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SET_PTK +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_SET_PTK prBowSetPTK; + CMD_802_11_KEY rCmdKey; + + ASSERT(prAdapter); + + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SET_PTK)) + return WLAN_STATUS_INVALID_LENGTH; + + prBowSetPTK = (P_BOW_SET_PTK) &(prCmd->aucPayload[0]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prBowSetPTK->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowSetPTK->aucPeerAddress[0], + prBowSetPTK->aucPeerAddress[1], + prBowSetPTK->aucPeerAddress[2], + prBowSetPTK->aucPeerAddress[3], + prBowSetPTK->aucPeerAddress[4], prBowSetPTK->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "rCmdKey.ucIsAuthenticator, %x.\n", kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress)); +#endif + + if (!bowCheckBowTableIfVaild(prAdapter, prBowSetPTK->aucPeerAddress)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (bowGetBowTableState(prAdapter, prBowSetPTK->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + + return WLAN_STATUS_NOT_ACCEPTED; + } + /* fill CMD_802_11_KEY */ + rCmdKey.ucAddRemove = 1; /* add */ + rCmdKey.ucTxKey = 1; + rCmdKey.ucKeyType = 1; + rCmdKey.ucIsAuthenticator = kalGetBowRole(prAdapter->prGlueInfo, prBowSetPTK->aucPeerAddress); + COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prBowSetPTK->aucPeerAddress); + rCmdKey.ucNetType = NETWORK_TYPE_BOW_INDEX; /* BT Over Wi-Fi */ + rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ + rCmdKey.ucKeyId = 0; + rCmdKey.ucKeyLen = 16; /* AES = 128bit */ + kalMemCopy(rCmdKey.aucKeyMaterial, prBowSetPTK->aucTemporalKey, 16); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prBowSetPTK->aucTemporalKey, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + prBowSetPTK->aucTemporalKey[0], + prBowSetPTK->aucTemporalKey[1], + prBowSetPTK->aucTemporalKey[2], + prBowSetPTK->aucTemporalKey[3], + prBowSetPTK->aucTemporalKey[4], + prBowSetPTK->aucTemporalKey[5], + prBowSetPTK->aucTemporalKey[6], + prBowSetPTK->aucTemporalKey[7], + prBowSetPTK->aucTemporalKey[8], + prBowSetPTK->aucTemporalKey[9], + prBowSetPTK->aucTemporalKey[10], + prBowSetPTK->aucTemporalKey[11], + prBowSetPTK->aucTemporalKey[12], + prBowSetPTK->aucTemporalKey[13], + prBowSetPTK->aucTemporalKey[14], prBowSetPTK->aucTemporalKey[15])); + + DBGLOG(BOW, EVENT, "rCmdKey.aucKeyMaterial, %x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x.\n", + rCmdKey.aucKeyMaterial[0], + rCmdKey.aucKeyMaterial[1], + rCmdKey.aucKeyMaterial[2], + rCmdKey.aucKeyMaterial[3], + rCmdKey.aucKeyMaterial[4], + rCmdKey.aucKeyMaterial[5], + rCmdKey.aucKeyMaterial[6], + rCmdKey.aucKeyMaterial[7], + rCmdKey.aucKeyMaterial[8], + rCmdKey.aucKeyMaterial[9], + rCmdKey.aucKeyMaterial[10], + rCmdKey.aucKeyMaterial[11], + rCmdKey.aucKeyMaterial[12], + rCmdKey.aucKeyMaterial[13], rCmdKey.aucKeyMaterial[14], rCmdKey.aucKeyMaterial[15])); +#endif + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + wlanbowCmdEventSetCommon, + wlanbowCmdTimeoutHandler, + sizeof(CMD_802_11_KEY), (PUINT_8)&rCmdKey, prCmd->rHeader.ucSeqNumber); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_READ_RSSI +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_READ_RSSI prBowReadRSSI; + + ASSERT(prAdapter); + + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_READ_RSSI)) + return WLAN_STATUS_INVALID_LENGTH; + + prBowReadRSSI = (P_BOW_READ_RSSI) &(prCmd->aucPayload[0]); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + wlanbowCmdEventReadRssi, + wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_READ_LINK_QUALITY +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_READ_LINK_QUALITY prBowReadLinkQuality; + + ASSERT(prAdapter); + + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(P_BOW_READ_LINK_QUALITY)) + return WLAN_STATUS_INVALID_LENGTH; + + prBowReadLinkQuality = (P_BOW_READ_LINK_QUALITY) &(prCmd->aucPayload[0]); + + return wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + wlanbowCmdEventReadLinkQuality, + wlanbowCmdTimeoutHandler, 0, NULL, prCmd->rHeader.ucSeqNumber); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_SHORT_RANGE_MODE +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + P_BOW_SHORT_RANGE_MODE prBowShortRangeMode; + CMD_TX_PWR_T rTxPwrParam; + + ASSERT(prAdapter); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowCmdShortRangeMode.\n"); +#endif + + prBowShortRangeMode = (P_BOW_SHORT_RANGE_MODE) &(prCmd->aucPayload[0]); + + /* parameter size check */ + if (prCmd->rHeader.u2PayloadLength != sizeof(BOW_SHORT_RANGE_MODE)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_INVALID_LENGTH; + } + + if (!bowCheckBowTableIfVaild(prAdapter, prBowShortRangeMode->aucPeerAddress)) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_UNACCEPTED); + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (bowGetBowTableState(prAdapter, prBowShortRangeMode->aucPeerAddress) != BOW_DEVICE_STATE_CONNECTED) { + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + return WLAN_STATUS_NOT_ACCEPTED; + } +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prBowShortRangeMode->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowShortRangeMode->aucPeerAddress[0], + prBowShortRangeMode->aucPeerAddress[1], + prBowShortRangeMode->aucPeerAddress[2], + prBowShortRangeMode->aucPeerAddress[3], + prBowShortRangeMode->aucPeerAddress[4], prBowShortRangeMode->aucPeerAddress[5])); +#endif + + rTxPwrParam.cTxPwr2G4Cck = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4OFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4OFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4OFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4HT20_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr2G4HT40_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr2G4HT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr5GOFDM_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_48Mbps = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GOFDM_54Mbps = (prBowShortRangeMode->cTxPower << 1); + + rTxPwrParam.cTxPwr5GHT20_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT20_MCS7 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_BPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_QPSK = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_16QAM = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS5 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS6 = (prBowShortRangeMode->cTxPower << 1); + rTxPwrParam.cTxPwr5GHT40_MCS7 = (prBowShortRangeMode->cTxPower << 1); + + if (nicUpdateTxPower(prAdapter, &rTxPwrParam) == WLAN_STATUS_SUCCESS) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowCmdShortRangeMode, %x.\n", WLAN_STATUS_SUCCESS); +#endif + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_SUCCESS); + return WLAN_STATUS_SUCCESS; + } + wlanbowCmdEventSetStatus(prAdapter, prCmd, BOWCMD_STATUS_FAILURE); + return WLAN_STATUS_FAILURE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is command handler for BOW_CMD_ID_GET_CHANNEL_LIST +* coming from 802.11 PAL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmd Pointer to the buffer that holds the command +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd) +{ + ASSERT(prAdapter); + + /* not supported yet */ + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is generic command done handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = prCmd->rHeader.ucSeqNumber; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + /* fill event body */ + prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = ucEventBuf; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is generic command done handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + /* fill event body */ + prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_AMPC_EVENT prEvent; + P_BOW_LINK_CONNECTED prBowLinkConnected; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); + + /* fill event body */ + prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prEvent->aucPayload); + kalMemZero(prBowLinkConnected, sizeof(BOW_LINK_CONNECTED)); + prBowLinkConnected->rChannel.ucChannelNum = prBssInfo->ucPrimaryChannel; + prBowLinkConnected->rChannel.ucChannelBand = prBssInfo->eBand; + COPY_MAC_ADDR(prBowLinkConnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); + DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); + DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); + DBGLOG(BOW, EVENT, + "prBowLinkConnected->rChannel.ucChannelNum, 0x%x\n", prBowLinkConnected->rChannel.ucChannelNum); + DBGLOG(BOW, EVENT, + "prBowLinkConnected->rChannel.ucChannelBand, 0x%x\n", prBowLinkConnected->rChannel.ucChannelBand); + DBGLOG(BOW, EVENT, + "wlanbowCmdEventLinkConnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5]); + DBGLOG(BOW, EVENT, + "wlanbowCmdEventLinkConnected, prBowLinkConnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowLinkConnected->aucPeerAddress[0], prBowLinkConnected->aucPeerAddress[1], + prBowLinkConnected->aucPeerAddress[2], prBowLinkConnected->aucPeerAddress[3], + prBowLinkConnected->aucPeerAddress[4], prBowLinkConnected->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkConnected, g_u4LinkCount, %x.\n", g_u4LinkCount); +#endif + + /*Indicate Event to PAL */ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_CONNECTED))); + + /*Release channel if granted */ + if (prBowFsmInfo->fgIsChannelGranted) { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + /* bowReleaseCh(prAdapter); */ + /*Requested, not granted yet */ + } else if (prBowFsmInfo->fgIsChannelRequested) { + prBowFsmInfo->fgIsChannelRequested = FALSE; + } + + /* set to connected status */ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTED); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_AMPC_EVENT prEvent; + P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; + P_BOW_FSM_INFO_T prBowFsmInfo; + BOW_TABLE_T rBowTable; + UINT_8 ucBowTableIdx; + ENUM_BOW_DEVICE_STATE eFsmState; + BOOLEAN fgSendDeauth = FALSE; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + /*do nothing */ + return; + } + /*Cancel scan */ + else if (eFsmState == BOW_DEVICE_STATE_SCANNING && !(prBowFsmInfo->fgIsChannelRequested)) { + bowResponderCancelScan(prAdapter, FALSE); + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_DISCONNECTING); + return; + } + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; + if ((prCmdInfo->u4PrivateData)) + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + else + prEvent->rHeader.ucSeqNumber = 0; + + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); + + /* fill event body */ + prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prEvent->aucPayload); + kalMemZero(prBowLinkDisconnected, sizeof(BOW_LINK_DISCONNECTED)); + prBowLinkDisconnected->ucReason = 0x0; + COPY_MAC_ADDR(prBowLinkDisconnected->aucPeerAddress, prBowFsmInfo->aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prEvent->rHeader.ucEventId, 0x%x\n", prEvent->rHeader.ucEventId); + DBGLOG(BOW, EVENT, "prEvent->rHeader.ucSeqNumber, 0x%x\n", prEvent->rHeader.ucSeqNumber); + DBGLOG(BOW, EVENT, "prEvent->rHeader.u2PayloadLength, 0x%x\n", prEvent->rHeader.u2PayloadLength); + + DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "wlanbowCmdEventLinkDisconnected, prBowLinkDisconnected->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowLinkDisconnected->aucPeerAddress[0], prBowLinkDisconnected->aucPeerAddress[1], + prBowLinkDisconnected->aucPeerAddress[2], prBowLinkDisconnected->aucPeerAddress[3], + prBowLinkDisconnected->aucPeerAddress[4], prBowLinkDisconnected->aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, "wlanbowCmdEventLinkDisconnected, g_u4LinkCount, %x.\n", g_u4LinkCount); +#endif + + /*Indicate BoW event to PAL */ +#if 0 + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); +#endif + + /* set to disconnected status */ + prBowFsmInfo->prTargetStaRec = + cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_BOW_INDEX, prBowLinkDisconnected->aucPeerAddress); + if (!(prBowFsmInfo->prTargetStaRec)) { + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); + ASSERT(FALSE); + return; + } + + /*Release channel if granted */ + if (prBowFsmInfo->fgIsChannelGranted) { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + bowReleaseCh(prAdapter); + /*Requested, not granted yet */ + } else if (prBowFsmInfo->fgIsChannelRequested) { + prBowFsmInfo->fgIsChannelRequested = FALSE; + /* bowReleaseCh(prAdapter); */ + } +#if 1 + /*Send Deauth to connected peer */ + if (eFsmState == BOW_DEVICE_STATE_CONNECTED && (prBowFsmInfo->prTargetStaRec->ucStaState == STA_STATE_3)) { + fgSendDeauth = TRUE; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "wlanbowCmdEventLinkDisconnected, bowGetBowTableState, %x.\n", + bowGetBowTableState(prAdapter, prBowLinkDisconnected->aucPeerAddress)); +#endif + authSendDeauthFrame(prAdapter, + prBowFsmInfo->prTargetStaRec, + (P_SW_RFB_T) NULL, + REASON_CODE_DEAUTH_LEAVING_BSS, (PFN_TX_DONE_HANDLER) bowDisconnectLink); + } +#endif + +#if 0 + /* 3 <3>Stop this link; flush Tx; + * send deAuthentication -> abort. SAA, AAA. need to check BOW table state == Connected. + */ + if (prAdapter->prGlueInfo->i4TxPendingFrameNum > 0) + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* flush pending security frames */ + if (prAdapter->prGlueInfo->i4TxPendingSecurityFrameNum > 0) + kalClearSecurityFrames(prAdapter->prGlueInfo); +#endif + + /*Update BoW table */ + bowGetBowTableEntryByPeerAddress(prAdapter, prBowLinkDisconnected->aucPeerAddress, &ucBowTableIdx); + rBowTable.fgIsValid = FALSE; + rBowTable.eState = BOW_DEVICE_STATE_DISCONNECTED; + kalMemZero(rBowTable.aucPeerAddress, sizeof(rBowTable.aucPeerAddress)); + bowSetBowTableContent(prAdapter, ucBowTableIdx, &rBowTable); + + /*Indicate BoW event to PAL */ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED))); + + /*Decrease link count */ + GLUE_DEC_REF_CNT(g_u4LinkCount); + + /*If no need to send deauth, DO disconnect now */ + /*If need to send deauth, DO disconnect at deauth Tx done */ + if (!fgSendDeauth) + bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command done handler for CMD_ID_CMD_BT_OVER_WIFI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + P_WIFI_CMD_T prWifiCmd; + P_CMD_BT_OVER_WIFI prCmdBtOverWifi; + P_BOW_FSM_INFO_T prBowFsmInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + /* restore original command for rPeerAddr */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prCmdBtOverWifi = (P_CMD_BT_OVER_WIFI) (prWifiCmd->aucBuffer); + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + /* fill event body */ + prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + prBowCmdStatus->ucStatus = BOWCMD_STATUS_SUCCESS; + + /*Indicate BoW event to PAL */ + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); + + /* set to starting status */ + kalSetBowState(prAdapter->prGlueInfo, BOW_DEVICE_STATE_STARTING, prCmdBtOverWifi->rPeerAddr); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the command done handler for BOW_CMD_ID_READ_LINK_QUALITY +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_AMPC_EVENT prEvent; + P_BOW_LINK_QUALITY prBowLinkQuality; + + ASSERT(prAdapter); + + prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_QUALITY; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_QUALITY); + + /* fill event body */ + prBowLinkQuality = (P_BOW_LINK_QUALITY) (prEvent->aucPayload); + kalMemZero(prBowLinkQuality, sizeof(BOW_LINK_QUALITY)); + prBowLinkQuality->ucLinkQuality = (UINT_8) prLinkQuality->cLinkQuality; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the command done handler for BOW_CMD_ID_READ_RSSI +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* \param[in] pucEventBuf Pointer to the set buffer OR event buffer +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_AMPC_EVENT prEvent; + P_BOW_RSSI prBowRssi; + + ASSERT(prAdapter); + + prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_RSSI; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_RSSI); + + /* fill event body */ + prBowRssi = (P_BOW_RSSI) (prEvent->aucPayload); + kalMemZero(prBowRssi, sizeof(BOW_RSSI)); + prBowRssi->cRssi = (INT_8) prLinkQuality->cRssi; + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_LINK_QUALITY))); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is the default command timeout handler +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] prCmdInfo Pointer to the buffer that holds the command info +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + P_AMPC_EVENT prEvent; + P_BOW_COMMAND_STATUS prBowCmdStatus; + + ASSERT(prAdapter); + + /* fill event header */ + prEvent = (P_AMPC_EVENT) kalMemAlloc((sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS)), VIR_MEM_TYPE); + if (!prEvent) { + ASSERT(FALSE); + return; + } + prEvent->rHeader.ucEventId = BOW_EVENT_ID_COMMAND_STATUS; + prEvent->rHeader.ucSeqNumber = (UINT_8) prCmdInfo->u4PrivateData; + prEvent->rHeader.u2PayloadLength = sizeof(BOW_COMMAND_STATUS); + + /* fill event body */ + prBowCmdStatus = (P_BOW_COMMAND_STATUS) (prEvent->aucPayload); + kalMemZero(prBowCmdStatus, sizeof(BOW_COMMAND_STATUS)); + + prBowCmdStatus->ucStatus = BOWCMD_STATUS_TIMEOUT; /* timeout */ + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prEvent); + + kalMemFree(prEvent, VIR_MEM_TYPE, (sizeof(AMPC_EVENT) + sizeof(BOW_COMMAND_STATUS))); + +} + +VOID bowStopping(IN P_ADAPTER_T prAdapter) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBowBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowStoping.\n"); + DBGLOG(BOW, EVENT, "bowStoping, SSID %s.\n", prBowBssInfo->aucSSID); + DBGLOG(BOW, EVENT, "bowStoping, prBowBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", + prBowBssInfo->aucBSSID[0], + prBowBssInfo->aucBSSID[1], + prBowBssInfo->aucBSSID[2], + prBowBssInfo->aucBSSID[3], prBowBssInfo->aucBSSID[4], prBowBssInfo->aucBSSID[5])); + DBGLOG(BOW, EVENT, "bowStoping, prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", + prBowBssInfo->aucOwnMacAddr[0], + prBowBssInfo->aucOwnMacAddr[1], + prBowBssInfo->aucOwnMacAddr[2], + prBowBssInfo->aucOwnMacAddr[3], + prBowBssInfo->aucOwnMacAddr[4], prBowBssInfo->aucOwnMacAddr[5])); + DBGLOG(BOW, EVENT, "bowStoping, prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", + prAdapter->rWifiVar.aucDeviceAddress[0], + prAdapter->rWifiVar.aucDeviceAddress[1], + prAdapter->rWifiVar.aucDeviceAddress[2], + prAdapter->rWifiVar.aucDeviceAddress[3], + prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); + DBGLOG(BOW, EVENT, "bowStopping, g_u4LinkCount, %x.\n", g_u4LinkCount); + DBGLOG(BOW, EVENT, "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); + kalPrint("BoW Stoping,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); +#endif + + if (g_u4LinkCount == 0) { + /*Stop beaconing */ + GLUE_DEC_REF_CNT(g_u4Beaconing); + + /*Deactive BoW network */ + /* prBowBssInfo->fgIsNetActive = FALSE; */ + /* prBowBssInfo->fgIsBeaconActivated = FALSE; */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_BOW_INDEX); + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + /*temp solution for FW hal_pwr_mgt.c#3037 ASSERT */ + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_BOW_INDEX); + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + + } + +} + +VOID bowStarting(IN P_ADAPTER_T prAdapter) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (g_u4LinkCount == 1) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "BoW Starting.\n"); + DBGLOG(BOW, EVENT, "BoW channel granted.\n"); +#endif + +#if 0 + /*Active BoW Network */ + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX); + nicActivateNetwork(prAdapter, NETWORK_TYPE_BOW_INDEX); +#endif + + /* 3 <1> Update BSS_INFO_T per Network Basis */ + /* 4 <1.1> Setup Operation Mode */ + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBssInfo->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prBssInfo->eCurrentOPMode = OP_MODE_BOW; + + /* 4 <1.2> Setup SSID */ + COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucDeviceAddress); + COPY_MAC_ADDR(prBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); + prBssInfo->ucSSIDLen = BOW_SSID_LEN; + bowAssignSsid(prBssInfo->aucSSID, prBssInfo->aucOwnMacAddr); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "SSID %s.\n", prBssInfo->aucSSID); + DBGLOG(BOW, EVENT, "prBssInfo->aucBSSID, %x:%x:%x:%x:%x:%x.\n", + prBssInfo->aucBSSID[0], + prBssInfo->aucBSSID[1], + prBssInfo->aucBSSID[2], + prBssInfo->aucBSSID[3], prBssInfo->aucBSSID[4], prBssInfo->aucBSSID[5])); + DBGLOG(BOW, EVENT, "prBssInfo->aucOwnMacAddr, %x:%x:%x:%x:%x:%x.\n", + prBssInfo->aucOwnMacAddr[0], + prBssInfo->aucOwnMacAddr[1], + prBssInfo->aucOwnMacAddr[2], + prBssInfo->aucOwnMacAddr[3], + prBssInfo->aucOwnMacAddr[4], prBssInfo->aucOwnMacAddr[5])); + DBGLOG(BOW, EVENT, "prAdapter->rWifiVar.aucDeviceAddress, %x:%x:%x:%x:%x:%x.\n", + prAdapter->rWifiVar.aucDeviceAddress[0], + prAdapter->rWifiVar.aucDeviceAddress[1], + prAdapter->rWifiVar.aucDeviceAddress[2], + prAdapter->rWifiVar.aucDeviceAddress[3], + prAdapter->rWifiVar.aucDeviceAddress[4], prAdapter->rWifiVar.aucDeviceAddress[5])); +#endif + + /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + prBssInfo->u2AssocId = 0; + + /* 4 <1.4> Setup Channel, Band and Phy Attributes */ + prBssInfo->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; + if (prBowFsmInfo->eBand == BAND_2G4) + prBssInfo->eBand = BAND_2G4; + else + prBssInfo->eBand = BAND_5G; + +#if CFG_BOW_SUPPORT_11N + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; + + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); + +#else + if (prBssInfo->eBand == BAND_2G4) { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; + + /* RATE_SET_ERP; */ + prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_ERP; + prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } else { + /* Depend on eBand */ + /* prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; */ + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + /* prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; */ + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11A; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; + + /* RATE_SET_ERP; */ + /* prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_ERP; */ + /* prBssInfo->u2OperationalRateSet = RATE_SET_ERP; */ + + /* RATE_SET_ERP; */ + prBssInfo->u2BSSBasicRateSet = BASIC_RATE_SET_OFDM; + prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; + prBssInfo->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } + +#endif + prBssInfo->fgErpProtectMode = FALSE; + + /* 4 <1.5> Setup MIB for current BSS */ + prBssInfo->u2BeaconInterval = prBowFsmInfo->u2BeaconInterval; + prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + prBssInfo->u2ATIMWindow = 0; + prBssInfo->ucBeaconTimeoutCount = 0; + if (prBowFsmInfo->fgSupportQoS) { + prAdapter->rWifiVar.fgSupportQoS = TRUE; + prBssInfo->fgIsQBSS = TRUE; + } + /* 3 <2> Update BSS_INFO_T common part */ +#if CFG_SUPPORT_AAA + bssInitForAP(prAdapter, prBssInfo, TRUE); + nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_BOW_INDEX); +#endif /* CFG_SUPPORT_AAA */ + prBssInfo->fgIsNetActive = TRUE; + prBssInfo->fgIsBeaconActivated = TRUE; + + /* 3 <3> Set MAC HW */ + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BOW_BSS_INFO_INIT(prAdapter, NETWORK_TYPE_BOW_INDEX); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], prBowFsmInfo->aucPeerAddress[4], + prBowFsmInfo->aucPeerAddress[5])); +#endif + + /* 4 <3.1> use command packets to inform firmware */ + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /* 4 <3.2> Update AdHoc PM parameter */ + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /* 4 <3.1> Reset HW TSF Update Mode and Beacon Mode */ + + /* 4 <3.2> Setup BSSID */ + /* TODO: rxmSetRxFilterBSSID0 */ +/* rxmSetRxFilterBSSID0(prBssInfo->ucHwBssidId, prBssInfo->aucBSSID); */ + + /* 4 <3.3> Setup RX Filter to accept Probe Request */ + /* TODO: f get/set RX filter. */ + +#if 0 + { + UINT_32 u4RxFilter; + + if (halMacRxGetRxFilters(&u4RxFilter) == HAL_STATUS_SUCCESS) { + + u4RxFilter &= ~BIT(RXFILTER_DROP_PROBE_REQ); + + halMacRxSetRxFilters(u4RxFilter); + } + } +#endif + } + + /*Update BoW Table */ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_STARTING); + +#if CFG_BOW_TEST + kalPrint("BoW Starting,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); + DBGLOG(BOW, EVENT, "bowStarting, g_u4LinkCount, %x.\n", g_u4LinkCount); +#endif + + /*Start beaconing */ + if (g_u4Beaconing < 1) { + GLUE_INC_REF_CNT(g_u4Beaconing); + bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); + cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); + } +#if 0 + /*Responder: Start to scan Initiator */ + if (prBowFsmInfo->ucRole == BOW_RESPONDER) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowStarting responder, start scan result searching.\n"); +#endif + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rChGrantedTimer); + bowReleaseCh(prAdapter); + bowResponderScan(prAdapter); + } + /*Initiator: Request channel, wait for responder */ + else { + /* Todo:: Nothing*/ + /* bowRequestCh(prAdapter); */ + } +#endif + +} + +VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 puOwnMacAddr) +{ + UINT_8 i; + UINT_8 aucSSID[] = BOW_WILDCARD_SSID; + + kalMemCopy(pucSsid, aucSSID, BOW_WILDCARD_SSID_LEN); + + for (i = 0; i < 6; i++) { + pucSsid[(3 * i) + 3] = 0x2D; + if ((*(puOwnMacAddr + i) >> 4) < 0xA) + *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x30; + else + *(pucSsid + (3 * i) + 4) = (*(puOwnMacAddr + i) >> 4) + 0x57; + + if ((*(puOwnMacAddr + i) & 0x0F) < 0xA) + pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x30; + else + pucSsid[(3 * i) + 5] = (*(puOwnMacAddr + i) & 0x0F) + 0x57; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + BOOLEAN fgReplyProbeResp = FALSE; + + ASSERT(prSwRfb); + ASSERT(pu4ControlFlags); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + +#if 0 /* CFG_BOW_TEST */ + DBGLOG(BOW, EVENT, "bowValidateProbeReq.\n"); +#endif + + /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) + prIeSsid = (P_IE_SSID_T) pucIE; + break; + } + } /* end of IE_FOR_EACH */ + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) + prIeSsid = (P_IE_SSID_T) pucIE; + break; + } + } /* end of IE_FOR_EACH */ + + /* 4 <2> Check network conditions */ + /*If BoW AP is beaconing */ + if (prBssInfo->eCurrentOPMode == OP_MODE_BOW && g_u4Beaconing > 0) { + + /*Check the probe requset sender is our peer */ + if (bowCheckBowTableIfVaild(prAdapter, prMgtHdr->aucSrcAddr)) + fgReplyProbeResp = TRUE; + /*Check the probe request target SSID is our SSID */ + else if ((prIeSsid) && + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prIeSsid->aucSSID, prIeSsid->ucLength)) + fgReplyProbeResp = TRUE; + else + fgReplyProbeResp = FALSE; + } + + return fgReplyProbeResp; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if ((g_u4Beaconing != 0) && (g_u4LinkCount > 0) && (g_u4LinkCount < CFG_BOW_PHYSICAL_LINK_NUM)) { + /* Send beacon */ + bssSendBeaconProbeResponse(prAdapter, NETWORK_TYPE_BOW_INDEX, NULL, 0); + cnmTimerStartTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer, prBowFsmInfo->u2BeaconInterval); + } +#if CFG_BOW_TEST + else + kalPrint("BoW Send Beacon,[%d,%d]\n", g_u4LinkCount, g_u4Beaconing); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowResponderScan(IN P_ADAPTER_T prAdapter) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_SCN_SCAN_REQ prScanReqMsg; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowResponderScan.\n"); + kalPrint("BOW SCAN [REQ:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq + 1); +#endif + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + + if (!prScanReqMsg) { + ASSERT(0); /* Can't trigger SCAN FSM */ + return; + } + + /*Fill scan message */ + prScanReqMsg->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfScanReq; + prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_BOW_INDEX; + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + prScanReqMsg->ucSSIDLength = BOW_SSID_LEN; + bowAssignSsid(prScanReqMsg->aucSSID, prBowFsmInfo->aucPeerAddress); + prScanReqMsg->ucChannelListNum = 1; + + if (prBowFsmInfo->eBand == BAND_2G4) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->arChnlInfoList[0].eBand = BAND_2G4; + } else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + prScanReqMsg->arChnlInfoList[0].eBand = BAND_5G; + } + + prScanReqMsg->arChnlInfoList[0].ucChannelNum = prBowFsmInfo->ucPrimaryChannel; + prScanReqMsg->u2IELen = 0; + + /*Send scan message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); + + /*Change state to SCANNING */ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_SCANNING); + + /* prBowFsmInfo->fgTryScan = FALSE; */ /* Will enable background sleep for infrastructure */ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_DESC_T prBssDesc; + UINT_8 ucSeqNumOfCompMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + ENUM_BOW_DEVICE_STATE eFsmState; + ENUM_SCAN_STATUS eScanStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + ASSERT(prScanDoneMsg->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX); + + ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; + eScanStatus = prScanDoneMsg->eScanStatus; + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowResponderScanDone.\n"); + kalPrint("BOW SCAN [DONE:%d]\n", ucSeqNumOfCompMsg); +#endif + + if (eScanStatus == SCAN_STATUS_CANCELLED) { +#if CFG_BOW_TEST + kalPrint("BOW SCAN [CANCELLED:%d]\n", ucSeqNumOfCompMsg); +#endif + if (eFsmState == BOW_DEVICE_STATE_DISCONNECTING) { + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, 0, NULL, 0); + } + return; + } else if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + /* bowDisconnectLink(prAdapter, NULL, TX_RESULT_SUCCESS); */ + return; + } else if (ucSeqNumOfCompMsg != prBowFsmInfo->ucSeqNumOfScanReq) { + DBGLOG(BOW, EVENT, "Sequence no. of BOW Responder scan done is not matched.\n"); + return; + } + prConnSettings->fgIsScanReqIssued = FALSE; + prBssDesc = scanSearchBssDescByBssid(prAdapter, prBowFsmInfo->aucPeerAddress); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "End scan result searching.\n"); +#endif + + /* Initiator is FOUND */ + if (prBssDesc != NULL) { + /* (prBssDesc->aucBSSID != NULL)) */ +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Search Bow Peer address - %x:%x:%x:%x:%x:%x.\n", prBssDesc->aucBSSID[0], + prBssDesc->aucBSSID[1], + prBssDesc->aucBSSID[2], + prBssDesc->aucBSSID[3], prBssDesc->aucBSSID[4], prBssDesc->aucBSSID[5]); + DBGLOG(BOW, EVENT, "Starting to join initiator.\n"); +#endif + /*Set target BssDesc */ + prBowFsmInfo->prTargetBssDesc = prBssDesc; + /*Request channel to do JOIN */ + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, + BOW_DEVICE_STATE_ACQUIRING_CHANNEL); + bowRequestCh(prAdapter); + } + /*Initiator is NOT FOUND */ + else { + /*Scan again, until PAL timeout */ + bowResponderScan(prAdapter); +#if 0 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, 0, NULL, 0); +#endif + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Function for cancelling scan request. There is another option to extend channel privilige +* for another purpose. +* +* @param fgIsChannelExtention - Keep the channel previlege, but can cancel scan timer. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention) +{ + + P_MSG_SCN_SCAN_CANCEL prScanCancel = (P_MSG_SCN_SCAN_CANCEL) NULL; + P_BOW_FSM_INFO_T prBowFsmInfo = (P_BOW_FSM_INFO_T) NULL; + + DEBUGFUNC("bowResponderCancelScan()"); + + do { + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (TRUE) { +#if CFG_BOW_TEST + kalPrint("BOW SCAN [CANCEL:%d]\n", prBowFsmInfo->ucSeqNumOfScanReq); +#endif + /* There is a channel privilege on hand. */ + + DBGLOG(P2P, TRACE, "BOW Cancel Scan\n"); + + prScanCancel = + (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancel) { + /* Buffer not enough, can not cancel scan request. */ + DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); + ASSERT(FALSE); + break; + } + + prScanCancel->rMsgHdr.eMsgId = MID_BOW_SCN_SCAN_CANCEL; + prScanCancel->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prScanCancel->ucSeqNum = prBowFsmInfo->ucSeqNumOfScanReq; +#if CFG_ENABLE_WIFI_DIRECT + prScanCancel->fgIsChannelExt = fgIsChannelExtention; +#endif + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancel, MSG_SEND_METHOD_BUF); + + } + + } while (FALSE); + +} /* bowResponderCancelScan */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialization of JOIN STATE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + ASSERT(prBssDesc); + ASSERT(prAdapter); + + DBGLOG(BOW, EVENT, "Starting bowResponderJoin.\n"); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> We are going to connect to this BSS. */ + prBssDesc->fgIsConnecting = TRUE; + bowSetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress, BOW_DEVICE_STATE_CONNECTING); + + /* 4 <2> Setup corresponding STA_RECORD_T */ + /*Support First JOIN and retry */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_BOW_AP, NETWORK_TYPE_BOW_INDEX, prBssDesc); + if (!prStaRec) + return; + + prBowFsmInfo->prTargetStaRec = prStaRec; + + /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ + prStaRec->fgIsReAssoc = FALSE; + prBowFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + + /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ + if (prBowFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(BOW, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); + prBowFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else { + ASSERT(0); + } + + /* 4 <4.1> sync. to firmware domain */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* 4 <5> Overwrite Connection Setting for eConnectionPolicy */ + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prBssDesc->aucSSID); + DBGLOG(BOW, EVENT, "bowResponderJoin, SSID %s.\n", prConnSettings->aucSSID); +#endif + } + /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); /* Can't trigger SAA FSM */ + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_BOW_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prBowFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + prBssInfo->prStaRecOfAP = prStaRec; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "prStaRec->eStaType, %x.\n", prStaRec->eStaType); + DBGLOG(BOW, INFO, "BoW trigger SAA [%pM]\n", prStaRec->aucMacAddr); +#endif + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Join Complete Event from SAA FSM for BOW FSM +* +* @param[in] prMsgHdr Message of Join Complete of SAA FSM. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_JOIN_COMP_T prJoinCompMsg; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prAssocRspSwRfb; + P_BSS_INFO_T prBssInfo; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; + UINT_16 u2IELength; + PUINT_8 pucIE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete.\n"); + DBGLOG(BOW, EVENT, "bowfsmRunEventJoinComplete ptr check\n"); + DBGLOG(BOW, EVENT, "prMsgHdr %x\n", prMsgHdr); + DBGLOG(BOW, EVENT, "prAdapter %x\n", prAdapter); + DBGLOG(BOW, EVENT, "prBowFsmInfo %x\n", prBowFsmInfo); + DBGLOG(BOW, EVENT, "prStaRec %x\n", prStaRec); +#endif + + ASSERT(prStaRec); + ASSERT(prBowFsmInfo); + + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prBowFsmInfo->ucSeqNumOfReqMsg) { + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); + + /* 4 <1> JOIN was successful */ + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - + WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + prStaRec->eStaType = STA_TYPE_BOW_AP; + prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; +#if CFG_BOW_RATE_LIMITATION + /* 4 <1.2>Update Rate Set */ + /*Limit Rate Set to 24M, 48M, 54M */ + prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); + /*If peer cannot support the above rate set, fix on the available highest rate */ + if (prStaRec->u2DesiredNonHTRateSet == 0) { + UINT_8 ucHighestRateIndex; + + if (rateGetHighestRateIndexFromRateSet + (prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) { + prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); + } + } +#endif + + /* 4 <1.1> Change FW's Media State immediately. */ + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + /* 4 <1.2> Update HT information and set channel */ + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ +#if CFG_BOW_SUPPORT_11N + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); +#endif + + /* 4 <1.3> Update BSS_INFO_T */ + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Finish bowUpdateBssInfoForJOIN.\n"); +#endif + /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowFsmRunEventJoinComplete, qmActivateStaRec.\n"); +#endif + + /* 4 <1.7> Set the Next State of BOW FSM */ + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); + } + /* 4 <2> JOIN was not successful */ + else { + /*Retry */ + bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); +#if 0 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, 0, NULL, 0); +#endif +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Start bowfsmRunEventJoinComplete -- Join failed.\n"); + DBGLOG(BOW, INFO, "BoW trigger SAA REJOIN\n"); +#endif + } + } + + cnmMemFree(prAdapter, prMsgHdr); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Media State to HOST +* +* @param[in] eConnectionState Current Media State +* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN BOOLEAN fgDelayIndication) +{ + EVENT_CONNECTION_STATUS rEventConnStatus; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + /* NOTE(Kevin): Move following line to bowChangeMediaState() macro per CM's request. */ + /* prBowBssInfo->eConnectionState = eConnectionState; */ + + /* For indicating the Disconnect Event only if current media state is + * disconnected and we didn't do indication yet. + */ + if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + if (prBssInfo->eConnectionStateIndicated == eConnectionState) + return; + } + + if (!fgDelayIndication) { + /* 4 <0> Cancel Delay Timer */ + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rIndicationOfDisconnectTimer); + + /* 4 <1> Fill EVENT_CONNECTION_STATUS */ + rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; + + if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + if (prBssInfo->eCurrentOPMode == OP_MODE_BOW) { + rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; + rEventConnStatus.u2AID = prBssInfo->u2AssocId; + rEventConnStatus.u2ATIMWindow = 0; + } else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; + rEventConnStatus.u2AID = 0; + rEventConnStatus.u2ATIMWindow = prBssInfo->u2ATIMWindow; + } else { + ASSERT(0); + } + + COPY_SSID(rEventConnStatus.aucSsid, + rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + COPY_MAC_ADDR(rEventConnStatus.aucBssid, prBssInfo->aucBSSID); + + rEventConnStatus.u2BeaconPeriod = prBssInfo->u2BeaconInterval; + rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prBssInfo->ucPrimaryChannel); + + switch (prBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_HR_DSSS_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + + case PHY_TYPE_ERP_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; + break; + + case PHY_TYPE_OFDM_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; + break; + + default: + ASSERT(0); + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + } + } else { +#if CFG_PRIVACY_MIGRATION + /* Clear the pmkid cache while media disconnect */ + secClearPmkid(prAdapter); +#endif + + rEventConnStatus.ucReasonOfDisconnect = prBssInfo->ucReasonOfDisconnect; + + } + + /* 4 <2> Indication */ + nicMediaStateChange(prAdapter, NETWORK_TYPE_BOW_INDEX, &rEventConnStatus); + prBssInfo->eConnectionStateIndicated = eConnectionState; + } else { + /* NOTE: Only delay the Indication of Disconnect Event */ + ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); + + DBGLOG(BOW, INFO, "Postpone the indication of Disconnect for %d seconds\n", + prConnSettings->ucDelayTimeOfDisconnectEvent); + + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rIndicationOfDisconnectTimer, + SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Event of Tx Fail of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowRunEventAAATxFail , bssRemoveStaRecFromClientList.\n"); + DBGLOG(BOW, INFO, "BoW AAA TxFail, target state %d\n", prStaRec->ucStaState + 1); +#endif + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + + ASSERT(prStaRec); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowRunEventAAAComplete, cnmStaRecChangeState, STA_STATE_3.\n"); + DBGLOG(BOW, INFO, "BoW AAA complete [%pM]\n", prStaRec->aucMacAddr); +#endif + + /*Update BssInfo to connected */ + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /*Update StaRec to State3 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + /*Connected */ + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, FALSE, wlanbowCmdEventLinkConnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle RxDeauth +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBowBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if (!IS_STA_IN_BOW(prStaRec)) + return WLAN_STATUS_NOT_ACCEPTED; + + eFsmState = bowGetBowTableState(prAdapter, prStaRec->aucMacAddr); + + if (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) { + /*do nothing */ + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (prStaRec->ucStaState > STA_STATE_1) { + + if (STA_STATE_3 == prStaRec->ucStaState) { + /* P_MSG_AIS_ABORT_T prAisAbortMsg; */ + + /* NOTE(Kevin): Change state immediately to avoid starvation of + * MSG buffer because of too many deauth frames before changing + * the STA state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + + COPY_MAC_ADDR(prBowFsmInfo->aucPeerAddress, prStaRec->aucMacAddr); + + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, wlanbowCmdEventLinkDisconnected, wlanbowCmdTimeoutHandler, 0, NULL, 0); + + return WLAN_STATUS_SUCCESS; + } + + return WLAN_STATUS_NOT_ACCEPTED; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function handle BoW Link disconnect. +* +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +* +* \note after receive deauth frame, callback function call this +*/ +/*----------------------------------------------------------------------------*/ +VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + /*Free target StaRec */ + if (prMsduInfo) + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + else + prStaRec = prBowFsmInfo->prTargetStaRec; + + if (prStaRec) + /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + kalPrint("bowDisconnectLink\n"); + /*No one connected */ + if (g_u4LinkCount == 0 && g_u4Beaconing != 0) { + cnmTimerStopTimer(prAdapter, &prBowFsmInfo->rStartingBeaconTimer); + bowStopping(prAdapter); + kalPrint("bowStopping\n"); + /*Restore TxPower from Short range mode */ +#if CFG_SUPPORT_NVRAM && 0 + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + /*Uninit BoW Interface */ +#if CFG_BOW_SEPARATE_DATA_PATH + kalUninitBowDevice(prAdapter->prGlueInfo); +#endif + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Assoc Req Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Assoc Resp +* @retval FALSE Don't reply the Assoc Resp +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) +{ + BOOLEAN fgReplyAssocResp = FALSE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; + OS_SYSTIME rCurrentTime; + static OS_SYSTIME rLastRejectAssocTime; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAssocReq, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, "bowValidateAssocReq, prAssocReqFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", + prAssocReqFrame->aucSrcAddr[0], + prAssocReqFrame->aucSrcAddr[1], + prAssocReqFrame->aucSrcAddr[2], + prAssocReqFrame->aucSrcAddr[3], + prAssocReqFrame->aucSrcAddr[4], prAssocReqFrame->aucSrcAddr[5])); +#endif + + /*Assoc Accept */ + while (EQUAL_MAC_ADDR(prAssocReqFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAssocReq, return wlanbowCmdEventLinkConnected.\n"); +#endif + /*Update StaRec */ + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_BOW_INDEX, prAssocReqFrame->aucSrcAddr); + if (!prStaRec) + break; + prStaRec->eStaType = STA_TYPE_BOW_CLIENT; + prStaRec->u2DesiredNonHTRateSet &= prBowBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prBowBssInfo->ucPhyTypeSet; + +#if CFG_BOW_RATE_LIMITATION + /*Limit Rate Set to 24M, 48M, 54M */ + prStaRec->u2DesiredNonHTRateSet &= (RATE_SET_BIT_24M | RATE_SET_BIT_48M | RATE_SET_BIT_54M); + /*If peer cannot support the above rate set, fix on the available highest rate */ + if (prStaRec->u2DesiredNonHTRateSet == 0) { + UINT_8 ucHighestRateIndex; + + if (rateGetHighestRateIndexFromRateSet(prBowBssInfo->u2OperationalRateSet, &ucHighestRateIndex)) + prStaRec->u2DesiredNonHTRateSet = BIT(ucHighestRateIndex); + else { + /*If no available rate is found, DECLINE the association */ + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + } +#endif + prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + + /*Undpate BssInfo to FW */ + bowChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + + /*reply successful */ + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + fgReplyAssocResp = TRUE; + break; + } + + /*Reject Assoc */ + if (*pu2StatusCode != STATUS_CODE_SUCCESSFUL) { + /*Reply Assoc with reject every 5s */ + rCurrentTime = kalGetTimeTick(); + if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAssocTime, MSEC_TO_SYSTIME(5000)) || + rLastRejectAssocTime == 0) { + fgReplyAssocResp = TRUE; + rLastRejectAssocTime = rCurrentTime; + } + } + + return fgReplyAssocResp; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Auth Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Auth +* @retval FALSE Don't reply the Auth +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +bowValidateAuth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) +{ + BOOLEAN fgReplyAuth = FALSE; + P_BSS_INFO_T prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; + OS_SYSTIME rCurrentTime; + static OS_SYSTIME rLastRejectAuthTime; + + /* TODO(Kevin): Call BoW functions to check .. + 1. Check we are BoW now. + 2. Check we can accept connection from thsi peer + 3. Check Black List here. + */ + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, prBowFsmInfo->aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + prBowFsmInfo->aucPeerAddress[0], + prBowFsmInfo->aucPeerAddress[1], + prBowFsmInfo->aucPeerAddress[2], + prBowFsmInfo->aucPeerAddress[3], + prBowFsmInfo->aucPeerAddress[4], prBowFsmInfo->aucPeerAddress[5])); + DBGLOG(BOW, EVENT, "bowValidateAuth, prAuthFrame->aucSrcAddr, %x:%x:%x:%x:%x:%x.\n", + prAuthFrame->aucSrcAddr[0], + prAuthFrame->aucSrcAddr[1], + prAuthFrame->aucSrcAddr[2], + prAuthFrame->aucSrcAddr[3], prAuthFrame->aucSrcAddr[4], prAuthFrame->aucSrcAddr[5])); +#endif + + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX, prAuthFrame->aucSrcAddr); + if (!prStaRec) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecAlloc.\n"); +#endif + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_BOW_INDEX); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + if (!prStaRec) + return fgReplyAuth; + COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + prBowBssInfo->prStaRecOfAP = prStaRec; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, cnmStaRecChangeState.\n"); +#endif + } else { + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucIndex, %x.\n", prStaRec->ucIndex); +#endif + bssRemoveStaRecFromClientList(prAdapter, prBowBssInfo, prStaRec); + } + + if (EQUAL_MAC_ADDR(prAuthFrame->aucSrcAddr, prBowFsmInfo->aucPeerAddress)) { + + prStaRec->eStaType = STA_TYPE_BOW_CLIENT; + prStaRec->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->eStaType, %x.\n", prStaRec->eStaType); + DBGLOG(BOW, EVENT, "bowValidateAuth, prStaRec->ucNetTypeIndex, %x.\n", prStaRec->ucNetTypeIndex); +#endif + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->ucJoinFailureCount = 0; + *pprStaRec = prStaRec; + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + fgReplyAuth = TRUE; + } else { + cnmStaRecFree(prAdapter, prStaRec, FALSE); + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + + /*Reply auth with reject every 5s */ + rCurrentTime = kalGetTimeTick(); + if (CHECK_FOR_TIMEOUT(rCurrentTime, rLastRejectAuthTime, MSEC_TO_SYSTIME(5000)) || + rLastRejectAuthTime == 0) { + fgReplyAuth = TRUE; + rLastRejectAuthTime = rCurrentTime; + } + } + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowValidateAuth, fgReplyAuth, %x.\n", fgReplyAuth); +#endif + return fgReplyAuth; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is invoked when CNM granted channel privilege +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prBowBssInfo; + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_GRANT_T prMsgChGrant; + UINT_8 ucTokenID; + UINT_32 u4GrantInterval; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prBowBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; + ucTokenID = prMsgChGrant->ucTokenID; + u4GrantInterval = prMsgChGrant->u4GrantInterval; + + /* 1. free message */ + cnmMemFree(prAdapter, prMsgHdr); + prBowFsmInfo->fgIsChannelGranted = TRUE; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Entering bowRunEventChGrant.\n"); +#endif + + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + /*Release channel */ + if ((!prBowFsmInfo->fgIsChannelRequested) || + (prBowFsmInfo->ucSeqNumOfChReq != ucTokenID) || + (eFsmState == BOW_DEVICE_STATE_DISCONNECTED) || (eFsmState == BOW_DEVICE_STATE_DISCONNECTING)) { +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "BoW Channel [GIVE UP:%d]\n", ucTokenID); + DBGLOG(BOW, INFO, "[Requested:%d][ucSeqNumOfChReq:%d][eFsmState:%d]\n", + prBowFsmInfo->fgIsChannelRequested, prBowFsmInfo->ucSeqNumOfChReq, eFsmState); +#endif + bowReleaseCh(prAdapter); + return; + } + + /* 2. channel privilege has been approved */ + prBowFsmInfo->u4ChGrantedInterval = u4GrantInterval; + +#if 0 + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, + prBowFsmInfo->u4ChGrantedInterval - BOW_JOIN_CH_GRANT_THRESHOLD); +#else + cnmTimerStartTimer(prAdapter, + &prBowFsmInfo->rChGrantedTimer, BOW_JOIN_CH_REQUEST_INTERVAL - BOW_JOIN_CH_GRANT_THRESHOLD); +#endif + + /* 3.2 set local variable to indicate join timer is ticking */ + prBowFsmInfo->fgIsInfraChannelFinished = FALSE; + +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "BoW Channel [GRANTED:%d].\n", ucTokenID); +#endif + + if (eFsmState == BOW_DEVICE_STATE_ACQUIRING_CHANNEL) { + bowStarting(prAdapter); + bowReleaseCh(prAdapter); + if (prBowFsmInfo->ucRole == BOW_RESPONDER) + bowResponderJoin(prAdapter, prBowFsmInfo->prTargetBssDesc); + } else { + /*update bssinfo */ + nicUpdateBss(prAdapter, NETWORK_TYPE_BOW_INDEX); + bowReleaseCh(prAdapter); + } + +} /* end of aisFsmRunEventChGrant() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM for channel privilege requesting +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID bowRequestCh(IN P_ADAPTER_T prAdapter) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_REQ_T prMsgChReq; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (prBowFsmInfo->fgIsChannelGranted == FALSE) { + +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "BoW channel [REQUEST:%d], %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq + 1, + prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); +#endif + prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel acquiring */ + return; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prMsgChReq->ucTokenID = ++prBowFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; +#if 0 + prMsgChReq->u4MaxInterval = BOW_JOIN_CH_REQUEST_INTERVAL; +#else + prMsgChReq->u4MaxInterval = 1; +#endif + /* prBowFsmInfo->prTargetBssDesc->ucChannelNum; */ + prMsgChReq->ucPrimaryChannel = prBowFsmInfo->ucPrimaryChannel; + /* prBowFsmInfo->prTargetBssDesc->eSco; */ + prMsgChReq->eRfSco = CHNL_EXT_SCN; + /* prBowFsmInfo->prTargetBssDesc->eBand; */ + prMsgChReq->eRfBand = prBowFsmInfo->eBand; + COPY_MAC_ADDR(prMsgChReq->aucBSSID, prBowFsmInfo->aucPeerAddress); + + prBowFsmInfo->fgIsChannelRequested = TRUE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform BOW that channel privilege is granted +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID bowReleaseCh(IN P_ADAPTER_T prAdapter) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + P_MSG_CH_ABORT_T prMsgChAbort; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + + if (prBowFsmInfo->fgIsChannelGranted != FALSE || prBowFsmInfo->fgIsChannelRequested != FALSE) { +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "BoW channel [RELEASE:%d] %d, %d.\n", prBowFsmInfo->ucSeqNumOfChReq, + prBowFsmInfo->ucPrimaryChannel, prBowFsmInfo->eBand); +#endif + + prBowFsmInfo->fgIsChannelRequested = FALSE; + prBowFsmInfo->fgIsChannelGranted = FALSE; + + /* 1. return channel privilege to CNM immediately */ + prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChAbort) { + ASSERT(0); /* Can't release Channel to CNM */ + return; + } + + prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + prMsgChAbort->ucTokenID = prBowFsmInfo->ucSeqNumOfChReq; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); + } + +} /* end of aisFsmReleaseCh() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) +{ + P_BOW_FSM_INFO_T prBowFsmInfo; + ENUM_BOW_DEVICE_STATE eFsmState; + + ASSERT(prAdapter); + + prBowFsmInfo = &(prAdapter->rWifiVar.rBowFsmInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "BoW Channel [TIMEOUT]\n"); +#endif +#if 1 + /* bowReleaseCh(prAdapter); */ + eFsmState = bowGetBowTableState(prAdapter, prBowFsmInfo->aucPeerAddress); + + /*If connecting is not completed, request CH again */ + if ((eFsmState == BOW_DEVICE_STATE_CONNECTING) || (eFsmState == BOW_DEVICE_STATE_STARTING)) + bowRequestCh(prAdapter); +#endif +} + +BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucBowTableIdx = 0; + CMD_INFO_T rCmdInfo; + + ASSERT(prAdapter); + + kalMemZero(&rCmdInfo, sizeof(CMD_INFO_T)); + + while (ucBowTableIdx < CFG_BOW_PHYSICAL_LINK_NUM) { + if (arBowTable[ucBowTableIdx].fgIsValid) { + COPY_MAC_ADDR(prAdapter->rWifiVar.rBowFsmInfo.aucPeerAddress, + arBowTable[ucBowTableIdx].aucPeerAddress); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "bowNotifyAllLinkDisconnected, arBowTable[%x].aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + ucBowTableIdx, arBowTable[ucBowTableIdx].aucPeerAddress[0], + arBowTable[ucBowTableIdx].aucPeerAddress[1], + arBowTable[ucBowTableIdx].aucPeerAddress[2], + arBowTable[ucBowTableIdx].aucPeerAddress[3], + arBowTable[ucBowTableIdx].aucPeerAddress[4], + arBowTable[ucBowTableIdx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, + "bowNotifyAllLinkDisconnected, arBowTable[%x].fgIsValid, %x.\n", ucBowTableIdx, + arBowTable[ucBowTableIdx].fgIsValid); +#endif +#if 1 + wlanoidSendSetQueryBowCmd(prAdapter, + CMD_ID_CMD_BT_OVER_WIFI, + TRUE, + FALSE, + wlanbowCmdEventLinkDisconnected, + wlanbowCmdTimeoutHandler, 0, NULL, 0); +#else + wlanbowCmdEventLinkDisconnected(prAdapter, &rCmdInfo, NULL); +#endif + } + + ucBowTableIdx += 1; + } + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ + +BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { + if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, + arBowTable[idx].fgIsValid); + +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + return FALSE; +} + +BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable) +{ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + if (arBowTable[ucBowTableIdx].fgIsValid) { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "bowGetBowTableContent, arBowTable[idx].fgIsValid, %x, %x.\n", ucBowTableIdx, + arBowTable[ucBowTableIdx].fgIsValid); + DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[ucBowTableIdx].eState); +#endif + prBowTable = &(arBowTable[ucBowTableIdx]); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return TRUE; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + +BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable) +{ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + COPY_MAC_ADDR(arBowTable[ucBowTableIdx].aucPeerAddress, prBowTable->aucPeerAddress); + arBowTable[ucBowTableIdx].eState = prBowTable->eState; + arBowTable[ucBowTableIdx].fgIsValid = prBowTable->fgIsValid; + arBowTable[ucBowTableIdx].ucAcquireID = prBowTable->ucAcquireID; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + kalSetBowState(prAdapter->prGlueInfo, prBowTable->eState, prBowTable->aucPeerAddress); + /* kalSetBowRole(prAdapter->prGlueInfo, prBowTable->ucRole, prBowTable->aucPeerAddress); */ + +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "SET State [%d]\n", arBowTable[ucBowTableIdx].eState); + DBGLOG(BOW, EVENT, + "kalCheckBowifVaild, arBowTable[ucBowTableIdx].fgIsValid, %x, %x.\n", ucBowTableIdx, + arBowTable[ucBowTableIdx].fgIsValid); +#endif + + return TRUE; + +} + +BOOLEAN +bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { + if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalCheckBowifVaild, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); + DBGLOG(BOW, EVENT, + "kalCheckBowifVaild, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, + "kalCheckBowifVaild, arBowTable[idx].fgIsValid, %x, %x.\n", idx, + arBowTable[idx].fgIsValid); +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + *pucBowTableIdx = idx; + + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + +BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { + if (!arBowTable[idx].fgIsValid) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, + "bowGetBowTableFreeEntry, arBowTable[idx].fgIsValid, %x, %x.\n", idx, + arBowTable[idx].fgIsValid); +#endif + *pucBowTableIdx = idx; + arBowTable[idx].fgIsValid = TRUE; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return TRUE; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return FALSE; +} + +ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]) +{ + UINT_8 idx; + + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + for (idx = 0; idx < CFG_BOW_PHYSICAL_LINK_NUM; idx++) { + if (arBowTable[idx].fgIsValid && EQUAL_MAC_ADDR(arBowTable[idx].aucPeerAddress, aucPeerAddress)) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "bowGetState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); + DBGLOG(BOW, EVENT, "bowGetState, arBowTable[idx].aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", idx, + arBowTable[idx].aucPeerAddress[0], + arBowTable[idx].aucPeerAddress[1], + arBowTable[idx].aucPeerAddress[2], + arBowTable[idx].aucPeerAddress[3], + arBowTable[idx].aucPeerAddress[4], arBowTable[idx].aucPeerAddress[5])); + DBGLOG(BOW, EVENT, + "bowGetState, arBowTable[idx].fgIsValid, %x, %x.\n", idx, arBowTable[idx].fgIsValid); + DBGLOG(BOW, EVENT, + "bowGetState, arBowTable[idx].eState;, %x, %x.\n", idx, arBowTable[idx].eState); + DBGLOG(BOW, INFO, "GET State [%d]\n", arBowTable[idx].eState); +#endif + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return arBowTable[idx].eState; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + return BOW_DEVICE_STATE_DISCONNECTED; +} + +BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState) +{ + UINT_8 ucBowTableIdx; + + if (bowGetBowTableEntryByPeerAddress(prAdapter, aucPeerAddress, &ucBowTableIdx)) { + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + arBowTable[ucBowTableIdx].eState = eState; +#if CFG_BOW_TEST + DBGLOG(BOW, INFO, "SET State [%d]\n", eState); +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_BOW_TABLE); + + kalSetBowState(prAdapter->prGlueInfo, eState, aucPeerAddress); + return TRUE; + } + return FALSE; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c new file mode 100644 index 0000000000000..1c59f861047e6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_lib.c @@ -0,0 +1,6240 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_lib.c#2 +*/ +/*! \file wlan_lib.c + \brief Internal driver stack will export the required procedures here for GLUE Layer. + + This file contains all routines which are exported from MediaTek 802.11 Wireless + LAN driver stack to GLUE Layer. +*/ + +/* +** Log: wlan_lib.c +** +** 08 15 2012 eason.tsai +** [ALPS00338170] [Need Patch] [Volunteer Patch] modify build warning +** fix build waring for codechange + * + * 07 13 2012 cp.wu + * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for termination + * after SDIO error has happened + * [driver domain] add force reset by host-to-device interrupt mechanism + * + * 06 11 2012 cp.wu + * [WCXRP00001252] [MT6620 Wi-Fi][Driver] Add debug message while encountering firmware response timeout + * output message while timeout event occurs + * + * 06 11 2012 eason.tsai + * NULL + * change from binay to hex code + * + * 06 08 2012 eason.tsai + * NULL + * Nvram context covert from 6620 to 6628 for old 6620 meta tool + * + * 05 11 2012 cp.wu + * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience + * show MAC address & source while initiliazation + * + * 03 29 2012 eason.tsai + * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define + * add conditional define. + * + * 03 04 2012 eason.tsai + * NULL + * modify the cal fail report code. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 16 2012 cp.wu + * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band + * configuration with corresponding network configuration correct scan result removing policy. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with + * corresponding network configuration add wlanSetPreferBandByNetwork() for glue layer to invoke + * for setting preferred band configuration corresponding to network type. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment + * when returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 11 14 2011 cm.chang + * [WCXRP00001104] [All Wi-Fi][FW] Show init process by HW mail-box register + * Show FW initial ID when timeout to wait for ready bit + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 10 18 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * when powering off, always clear pending interrupts, then wait for RDY to be de-asserted + * + * 10 14 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * shorten the packet length for firmware download if no more than 2048 bytes. + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware download path in divided scatters. + * + * 10 03 2011 cp.wu + * [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware downloading aggregated path. + * + * 09 30 2011 cm.chang + * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band + * . + * + * 09 20 2011 cp.wu + * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized + * 1. always show error message for SDIO bus errors. + * 2. reset bus error flag when re-initialization + * + * 08 26 2011 cm.chang + * [WCXRP00000952] [MT5931 Wi-Fi][FW] Handshake with BWCS before DPD/TX power calibration + * Fix compiling error for WinXP MT5931 driver + * + * 08 25 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS Sync ready for WinXP. + * + * 08 25 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add DFS switch. + * + * 08 24 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Update RDD test mode cases. + * + * 08 19 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * escape from normal path if any error is occurred. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * reuse firmware download logic of MT6620 for MT6628. + * + * 08 15 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a + * disconnecting device issue. + * Fix GO send deauth frame issue. + * + * 07 22 2011 jeffrey.chang + * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time + * modify driver to set OSC stable time after f/w download + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 06 24 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * if there is no valid address in chip, generate a new one from driver domain instead of firmware domain + * due to sufficient randomness + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 06 20 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * disable whole-chip resetting mechanism due to the need of further ECO to work as expected. + * + * 05 31 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * changed to use non-zero checking for valid bit in NVRAM content + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 18 2011 cp.wu + * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain + * pass PHY_PARAM in NVRAM from driver to firmware. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * correct assertion. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 05 11 2011 cm.chang + * [WCXRP00000717] [MT5931 Wi-Fi][Driver] Handle wrong NVRAM content about AP bandwidth setting + * . + * + * 05 05 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * change delay from 100ms to 120ms upon DE's suggestion. + * + * 05 05 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * add delay after whole-chip resetting for MT5931 E1 ASIC. + * + * 04 22 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space + * process for RESET_START and RESET_END events skip power-off handshaking when RESET indication is received. + * + * 04 22 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * . + * + * 04 18 2011 cp.wu + * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) + * 1) add API for glue layer to query ACPI state + * 2) Windows glue should not access to hardware after switched into D3 state + * + * 04 15 2011 cp.wu + * [WCXRP00000654] [MT6620 Wi-Fi][Driver] Add loop termination criterion for wlanAdapterStop(). + * add loop termination criteria for wlanAdapterStop(). + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing + * frame dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 04 06 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure + * happend inside wlanAdapterStart invoke nicReleaseAdapterMemory() as failure handling in case + * wlanAdapterStart() failed unexpectedly + * + * 03 29 2011 wh.su + * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error + * fixed the kclocwork error. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically + * continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 02 25 2011 cp.wu + * [WCXRP00000496] [MT5931][Driver] Apply host-triggered chip reset before initializing firmware download procedures + * apply host-triggered chip reset mechanism before initializing firmware download procedures. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Change GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 01 2011 george.huang + * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers + * init variable for CTIA. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer when the + * corresponding BSS is disconnected due to beacon timeout remove from scanning result when the BSS + * is disconnected due to beacon timeout. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to + * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous + * and physically-continuous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * while being unloaded, clear all pending interrupt then set LP-own to firmware + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay + * to avoid blocking to system scheduling change to use msleep() and shorten waiting interval + * to reduce blocking to other task while Wi-Fi driver is being loaded + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 22 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Remove controling auto rate from initial setting. The initial setting is defined by FW code. + * + * 12 15 2010 cp.wu + * NULL + * sync. with ALPS code by enabling interrupt just before leaving wlanAdapterStart() + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * Change Param name for invitation connection. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 03 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) use 8 buffers for MT5931 which is equipped with less memory + * 2) modify MT5931 debug level to TRACE when download is successful + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * for MT5931, adapter initialization is done *after* firmware is downloaded. + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * correct MT5931 firmware download procedure: + * MT5931 will download firmware first then acquire LP-OWN + * + * 11 02 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) update MT5931 firmware encryption tool. (using 64-bytes unit) + * 2) update MT5931 firmware download procedure + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying + * current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function + * for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 25 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add option for enable/disable TX PWR gain adjustment (default: off) + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 15 2010 cp.wu + * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A + * bugfix: always reset pointer to IEbuf to zero when keeping scanning result for the connected AP + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced + * by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with + * AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 13 2010 cp.wu + * NULL + * acquire & release power control in oid handing wrapper. + * + * 09 09 2010 cp.wu + * NULL + * move IE to buffer head when the IE pointer is not pointed at head. + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 09 01 2010 cp.wu + * NULL + * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 13 2010 cp.wu + * NULL + * correction issue: desired phy type not initialized as ABGN mode. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 10 2010 cm.chang + * NULL + * Support EEPROM read/write in RF test mode + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 13 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Reduce unnecessary type casting + * + * 07 13 2010 cp.wu + * + * use multiple queues to keep 1x/MMPDU/CMD's strict order even when there is incoming 1x frames. + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent + * network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * initialize mbox & ais_fsm in wlanAdapterStart() + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * simplify timer usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable interrupt then send power control command packet. + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when stopping adapter, wait til RDY bit has been cleaerd. + * 2) set TASK_OFFLOAD as driver-core OIDs + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * roll-back to rev.60. + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove redundant firmware image unloading + * 2) use compile-time macros to separate logic related to accquiring own + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always set fw-own before driver is unloaded. + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * 2) command sequence number is now increased atomically + * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * 2) add 2 kal API for later integration + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) eliminate unused definitions + * 2) ready bit will be polled for limited iteration + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * kalOidComplete is not necessary in linux + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use pass-in prRegInfo instead of accessing prGlueInfo directly + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding none-glue code portability + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding non-glue code portability + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve non-glue code portability + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load address & start address are now configured from config.h + * due to the different configurations on FPGA and ASIC + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * only send CMD_NIC_POWER_CTRL in wlanAdapterStop() when card is not removed and is not in D3 state + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * +* 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when starting adapter, read local adminsitrated address from registry and send to firmware via CMD_BASIC_CONFIG. + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 03 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add command/event definitions for initial states + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for QM_TEST_MODE + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct function name .. + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * separate wlanProcesQueuePacket() into 2 APIs upon request + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct wlanAdapterStart + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * 2) firmware image length is now retrieved via NdisFileOpen + * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * 4) nicRxWaitResponse() revised + * 5) another set of TQ counter default value is added for fw-download state + * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * 2. follow MSDN defined behavior when associates to another AP + * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * wlanoidSetFrequency is now implemented by RF test command. + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * QueryRssi is no longer w/o hardware access, it is now implemented by command/event handling loop + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. clear prPendingCmdInfo properly + * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. + * + * 01 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * allow MCR read/write OIDs in RF test mode + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * 2. block TX/ordinary OID when RF test mode is engaged + * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * 4. correct some HAL implementation + * + * 01 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-12-10 16:54:36 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-12-09 20:04:59 GMT mtk02752 +** only report as connected when CFG_HIF_EMULATION_TEST is set to 1 +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-12-08 17:39:41 GMT mtk02752 +** wlanoidRftestQueryAutoTest could be executed without touching hardware +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-12-03 16:10:26 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-02 22:05:33 GMT mtk02752 +** kalOidComplete() will decrease i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-01 23:02:36 GMT mtk02752 +** remove unnecessary spinlock +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-01 22:50:38 GMT mtk02752 +** use TC4 for command, maintein i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-27 12:45:34 GMT mtk02752 +** prCmdInfo should be freed when invoking wlanReleasePendingOid() to clear pending oid +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-24 19:55:51 GMT mtk02752 +** wlanSendPacket & wlanRetransmitOfPendingFrames is only used in old data path +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-23 17:59:55 GMT mtk02752 +** clear prPendingOID inside wlanSendCommand() when the OID didn't need to be replied. +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-23 14:45:29 GMT mtk02752 +** add another version of wlanSendCommand() for command-sending only without blocking for response +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-17 22:40:44 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 10:14:56 GMT mtk01084 +** modify place to invoke wlanIst +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-10-30 18:17:07 GMT mtk01084 +** fix compiler warning +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-10-29 19:46:15 GMT mtk01084 +** invoke interrupt process routine +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-10-13 21:58:24 GMT mtk01084 +** modify for new HW architecture +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-09-09 17:26:01 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-05-20 12:21:27 GMT mtk01461 +** Add SeqNum check when process Event Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-05-19 10:38:44 GMT mtk01461 +** Add wlanReleasePendingOid() for mpReset() if there is a pending OID and no available TX resource to send it. +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-04-29 15:41:34 GMT mtk01461 +** Add handle of EVENT of CMD Result in wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-04-22 09:11:23 GMT mtk01461 +** Fix wlanSendCommand() for Driver Domain CR +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-04-21 09:33:56 GMT mtk01461 +** Update wlanSendCommand() for Driver Domain Response and handle Event Packet, +** wlanQuery/SetInformation() for enqueue CMD_INFO_T +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-17 20:00:08 GMT mtk01461 +** Update wlanImageSectionDownload for optimized CMD process +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-14 20:50:51 GMT mtk01426 +** Fixed compile error +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-13 16:38:40 GMT mtk01084 +** add wifi start function +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-13 14:26:44 GMT mtk01084 +** modify a parameter about FW download length +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-10 21:53:42 GMT mtk01461 +** Update wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-08 16:51:04 GMT mtk01084 +** Update for the image download part +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-01 10:32:47 GMT mtk01461 +** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-03-23 21:44:13 GMT mtk01461 +** Refine TC assignment for WmmAssoc flag +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 16:51:57 GMT mtk01084 +** modify the input argument of caller to RECLAIM_POWER_CONTROL_TO_PM() +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:27:13 GMT mtk01461 +** Add reference code of FW Image Download +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:37 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:08 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 16:28:45 GMT mtk01426 +** Init develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" +#include "mgmt/ais_fsm.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */ +/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to Traffic Class */ +const UINT_8 aucPriorityParam2TC[] = { + TC1_INDEX, + TC0_INDEX, + TC0_INDEX, + TC1_INDEX, + TC2_INDEX, + TC2_INDEX, + TC3_INDEX, + TC3_INDEX +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _CODE_MAPPING_T { + UINT_32 u4RegisterValue; + INT_32 i4TxpowerOffset; +} CODE_MAPPING_T, *P_CODE_MAPPING_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +BOOLEAN fgIsBusAccessFailed = FALSE; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define SIGNED_EXTEND(n, _sValue) \ + (((_sValue) & BIT((n)-1)) ? ((_sValue) | BITS(n, 31)) : \ + ((_sValue) & ~BITS(n, 31))) + +/* TODO: Check */ +/* OID set handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = { + wlanoidSetChannel, + wlanoidSetBeaconInterval, + wlanoidSetAtimWindow, + wlanoidSetFrequency, +}; + +/* TODO: Check */ +/* OID query handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = { + wlanoidQueryBssid, + wlanoidQuerySsid, + wlanoidQueryInfrastructureMode, + wlanoidQueryAuthMode, + wlanoidQueryEncryptionStatus, + wlanoidQueryPmkid, + wlanoidQueryNetworkTypeInUse, + wlanoidQueryBssidList, + wlanoidQueryAcpiDevicePowerState, + wlanoidQuerySupportedRates, + wlanoidQueryDesiredRates, + wlanoidQuery802dot11PowerSaveProfile, + wlanoidQueryBeaconInterval, + wlanoidQueryAtimWindow, + wlanoidQueryFrequency, +}; + +/* OID set handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = { + wlanoidRftestSetTestMode, + wlanoidRftestSetAbortTestMode, + wlanoidRftestSetAutoTest, + wlanoidSetMcrWrite, + wlanoidSetEepromWrite +}; + +/* OID query handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC apfnOidQueryHandlerAllowedInRFTest[] = { + wlanoidRftestQueryAutoTest, + wlanoidQueryMcrRead, + wlanoidQueryEepromRead +} + +; + +PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = { + wlanoidRftestSetTestMode, + wlanoidRftestSetAbortTestMode, + wlanoidSetAcpiDevicePowerState, +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 /* no use */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is a private routine, which is used to check if HW access is needed +* for the OID query/ set handlers. +* +* \param[IN] pfnOidHandler Pointer to the OID handler. +* \param[IN] fgSetInfo It is a Set information handler. +* +* \retval TRUE This function needs HW access +* \retval FALSE This function does not need HW access +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerWOHwAccess; + UINT_32 i; + UINT_32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); + } else { + apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler) + return FALSE; + } + + return TRUE; +} /* wlanIsHandlerNeedHwAccess */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set flag for later handling card +* ejected event. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +* +* \note When surprised removal happens, Glue layer should invoke this +* function to notify WPDD not to do any hw access. +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanCardEjected(IN P_ADAPTER_T prAdapter) +{ + DEBUGFUNC("wlanCardEjected"); + /* INITLOG(("\n")); */ + + ASSERT(prAdapter); + + /* mark that the card is being ejected, NDIS will shut us down soon */ + nicTxRelease(prAdapter); + +} /* wlanCardEjected */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Create adapter object +* +* \param prAdapter This routine is call to allocate the driver software objects. +* If fails, return NULL. +* \retval NULL If it fails, NULL is returned. +* \retval NOT NULL If the adapter was initialized successfully. +*/ +/*----------------------------------------------------------------------------*/ +P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdpater = (P_ADAPTER_T) NULL; + + DEBUGFUNC("wlanAdapterCreate"); + + do { + prAdpater = (P_ADAPTER_T) kalMemAlloc(sizeof(ADAPTER_T), VIR_MEM_TYPE); + + if (!prAdpater) { + DBGLOG(INIT, ERROR, "Allocate ADAPTER memory ==> FAILED\n"); + break; + } + + kalMemZero(prAdpater, sizeof(ADAPTER_T)); + prAdpater->prGlueInfo = prGlueInfo; + + } while (FALSE); + + return prAdpater; +} /* wlanAdapterCreate */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Destroy adapter object +* +* \param prAdapter This routine is call to destroy the driver software objects. +* If fails, return NULL. +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter) +{ + + if (!prAdapter) + return; + + kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T)); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initialize the adapter. The sequence is +* 1. Disable interrupt +* 2. Read adapter configuration from EEPROM and registry, verify chip ID. +* 3. Create NIC Tx/Rx resource. +* 4. Initialize the chip +* 5. Initialize the protocol +* 6. Enable Interrupt +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanAdapterStart(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 i, u4Value = 0; + UINT_32 u4WHISR = 0; + UINT_8 aucTxCount[8]; +#if CFG_ENABLE_FW_DOWNLOAD + UINT_32 u4FwLoadAddr, u4ImgSecSize; +#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + UINT_32 j; + P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; + BOOLEAN fgValidHead; + const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); +#endif +#endif + enum Adapter_Start_Fail_Reason { + ALLOC_ADAPTER_MEM_FAIL, + DRIVER_OWN_FAIL, + INIT_ADAPTER_FAIL, + RAM_CODE_DOWNLOAD_FAIL, + WAIT_FIRMWARE_READY_FAIL, + FAIL_REASON_MAX + } eFailReason; + ASSERT(prAdapter); + + DEBUGFUNC("wlanAdapterStart"); + + eFailReason = FAIL_REASON_MAX; + /* 4 <0> Reset variables in ADAPTER_T */ + prAdapter->fgIsFwOwn = TRUE; + prAdapter->fgIsEnterD3ReqIssued = FALSE; + + QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue)); + + /* Initialize rWlanInfo */ + kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + + /* 4 <0.1> reset fgIsBusAccessFailed */ + fgIsBusAccessFailed = FALSE; + prAdapter->ulSuspendFlag = 0; + + do { + u4Status = nicAllocateAdapterMemory(prAdapter); + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "nicAllocateAdapterMemory Error!\n"); + u4Status = WLAN_STATUS_FAILURE; + eFailReason = ALLOC_ADAPTER_MEM_FAIL; + break; + } + + prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; + + DBGLOG(INIT, TRACE, "wlanAdapterStart(): Acquiring LP-OWN %d\n", fgIsResetting); + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + +#if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); +#endif + + if (prAdapter->fgIsFwOwn == TRUE) { + DBGLOG(INIT, ERROR, "nicpmSetDriverOwn() failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + eFailReason = DRIVER_OWN_FAIL; + break; + } + /* 4 <1> Initialize the Adapter */ + u4Status = nicInitializeAdapter(prAdapter); + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "nicInitializeAdapter failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + eFailReason = INIT_ADAPTER_FAIL; + break; + } + + /* init wake lock before interrupt enable and tx thread */ + KAL_WAKE_LOCK_INIT(prAdapter, &prAdapter->rTxThreadWakeLock, "WLAN TX THREAD"); + + /* 4 <2> Initialize System Service (MGMT Memory pool and STA_REC) */ + nicInitSystemService(prAdapter); + + /* 4 <3> Initialize Tx */ + nicTxInitialize(prAdapter); + wlanDefTxPowerCfg(prAdapter); + + /* 4 <4> Initialize Rx */ + nicRxInitialize(prAdapter); + +#if CFG_ENABLE_FW_DOWNLOAD + if (pvFwImageMapFile == NULL) { + DBGLOG(INIT, ERROR, "No Firmware found!\n"); + u4Status = WLAN_STATUS_FAILURE; + eFailReason = RAM_CODE_DOWNLOAD_FAIL; + break; + } + + /* 1. disable interrupt, download is done by polling mode only */ + nicDisableInterrupt(prAdapter); + + /* 2. Initialize Tx Resource to fw download state */ + nicTxInitResetResource(prAdapter); + + /* 3. FW download here */ + u4FwLoadAddr = prRegInfo->u4LoadAddress; + +#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + /* 3a. parse file header for decision of divided firmware download or not */ + prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; + + if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && + prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, + u4FwImageFileLength - u4CRCOffset)) { + fgValidHead = TRUE; + } else { + fgValidHead = FALSE; + } + + /* 3b. engage divided firmware downloading */ + if (fgValidHead == TRUE) { + DBGLOG(INIT, TRACE, "wlanAdapterStart(): fgValidHead == TRUE\n"); + + for (i = 0; i < prFwHead->u4NumOfEntries; i++) { + +#if CFG_START_ADDRESS_IS_1ST_SECTION_ADDR + if (i == 0) { + prRegInfo->u4StartAddress = prFwHead->arSection[i].u4DestAddr; + DBGLOG(INIT, TRACE, + "wlanAdapterStart(): FW start address 0x%08x\n", + prRegInfo->u4StartAddress); + } +#endif + +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if (wlanImageSectionDownloadAggregated(prAdapter, + prFwHead->arSection[i].u4DestAddr, + prFwHead->arSection[i].u4Length, + (PUINT_8) pvFwImageMapFile + + prFwHead->arSection[i].u4Offset) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + } +#else + for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { + if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = prFwHead->arSection[i].u4Length - j; + + if (wlanImageSectionDownload(prAdapter, + prFwHead->arSection[i].u4DestAddr + j, + u4ImgSecSize, + (PUINT_8) pvFwImageMapFile + + prFwHead->arSection[i].u4Offset + j) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Firmware scatter download failed %d!\n", (int)i); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } +#endif + + /* escape from loop if any pending error occurs */ + if (u4Status == WLAN_STATUS_FAILURE) + break; + } + } else +#endif +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if (wlanImageSectionDownloadAggregated(prAdapter, + u4FwLoadAddr, + u4FwImageFileLength, + (PUINT_8) pvFwImageMapFile) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + } +#else + for (i = 0; i < u4FwImageFileLength; i += CMD_PKT_SIZE_FOR_IMAGE) { + if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImageFileLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImageFileLength - i; + + if (wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8) pvFwImageMapFile + i) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } +#endif + + if (u4Status != WLAN_STATUS_SUCCESS) { + eFailReason = RAM_CODE_DOWNLOAD_FAIL; + break; + } +#if !CFG_ENABLE_FW_DOWNLOAD_ACK + /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ + if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Firmware download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } +#endif + + /* 4. send Wi-Fi Start command */ + DBGLOG(INIT, INFO, " send Wi-Fi Start command\n"); +#if CFG_OVERRIDE_FW_START_ADDRESS + wlanConfigWifiFunc(prAdapter, TRUE, prRegInfo->u4StartAddress); +#else + wlanConfigWifiFunc(prAdapter, FALSE, 0); +#endif +#endif + + DBGLOG(INIT, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); + /* 4 <5> check Wi-Fi FW asserts ready bit */ + i = 0; + while (1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + DBGLOG(INIT, TRACE, "Ready bit asserted\n"); + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + eFailReason = WAIT_FIRMWARE_READY_FAIL; + break; + } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { + UINT_32 u4MailBox0; + + nicGetMailbox(prAdapter, 0, &u4MailBox0); + DBGLOG(INIT, ERROR, "Waiting for Ready bit: Timeout, ID=%u\n", + (u4MailBox0 & 0x0000FFFF)); + u4Status = WLAN_STATUS_FAILURE; + eFailReason = WAIT_FIRMWARE_READY_FAIL; + break; + } + i++; + kalMsleep(10); + } + + if (u4Status == WLAN_STATUS_SUCCESS) { + /* 1. reset interrupt status */ + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if (HAL_IS_TX_DONE_INTR(u4WHISR)) + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + + /* 2. reset TX Resource for normal operation */ + nicTxResetResource(prAdapter); + + /* 3. query for permanent address by polling */ + wlanQueryPermanentAddress(prAdapter); + +#if (CFG_SUPPORT_NIC_CAPABILITY == 1) + /* 4. query for NIC capability */ + wlanQueryNicCapability(prAdapter); +#endif + /* 4.1 query for compiler flags */ + wlanQueryCompileFlags(prAdapter); + + /* 5. Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + /* 6. indicate disconnection as default status */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + if (u4Status != WLAN_STATUS_SUCCESS) { + eFailReason = WAIT_FIRMWARE_READY_FAIL; + break; + } + + /* OID timeout timer initialize */ + cnmTimerInitTimer(prAdapter, + &prAdapter->rOidTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC) wlanReleasePendingOid, (ULONG) NULL); + + /* Return Indicated Rfb list timer */ + cnmTimerInitTimer(prAdapter, + &prAdapter->rReturnIndicatedRfbListTimer, + (PFN_MGMT_TIMEOUT_FUNC) wlanReturnIndicatedPacketsTimeOut, (ULONG) NULL); + + /* Power state initialization */ + prAdapter->fgWiFiInSleepyState = FALSE; + prAdapter->rAcpiState = ACPI_STATE_D0; + + /* Online scan option */ + if (prRegInfo->fgDisOnlineScan == 0) + prAdapter->fgEnOnlineScan = TRUE; + else + prAdapter->fgEnOnlineScan = FALSE; + + /* Beacon lost detection option */ + if (prRegInfo->fgDisBcnLostDetection != 0) + prAdapter->fgDisBcnLostDetection = TRUE; + + /* Load compile time constant */ + prAdapter->rWlanInfo.u2BeaconPeriod = CFG_INIT_ADHOC_BEACON_INTERVAL; + prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW; + +#if 1 /* set PM parameters */ + prAdapter->fgEnArpFilter = prRegInfo->fgEnArpFilter; + prAdapter->u4PsCurrentMeasureEn = prRegInfo->u4PsCurrentMeasureEn; + + prAdapter->u4UapsdAcBmp = prRegInfo->u4UapsdAcBmp; + + prAdapter->u4MaxSpLen = prRegInfo->u4MaxSpLen; + + DBGLOG(INIT, TRACE, "[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x", + prAdapter->fgEnArpFilter, prAdapter->u4UapsdAcBmp, prAdapter->u4MaxSpLen); + + prAdapter->fgEnCtiaPowerMode = FALSE; + +#if CFG_SUPPORT_DBG_POWERMODE + prAdapter->fgEnDbgPowerMode = FALSE; +#endif + +#endif + + /* MGMT Initialization */ + nicInitMGMT(prAdapter, prRegInfo); + + /* Enable WZC Disassociation */ + prAdapter->rWifiVar.fgSupportWZCDisassociation = TRUE; + + /* Apply Rate Setting */ + if ((ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate) < FIXED_RATE_NUM) + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate); + else + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + + if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + } else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) + || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) { + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + } else { + /* Force Long Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + } + + /* Disable Hidden SSID Join */ + prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = FALSE; + + /* Enable Short Slot Time */ + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = TRUE; + + /* configure available PHY type set */ + nicSetAvailablePhyTypeSet(prAdapter); + +#if 1 /* set PM parameters */ + { +#if CFG_SUPPORT_PWR_MGT + prAdapter->u4PowerMode = prRegInfo->u4PowerMode; + prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucNetTypeIndex = + NETWORK_TYPE_P2P_INDEX; + prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile = ENUM_PSP_FAST_SWITCH; +#else + prAdapter->u4PowerMode = ENUM_PSP_CONTINUOUS_ACTIVE; +#endif + + nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, /* FIXIT */ + prAdapter->u4PowerMode, FALSE); + } + +#endif + +#if CFG_SUPPORT_NVRAM + /* load manufacture data */ + wlanLoadManufactureData(prAdapter, prRegInfo); +#endif + +#ifdef CONFIG_MTK_TC1_FEATURE /* 1 //keep alive packet time change from default 30secs to 20secs. //TC01// */ + { + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + + rCmdSwCtrl.u4Id = 0x90100000; + rCmdSwCtrl.u4Data = 30; + DBGLOG(INIT, TRACE, "wlanAdapterStart Keepaliveapcket 0x%x, %d\n", + rCmdSwCtrl.u4Id, rCmdSwCtrl.u4Data); + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8) (&rCmdSwCtrl), NULL, 0); + } +#endif + +#if 0 + /* Update Auto rate parameters in FW */ + nicRlmArUpdateParms(prAdapter, + prRegInfo->u4ArSysParam0, + prRegInfo->u4ArSysParam1, prRegInfo->u4ArSysParam2, prRegInfo->u4ArSysParam3); +#endif + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + /* clock gating workaround */ + prAdapter->fgIsClockGatingEnabled = FALSE; +#endif + + } while (FALSE); + + if (u4Status == WLAN_STATUS_SUCCESS) { + /* restore to hardware default */ + HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter); + HAL_SET_MAILBOX_READ_CLEAR(prAdapter, FALSE); + + /* Enable interrupt */ + nicEnableInterrupt(prAdapter); + + } else { + /* release allocated memory */ + switch (eFailReason) { + case WAIT_FIRMWARE_READY_FAIL: + DBGLOG(INIT, ERROR, "Wait firmware ready fail, FailReason: %d\n", + eFailReason); + g_IsNeedDoChipReset = 1; + kalSendAeeWarning("[Wait firmware ready fail!]", __func__); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); + nicRxUninitialize(prAdapter); + nicTxRelease(prAdapter); + /* System Service Uninitialization */ + nicUninitSystemService(prAdapter); + nicReleaseAdapterMemory(prAdapter); + break; + case RAM_CODE_DOWNLOAD_FAIL: + DBGLOG(INIT, ERROR, "Ram code download fail, FailReason: %d\n", + eFailReason); + g_IsNeedDoChipReset = 1; + kalSendAeeWarning("[Ram code download fail!]", __func__); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); + nicRxUninitialize(prAdapter); + nicTxRelease(prAdapter); + /* System Service Uninitialization */ + nicUninitSystemService(prAdapter); + nicReleaseAdapterMemory(prAdapter); + break; + case INIT_ADAPTER_FAIL: + nicReleaseAdapterMemory(prAdapter); + break; + case DRIVER_OWN_FAIL: + nicReleaseAdapterMemory(prAdapter); + break; + case ALLOC_ADAPTER_MEM_FAIL: + break; + default: + break; + } + } + + return u4Status; +} /* wlanAdapterStart */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Uninitialize the adapter +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i, u4Value = 0; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == TRUE) + nicDisableClockGating(prAdapter); +#endif + + /* MGMT - unitialization */ + nicUninitMGMT(prAdapter); + + if (prAdapter->rAcpiState == ACPI_STATE_D0 && +#if (CFG_CHIP_RESET_SUPPORT == 1) + kalIsResetting() == FALSE && +#endif + kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { + + /* 0. Disable interrupt, this can be done without Driver own */ + nicDisableInterrupt(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* 1. Set CMD to FW to tell WIFI to stop (enter power off state) */ + /* the command must be issue to firmware even in wlanRemove() */ + if (prAdapter->fgIsFwOwn == FALSE && wlanSendNicPowerCtrlCmd(prAdapter, 1) == WLAN_STATUS_SUCCESS) { + /* 2. Clear pending interrupt */ + i = 0; + while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + i++; + }; + + /* 3. Wait til RDY bit has been cleaerd */ + i = 0; + while (1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if ((u4Value & WCIR_WLAN_READY) == 0) + break; + else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE || i >= CFG_RESPONSE_POLLING_TIMEOUT) { + g_IsNeedDoChipReset = 1; + kalSendAeeWarning("[Read WCIR_WLAN_READY fail!]", __func__); + break; + } + i++; + kalMsleep(10); + } + } + + /* 4. Set Onwership to F/W */ + nicpmSetFWOwn(prAdapter, FALSE); + +#if CFG_FORCE_RESET_UNDER_BUS_ERROR + if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == TRUE) { + /* force acquire firmware own */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + + /* delay for 10ms */ + kalMdelay(10); + + /* force firmware reset via software interrupt */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, WSICR_H2D_SW_INT_SET); + + /* force release firmware own */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); + } +#endif + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } + + nicRxUninitialize(prAdapter); + + nicTxRelease(prAdapter); + + /* System Service Uninitialization */ + nicUninitSystemService(prAdapter); + + nicReleaseAdapterMemory(prAdapter); + +#if defined(_HIF_SPI) + /* Note: restore the SPI Mode Select from 32 bit to default */ + nicRestoreSpiDefMode(prAdapter); +#endif + + return u4Status; +} /* wlanAdapterStop */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by ISR (interrupt). +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \retval TRUE: NIC's interrupt +* \retval FALSE: Not NIC's interrupt +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl) +{ + ASSERT(prAdapter); + + if (fgGlobalIntrCtrl) { + nicDisableInterrupt(prAdapter); + + /* wlanIST(prAdapter); */ + } + + return TRUE; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by IST (task_let). +* +* \param prAdapter Pointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanIST(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* wake up CONNSYS */ + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* handle interrupts */ + nicProcessIST(prAdapter); + + /* re-enable HIF interrupts */ + nicEnableInterrupt(prAdapter); + + /* CONNSYS can decide to sleep */ + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will check command queue to find out if any could be dequeued +* and/or send to HIF to MT6620 +* +* \param prAdapter Pointer of Adapter Data Structure +* \param prCmdQue Pointer of Command Queue (in Glue Layer) +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue) +{ + WLAN_STATUS rStatus; + QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue; + P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue; + P_QUE_ENTRY_T prQueueEntry; + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT; + + KAL_SPIN_LOCK_DECLARATION(); + + /* sanity check */ + ASSERT(prAdapter); + ASSERT(prCmdQue); + + /* init */ + prTempCmdQue = &rTempCmdQue; + prMergeCmdQue = &rMergeCmdQue; + prStandInCmdQue = &rStandInCmdQue; + + QUEUE_INITIALIZE(prTempCmdQue); + QUEUE_INITIALIZE(prMergeCmdQue); + QUEUE_INITIALIZE(prStandInCmdQue); + + /* 4 <1> Move whole list of CMD_INFO to the temp queue */ + /* copy all commands to prTempCmdQue and empty prCmdQue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + /* 4 <2> Dequeue from head and check it is able to be sent */ + /* remove the first one */ + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + /* check how to handle the command: drop, queue, or tx */ + switch (prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + /* command packet will be always sent */ + eFrameAction = FRAME_ACTION_TX_PKT; + break; + + case COMMAND_TYPE_SECURITY_FRAME: + /* inquire with QM */ + eFrameAction = qmGetFrameAction(prAdapter, + prCmdInfo->eNetworkType, + prCmdInfo->ucStaRecIndex, NULL, FRAME_TYPE_802_1X); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + /* inquire with QM */ + prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); + + eFrameAction = qmGetFrameAction(prAdapter, + prMsduInfo->ucNetworkType, + prMsduInfo->ucStaRecIndex, prMsduInfo, FRAME_TYPE_MMPDU); + break; + + default: + ASSERT(0); + break; + } + + /* 4 <3> handling upon dequeue result */ + if (eFrameAction == FRAME_ACTION_DROP_PKT) { + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) + DBGLOG(TX, WARN, "Drop Security frame seqNo=%d\n", + prCmdInfo->ucCmdSeqNum); + wlanReleaseCommand(prAdapter, prCmdInfo); + } else if (eFrameAction == FRAME_ACTION_QUEUE_PKT) { + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) + DBGLOG(TX, INFO, "Queue Security frame seqNo=%d\n", + prCmdInfo->ucCmdSeqNum); + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + } else if (eFrameAction == FRAME_ACTION_TX_PKT) { + /* 4 <4> Send the command */ + rStatus = wlanSendCommand(prAdapter, prCmdInfo); + + if (rStatus == WLAN_STATUS_RESOURCES) { + /* no more TC4 resource for further transmission */ + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + DBGLOG(TX, EVENT, "No TC4 resource to send cmd, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", + prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, + prCmdInfo->eCmdType, prCmdInfo->fgIsOid); + break; + } else if (rStatus == WLAN_STATUS_PENDING) { + /* command packet which needs further handling upon response */ + /* i.e. we need to wait for FW's response */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), prQueueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + } else { + /* send success or fail */ + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* send success */ + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prCmdInfo->pucInfoBuffer); + } + } else { + /* send fail */ + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, rStatus); + } + DBGLOG(TX, WARN, "Send CMD, status=%u, CID=%d, SEQ=%d, CMD type=%d, OID=%d\n", + rStatus, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, + prCmdInfo->eCmdType, prCmdInfo->fgIsOid); + } + + /* free the command memory */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } else { + + /* impossible, wrong eFrameAction */ + ASSERT(0); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + /* 4 <3> Merge back to original queue */ + /* 4 <3.1> Merge prMergeCmdQue & prTempCmdQue */ + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue); + + /* 4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ due to incoming 802.1X frames */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + /* ??? here, prCmdQue shall be empty, why QUEUE_MOVE_ALL ??? */ + QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue); + + /* 4 <3.3> concatenate prStandInQue to prMergeCmdQue */ + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue); + + /* 4 <3.4> then move prMergeCmdQue to prCmdQue */ + QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanProcessCommandQueue() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will take CMD_INFO_T which carry some information of +* incoming OID and notify the NIC_TX to send CMD. +* +* \param prAdapter Pointer of Adapter Data Structure +* \param prCmdInfo Pointer of P_CMD_INFO_T +* +* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately. +* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous +* frame finishing their transmission. +* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + P_TX_CTRL_T prTxCtrl; + UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + BOOLEAN pfgIsSecOrMgmt = FALSE; + + /* sanity check */ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + /* init */ + prTxCtrl = &prAdapter->rTxCtrl; + + /* DbgPrint("wlanSendCommand()\n"); */ + /* */ + /* */ +#if DBG && 0 + LOG_FUNC("wlanSendCommand()\n"); + LOG_FUNC("CmdType %u NetworkType %u StaRecIndex %u Oid %u CID 0x%x SetQuery %u NeedResp %u CmdSeqNum %u\n", + prCmdInfo->eCmdType, + prCmdInfo->eNetworkType, + prCmdInfo->ucStaRecIndex, + prCmdInfo->fgIsOid, + prCmdInfo->ucCID, prCmdInfo->fgSetQuery, prCmdInfo->fgNeedResp, prCmdInfo->ucCmdSeqNum); +#endif + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == TRUE) + nicDisableClockGating(prAdapter); +#endif + + do { + /* <0> card removal check */ + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + rStatus = WLAN_STATUS_FAILURE; + break; + } + /* <1> Normal case of sending CMD Packet */ + if (!prCmdInfo->fgDriverDomainMCR) { + /* <1.1> Assign Traffic Class(TC) = TC4. */ + ucTC = TC4_INDEX; + + if ((prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) || + (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME)) + pfgIsSecOrMgmt = TRUE; + + /* <1.2> Check if pending packet or resource was exhausted */ + rStatus = nicTxAcquireResource(prAdapter, ucTC, pfgIsSecOrMgmt); + if (rStatus == WLAN_STATUS_RESOURCES) { + DbgPrint("NO Resource:%d\n", ucTC); + break; + } + /* <1.3> Forward CMD_INFO_T to NIC Layer */ + rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC); + + /* <1.4> Set Pending in response to Query Command/Need Response */ + if (rStatus == WLAN_STATUS_SUCCESS) { + if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) + rStatus = WLAN_STATUS_PENDING; + } + } + /* <2> "Special case" for access Driver Domain MCR */ + else { + + P_CMD_ACCESS_REG prCmdAccessReg; + + prCmdAccessReg = (P_CMD_ACCESS_REG) (prCmdInfo->pucInfoBuffer + CMD_HDR_SIZE); + + if (prCmdInfo->fgSetQuery) { + /* address is in DWORD unit */ + HAL_MCR_WR(prAdapter, (prCmdAccessReg->u4Address & BITS(2, 31)), + prCmdAccessReg->u4Data); + } else { + P_CMD_ACCESS_REG prEventAccessReg; + UINT_32 u4Address; + + u4Address = prCmdAccessReg->u4Address; + prEventAccessReg = (P_CMD_ACCESS_REG) prCmdInfo->pucInfoBuffer; + prEventAccessReg->u4Address = u4Address; + /* address is in DWORD unit */ + HAL_MCR_RD(prAdapter, prEventAccessReg->u4Address & BITS(2, 31), + &prEventAccessReg->u4Data); + } + } + + } while (FALSE); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == FALSE) + nicEnableClockGating(prAdapter); +#endif + + return rStatus; +} /* end of wlanSendCommand() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will release thd CMD_INFO upon its attribution + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdInfo Pointer of CMD_INFO_T + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + + switch (prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + if (prCmdInfo->fgIsOid) { + /* for OID command, we need to do complete() to wake up kalIoctl() */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_FAILURE); + } + break; + + case COMMAND_TYPE_SECURITY_FRAME: + /* free packets in kalSecurityFrameSendComplete() */ + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; + + /* invoke callbacks */ + if (prMsduInfo->pfTxDoneHandler != NULL) + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); + + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + cnmMgtPktFree(prAdapter, prMsduInfo); + break; + + default: + /* impossible, shall not be here */ + ASSERT(0); + break; + } + + /* free command buffer and return the command header to command pool */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + +} /* end of wlanReleaseCommand() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will search the CMD Queue to look for the pending OID and +* compelete it immediately when system request a reset. +* +* \param prAdapter ointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("wlanReleasePendingOid"); + + ASSERT(prAdapter); + + DBGLOG(OID, ERROR, "OID Timeout! Releasing pending OIDs ..\n"); + + do { + /* 1: Handle OID commands in pending queue */ + /* Clear Pending OID in prAdapter->rPendingCmdQueue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + /* move all pending commands to prTempCmdQue and empty prCmdQue */ + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + /* get first pending command */ + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->fgIsOid) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } else { + /* send complete() to wake up kalIoctl() */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); + } + + /* free command memory */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + /* nothing to do so re-queue it to prCmdQue */ + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + /* 2: Clear pending OID staying in command queue */ + kalOidCmdClearance(prAdapter->prGlueInfo); + + /* 3: Do complete(), do we need this? because we have completed in kalOidComplete */ + kalOidClearance(prAdapter->prGlueInfo); + + } while (FALSE); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will search the CMD Queue to look for the pending CMD/OID for specific +* NETWORK TYPE and compelete it immediately when system request a reset. +* +* \param prAdapter ointer of Adapter Data Structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + /* only free commands from the network interface, AIS, P2P, or BOW */ + + do { + /* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + DBGLOG(P2P, TRACE, "Pending CMD for Network Type:%d\n", prCmdInfo->eNetworkType); + + if (prCmdInfo->eNetworkType == eNetworkType) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } else + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + } while (FALSE); + +} /* wlanReleasePendingCMDbyNetwork */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return the packet buffer and reallocate one to the RFB +* +* \param prAdapter Pointer of Adapter Data Structure +* \param pvPacket Pointer of returned packet +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("wlanReturnPacket"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* free the packet */ + if (pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, pvPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1); +#if CFG_NATIVE_802_11 + if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) { + /*Todo:: nothing*/ + /*Todo:: nothing*/ + } +#endif + } + + /* free the packet control block */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (!prSwRfb) { + ASSERT(0); + return; + } + + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + ASSERT(0); + /* return; // Don't return here or it would lost SwRfb --kc */ + if (!timerPendingTimer(&prAdapter->rReturnIndicatedRfbListTimer)) { + DBGLOG(RX, WARN, + "wlanReturnPacket, Start ReturnIndicatedRfbList Timer (%ds)\n", + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + cnmTimerStartTimer(prAdapter, &prAdapter->rReturnIndicatedRfbListTimer, + SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } + } + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return the indicated packet buffer and reallocate one to the RFB +* +* \param prAdapter Pointer of Adapter Data Structure +* \param pvPacket Pointer of returned packet +* +* \retval WLAN_STATUS_SUCCESS: Success +* \retval WLAN_STATUS_FAILURE: Failed +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = NULL; + + KAL_SPIN_LOCK_DECLARATION(); + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_QUE_T prQueList; + + DEBUGFUNC("wlanReturnIndicatedPacketsTimeOut"); + DBGLOG(RX, WARN, "wlanReturnIndicatedPacketsTimeOut"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prQueList = &prRxCtrl->rIndicatedRfbList; + DBGLOG(RX, WARN, "IndicatedRfbList num = %u\n", (unsigned int)prQueList->u4NumElem); + + while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rIndicatedRfbList)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + status = WLAN_STATUS_RESOURCES; + ASSERT(0); + } + nicRxReturnRFB(prAdapter, prSwRfb); + if (status == WLAN_STATUS_RESOURCES) + break; + } + if (status == WLAN_STATUS_RESOURCES) { + DBGLOG(RX, WARN, "Start ReturnIndicatedRfbList Timer (%ds)\n", RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + /* restart timer */ + cnmTimerStartTimer(prAdapter, + &prAdapter->rReturnIndicatedRfbListTimer, + SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a required function that returns information about +* the capabilities and status of the driver and/or its network adapter. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] pfnOidQryHandler Function pointer for the OID query handler. +* \param[IN] pvInfoBuf Points to a buffer for return the query information. +* \param[IN] u4QueryBufferLen Specifies the number of bytes at pvInfoBuf. +* \param[OUT] pu4QueryInfoLen Points to the number of bytes it written or is needed. +* +* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidQryHandler, + IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4QryInfoLen); + + /* ignore any OID request after connected, under PS current measurement mode */ + /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for + * blocking OIDs during current measurement + */ + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) + return WLAN_STATUS_SUCCESS; +#if 1 + /* most OID handler will just queue a command packet */ + status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); +#else + if (wlanIsHandlerNeedHwAccess(pfnOidQryHandler, FALSE)) { + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if (prAdapter->fgWiFiInSleepyState == TRUE) + prAdapter->fgWiFiInSleepyState = FALSE; + + status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } else + status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen); +#endif + + return status; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a required function that allows bound protocol drivers, +* or NDIS, to request changes in the state information that the miniport +* maintains for particular object identifiers, such as changes in multicast +* addresses. +* +* \param[IN] prAdapter Pointer to the Glue info structure. +* \param[IN] pfnOidSetHandler Points to the OID set handlers. +* \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data for the set. +* \param[IN] u4InfoBufLen Specifies the number of bytes at prSetBuffer. +* \param[OUT] pu4SetInfoLen Points to the number of bytes it read or is needed. +* +* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSetInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidSetHandler, + IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* ignore any OID request after connected, under PS current measurement mode */ + /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS for blocking + * OIDs during current measurement + */ + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) + return WLAN_STATUS_SUCCESS; +#if 1 + /* most OID handler will just queue a command packet + * for power state transition OIDs, handler will acquire power control by itself + */ + status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); +#else + if (wlanIsHandlerNeedHwAccess(pfnOidSetHandler, TRUE)) { + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if (prAdapter->fgWiFiInSleepyState == TRUE) + prAdapter->fgWiFiInSleepyState = FALSE; + + status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + } else { + status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen); + } +#endif + + return status; +} + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a used to query driver's config wapi mode or not +* +* \param[IN] prAdapter Pointer to the Glue info structure. +* +* \retval TRUE for use wapi mode +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->rWifiVar.rConnSettings.fgWapiMode; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to set RX filter to Promiscuous Mode. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode) +{ + ASSERT(prAdapter); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to set RX filter to allow to receive +* broadcast address packets. +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to send out CMD_NIC_POWER_CTRL command packet +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] ucPowerMode refer to CMD/EVENT document +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + /* 1. Prepare CMD */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL))); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* 2.1 increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* 2.2 Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL); + + /* 2.3 Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL)); + ((P_CMD_NIC_POWER_CTRL) (prWifiCmd->aucBuffer))->ucPowerMode = ucPowerMode; + + /* 3. Issue CMD for entering specific power mode */ + ucTC = TC4_INDEX; + + while (1) { + /* 3.0 Removal check */ + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + status = WLAN_STATUS_FAILURE; + break; + } + /* 3.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { + + /* wait and poll tx resource */ + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); + status = WLAN_STATUS_FAILURE; + break; + } + continue; + } + /* 3.2 Send CMD Info Packet */ + if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Fail to transmit CMD_NIC_POWER_CTRL command\n"); + status = WLAN_STATUS_FAILURE; + } + + break; + }; + + /* 4. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + /* 5. Add flag */ + if (ucPowerMode == 1) + prAdapter->fgIsEnterD3ReqIssued = TRUE; + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to check if it is RF test mode and +* the OID is allowed to be called or not +* +* \param[IN] prAdapter Pointer to the Adapter structure. +* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerAllowedInRFTest; + UINT_32 i; + UINT_32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerAllowedInRFTest = apfnOidSetHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); + } else { + apfnOidHandlerAllowedInRFTest = apfnOidQueryHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler) + return TRUE; + } + + return FALSE; +} + +#if CFG_ENABLE_FW_DOWNLOAD +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to download FW image in an aggregated way +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) +{ +#if defined(MT6620) || defined(MT6628) + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 u4PktCnt, u4Offset, u4Length; + UINT_32 u4TotalLength; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + + pucOutputBuf = prAdapter->rTxCtrl.pucTxCoalescingBufPtr; + + DEBUGFUNC("wlanImageSectionDownloadAggregated"); + + if (u4ImgSecSize == 0) + return WLAN_STATUS_SUCCESS; + /* 1. Allocate CMD Info Packet and Pre-fill Headers */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + + CMD_PKT_SIZE_FOR_IMAGE); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + CMD_PKT_SIZE_FOR_IMAGE; + + /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ + ucTC = TC0_INDEX; + + /* 3. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->ucEtherTypeOffset = 0; + prInitHifTxHeader->ucCSflags = 0; + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; + + /* 4. Setup CMD_DOWNLOAD_BUF */ + prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdDownloadBuf->u4DataMode = 0 +#if CFG_ENABLE_FW_ENCRYPTION + | DOWNLOAD_BUF_ENCRYPTION_MODE +#endif + ; + + /* 5.0 reset loop control variable */ + u4TotalLength = 0; + u4Offset = u4PktCnt = 0; + + /* 5.1 main loop for maximize transmission count per access */ + while (u4Offset < u4ImgSecSize) { + if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_SUCCESS) { + /* 5.1.1 calculate u4Length */ + if (u4Offset + CMD_PKT_SIZE_FOR_IMAGE < u4ImgSecSize) + u4Length = CMD_PKT_SIZE_FOR_IMAGE; + else + u4Length = u4ImgSecSize - u4Offset; + + /* 5.1.1 increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5.1.2 update HIF TX hardware header */ + prInitHifTxHeader->u2TxByteCount = + ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4Length); + + /* 5.1.3 fill command header */ + prInitCmdDownloadBuf->u4Address = u4DestAddr + u4Offset; + prInitCmdDownloadBuf->u4Length = u4Length; + prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf + u4Offset, u4Length); + + /* 5.1.4.1 copy header to coalescing buffer */ + kalMemCopy(pucOutputBuf + u4TotalLength, + (PVOID) prCmdInfo->pucInfoBuffer, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF)); + + /* 5.1.4.2 copy payload to coalescing buffer */ + kalMemCopy(pucOutputBuf + u4TotalLength + sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_DOWNLOAD_BUF), pucImgSecBuf + u4Offset, u4Length); + + /* 5.1.4.3 update length and other variables */ + u4TotalLength += + ALIGN_4(sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4Length); + u4Offset += u4Length; + u4PktCnt++; + + if (u4Offset < u4ImgSecSize) + continue; + } else if (u4PktCnt == 0) { + /* no resource, so get some back */ + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); + break; + } + } + + if (u4PktCnt != 0) { + /* start transmission */ + HAL_WRITE_TX_PORT(prAdapter, + 0, + u4TotalLength, (PUINT_8) pucOutputBuf, prAdapter->u4CoalescingBufCachedSize); + + /* reset varaibles */ + u4PktCnt = 0; + u4TotalLength = 0; + } + } + + /* 8. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; + +#else +#error "Only MT6620/MT6628/MT6582 supports firmware download in an aggregated way" + + return WLAN_STATUS_FAILURE; + +#endif +} + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to download FW image. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_DOWNLOAD_BUF prInitCmdDownloadBuf; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); + + DEBUGFUNC("wlanImageSectionDownload"); + + if (u4ImgSecSize == 0) + return WLAN_STATUS_SUCCESS; + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + u4ImgSecSize); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_BUF) + (UINT_16) u4ImgSecSize; + + /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ + ucTC = TC0_INDEX; + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_BUF; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Setup CMD_DOWNLOAD_BUF */ + prInitCmdDownloadBuf = (P_INIT_CMD_DOWNLOAD_BUF) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdDownloadBuf->u4Address = u4DestAddr; + prInitCmdDownloadBuf->u4Length = u4ImgSecSize; + prInitCmdDownloadBuf->u4CRC32 = wlanCRC32(pucImgSecBuf, u4ImgSecSize); + + prInitCmdDownloadBuf->u4DataMode = 0 +#if CFG_ENABLE_FW_DOWNLOAD_ACK + | DOWNLOAD_BUF_ACK_OPTION /* ACK needed */ +#endif +#if CFG_ENABLE_FW_ENCRYPTION + | DOWNLOAD_BUF_ENCRYPTION_MODE +#endif + ; + + kalMemCopy(prInitCmdDownloadBuf->aucBuffer, pucImgSecBuf, u4ImgSecSize); + + /* 6. Send FW_Download command */ + while (1) { + /* 6.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); + break; + } + continue; + } + /* 6.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); + } + + break; + }; + +#if CFG_ENABLE_FW_DOWNLOAD_ACK + /* 7. Wait for INIT_EVENT_ID_CMD_RESULT */ + u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum); +#endif + + /* 8. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +#if !CFG_ENABLE_FW_DOWNLOAD_ACK +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to confirm previously firmware download is done without error +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR)]; + UINT_32 u4RxPktLength; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_PENDING_ERROR prEventPendingError; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanImageQueryStatus"); + + /* 1. Allocate CMD Info Packet and it Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo, sizeof(INIT_HIF_TX_HEADER_T)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); + + /* 2. Use TC0's resource to download image. (only TC0 is allowed) */ + ucTC = TC0_INDEX; + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Send command */ + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); + break; + } + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to transmit image download command\n"); + } + + break; + }; + + /* 6. Wait for INIT_EVENT_ID_PENDING_ERROR */ + do { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + } else if (nicRxWaitResponse(prAdapter, + 0, + aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; + + /* EID / SeqNum check */ + if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PENDING_ERROR) { + u4Status = WLAN_STATUS_FAILURE; + } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prEventPendingError = + (P_INIT_EVENT_PENDING_ERROR) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); + if (prEventPendingError->ucStatus != 0) { /* 0 for download success */ + u4Status = WLAN_STATUS_FAILURE; + } else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (FALSE); + + /* 7. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +#else +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to confirm the status of +* previously downloaded firmware scatter +* +* @param prAdapter Pointer to the Adapter structure. +* ucCmdSeqNum Sequence number of previous firmware scatter +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum) +{ + UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)]; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_CMD_RESULT prEventCmdResult; + UINT_32 u4RxPktLength; + WLAN_STATUS u4Status; + + ASSERT(prAdapter); + + do { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + DBGLOG(INIT, ERROR, "kalIsCardRemoved or fgIsBusAccessFailed\n"); + u4Status = WLAN_STATUS_FAILURE; + } else if (nicRxWaitResponse(prAdapter, + 0, + aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT),/* 4B + 4B */ + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "nicRxWaitResponse fail\n"); + u4Status = WLAN_STATUS_FAILURE; + } else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer; + + /* EID / SeqNum check */ + if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT) { + DBGLOG(INIT, ERROR, "rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT\n"); + u4Status = WLAN_STATUS_FAILURE; + g_IsNeedDoChipReset = 1; + kalSendAeeWarning("[Check EID error!]", __func__); + } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { + DBGLOG(INIT, ERROR, "rInitWifiEvent.ucSeqNum != ucCmdSeqNum\n"); + u4Status = WLAN_STATUS_FAILURE; + g_IsNeedDoChipReset = 1; + kalSendAeeWarning("[Check SeqNum error!]", __func__); + } else { + prEventCmdResult = + (P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer); + if (prEventCmdResult->ucStatus != 0) { /* 0 for download success */ + /* + 0: success + 1: rejected by invalid param + 2: rejected by incorrect CRC + 3: rejected by decryption failure + 4: unknown CMD + */ + DBGLOG(INIT, ERROR, "Read Response status error = %d\n", + prEventCmdResult->ucStatus); + u4Status = WLAN_STATUS_FAILURE; + } else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (FALSE); + + return u4Status; +} + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to start FW normal operation. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_WIFI_START prInitCmdWifiStart; + UINT_8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanConfigWifiFunc"); + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START); + + /* 2. Always use TC0 */ + ucTC = TC0_INDEX; + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_WIFI_START; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + prInitCmdWifiStart = (P_INIT_CMD_WIFI_START) (prInitHifTxHeader->rInitWifiCmd.aucBuffer); + prInitCmdWifiStart->u4Override = (fgEnable == TRUE ? 1 : 0); + prInitCmdWifiStart->u4Address = u4StartAddress; + + /* 5. Seend WIFI start command */ + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, FALSE) == WLAN_STATUS_RESOURCES) { + + /* wait and poll tx resource */ + if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n"); + break; + } + + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, "Fail to transmit WIFI start command\n"); + } + + break; + }; + + /* 6. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate CRC32 checksum +* +* @param buf Pointer to the data. +* @param len data length +* +* @return crc32 value +*/ +/*----------------------------------------------------------------------------*/ +static const UINT_32 crc32_ccitt_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + +UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len) +{ + UINT_32 i, crc32 = 0xFFFFFFFF; + + for (i = 0; i < len; i++) + crc32 = crc32_ccitt_table[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8); + + return ~crc32; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to process queued RX packets +* +* @param prAdapter Pointer to the Adapter structure. +* prSwRfbListHead Pointer to head of RX packets link list +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) +{ + P_SW_RFB_T prSwRfb, prNextSwRfb; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(prSwRfbListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prSwRfb = prSwRfbListHead; + + do { + /* save next first */ + prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); + + switch (prSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: + /* to host */ + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + /* need ot forward */ + nicRxProcessForwardPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + /* to host and forward */ + nicRxProcessGOBroadcastPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + /* free it */ + nicRxReturnRFB(prAdapter, prSwRfb); + break; + + default: + break; + } + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + + /* check next queued packet */ + prSwRfb = prNextSwRfb; + } while (prSwRfb); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to purge queued TX packets +* by indicating failure to OS and returned to free list +* +* @param prAdapter Pointer to the Adapter structure. +* prMsduInfoListHead Pointer to head of TX packets link list +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if the OID handler needs timeout +* +* @param prAdapter Pointer to the Adapter structure. +* pfnOidHandler Pointer to the OID handler +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerWOTimeoutCheck; + UINT_32 i; + UINT_32 u4NumOfElem; + + apfnOidHandlerWOTimeoutCheck = apfnOidWOTimeoutCheck; + u4NumOfElem = sizeof(apfnOidWOTimeoutCheck) / sizeof(PFN_OID_HANDLER_FUNC); + + /* skip some OID timeout checks ? */ + for (i = 0; i < u4NumOfElem; i++) { + if (apfnOidHandlerWOTimeoutCheck[i] == pfnOidHandler) + return FALSE; + } + + /* set timer if need timeout check */ + /* cnmTimerStartTimer(prAdapter, */ + /* &(prAdapter->rOidTimeoutTimer), */ + /* 1000); */ + cnmTimerStartTimer(prAdapter, &(prAdapter->rOidTimeoutTimer), 2000); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to clear any pending OID timeout check +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + cnmTimerStopTimer(prAdapter, &(prAdapter->rOidTimeoutTimer)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update network address in firmware domain +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return WLAN_STATUS_FAILURE The request could not be processed +* WLAN_STATUS_PENDING The request has been queued for later processing +* WLAN_STATUS_SUCCESS The request has been processed +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter) +{ + const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + PARAM_MAC_ADDRESS rMacAddr = {0}; + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_BASIC_CONFIG prCmdBasicConfig; + UINT_32 u4SysTime; + + DEBUGFUNC("wlanUpdateNetworkAddress"); + + ASSERT(prAdapter); + + if (kalRetrieveNetworkAddress(prAdapter->prGlueInfo, &rMacAddr) == FALSE || IS_BMCAST_MAC_ADDR(rMacAddr) + || EQUAL_MAC_ADDR(aucZeroMacAddr, rMacAddr)) { + /* eFUSE has a valid address, don't do anything */ + if (prAdapter->fgIsEmbbededMacAddrValid == TRUE) { +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "Using embedded MAC address"); +#endif + return WLAN_STATUS_SUCCESS; + } +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, TRACE, "Using dynamically generated MAC address"); +#endif + /* dynamic generate */ + u4SysTime = kalGetTimeTick(); + + rMacAddr[0] = 0x00; + rMacAddr[1] = 0x08; + rMacAddr[2] = 0x22; + + kalMemCopy(&rMacAddr[3], &u4SysTime, 3); + } else { +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "Using host-supplied MAC address"); +#endif + } + + /* allocate command memory */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + /* configure CMD_BASIC_CONFIG */ + prCmdBasicConfig = (P_CMD_BASIC_CONFIG) (prWifiCmd->aucBuffer); + kalMemCopy(&(prCmdBasicConfig->rMyMacAddr), &rMacAddr, PARAM_MAC_ADDR_LEN); + prCmdBasicConfig->ucNative80211 = 0; + prCmdBasicConfig->rCsumOffload.u2RxChecksum = 0; + prCmdBasicConfig->rCsumOffload.u2TxChecksum = 0; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(2); + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(1); + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(0); + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(2); + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(1); + + if (prAdapter->u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(0); +#endif + + /* send the command to FW */ + if (wlanSendCommand(prAdapter, prCmdInfo) == WLAN_STATUS_RESOURCES) { + + /* backup the command to wait response */ + prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryAddress; + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + return WLAN_STATUS_PENDING; + } + /* send ok without response */ + nicCmdEventQueryAddress(prAdapter, prCmdInfo, (PUINT_8) prCmdBasicConfig); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return WLAN_STATUS_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if the device is in RF test mode +* +* @param pfnOidHandler Pointer to the OID handler +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->fgTestMode; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to identify 802.1x and Bluetooth-over-Wi-Fi +* security frames, and queued into command queue for strict ordering +* due to 802.1x frames before add-key OIDs are not to be encrypted +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prPacket Pointer of native packet +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket) +{ + UINT_8 ucPriorityParam; + UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; + BOOLEAN fgIs1x = FALSE; + BOOLEAN fgIsPAL = FALSE; + UINT_32 u4PacketLen; + ULONG u4SysTime; + UINT_8 ucNetworkType; + P_CMD_INFO_T prCmdInfo; + UINT_8 ucCmdSeqNo = 0; + + /* 1x data packets */ + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prPacket); + + /* retrieve some information for packet classification */ + if (kalQoSFrameClassifierAndPacketInfo(prAdapter->prGlueInfo, + prPacket, + &ucPriorityParam, + &u4PacketLen, + aucEthDestAddr, + &fgIs1x, + &fgIsPAL, + &ucNetworkType, + &ucCmdSeqNo) == TRUE) { + /* almost TRUE except frame length < 14B */ + + if (fgIs1x == FALSE) + return FALSE; + + /* get a free command entry */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + P_STA_RECORD_T prStaRec; + + /* fill arrival time */ + u4SysTime = (OS_SYSTIME) kalGetTimeTick(); + GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); + + kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); + + prCmdInfo->eCmdType = COMMAND_TYPE_SECURITY_FRAME; + prCmdInfo->u2InfoBufLen = (UINT_16) u4PacketLen; + prCmdInfo->pucInfoBuffer = NULL; + prCmdInfo->prPacket = prPacket; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNo; +#if 0 + prCmdInfo->ucStaRecIndex = qmGetStaRecIdx(prAdapter, + aucEthDestAddr, + (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType); +#endif + prStaRec = cnmGetStaRecByAddress(prAdapter, + (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType, + aucEthDestAddr); + if (prStaRec) + prCmdInfo->ucStaRecIndex = prStaRec->ucIndex; + else + prCmdInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + + prCmdInfo->eNetworkType = (ENUM_NETWORK_TYPE_INDEX_T) ucNetworkType; + prCmdInfo->pfCmdDoneHandler = wlanSecurityFrameTxDone; + prCmdInfo->pfCmdTimeoutHandler = wlanSecurityFrameTxTimeout; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + + /* + queue the 1x packet and we will send the packet to CONNSYS by + using command queue + */ + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* TRUE: means we have already handled it in the function */ + return TRUE; + } + + /* no memory, why assert ? can skip the packet ? */ + ASSERT(0); + return FALSE; + } + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi +* security frames has been sent to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prCmdInfo Pointer of CMD_INFO_T +* @param pucEventBuf meaningless, only for API compatibility +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->eNetworkType == NETWORK_TYPE_AIS_INDEX && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) { + + /* AIS counter measure so change RSN FSM to SEND_DEAUTH state */ + P_STA_RECORD_T prSta = cnmGetStaRecByIndex(prAdapter, prCmdInfo->ucStaRecIndex); + + if (prSta) { + kalMsleep(10); + secFsmEventEapolTxDone(prAdapter, prSta, TX_RESULT_SUCCESS); + } + } + + /* free the packet */ + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_SUCCESS); + DBGLOG(TX, INFO, "Security frame tx done, SeqNum: %d\n", prCmdInfo->ucCmdSeqNum); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi +* security frames has failed sending to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prCmdInfo Pointer of CMD_INFO_T +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + /* free the packet */ + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called before AIS is starting a new scan +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter) +{ + BOOLEAN fgKeepCurrOne = FALSE; + UINT_32 i; + + ASSERT(prAdapter); + + /* clear scanning result except current one */ + /* copy current one to prAdapter->rWlanInfo.arScanResult[0] */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { + fgKeepCurrOne = TRUE; + + if (i != 0) { + /* copy structure */ + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[0]), + &(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + } + + if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { + if (prAdapter->rWlanInfo.apucScanResultIEs[i] != + &(prAdapter->rWlanInfo.aucScanIEBuf[0])) { + /* move IEs to head */ + kalMemCopy(prAdapter->rWlanInfo.aucScanIEBuf, + prAdapter->rWlanInfo.apucScanResultIEs[i], + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + } + /* modify IE pointer */ + prAdapter->rWlanInfo.apucScanResultIEs[0] = + &(prAdapter->rWlanInfo.aucScanIEBuf[0]); + } else { + prAdapter->rWlanInfo.apucScanResultIEs[0] = NULL; + } + + break; + } + } + } + + if (fgKeepCurrOne == TRUE) { + prAdapter->rWlanInfo.u4ScanResultNum = 1; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = ALIGN_4(prAdapter->rWlanInfo.arScanResult[0].u4IELength); + } else { + prAdapter->rWlanInfo.u4ScanResultNum = 0; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = 0; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when AIS received a beacon timeout event +* +* @param prAdapter Pointer of Adapter Data Structure +* @param arBSSID MAC address of the specified BSS +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID) +{ + UINT_32 i, j, u4IELength = 0, u4IEMoveLength; + PUINT_8 pucIEPtr; + + ASSERT(prAdapter); + + /* clear the scanning result for arBSSID */ + i = 0; + while (1) { + if (i >= prAdapter->rWlanInfo.u4ScanResultNum) + break; + + if (EQUAL_MAC_ADDR(arBSSID, prAdapter->rWlanInfo.arScanResult[i].arMacAddress)) { + + /* backup current IE length */ + u4IELength = ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4IELength); + pucIEPtr = prAdapter->rWlanInfo.apucScanResultIEs[i]; + + /* removed from middle */ + for (j = i + 1; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[j - 1]), + &(prAdapter->rWlanInfo.arScanResult[j]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + prAdapter->rWlanInfo.apucScanResultIEs[j - 1] = + prAdapter->rWlanInfo.apucScanResultIEs[j]; + } + + prAdapter->rWlanInfo.u4ScanResultNum--; + + /* remove IE buffer if needed := move rest of IE buffer */ + if (u4IELength > 0) { + u4IEMoveLength = prAdapter->rWlanInfo.u4ScanIEBufferUsage - + (((ULONG) pucIEPtr) + (ULONG) u4IELength - + ((ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])))); + + kalMemCopy(pucIEPtr, pucIEPtr + u4IELength, u4IEMoveLength); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4IELength; + + /* correction of pointers to IE buffer */ + for (j = 0; j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { + if (prAdapter->rWlanInfo.apucScanResultIEs[j] > pucIEPtr) { + prAdapter->rWlanInfo.apucScanResultIEs[j] = + (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[j]) - + u4IELength); + } + } + } + } + + i++; + } + +} + +#if CFG_TEST_WIFI_DIRECT_GO +VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter) +{ +#if 0 + P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; + + prMsgFuncSwitch = + (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + if (!prMsgFuncSwitch) { + ASSERT(FALSE); + return; + } + + prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prMsgFuncSwitch->fgIsFuncOn = TRUE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); +#endif + +} + +VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter) +{ + + P_MSG_P2P_CONNECTION_REQUEST_T prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; + UINT_8 aucTargetDeviceID[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + prMsgConnReq = + (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + if (!prMsgConnReq) { + ASSERT(FALSE); + return; + } + + prMsgConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + /*=====Param Modified for test=====*/ + COPY_MAC_ADDR(prMsgConnReq->aucDeviceID, aucTargetDeviceID); + prMsgConnReq->fgIsTobeGO = TRUE; + prMsgConnReq->fgIsPersistentGroup = FALSE; + + /*=====Param Modified for test=====*/ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgConnReq, MSG_SEND_METHOD_BUF); + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve permanent address from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_EVENT_BASIC_CONFIG prEventBasicConfig; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryPermanentAddress"); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG); + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + /* send the command */ + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + /* wait for response */ + if (nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(EVENT_BASIC_CONFIG), /* 8B + 12B */ + &u4RxPktLength) != WLAN_STATUS_SUCCESS) + return WLAN_STATUS_FAILURE; + /* header checking .. */ + prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; + if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) + return WLAN_STATUS_FAILURE; + + prEvent = (P_WIFI_EVENT_T) aucBuffer; + if (prEvent->ucEID != EVENT_ID_BASIC_CONFIG) + return WLAN_STATUS_FAILURE; + + prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (prEvent->aucBuffer); + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucPermanentAddress, &(prEventBasicConfig->rMyMacAddr)); + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, &(prEventBasicConfig->rMyMacAddr)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve NIC capability from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_32 u4FwIDVersion = 0; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_EVENT_NIC_CAPABILITY prEventNicCapability; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryNicCapability"); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + /* send the command */ + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + /* wait for FW response */ + if (nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) + return WLAN_STATUS_FAILURE; + /* header checking .. */ + prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; + if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) + return WLAN_STATUS_FAILURE; + + prEvent = (P_WIFI_EVENT_T) aucBuffer; + if (prEvent->ucEID != EVENT_ID_NIC_CAPABILITY) + return WLAN_STATUS_FAILURE; + + prEventNicCapability = (P_EVENT_NIC_CAPABILITY) (prEvent->aucBuffer); + + prAdapter->rVerInfo.u2FwProductID = prEventNicCapability->u2ProductID; + prAdapter->rVerInfo.u2FwOwnVersion = prEventNicCapability->u2FwVersion; + prAdapter->rVerInfo.u2FwPeerVersion = prEventNicCapability->u2DriverVersion; + prAdapter->fgIsHw5GBandDisabled = (BOOLEAN) prEventNicCapability->ucHw5GBandDisabled; + prAdapter->fgIsEepromUsed = (BOOLEAN) prEventNicCapability->ucEepromUsed; + prAdapter->fgIsEfuseValid = (BOOLEAN) prEventNicCapability->ucEfuseValid; + prAdapter->fgIsEmbbededMacAddrValid = (BOOLEAN) prEventNicCapability->ucMacAddrValid; + + u4FwIDVersion = (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); + mtk_wcn_wmt_set_wifi_ver(u4FwIDVersion); +#if (CFG_SUPPORT_TDLS == 1) + if (prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_TDLS)) + prAdapter->fgTdlsIsSup = TRUE; + DBGLOG(TDLS, TRACE, " support flag: 0x%x\n", prEventNicCapability->ucFeatureSet); +#else + prAdapter->fgTdlsIsSup = 0; +#endif /* CFG_SUPPORT_TDLS */ + + if (!(prEventNicCapability->ucFeatureSet & (1 << FEATURE_SET_OFFSET_5G_SUPPORT))) + prAdapter->fgEnable5GBand = FALSE; /* firmware does not support */ + +#if CFG_ENABLE_CAL_LOG + DBGLOG(INIT, LOUD, " RF CAL FAIL = (%d),BB CAL FAIL = (%d)\n", + prEventNicCapability->ucRfCalFail, prEventNicCapability->ucBbCalFail); +#endif + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve NIC capability from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryDebugCode"); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_GET_DEBUG_CODE; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + /* send the command */ + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to retrieve compiler flag from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryCompileFlag(IN P_ADAPTER_T prAdapter, IN UINT_32 u4QueryID, OUT PUINT_32 pu4CompilerFlag) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_CMD_SW_DBG_CTRL_T prCmdNicCompileFlag, prEventNicCompileFlag; + + ASSERT(prAdapter); + + DEBUGFUNC(__func__); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_SW_DBG_CTRL_T); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_SW_DBG_CTRL; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + /* Fill up SW CR */ + prCmdNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prWifiCmd->aucBuffer); + + prCmdNicCompileFlag->u4Id = u4QueryID; + + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + if (nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(CMD_SW_DBG_CTRL_T), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) + return WLAN_STATUS_FAILURE; + /* header checking .. */ + prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; + if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) + return WLAN_STATUS_FAILURE; + + prEvent = (P_WIFI_EVENT_T) aucBuffer; + if (prEvent->ucEID != EVENT_ID_SW_DBG_CTRL) + return WLAN_STATUS_FAILURE; + + prEventNicCompileFlag = (P_CMD_SW_DBG_CTRL_T) (prEvent->aucBuffer); + + *pu4CompilerFlag = prEventNicCompileFlag->u4Data; + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter) +{ + wlanQueryCompileFlag(prAdapter, 0xA0240000, &prAdapter->u4FwCompileFlag0); + wlanQueryCompileFlag(prAdapter, 0xA0240001, &prAdapter->u4FwCompileFlag1); + + DBGLOG(INIT, TRACE, + "Compile Flags: 0x%08x 0x%08x\n", prAdapter->u4FwCompileFlag0, prAdapter->u4FwCompileFlag1); + + return WLAN_STATUS_SUCCESS; +} + +#if defined(MT6628) +static INT_32 wlanChangeCodeWord(INT_32 au4Input) +{ + + UINT_16 i; +#if TXPWR_USE_PDSLOPE + CODE_MAPPING_T arCodeTable[] = { + {0X100, -40}, + {0X104, -35}, + {0X128, -30}, + {0X14C, -25}, + {0X170, -20}, + {0X194, -15}, + {0X1B8, -10}, + {0X1DC, -5}, + {0, 0}, + {0X24, 5}, + {0X48, 10}, + {0X6C, 15}, + {0X90, 20}, + {0XB4, 25}, + {0XD8, 30}, + {0XFC, 35}, + {0XFF, 40}, + + }; +#else + CODE_MAPPING_T arCodeTable[] = { + {0X100, 0x80}, + {0X104, 0x80}, + {0X128, 0x80}, + {0X14C, 0x80}, + {0X170, 0x80}, + {0X194, 0x94}, + {0X1B8, 0XB8}, + {0X1DC, 0xDC}, + {0, 0}, + {0X24, 0x24}, + {0X48, 0x48}, + {0X6C, 0x6c}, + {0X90, 0x7F}, + {0XB4, 0x7F}, + {0XD8, 0x7F}, + {0XFC, 0x7F}, + {0XFF, 0x7F}, + + }; +#endif + + for (i = 0; i < sizeof(arCodeTable) / sizeof(CODE_MAPPING_T); i++) { + + if (arCodeTable[i].u4RegisterValue == au4Input) + return arCodeTable[i].i4TxpowerOffset; + } + + return 0; +} +#endif + +#if TXPWR_USE_PDSLOPE + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo) +{ + UINT_8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_32 u4RxPktLength; + UINT_8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG)]; + P_HIF_RX_HEADER_T prHifRxHdr; + P_WIFI_EVENT_T prEvent; + P_CMD_ACCESS_REG prCmdMcrQuery; + + ASSERT(prAdapter); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_ACCESS_REG; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_ACCESS_REG); + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + kalMemCopy(prWifiCmd->aucBuffer, prMcrRdInfo, sizeof(CMD_ACCESS_REG)); + + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + if (nicRxWaitResponse(prAdapter, + 1, + aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG), &u4RxPktLength) != WLAN_STATUS_SUCCESS) + return WLAN_STATUS_FAILURE; + /* header checking .. */ + prHifRxHdr = (P_HIF_RX_HEADER_T) aucBuffer; + if ((prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK) != HIF_RX_PKT_TYPE_EVENT) + return WLAN_STATUS_FAILURE; + + prEvent = (P_WIFI_EVENT_T) aucBuffer; + + if (prEvent->ucEID != EVENT_ID_ACCESS_REG) + return WLAN_STATUS_FAILURE; + + prCmdMcrQuery = (P_CMD_ACCESS_REG) (prEvent->aucBuffer); + prMcrRdInfo->u4McrOffset = prCmdMcrQuery->u4Address; + prMcrRdInfo->u4McrData = prCmdMcrQuery->u4Data; + + return WLAN_STATUS_SUCCESS; +} + +static INT_32 wlanIntRound(INT_32 au4Input) +{ + + if (au4Input >= 0) { + if ((au4Input % 10) == 5) { + au4Input = au4Input + 5; + return au4Input; + } + } + + if (au4Input < 0) { + if ((au4Input % 10) == -5) { + au4Input = au4Input - 5; + return au4Input; + } + } + + return au4Input; +} + +static INT_32 wlanCal6628EfuseForm(IN P_ADAPTER_T prAdapter, INT_32 au4Input) +{ + + PARAM_MCR_RW_STRUCT_T rMcrRdInfo; + INT_32 au4PdSlope, au4TxPwrOffset, au4TxPwrOffset_Round; + INT_8 auTxPwrOffset_Round; + + rMcrRdInfo.u4McrOffset = 0x60205c68; + rMcrRdInfo.u4McrData = 0; + au4TxPwrOffset = au4Input; + wlanQueryPdMcr(prAdapter, &rMcrRdInfo); + + au4PdSlope = (rMcrRdInfo.u4McrData) & BITS(0, 6); + au4TxPwrOffset_Round = wlanIntRound((au4TxPwrOffset * au4PdSlope)) / 10; + + au4TxPwrOffset_Round = -au4TxPwrOffset_Round; + + if (au4TxPwrOffset_Round < -128) + au4TxPwrOffset_Round = 128; + else if (au4TxPwrOffset_Round < 0) + au4TxPwrOffset_Round += 256; + else if (au4TxPwrOffset_Round > 127) + au4TxPwrOffset_Round = 127; + + auTxPwrOffset_Round = (UINT8) au4TxPwrOffset_Round; + + return au4TxPwrOffset_Round; +} + +#endif + +#if defined(MT6628) +static VOID wlanChangeNvram6620to6628(PUINT_8 pucEFUSE) +{ + +#define EFUSE_CH_OFFSET1_L_MASK_6620 BITS(0, 8) +#define EFUSE_CH_OFFSET1_L_SHIFT_6620 0 +#define EFUSE_CH_OFFSET1_M_MASK_6620 BITS(9, 17) +#define EFUSE_CH_OFFSET1_M_SHIFT_6620 9 +#define EFUSE_CH_OFFSET1_H_MASK_6620 BITS(18, 26) +#define EFUSE_CH_OFFSET1_H_SHIFT_6620 18 +#define EFUSE_CH_OFFSET1_VLD_MASK_6620 BIT(27) +#define EFUSE_CH_OFFSET1_VLD_SHIFT_6620 27 + +#define EFUSE_CH_OFFSET1_L_MASK_5931 BITS(0, 7) +#define EFUSE_CH_OFFSET1_L_SHIFT_5931 0 +#define EFUSE_CH_OFFSET1_M_MASK_5931 BITS(8, 15) +#define EFUSE_CH_OFFSET1_M_SHIFT_5931 8 +#define EFUSE_CH_OFFSET1_H_MASK_5931 BITS(16, 23) +#define EFUSE_CH_OFFSET1_H_SHIFT_5931 16 +#define EFUSE_CH_OFFSET1_VLD_MASK_5931 BIT(24) +#define EFUSE_CH_OFFSET1_VLD_SHIFT_5931 24 +#define EFUSE_ALL_CH_OFFSET1_MASK_5931 BITS(25, 27) +#define EFUSE_ALL_CH_OFFSET1_SHIFT_5931 25 + + INT_32 au4ChOffset; + INT_16 au2ChOffsetL, au2ChOffsetM, au2ChOffsetH; + + au4ChOffset = *(UINT_32 *) (pucEFUSE + 72); + + if ((au4ChOffset & EFUSE_CH_OFFSET1_VLD_MASK_6620) && ((*(UINT_32 *) (pucEFUSE + 28)) == 0)) { + + au2ChOffsetL = ((au4ChOffset & EFUSE_CH_OFFSET1_L_MASK_6620) >> EFUSE_CH_OFFSET1_L_SHIFT_6620); + + au2ChOffsetM = ((au4ChOffset & EFUSE_CH_OFFSET1_M_MASK_6620) >> EFUSE_CH_OFFSET1_M_SHIFT_6620); + + au2ChOffsetH = ((au4ChOffset & EFUSE_CH_OFFSET1_H_MASK_6620) >> EFUSE_CH_OFFSET1_H_SHIFT_6620); + + au2ChOffsetL = wlanChangeCodeWord(au2ChOffsetL); + au2ChOffsetM = wlanChangeCodeWord(au2ChOffsetM); + au2ChOffsetH = wlanChangeCodeWord(au2ChOffsetH); + + au4ChOffset = 0; + au4ChOffset |= *(UINT_32 *) (pucEFUSE + 72) + >> (EFUSE_CH_OFFSET1_VLD_SHIFT_6620 - + EFUSE_CH_OFFSET1_VLD_SHIFT_5931) & EFUSE_CH_OFFSET1_VLD_MASK_5931; + + au4ChOffset |= + ((((UINT_32) au2ChOffsetL) << EFUSE_CH_OFFSET1_L_SHIFT_5931) & EFUSE_CH_OFFSET1_L_MASK_5931); + au4ChOffset |= + ((((UINT_32) au2ChOffsetM) << EFUSE_CH_OFFSET1_M_SHIFT_5931) & EFUSE_CH_OFFSET1_M_MASK_5931); + au4ChOffset |= + ((((UINT_32) au2ChOffsetH) << EFUSE_CH_OFFSET1_H_SHIFT_5931) & EFUSE_CH_OFFSET1_H_MASK_5931); + + *((INT_32 *) ((pucEFUSE + 28))) = au4ChOffset; + + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to load manufacture data from NVRAM +* if available and valid +* +* @param prAdapter Pointer of Adapter Data Structure +* @param prRegInfo Pointer of REG_INFO_T +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) +{ +#if CFG_SUPPORT_RDD_TEST_MODE + CMD_RDD_CH_T rRddParam; +#endif + + ASSERT(prAdapter); + + /* 1. Version Check */ + kalGetConfigurationVersion(prAdapter->prGlueInfo, + &(prAdapter->rVerInfo.u2Part1CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part1CfgPeerVersion), + &(prAdapter->rVerInfo.u2Part2CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part2CfgPeerVersion)); + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + if (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION) { + return WLAN_STATUS_FAILURE; + } +#endif + + /* MT6620 E1/E2 would be ignored directly */ + if (prAdapter->rVerInfo.u2Part1CfgOwnVersion == 0x0001) { + prRegInfo->ucTxPwrValid = 1; + } else { + /* 2. Load TX power gain parameters if valid */ + if (prRegInfo->ucTxPwrValid != 0) { + /* send to F/W */ + nicUpdateTxPower(prAdapter, (P_CMD_TX_PWR_T) (&(prRegInfo->rTxPwr))); + } + } + + /* Workaround for supporting 5G */ + prRegInfo->ucEnable5GBand = 1; + prRegInfo->ucSupport5GBand = 1; + + /* 3. Check if needs to support 5GHz */ + /* if(prRegInfo->ucEnable5GBand) { // Frank workaround */ + if (1) { + /* check if it is disabled by hardware */ + if (prAdapter->fgIsHw5GBandDisabled || prRegInfo->ucSupport5GBand == 0) + prAdapter->fgEnable5GBand = FALSE; + else + prAdapter->fgEnable5GBand = TRUE; + } else + prAdapter->fgEnable5GBand = FALSE; + /* Workaround for supporting 5G */ + prAdapter->fgEnable5GBand = TRUE; +/* + DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d)\n", + prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled); +*/ + /* 4. Send EFUSE data */ +#if defined(MT6628) + wlanChangeNvram6620to6628(prRegInfo->aucEFUSE); +#endif + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PHY_PARAM, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_PHY_PARAM_T), (PUINT_8) (prRegInfo->aucEFUSE), NULL, 0); + +#if CFG_SUPPORT_RDD_TEST_MODE + rRddParam.ucRddTestMode = (UINT_8) prRegInfo->u4RddTestMode; + rRddParam.ucRddShutCh = (UINT_8) prRegInfo->u4RddShutFreq; + rRddParam.ucRddStartCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStartFreq); + rRddParam.ucRddStopCh = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4RddStopFreq); + rRddParam.ucRddDfs = (UINT_8) prRegInfo->u4RddDfs; + prAdapter->ucRddStatus = 0; + nicUpdateRddTestMode(prAdapter, (P_CMD_RDD_CH_T) (&rRddParam)); +#endif + + /* 5. Get 16-bits Country Code and Bandwidth */ + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((UINT_16) prRegInfo->au2CountryCode[0]) << 8) | (((UINT_16) prRegInfo->au2CountryCode[1]) & BITS(0, 7)); + + DBGLOG(INIT, INFO, "NVRAM 5G Enable(%d) SW_En(%d) HW_Dis(%d) CountryCode(0x%x 0x%x)\n", + prRegInfo->ucEnable5GBand, prRegInfo->ucSupport5GBand, prAdapter->fgIsHw5GBandDisabled, + prRegInfo->au2CountryCode[0], prRegInfo->au2CountryCode[1]); + +#if 0 /* Bandwidth control will be controlled by GUI. 20110930 + * So ignore the setting from registry/NVRAM + */ + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = + prRegInfo->uc2G4BwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = + prRegInfo->uc5GBwFixed20M ? CONFIG_BW_20M : CONFIG_BW_20_40M; +#endif + + /* 6. Set domain and channel information to chip */ + rlmDomainSendCmd(prAdapter, FALSE); + /* Update supported channel list in channel table */ + wlanUpdateChannelTable(prAdapter->prGlueInfo); + + /* 7. Set band edge tx power if available */ + if (prRegInfo->fg2G4BandEdgePwrUsed) { + CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; + + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK = prRegInfo->cBandEdgeMaxPwrCCK; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 = prRegInfo->cBandEdgeMaxPwrOFDM20; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 = prRegInfo->cBandEdgeMaxPwrOFDM40; + + DBGLOG(INIT, TRACE, "NVRAM 2G Bandedge CCK(%d) HT20(%d)HT40(%d)\n", + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK, + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_EDGE_TXPWR_LIMIT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); + } + /* 8. set 5G band edge tx power if available (add for 6625) */ + if (prAdapter->fgEnable5GBand) { +#define NVRAM_5G_TX_BANDEDGE_VALID_OFFSET 10 +#define NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET 11 +#define NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET 12 + + if (prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_VALID_OFFSET]) { + CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; + + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 + = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM20_OFFSET]; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 + = prRegInfo->aucEFUSE[NVRAM_5G_TX_BANDEDGE_OFDM40_OFFSET]; + + DBGLOG(INIT, TRACE, "NVRAM 5G Bandedge HT20(%d)HT40(%d)\n", + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20, rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_EDGE_TXPWR_LIMIT_T), (PUINT_8)&rCmdEdgeTxPwrLimit, NULL, 0); + } + } + /* 9. set RSSI compensation */ + /* DBGLOG(INIT, INFO, ("[frank] RSSI valid(%d) 2G(%d) 5G(%d)", + prRegInfo->fgRssiCompensationValidbit, + prRegInfo->uc2GRssiCompensation, + prRegInfo->uc5GRssiCompensation)); */ + if (prRegInfo->fgRssiCompensationValidbit) { + CMD_RSSI_COMPENSATE_T rCmdRssiCompensate; + + rCmdRssiCompensate.uc2GRssiCompensation = prRegInfo->uc2GRssiCompensation; + rCmdRssiCompensate.uc5GRssiCompensation = prRegInfo->uc5GRssiCompensation; + + DBGLOG(INIT, LOUD, "NVRAM RSSI Comp. 2G(%d)5G(%d)\n", + rCmdRssiCompensate.uc2GRssiCompensation, rCmdRssiCompensate.uc5GRssiCompensation); + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RSSI_COMPENSATE, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_RSSI_COMPENSATE_T), (PUINT_8)&rCmdRssiCompensate, NULL, 0); + } + /* 10. notify FW Band Support 5G */ + if (prAdapter->fgEnable5GBand) { + CMD_BAND_SUPPORT_T rCmdBandSupport; + + rCmdBandSupport.uc5GBandSupport = TRUE; + DBGLOG(INIT, TRACE, "NVRAM 5G BandSupport\n"); + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BAND_SUPPORT, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_BAND_SUPPORT_T), (PUINT_8)&rCmdBandSupport, NULL, 0); + + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check +* Media Stream Mode is set to non-default value or not, +* and clear to default value if above criteria is met +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return TRUE +* The media stream mode was non-default value and has been reset +* FALSE +* The media stream mode is default value +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode != 0) { + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + + return TRUE; + } else { + return FALSE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if any pending timer has expired +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* check timer status */ + cnmTimerDoTimeOutCheck(prAdapter); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to check if any pending mailbox message +* to be handled +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i; + + ASSERT(prAdapter); + + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { /* MBOX_ID_TOTAL_NUM = 1 */ + mboxRcvAllMsg(prAdapter, (ENUM_MBOX_ID_T) i); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to enqueue a single TX packet into CORE +* +* @param prAdapter Pointer of Adapter Data Structure +* prNativePacket Pointer of Native Packet +* +* @return WLAN_STATUS_SUCCESS +* WLAN_STATUS_RESOURCES +* WLAN_STATUS_INVALID_PACKET +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + /* get a free packet header */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if (prMsduInfo == NULL) + return WLAN_STATUS_RESOURCES; + + prMsduInfo->eSrc = TX_PACKET_OS; + + if (nicTxFillMsduInfo(prAdapter, prMsduInfo, prNativePacket) == FALSE) { + /* packet is not extractable */ + + /* fill fails */ + kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_INVALID_PACKET); + + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + + return WLAN_STATUS_INVALID_PACKET; + } + /* enqueue to QM */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to flush pending TX packets in CORE +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return nicTxFlush(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function sends pending MSDU_INFO_T to MT6620 +* +* @param prAdapter Pointer to the Adapter structure. +* @param pfgHwAccess Pointer for tracking LP-OWN status +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + ASSERT(pfgHwAccess); + + /* <1> dequeue packets by txDequeuTxPackets() */ + /* Note: prMsduInfo is a packet list queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmDequeueTxPackets(prAdapter, &prTxCtrl->rTc); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prMsduInfo != NULL) { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == FALSE) { + /* <2> Acquire LP-OWN if necessary */ + if (*pfgHwAccess == FALSE) { + *pfgHwAccess = TRUE; + + wlanAcquirePowerControl(prAdapter); + } +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == TRUE) + nicDisableClockGating(prAdapter); +#endif + /* <3> send packet"s" to HIF */ + nicTxMsduInfoList(prAdapter, prMsduInfo); + + /* <4> update TC by txAdjustTcQuotas() */ + nicTxAdjustTcq(prAdapter); + } else + wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); /* free the packet */ + } +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == FALSE) + nicEnableClockGating(prAdapter); +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to acquire power control from firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* do driver own */ + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state *//* no use */ + if (prAdapter->fgWiFiInSleepyState == TRUE) + prAdapter->fgWiFiInSleepyState = FALSE; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to release power control to firmware +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* do FW own */ + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to report currently pending TX frames count +* (command packets are not included) +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return number of pending TX frames +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + UINT_32 u4Num; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + /* number in prTxQueue + number in RX forward */ + u4Num = kalGetTxPendingFrameCount(prAdapter->prGlueInfo) + (UINT_32) (prTxCtrl->i4PendingFwdFrameCount); + + return u4Num; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to report current ACPI state +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return ACPI_STATE_D0 Normal Operation Mode +* ACPI_STATE_D3 Suspend Mode +*/ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->rAcpiState; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to update current ACPI state only +* +* @param prAdapter Pointer of Adapter Data Structure +* @param ePowerState ACPI_STATE_D0 Normal Operation Mode +* ACPI_STATE_D3 Suspend Mode +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState) +{ + ASSERT(prAdapter); + ASSERT(ePowerState <= ACPI_STATE_D3); + + prAdapter->rAcpiState = ePowerState; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to query ECO version from HIFSYS CR +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return zero Unable to retrieve ECO version information +* non-zero ECO version (1-based) +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (nicVerifyChipID(prAdapter) == TRUE) + return prAdapter->ucRevID + 1; + else + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to setting the default Tx Power configuration +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return zero Unable to retrieve ECO version information +* non-zero ECO version (1-based) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter) +{ + UINT_8 i; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_SET_TXPWR_CTRL_T prTxpwr; + + ASSERT(prGlueInfo); + + prTxpwr = &prGlueInfo->rTxPwr; + + prTxpwr->c2GLegacyStaPwrOffset = 0; + prTxpwr->c2GHotspotPwrOffset = 0; + prTxpwr->c2GP2pPwrOffset = 0; + prTxpwr->c2GBowPwrOffset = 0; + prTxpwr->c5GLegacyStaPwrOffset = 0; + prTxpwr->c5GHotspotPwrOffset = 0; + prTxpwr->c5GP2pPwrOffset = 0; + prTxpwr->c5GBowPwrOffset = 0; + prTxpwr->ucConcurrencePolicy = 0; + for (i = 0; i < 3; i++) + prTxpwr->acReserved1[i] = 0; + + for (i = 0; i < 14; i++) + prTxpwr->acTxPwrLimit2G[i] = 63; + + for (i = 0; i < 4; i++) + prTxpwr->acTxPwrLimit5G[i] = 63; + + for (i = 0; i < 2; i++) + prTxpwr->acReserved2[i] = 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to +* set preferred band configuration corresponding to network type +* +* @param prAdapter Pointer of Adapter Data Structure +* @param eBand Given band +* @param eNetTypeIndex Given Network Type +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + /* 1. set prefer band according to network type */ + prAdapter->aePreferBand[eNetTypeIndex] = eBand; + + /* 2. remove buffered BSS descriptors correspondingly */ + if (eBand == BAND_2G4) + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_5G, eNetTypeIndex); + else if (eBand == BAND_5G) + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_2G4, eNetTypeIndex); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to +* get channel information corresponding to specified network type +* +* @param prAdapter Pointer of Adapter Data Structure +* @param eNetTypeIndex Given Network Type +* +* @return channel number +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + return prBssInfo->ucPrimaryChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to +* get BSS descriptor information corresponding to specified network type +* +* @param prAdapter Pointer of Adapter Data Structure +* @param eNetTypeIndex Given Network Type +* +* @return pointer to BSS_DESC_T +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + switch (eNetTypeIndex) { + case NETWORK_TYPE_AIS_INDEX: + return prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + + case NETWORK_TYPE_P2P_INDEX: + return NULL; + + case NETWORK_TYPE_BOW_INDEX: + return prAdapter->rWifiVar.rBowFsmInfo.prTargetBssDesc; + + default: + return NULL; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to +* check unconfigured system properties and generate related message on +* scan list to notify users +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter) +{ +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) || (CFG_SW_NVRAM_VERSION_CHECK == 1) + const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + const UINT_8 aucBCAddr[] = BC_MAC_ADDR; + BOOLEAN fgIsConfExist = TRUE; + BOOLEAN fgGenErrMsg = FALSE; + P_REG_INFO_T prRegInfo = NULL; + P_WLAN_BEACON_FRAME_T prBeacon = NULL; + P_IE_SSID_T prSsid = NULL; + UINT_32 u4ErrCode = 0; + UINT_8 aucErrMsg[32]; + PARAM_SSID_T rSsid; + PARAM_802_11_CONFIG_T rConfiguration; + PARAM_RATES_EX rSupportedRates; +#endif + + DEBUGFUNC("wlanCheckSystemConfiguration"); + + ASSERT(prAdapter); + +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) { + fgIsConfExist = FALSE; + fgGenErrMsg = TRUE; + } +#endif + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + prRegInfo = kalGetConfiguration(prAdapter->prGlueInfo); + + if (fgIsConfExist == TRUE && (CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion + || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + || prAdapter->fgIsPowerLimitTableValid == FALSE +#endif + || (prAdapter->fgIsEmbbededMacAddrValid == FALSE && + (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) + || EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) + || prRegInfo->ucTxPwrValid == 0)) + fgGenErrMsg = TRUE; +#endif + + if (fgGenErrMsg == TRUE) { + prBeacon = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); + if (!prBeacon) { + ASSERT(FALSE); + return WLAN_STATUS_FAILURE; + } + + /* initialization */ + kalMemZero(prBeacon, sizeof(WLAN_BEACON_FRAME_T) + sizeof(IE_SSID_T)); + + /* prBeacon initialization */ + prBeacon->u2FrameCtrl = MAC_FRAME_BEACON; + COPY_MAC_ADDR(prBeacon->aucDestAddr, aucBCAddr); + COPY_MAC_ADDR(prBeacon->aucSrcAddr, aucZeroMacAddr); + COPY_MAC_ADDR(prBeacon->aucBSSID, aucZeroMacAddr); + prBeacon->u2BeaconInterval = 100; + prBeacon->u2CapInfo = CAP_INFO_ESS; + + /* prSSID initialization */ + prSsid = (P_IE_SSID_T) (&prBeacon->aucInfoElem[0]); + prSsid->ucId = ELEM_ID_SSID; + + /* rConfiguration initialization */ + rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + rConfiguration.u4BeaconPeriod = 100; + rConfiguration.u4ATIMWindow = 1; + rConfiguration.u4DSConfig = 2412; + rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + /* rSupportedRates initialization */ + kalMemZero(rSupportedRates, sizeof(PARAM_RATES_EX)); + } +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) +#define NVRAM_ERR_MSG "NVRAM WARNING: Err = 0x01" + if ((kalIsConfigurationExist(prAdapter->prGlueInfo) == FALSE) && (prBeacon) && (prSsid)) { + COPY_SSID(prSsid->aucSSID, prSsid->ucLength, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); + + kalIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prBeacon, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, + aucSSID) + prSsid->ucLength, + 1, 0); + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); + nicAddScanResult(prAdapter, + prBeacon->aucBSSID, + &rSsid, + 0, + 0, + PARAM_NETWORK_TYPE_FH, + &rConfiguration, + NET_TYPE_INFRA, + rSupportedRates, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, + aucSSID) + prSsid->ucLength - + WLAN_MAC_MGMT_HEADER_LEN, (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); + } +#endif + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) +#define VER_ERR_MSG "NVRAM WARNING: Err = 0x%02X" + if ((fgIsConfExist == TRUE) && (prBeacon) && (prSsid)) { + if ((CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part1CfgPeerVersion + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2Part2CfgPeerVersion + || prAdapter->rVerInfo.u2Part1CfgOwnVersion <= CFG_DRV_PEER_VERSION + || prAdapter->rVerInfo.u2Part2CfgOwnVersion <= CFG_DRV_PEER_VERSION /* NVRAM */ + || CFG_DRV_OWN_VERSION < prAdapter->rVerInfo.u2FwPeerVersion + || prAdapter->rVerInfo.u2FwOwnVersion <= CFG_DRV_PEER_VERSION)) + u4ErrCode |= NVRAM_ERROR_VERSION_MISMATCH; + + if (prRegInfo->ucTxPwrValid == 0) + u4ErrCode |= NVRAM_ERROR_INVALID_TXPWR; + + if (prAdapter->fgIsEmbbededMacAddrValid == FALSE && (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) + || EQUAL_MAC_ADDR(aucZeroMacAddr, + prRegInfo->aucMacAddr))) + u4ErrCode |= NVRAM_ERROR_INVALID_MAC_ADDR; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + if (prAdapter->fgIsPowerLimitTableValid == FALSE) + u4ErrCode |= NVRAM_POWER_LIMIT_TABLE_INVALID; +#endif + if (u4ErrCode != 0) { + sprintf(aucErrMsg, VER_ERR_MSG, (unsigned int)u4ErrCode); + COPY_SSID(prSsid->aucSSID, prSsid->ucLength, aucErrMsg, strlen(aucErrMsg)); + + kalIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prBeacon, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, + aucSSID) + + prSsid->ucLength, 1, 0); + + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, NVRAM_ERR_MSG, strlen(NVRAM_ERR_MSG)); + nicAddScanResult(prAdapter, + prBeacon->aucBSSID, + &rSsid, + 0, + 0, + PARAM_NETWORK_TYPE_FH, + &rConfiguration, + NET_TYPE_INFRA, + rSupportedRates, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem) + OFFSET_OF(IE_SSID_T, + aucSSID) + + prSsid->ucLength - WLAN_MAC_MGMT_HEADER_LEN, + (PUINT_8) ((ULONG) (prBeacon) + WLAN_MAC_MGMT_HEADER_LEN)); + } + } +#endif + + if (fgGenErrMsg == TRUE) + cnmMemFree(prAdapter, prBeacon); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prStaRec, prTempStaRec; + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics; + UINT_8 ucStaRecIdx; + P_QUE_MGT_T prQM = &prAdapter->rQM; + CMD_GET_STA_STATISTICS_T rQueryCmdStaStatistics; + UINT_8 ucIdx; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + do { + ASSERT(pvQueryBuffer); + + /* 4 1. Sanity test */ + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) + break; + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) + break; + + if (u4QueryBufferLen < sizeof(PARAM_GET_STA_STA_STATISTICS)) { + *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prQueryStaStatistics = (P_PARAM_GET_STA_STATISTICS) pvQueryBuffer; + *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); + + /* 4 5. Get driver global QM counter */ + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { + prQueryStaStatistics->au4TcAverageQueLen[ucIdx] = prQM->au4AverageQueLen[ucIdx]; + prQueryStaStatistics->au4TcCurrentQueLen[ucIdx] = prQM->au4CurrentTcResource[ucIdx]; + } + + /* 4 2. Get StaRec by MAC address */ + prStaRec = NULL; + + for (ucStaRecIdx = 0; ucStaRecIdx < CFG_NUM_OF_STA_RECORD; ucStaRecIdx++) { + prTempStaRec = &(prAdapter->arStaRec[ucStaRecIdx]); + if (prTempStaRec->fgIsValid && prTempStaRec->fgIsInUse) { + if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prQueryStaStatistics->aucMacAddr)) { + prStaRec = prTempStaRec; + break; + } + } + } + + if (!prStaRec) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + prQueryStaStatistics->u4Flag |= BIT(0); + +#if CFG_ENABLE_PER_STA_STATISTICS + /* 4 3. Get driver statistics */ + DBGLOG(TX, INFO, "skbToDriver %lld, skbFreed: %lld\n", + prAdapter->prGlueInfo->u8SkbToDriver, + prAdapter->prGlueInfo->u8SkbFreed); + prAdapter->prGlueInfo->u8SkbFreed = 0; + prAdapter->prGlueInfo->u8SkbToDriver = 0; + + prQueryStaStatistics->u4TxTotalCount = prStaRec->u4TotalTxPktsNumber; + prQueryStaStatistics->u4TxExceedThresholdCount = prStaRec->u4ThresholdCounter; + prQueryStaStatistics->u4TxMaxTime = prStaRec->u4MaxTxPktsTime; + prQueryStaStatistics->u4TxMaxHifTime = prStaRec->u4MaxTxPktsHifTime; + if (prStaRec->u4TotalTxPktsNumber) { + prQueryStaStatistics->u4TxAverageProcessTime = + (prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber); + prQueryStaStatistics->u4TxAverageHifTime = + (prStaRec->u4TotalTxPktsHifTime / prStaRec->u4TotalTxPktsNumber); + } else + prQueryStaStatistics->u4TxAverageProcessTime = 0; + + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { + prQueryStaStatistics->au4TcResourceEmptyCount[ucIdx] = + prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx]; + /* Reset */ + prQM->au4QmTcResourceEmptyCounter[prStaRec->ucNetTypeIndex][ucIdx] = 0; + prQueryStaStatistics->au4TcResourceBackCount[ucIdx] = + prQM->au4QmTcResourceBackCounter[ucIdx]; + prQM->au4QmTcResourceBackCounter[ucIdx] = 0; + + prQueryStaStatistics->au4DequeueNoTcResource[ucIdx] = + prQM->au4DequeueNoTcResourceCounter[ucIdx]; + prQM->au4DequeueNoTcResourceCounter[ucIdx] = 0; + prQueryStaStatistics->au4TcResourceUsedCount[ucIdx] = + prQM->au4ResourceUsedCounter[ucIdx]; + prQM->au4ResourceUsedCounter[ucIdx] = 0; + prQueryStaStatistics->au4TcResourceWantedCount[ucIdx] = + prQM->au4ResourceWantedCounter[ucIdx]; + prQM->au4ResourceWantedCounter[ucIdx] = 0; + } + + prQueryStaStatistics->u4EnqueueCounter = prQM->u4EnqeueuCounter; + prQueryStaStatistics->u4DequeueCounter = prQM->u4DequeueCounter; + prQueryStaStatistics->u4EnqueueStaCounter = prStaRec->u4EnqeueuCounter; + prQueryStaStatistics->u4DequeueStaCounter = prStaRec->u4DeqeueuCounter; + + prQueryStaStatistics->IsrCnt = prGlueInfo->IsrCnt - prGlueInfo->IsrPreCnt; + prQueryStaStatistics->IsrPassCnt = prGlueInfo->IsrPassCnt - prGlueInfo->IsrPrePassCnt; + prQueryStaStatistics->TaskIsrCnt = prGlueInfo->TaskIsrCnt - prGlueInfo->TaskPreIsrCnt; + + prQueryStaStatistics->IsrAbnormalCnt = prGlueInfo->IsrAbnormalCnt; + prQueryStaStatistics->IsrSoftWareCnt = prGlueInfo->IsrSoftWareCnt; + prQueryStaStatistics->IsrRxCnt = prGlueInfo->IsrRxCnt; + prQueryStaStatistics->IsrTxCnt = prGlueInfo->IsrTxCnt; + + /* 4 4.1 Reset statistics */ + prStaRec->u4ThresholdCounter = 0; + prStaRec->u4TotalTxPktsNumber = 0; + prStaRec->u4TotalTxPktsTime = 0; + prStaRec->u4MaxTxPktsTime = 0; + prStaRec->u4MaxTxPktsHifTime = 0; + + prStaRec->u4EnqeueuCounter = 0; + prStaRec->u4DeqeueuCounter = 0; + + prQM->u4EnqeueuCounter = 0; + prQM->u4DequeueCounter = 0; + + prGlueInfo->IsrPreCnt = prGlueInfo->IsrCnt; + prGlueInfo->IsrPrePassCnt = prGlueInfo->IsrPassCnt; + prGlueInfo->TaskPreIsrCnt = prGlueInfo->TaskIsrCnt; + prGlueInfo->IsrAbnormalCnt = 0; + prGlueInfo->IsrSoftWareCnt = 0; + prGlueInfo->IsrRxCnt = 0; + prGlueInfo->IsrTxCnt = 0; +#endif + + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) + prQueryStaStatistics->au4TcQueLen[ucIdx] = prStaRec->arTxQueue[ucIdx].u4NumElem; + + rResult = WLAN_STATUS_SUCCESS; + + /* 4 6. Ensure FW supports get station link status */ + if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { + + rQueryCmdStaStatistics.ucIndex = prStaRec->ucIndex; + COPY_MAC_ADDR(rQueryCmdStaStatistics.aucMacAddr, prQueryStaStatistics->aucMacAddr); + rQueryCmdStaStatistics.ucReadClear = TRUE; + + rResult = wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STA_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryStaStatistics, + nicOidCmdTimeoutCommon, + sizeof(CMD_GET_STA_STATISTICS_T), + (PUINT_8)&rQueryCmdStaStatistics, + pvQueryBuffer, u4QueryBufferLen); + + prQueryStaStatistics->u4Flag |= BIT(1); + } else { + rResult = WLAN_STATUS_NOT_SUPPORTED; + } + + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pVersion */ + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + +/* 4 Auto Channel Selection */ +WLAN_STATUS +wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + /* P_PARAM_GET_CHN_LOAD prQueryChnLoad; */ + P_PARAM_GET_LTE_MODE prLteMode; + CMD_GET_LTE_SAFE_CHN_T rQuery_LTE_SAFE_CHN; + + DBGLOG(P2P, INFO, "[Auto Channel]wlanoidQueryACSChannelList\n"); + do { + ASSERT(pvQueryBuffer); + + /* 4 1. Sanity test */ + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) + break; + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) + break; + + prLteMode = (P_PARAM_GET_LTE_MODE) pvQueryBuffer; + + /* 4 3. Ensure FW supports get station link status */ +#if 0 + if (prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) { + CMD_ACCESS_REG rCmdAccessReg; + + rCmdAccessReg.u4Address = 0xFFFFFFFF; + rCmdAccessReg.u4Data = ELEM_RM_TYPE_ACS_CHN; + + rResult = wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + TRUE, + TRUE, + /* The handler to receive firmware notification */ + nicCmdEventQueryChannelLoad, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8)&rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); + + prQueryChnLoad->u4Flag |= BIT(1); + } else { + rResult = WLAN_STATUS_NOT_SUPPORTED; + } +#endif + /* 4 4.Avoid LTE Channels */ + prLteMode->u4Flags &= BIT(0); + /*if(prAdapter->u4FwCompileFlag0 & COMPILE_FLAG0_GET_STA_LINK_STATUS) */ { + + rResult = wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LTE_CHN, + FALSE, + TRUE, + /* Query ID */ + TRUE, + /* The handler to receive firmware notification */ + nicCmdEventQueryLTESafeChn, + nicOidCmdTimeoutCommon, + sizeof(CMD_GET_LTE_SAFE_CHN_T), + (PUINT_8)&rQuery_LTE_SAFE_CHN, + pvQueryBuffer, u4QueryBufferLen); + + DBGLOG(P2P, INFO, "[Auto Channel] Get LTE Channels\n"); + prLteMode->u4Flags |= BIT(1); + } + + /* 4 5. Calc the value */ + + DBGLOG(P2P, INFO, "[Auto Channel] Candidated Channels\n"); + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pVersion */ +#endif +#if CFG_SUPPORT_CFG_FILE + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey) +{ + + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + UINT_32 i; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + ASSERT(pucKey); + + prWlanCfgEntry = NULL; + + for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; + if (prWlanCfgEntry->aucKey[0] != '\0') { + DBGLOG(INIT, LOUD, "compare key %s saved key %s\n", pucKey, prWlanCfgEntry->aucKey); + if (kalStrniCmp(pucKey, prWlanCfgEntry->aucKey, WLAN_CFG_KEY_LEN_MAX - 1) == 0) + return prWlanCfgEntry; + } + } + + DBGLOG(INIT, LOUD, "wifi config there is no entry \'%s\'\n", pucKey); + return NULL; + +} + +WLAN_STATUS wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags) +{ + + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + ASSERT(pucValue); + + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); + + if (prWlanCfgEntry) { + kalStrnCpy(pucValue, prWlanCfgEntry->aucValue, WLAN_CFG_VALUE_LEN_MAX - 1); + return WLAN_STATUS_SUCCESS; + } + if (pucValueDef) + kalStrnCpy(pucValue, pucValueDef, WLAN_CFG_VALUE_LEN_MAX - 1); + return WLAN_STATUS_FAILURE; + +} + +UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + UINT_32 u4Value; + INT_32 u4Ret; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + u4Value = u4ValueDef; + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); + + if (prWlanCfgEntry) { + u4Ret = kalkStrtou32(prWlanCfgEntry->aucValue, 0, &u4Value); + if (u4Ret) + DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue u4Ret=%u\n", u4Ret); + /* u4Value = kalStrtoul(prWlanCfgEntry->aucValue, NULL, 0); */ + } + + return u4Value; +} + +INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + INT_32 i4Value; + INT_32 i4Ret; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + i4Value = i4ValueDef; + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); + + if (prWlanCfgEntry) { + i4Ret = kalkStrtos32(prWlanCfgEntry->aucValue, 0, &i4Value); + /* i4Ret = kalStrtol(prWlanCfgEntry->aucValue, NULL, 0); */ + if (i4Ret) + DBGLOG(INIT, ERROR, "parse prWlanCfgEntry->aucValue i4Ret=%u\n\r", i4Ret); + } + + return i4Value; +} + +WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags) +{ + + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + UINT_32 u4EntryIndex; + UINT_32 i; + UINT_8 ucExist; + + prWlanCfg = prAdapter->prWlanCfg; + ASSERT(prWlanCfg); + ASSERT(pucKey); + + /* Find the exist */ + ucExist = 0; + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); + + if (!prWlanCfgEntry) { + /* Find the empty */ + for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; + if (prWlanCfgEntry->aucKey[0] == '\0') + break; + } + + u4EntryIndex = i; + if (u4EntryIndex < WLAN_CFG_ENTRY_NUM_MAX) { + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[u4EntryIndex]; + kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); + } else { + prWlanCfgEntry = NULL; + DBGLOG(INIT, ERROR, "wifi config there is no empty entry\n"); + } + } /* !prWlanCfgEntry */ + else + ucExist = 1; + + if (prWlanCfgEntry) { + if (ucExist == 0) { + kalStrnCpy(prWlanCfgEntry->aucKey, pucKey, WLAN_CFG_KEY_LEN_MAX - 1); + prWlanCfgEntry->aucKey[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + } + + if (pucValue && pucValue[0] != '\0') { + kalStrnCpy(prWlanCfgEntry->aucValue, pucValue, WLAN_CFG_VALUE_LEN_MAX - 1); + prWlanCfgEntry->aucValue[WLAN_CFG_VALUE_LEN_MAX - 1] = '\0'; + + if (ucExist) { + if (prWlanCfgEntry->pfSetCb) + prWlanCfgEntry->pfSetCb(prAdapter, + prWlanCfgEntry->aucKey, + prWlanCfgEntry->aucValue, prWlanCfgEntry->pPrivate, 0); + } + } else { + /* Call the pfSetCb if value is empty ? */ + /* remove the entry if value is empty */ + kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); + } + + } + /* prWlanCfgEntry */ + if (prWlanCfgEntry) { + DBGLOG(INIT, LOUD, "Set wifi config exist %u \'%s\' \'%s\'\n", + ucExist, prWlanCfgEntry->aucKey, prWlanCfgEntry->aucValue); + return WLAN_STATUS_SUCCESS; + } + if (pucKey) + DBGLOG(INIT, ERROR, "Set wifi config error key \'%s\'\n", pucKey); + if (pucValue) + DBGLOG(INIT, ERROR, "Set wifi config error value \'%s\'\n", pucValue); + return WLAN_STATUS_FAILURE; + +} + +WLAN_STATUS +wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags) +{ + + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + + prWlanCfg = prAdapter->prWlanCfg; + ASSERT(prWlanCfg); + + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey); + + if (prWlanCfgEntry) { + prWlanCfgEntry->pfSetCb = pfSetCb; + prWlanCfgEntry->pPrivate = pPrivate; + } + + if (prWlanCfgEntry) + return WLAN_STATUS_SUCCESS; + else + return WLAN_STATUS_FAILURE; + +} + +WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value) +{ + + P_WLAN_CFG_T prWlanCfg; + UINT_8 aucBuf[WLAN_CFG_VALUE_LEN_MAX]; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + kalMemZero(aucBuf, sizeof(aucBuf)); + + kalSnprintf(aucBuf, WLAN_CFG_VALUE_LEN_MAX, "0x%x", (unsigned int)u4Value); + + return wlanCfgSet(prAdapter, pucKey, aucBuf, 0); +} + +enum { + STATE_EOF = 0, + STATE_TEXT = 1, + STATE_NEWLINE = 2 +}; + +struct WLAN_CFG_PARSE_STATE_S { + CHAR *ptr; + CHAR *text; + INT_32 nexttoken; + UINT_32 maxSize; +}; + +INT_32 wlanCfgFindNextToken(struct WLAN_CFG_PARSE_STATE_S *state) +{ + CHAR *x = state->ptr; + CHAR *s; + + if (state->nexttoken) { + INT_32 t = state->nexttoken; + + state->nexttoken = 0; + return t; + } + + for (;;) { + switch (*x) { + case 0: + state->ptr = x; + return STATE_EOF; + case '\n': + x++; + state->ptr = x; + return STATE_NEWLINE; + case ' ': + case '\t': + case '\r': + x++; + continue; + case '#': + while (*x && (*x != '\n')) + x++; + if (*x == '\n') { + state->ptr = x + 1; + return STATE_NEWLINE; + } + state->ptr = x; + return STATE_EOF; + default: + goto text; + } + } + +textdone: + state->ptr = x; + *s = 0; + return STATE_TEXT; +text: + state->text = s = x; +textresume: + for (;;) { + switch (*x) { + case 0: + goto textdone; + case ' ': + case '\t': + case '\r': + x++; + goto textdone; + case '\n': + state->nexttoken = STATE_NEWLINE; + x++; + goto textdone; + case '"': + x++; + for (;;) { + switch (*x) { + case 0: + /* unterminated quoted thing */ + state->ptr = x; + return STATE_EOF; + case '"': + x++; + goto textresume; + default: + *s++ = *x++; + } + } + break; + case '\\': + x++; + switch (*x) { + case 0: + goto textdone; + case 'n': + *s++ = '\n'; + break; + case 'r': + *s++ = '\r'; + break; + case 't': + *s++ = '\t'; + break; + case '\\': + *s++ = '\\'; + break; + case '\r': + /* \ -> line continuation */ + if (x[1] != '\n') { + x++; + continue; + } + case '\n': + /* \ -> line continuation */ + x++; + /* eat any extra whitespace */ + while ((*x == ' ') || (*x == '\t')) + x++; + continue; + default: + /* unknown escape -- just copy */ + *s++ = *x++; + } + continue; + default: + *s++ = *x++; + } + } + return STATE_EOF; +} + +WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]) +{ + struct WLAN_CFG_PARSE_STATE_S state; + CHAR **args; + INT_32 nargs; + + if (cmdLine == NULL || argc == NULL || argv == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + args = argv; + nargs = 0; + state.ptr = cmdLine; + state.nexttoken = 0; + state.maxSize = 0; + + if (kalStrnLen(cmdLine, 512) >= 512) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + goto exit; + case STATE_NEWLINE: + goto exit; + case STATE_TEXT: + if (nargs < WLAN_CFG_ARGV_MAX) + args[nargs++] = state.text; + break; + } + } + +exit: + *argc = nargs; + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanCfgParseAddEntry(IN P_ADAPTER_T prAdapter, + PUINT_8 pucKeyHead, PUINT_8 pucKeyTail, PUINT_8 pucValueHead, PUINT_8 pucValueTail) +{ + + UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + UINT_32 u4Len; + + kalMemZero(aucKey, sizeof(aucKey)); + kalMemZero(aucValue, sizeof(aucValue)); + + if ((pucKeyHead == NULL) + || (pucValueHead == NULL) + ) + return WLAN_STATUS_FAILURE; + + if (pucKeyTail) { + if (pucKeyHead > pucKeyTail) + return WLAN_STATUS_FAILURE; + u4Len = pucKeyTail - pucKeyHead + 1; + } else + u4Len = kalStrnLen(pucKeyHead, WLAN_CFG_KEY_LEN_MAX - 1); + + if (u4Len >= WLAN_CFG_KEY_LEN_MAX) + u4Len = WLAN_CFG_KEY_LEN_MAX - 1; + + if (u4Len < WLAN_CFG_VALUE_LEN_MAX) + kalStrnCpy(aucKey, pucKeyHead, u4Len); + else + DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); + + if (pucValueTail) { + if (pucValueHead > pucValueTail) + return WLAN_STATUS_FAILURE; + u4Len = pucValueTail - pucValueHead + 1; + } else + u4Len = kalStrnLen(pucValueHead, WLAN_CFG_VALUE_LEN_MAX - 1); + + if (u4Len >= WLAN_CFG_VALUE_LEN_MAX) + u4Len = WLAN_CFG_VALUE_LEN_MAX - 1; + + if (u4Len < WLAN_CFG_VALUE_LEN_MAX) + kalStrnCpy(aucValue, pucValueHead, u4Len); + else + DBGLOG(INIT, ERROR, "wifi entry parse error: Data len > %d\n", u4Len); + + return wlanCfgSet(prAdapter, aucKey, aucValue, 0); +} + +enum { + WAIT_KEY_HEAD = 0, + WAIT_KEY_TAIL, + WAIT_VALUE_HEAD, + WAIT_VALUE_TAIL, + WAIT_COMMENT_TAIL +}; + +WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen) +{ + + struct WLAN_CFG_PARSE_STATE_S state; + PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; + CHAR **args; + INT_32 nargs; + + if (pucConfigBuf == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (kalStrnLen(pucConfigBuf, 4000) >= 4000) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (u4ConfigBufLen == 0) + return WLAN_STATUS_FAILURE; + args = apcArgv; + nargs = 0; + state.ptr = pucConfigBuf; + state.nexttoken = 0; + state.maxSize = u4ConfigBufLen; + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + if (nargs > 1) + wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); + goto exit; + case STATE_NEWLINE: + if (nargs > 1) + wlanCfgParseAddEntry(prAdapter, args[0], NULL, args[1], NULL); + nargs = 0; + break; + case STATE_TEXT: + if (nargs < WLAN_CFG_ARGV_MAX) + args[nargs++] = state.text; + break; + } + } + +exit: + return WLAN_STATUS_SUCCESS; + +#if 0 + /* Old version */ + UINT_32 i; + UINT_8 c; + PUINT_8 pbuf; + UINT_8 ucState; + PUINT_8 pucKeyTail = NULL; + PUINT_8 pucKeyHead = NULL; + PUINT_8 pucValueHead = NULL; + PUINT_8 pucValueTail = NULL; + + ucState = WAIT_KEY_HEAD; + pbuf = pucConfigBuf; + + for (i = 0; i < u4ConfigBufLen; i++) { + c = pbuf[i]; + if (c == '\r' || c == '\n') { + + if (ucState == WAIT_VALUE_TAIL) { + /* Entry found */ + if (pucValueHead) + wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, + pucValueHead, pucValueTail); + } + ucState = WAIT_KEY_HEAD; + pucKeyTail = NULL; + pucKeyHead = NULL; + pucValueHead = NULL; + pucValueTail = NULL; + + } else if (c == '=') { + if (ucState == WAIT_KEY_TAIL) { + pucKeyTail = &pbuf[i - 1]; + ucState = WAIT_VALUE_HEAD; + } + } else if (c == ' ' || c == '\t') { + if (ucState == WAIT_KEY_HEAD) + ; + else if (ucState == WAIT_KEY_TAIL) { + pucKeyTail = &pbuf[i - 1]; + ucState = WAIT_VALUE_HEAD; + } + } else { + + if (c == '#') { + /* comments */ + if (ucState == WAIT_KEY_HEAD) + ucState = WAIT_COMMENT_TAIL; + else if (ucState == WAIT_VALUE_TAIL) + pucValueTail = &pbuf[i]; + + } else { + if (ucState == WAIT_KEY_HEAD) { + pucKeyHead = &pbuf[i]; + pucKeyTail = &pbuf[i]; + ucState = WAIT_KEY_TAIL; + } else if (ucState == WAIT_VALUE_HEAD) { + pucValueHead = &pbuf[i]; + pucValueTail = &pbuf[i]; + ucState = WAIT_VALUE_TAIL; + } else if (ucState == WAIT_VALUE_TAIL) + pucValueTail = &pbuf[i]; + } + } + + } /* for */ + + if (ucState == WAIT_VALUE_TAIL) { + /* Entry found */ + if (pucValueTail) + wlanCfgParseAddEntry(prAdapter, pucKeyHead, pucKeyTail, pucValueHead, pucValueTail); + } +#endif + + return WLAN_STATUS_SUCCESS; +} +#endif + +#if CFG_SUPPORT_CFG_FILE +WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags) +{ + P_WLAN_CFG_T prWlanCfg; + /* P_WLAN_CFG_ENTRY_T prWlanCfgEntry; */ + prAdapter->prWlanCfg = &prAdapter->rWlanCfg; + prWlanCfg = prAdapter->prWlanCfg; + + kalMemZero(prWlanCfg, sizeof(WLAN_CFG_T)); + ASSERT(prWlanCfg); + prWlanCfg->u4WlanCfgEntryNumMax = WLAN_CFG_ENTRY_NUM_MAX; + prWlanCfg->u4WlanCfgKeyLenMax = WLAN_CFG_KEY_LEN_MAX; + prWlanCfg->u4WlanCfgValueLenMax = WLAN_CFG_VALUE_LEN_MAX; +#if 0 + DBGLOG(INIT, INFO, "Init wifi config len %u max entry %u\n", u4ConfigBufLen, prWlanCfg->u4WlanCfgEntryNumMax); +#endif + /* self test */ + wlanCfgSet(prAdapter, "ConfigValid", "0x123", 0); + if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 0x123) + DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); + wlanCfgSet(prAdapter, "ConfigValid", "1", 0); + if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 1) + DBGLOG(INIT, ERROR, "wifi config error %u\n", __LINE__); +#if 0 /* soc chip didn't support these parameters now */ + /* Add initil config */ + /* use g,wlan,p2p,ap as prefix */ + /* Don't set cb here , overwrite by another api */ + wlanCfgSet(prAdapter, "TxLdpc", "1", 0); + wlanCfgSet(prAdapter, "RxLdpc", "1", 0); + wlanCfgSet(prAdapter, "RxBeamformee", "1", 0); + wlanCfgSet(prAdapter, "RoamTh1", "100", 0); + wlanCfgSet(prAdapter, "RoamTh2", "150", 0); + wlanCfgSet(prAdapter, "wlanRxLdpc", "1", 0); + wlanCfgSet(prAdapter, "apRxLdpc", "1", 0); + wlanCfgSet(prAdapter, "p2pRxLdpc", "1", 0); +#endif + /* Parse the pucConfigBuff */ + + if (pucConfigBuf && (u4ConfigBufLen > 0)) + wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigBufLen); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to initialize WLAN feature options +* +* @param prAdapter Pointer of ADAPTER_T +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanCfgApply(IN P_ADAPTER_T prAdapter) +{ +#define STR2BYTE(s) (((((PUINT_8)s)[0]-'0')*10)+(((PUINT_8)s)[1]-'0')) + CHAR aucValue[WLAN_CFG_VALUE_LEN_MAX]; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + P_REG_INFO_T prRegInfo = &prAdapter->prGlueInfo->rRegInfo; + P_TX_PWR_PARAM_T prTxPwr = &prRegInfo->rTxPwr; + + kalMemZero(aucValue, sizeof(aucValue)); + DBGLOG(INIT, LOUD, "CFG_FILE: Apply Config File\n"); + /* Apply COUNTRY Config */ + if (wlanCfgGet(prAdapter, "country", aucValue, "", 0) == WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, LOUD, "CFG_FILE: Found Country Key, Value=%s\n", aucValue); + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((UINT_16) aucValue[0]) << 8) | ((UINT_16) aucValue[1]); + prRegInfo->au2CountryCode[0] = aucValue[0]; + prRegInfo->au2CountryCode[1] = aucValue[1]; + } + prWifiVar->ucApWpsMode = (UINT_8) wlanCfgGetUint32(prAdapter, "ApWpsMode", 0); + prWifiVar->ucCert11nMode = (UINT_8)wlanCfgGetUint32(prAdapter, "Cert11nMode", 0); + DBGLOG(INIT, LOUD, "CFG_FILE: ucApWpsMode = %u, ucCert11nMode = %u\n", + prWifiVar->ucApWpsMode, prWifiVar->ucCert11nMode); + if (prWifiVar->ucCert11nMode == 1) + nicWriteMcr(prAdapter, 0x11111115 , 1); + + if (wlanCfgGet(prAdapter, "5G_support", aucValue, "", 0) == WLAN_STATUS_SUCCESS) + prRegInfo->ucSupport5GBand = (*aucValue == 'y') ? 1 : 0; + if (wlanCfgGet(prAdapter, "TxPower2G4CCK", aucValue, "", 0) == WLAN_STATUS_SUCCESS + && kalStrLen(aucValue) == 2) { + prTxPwr->cTxPwr2G4Cck = STR2BYTE(aucValue); + DBGLOG(INIT, LOUD, "2.4G cck=%d\n", prTxPwr->cTxPwr2G4Cck); + } + if (wlanCfgGet(prAdapter, "TxPower2G4OFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS && + kalStrLen(aucValue) == 10) { + prTxPwr->cTxPwr2G4OFDM_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr2G4OFDM_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr2G4OFDM_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr2G4OFDM_48Mbps = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr2G4OFDM_54Mbps = STR2BYTE(aucValue + 8); + DBGLOG(INIT, LOUD, "2.4G OFDM=%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr2G4OFDM_BPSK, prTxPwr->cTxPwr2G4OFDM_QPSK, + prTxPwr->cTxPwr2G4OFDM_16QAM, prTxPwr->cTxPwr2G4OFDM_48Mbps, + prTxPwr->cTxPwr2G4OFDM_54Mbps); + } + if (wlanCfgGet(prAdapter, "TxPower2G4HT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS && + kalStrLen(aucValue) == 12) { + prTxPwr->cTxPwr2G4HT20_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr2G4HT20_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr2G4HT20_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr2G4HT20_MCS5 = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr2G4HT20_MCS6 = STR2BYTE(aucValue + 8); + prTxPwr->cTxPwr2G4HT20_MCS7 = STR2BYTE(aucValue + 10); + DBGLOG(INIT, LOUD, "2.4G HT20=%d,%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr2G4HT20_BPSK, prTxPwr->cTxPwr2G4HT20_QPSK, + prTxPwr->cTxPwr2G4HT20_16QAM, prTxPwr->cTxPwr2G4HT20_MCS5, + prTxPwr->cTxPwr2G4HT20_MCS6, prTxPwr->cTxPwr2G4HT20_MCS7); + } + if (wlanCfgGet(prAdapter, "TxPower2G4HT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS && + kalStrLen(aucValue) == 12) { + prTxPwr->cTxPwr2G4HT40_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr2G4HT40_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr2G4HT40_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr2G4HT40_MCS5 = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr2G4HT40_MCS6 = STR2BYTE(aucValue + 8); + prTxPwr->cTxPwr2G4HT40_MCS7 = STR2BYTE(aucValue + 10); + DBGLOG(INIT, LOUD, "2.4G HT40=%d,%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr2G4HT40_BPSK, prTxPwr->cTxPwr2G4HT40_QPSK, + prTxPwr->cTxPwr2G4HT40_16QAM, prTxPwr->cTxPwr2G4HT40_MCS5, + prTxPwr->cTxPwr2G4HT40_MCS6, prTxPwr->cTxPwr2G4HT40_MCS7); + } + if (wlanCfgGet(prAdapter, "TxPower5GOFDM", aucValue, "", 0) == WLAN_STATUS_SUCCESS + && kalStrLen(aucValue) == 10) { + prTxPwr->cTxPwr5GOFDM_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr5GOFDM_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr5GOFDM_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr5GOFDM_48Mbps = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr5GOFDM_54Mbps = STR2BYTE(aucValue + 8); + DBGLOG(INIT, LOUD, "5G OFDM=%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr5GOFDM_BPSK, prTxPwr->cTxPwr5GOFDM_QPSK, + prTxPwr->cTxPwr5GOFDM_16QAM, prTxPwr->cTxPwr5GOFDM_48Mbps, + prTxPwr->cTxPwr5GOFDM_54Mbps); + } + if (wlanCfgGet(prAdapter, "TxPower5GHT20", aucValue, "", 0) == WLAN_STATUS_SUCCESS + && kalStrLen(aucValue) == 12) { + prTxPwr->cTxPwr5GHT20_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr5GHT20_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr5GHT20_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr5GHT20_MCS5 = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr5GHT20_MCS6 = STR2BYTE(aucValue + 8); + prTxPwr->cTxPwr5GHT20_MCS7 = STR2BYTE(aucValue + 10); + DBGLOG(INIT, LOUD, "5G HT20=%d,%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr5GHT20_BPSK, prTxPwr->cTxPwr5GHT20_QPSK, + prTxPwr->cTxPwr5GHT20_16QAM, prTxPwr->cTxPwr5GHT20_MCS5, prTxPwr->cTxPwr5GHT20_MCS6, + prTxPwr->cTxPwr5GHT20_MCS7); + } + if (wlanCfgGet(prAdapter, "TxPower5GHT40", aucValue, "", 0) == WLAN_STATUS_SUCCESS + && kalStrLen(aucValue) == 12) { + prTxPwr->cTxPwr5GHT40_BPSK = STR2BYTE(aucValue); + prTxPwr->cTxPwr5GHT40_QPSK = STR2BYTE(aucValue + 2); + prTxPwr->cTxPwr5GHT40_16QAM = STR2BYTE(aucValue + 4); + prTxPwr->cTxPwr5GHT40_MCS5 = STR2BYTE(aucValue + 6); + prTxPwr->cTxPwr5GHT40_MCS6 = STR2BYTE(aucValue + 8); + prTxPwr->cTxPwr5GHT40_MCS7 = STR2BYTE(aucValue + 10); + DBGLOG(INIT, LOUD, "5G HT40=%d,%d,%d,%d,%d,%d\n", + prTxPwr->cTxPwr5GHT40_BPSK, prTxPwr->cTxPwr5GHT40_QPSK, + prTxPwr->cTxPwr5GHT40_16QAM, prTxPwr->cTxPwr5GHT40_MCS5, prTxPwr->cTxPwr5GHT40_MCS6, + prTxPwr->cTxPwr5GHT40_MCS7); + } + /* TODO: Apply other Config */ +} +#endif /* CFG_SUPPORT_CFG_FILE */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c new file mode 100644 index 0000000000000..993ff061ed203 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_oid.c @@ -0,0 +1,11050 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/common/wlan_oid.c#5 +*/ + +/*! \file wlanoid.c + \brief This file contains the WLAN OID processing routines of Windows driver for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_oid.c +** +** 09 05 2013 cp.wu +** isolate logic regarding roaming & reassociation +** +** 09 03 2013 cp.wu +** add path for reassociation +** +** 09 02 2013 cp.wu +** add path to handle reassociation request +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 06 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * using the wlanSendSetQueryCmd to set the tx power control cmd. + * + * 01 06 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * change the set tx power cmd name. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 12 20 2011 cp.wu + * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information + * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO + * to expose version information + * + * 12 05 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * add CONNECT_BY_BSSID policy + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to + * asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state + * without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 21 2011 cp.wu + * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing + * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer + * add more checking for such cases + * + * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. + * add some tweaking to protect such cases because that net device has become invalid. + * + * 11 15 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of bb and ar for xlog. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 11 09 2011 george.huang + * [WCXRP00000871] [MT6620 Wi-Fi][FW] Include additional wakeup condition, which is by + * consequent DTIM unicast indication add XLOG for Set PS mode entry + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 11 02 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add RDD certification features. + * + * 10 21 2011 eddie.chen + * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout + * Add switch to ignore the STA aging timeout. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 15 2011 tsaiyuan.hsu + * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA + * correct fifo full control from query to set operation for CTIA. + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 08 17 2011 tsaiyuan.hsu + * [WCXRP00000938] [MT6620 Wi-Fi][FW] add system config for CTIA + * add system config for CTIA. + * + * 08 15 2011 george.huang + * [MT6620 Wi-Fi][FW] handle TSF drift for connection detection + * . + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, + * for customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 05 02 2011 eddie.chen + * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control + * Fix compile warning. + * + * 04 29 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * . + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * add more debug message + * + * 04 26 2011 eddie.chen + * [WCXRP00000373] [MT6620 Wi-Fi][FW] SW debug control + * Add rx path profiling. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 31 2011 puff.wen + * NULL + * . + * + * 03 29 2011 puff.wen + * NULL + * Add chennel switch for stress test + * + * 03 29 2011 cp.wu + * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning + * surpress klock warning with code path rewritten + * + * 03 24 2011 wh.su + * [WCXRP00000595] [MT6620 Wi-Fi][Driver] at CTIA indicate disconnect to make the ps profile can apply + * use disconnect event instead of ais abort for CTIA testing. + * + * 03 23 2011 george.huang + * [WCXRP00000586] [MT6620 Wi-Fi][FW] Modify for blocking absence request right after connected + * revise for CTIA power mode setting + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 17 2011 yarco.yang + * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage + * . + * + * 03 15 2011 george.huang + * [WCXRP00000557] [MT6620 Wi-Fi] Support current consumption test mode commands + * Support current consumption measurement mode command + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 04 2011 cp.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * surpress compile warning occurred when compiled by GNU compiler collection. + * + * 03 03 2011 wh.su + * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue + * fixed the enter ctia test mode issue. + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Update sigma CAPI for U-APSD setting + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as + * initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 01 27 2011 george.huang + * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting + * Support CTIA power mode setting. + * + * 01 26 2011 wh.su + * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux + * adding the SW cmd ioctl support, use set/get structure ioctl. + * + * 01 25 2011 cp.wu + * [WCXRP00000394] [MT6620 Wi-Fi][Driver] Count space needed for generating error message in + * scanning list into buffer size checking + * when doing size prechecking, check illegal MAC address as well + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cp.wu + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * check if allow to switch to IBSS mode via concurrent module before setting to IBSS mode + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 01 04 2011 cp.wu + * [WCXRP00000342] [MT6620 Wi-Fi][Driver] show error code in scanning list when MAC address is not + * correctly configured in NVRAM + * show error code 0x10 when MAC address in NVRAM is not configured correctly. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations + * to ease physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 28 2010 george.huang + * [WCXRP00000232] [MT5931 Wi-Fi][FW] Modifications for updated HW power on sequence and related design + * support WMM-PS U-APSD AC assignment. + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 16 2010 cp.wu + * [WCXRP00000268] [MT6620 Wi-Fi][Driver] correction for WHQL failed items + * correction for OID_802_11_NETWORK_TYPES_SUPPORTED handlers + * + * 12 13 2010 cp.wu + * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork + * suppress warning reported by Klockwork. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 30 2010 cp.wu + * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 + * . + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only + * with necessary data field checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available + * but extra scan result used to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 21 2010 wh.su + * [WCXRP00000192] [MT6620 Wi-Fi][Driver] Fixed fail trying to build connection with Security + * AP while enable WAPI message check + * Not set the wapi mode while the wapi assoc info set non-wapi ie. + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying + * current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 22 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * dos2unix conversion. + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version + * Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android complete + * implementation of Android NVRAM access + * + * 10 06 2010 yuche.tsai + * NULL + * Update SLT 5G Test Channel Set. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 06 2010 yuche.tsai + * NULL + * Update For SLT 5G Test Channel Selection Rule. + * + * 10 05 2010 cp.wu + * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form + * Query buffer size needs to be enlarged due to result is filled in 4-bytes alignment boundary + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and + * replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions + * + * 10 04 2010 cp.wu + * [WCXRP00000075] [MT6620 Wi-Fi][Driver] Fill query buffer for OID_802_11_BSSID_LIST in 4-bytes aligned form + * Extend result length to multiples of 4-bytes + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Update SLT due to API change of SCAN module. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 yuche.tsai + * NULL + * Refine SLT IO control handler. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 chinglan.wang + * NULL + * Modify the rescan condition. + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 27 2010 chinglan.wang + * NULL + * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 16 2010 george.huang + * NULL + * . + * + * 08 16 2010 george.huang + * NULL + * update params defined in CMD_SET_NETWORK_ADDRESS_LIST + * + * 08 04 2010 cp.wu + * NULL + * fix for check build WHQL testing: + * 1) do not assert query buffer if indicated buffer length is zero + * 2) sdio.c has bugs which cause freeing same pointer twice + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 04 2010 cp.wu + * NULL + * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. + * + * 08 04 2010 cp.wu + * NULL + * bypass u4FuncData for RF-Test query request as well. + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 26 2010 cp.wu + * + * re-commit code logic being overwriten. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 20 2010 cp.wu + * + * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one + * 2) refine disconnection behaviour when issued during BG-SCAN process + * + * 07 19 2010 wh.su + * + * modify the auth and encry status variable. + * + * 07 16 2010 cp.wu + * + * remove work-around in case SCN is not available. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. + * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add SCN compilation option. + * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement SCAN-REQUEST oid as mailbox message dispatching. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * adding the compiling flag for oid pmkid. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 28 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * simplify cmd packet sending for RF test and MCR access OIDs + * + * 05 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable radio even when STA is not associated. + * + * 05 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct 2 OID behaviour to meet WHQL requirement. + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power management macro + * + * 05 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct BSSID_LIST oid when radio if turned off. + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll + * 2) correct address list parsing + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * disable wlanoidSetNetworkAddress() temporally. + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * some OIDs should be DRIVER_CORE instead of GLUE_EXTENSION + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. + * 2) finish statistics OIDs + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct wlanoidSet802dot11PowerSaveProfile implementation. + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) enable CMD/EVENT ver 0.9 definition. + * 2) abandon use of ENUM_MEDIA_STATE + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add dissassocation support for wpa supplicant + * + * 05 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct return value. + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * for disassociation, still use parameter with current setting. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * for disassociation, generate a WZC-compatible invalid SSID. + * + * 05 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * associate to illegal SSID when handling OID_802_11_DISASSOCIATE + * + * 04 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * reserve field of privacy filter and RTS threshold setting. + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 04 22 2010 cp.wu + * [WPD00003830]add OID_802_11_PRIVACY_FILTER support + * enable RX filter OID + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add ioctl of power management + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * 2) command sequence number is now increased atomically + * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_CONFIGURATION query for infrastructure mode. + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) remove unused spin lock declaration + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * are done in adapter layer. + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)improve none-glue code portability + * (2) disable set Multicast address during atomic context + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve glue code portability + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * the frequency is used for adhoc connection only + * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * + * + * 03 22 2010 cp.wu + * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list + * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result + * + * 03 19 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * adding the check for pass WHQL test item. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * +* 03 16 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * fixed some whql pre-test fail case. + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. + * + * 02 24 2010 wh.su + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Don't needed to check the auth mode, WHQL testing not specific at auth wpa2. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not check SSID validity anymore. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * 2. follow MSDN defined behavior when associates to another AP + * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move ucCmdSeqNum as instance variable + * + * 02 04 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when OID_CUSTOM_OID_INTERFACE_VERSION is queried, do modify connection states + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * 2. block TX/ordinary OID when RF test mode is engaged + * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * 4. correct some HAL implementation + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * OID_802_11_RSSI, + * OID_802_11_RSSI_TRIGGER, + * OID_802_11_STATISTICS, + * OID_802_11_DISASSOCIATE, + * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not fill ucJoinOnly currently + * + * 01 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable to connect to ad-hoc network + * + * 01 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * .implement Set/Query BeaconInterval/AtimWindow + * + * 01 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * .Set/Get AT Info is not blocked even when driver is not in fg test mode + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * and result is retrieved by get ATInfo instead + * 2) add 4 counter for recording aggregation statistics + * + * 12 28 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate redundant variables for connection_state +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-12-16 22:13:36 GMT mtk02752 +** change hard-coded MAC address to match with FW (temporally) +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-12-10 16:49:50 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-12-08 17:38:49 GMT mtk02752 +** + add OID for RF test +** * MCR RD/WR are modified to match with cmd/event definition +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-12-08 11:32:20 GMT mtk02752 +** add skeleton for RF test implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-12-03 16:43:24 GMT mtk01461 +** Modify query SCAN list oid by adding prEventScanResult +** +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-03 16:39:27 GMT mtk01461 +** Sync CMD data structure in set ssid oid +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-03 16:28:22 GMT mtk01461 +** Add invalid check of set SSID oid and fix query scan list oid +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-30 17:33:08 GMT mtk02752 +** implement wlanoidSetInfrastructureMode/wlanoidQueryInfrastructureMode +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-30 10:53:49 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-30 09:22:48 GMT mtk02752 +** correct wifi cmd length mismatch +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-25 21:34:33 GMT mtk02752 +** sync EVENT_SCAN_RESULT_T with firmware +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 21:03:27 GMT mtk02752 +** implement wlanoidQueryBssidList() +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-25 18:17:17 GMT mtk02752 +** refine GL_WLAN_INFO_T for buffering scan result +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-23 20:28:51 GMT mtk02752 +** some OID will be set to WLAN_STATUS_PENDING until it is sent via wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-23 17:56:36 GMT mtk02752 +** implement wlanoidSetBssidListScan(), wlanoidSetBssid() and wlanoidSetSsid() +** +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-13 17:20:53 GMT mtk02752 +** add Set BSSID/SSID path but disabled temporally due to FW is not ready yet +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 12:28:58 GMT mtk02752 +** add wlanoidSetBssidListScan -> cmd_info path +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-09 22:48:07 GMT mtk01084 +** modify test cases entry +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-04 14:10:58 GMT mtk01084 +** add new test interfaces +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-30 18:17:10 GMT mtk01084 +** fix compiler warning +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:46:26 GMT mtk01084 +** add test functions +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:07:56 GMT mtk01084 +** include new file +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:29 GMT mtk01084 +** modify for new HW architecture +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-02 13:48:49 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-09-09 17:26:04 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-21 12:09:50 GMT mtk01461 +** Update for MCR Write OID +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:35:18 GMT mtk01461 +** Update wlanoidQueryMcrRead() for composing CMD_INFO_T +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 18:09:51 GMT mtk01426 +** Remove kalIndicateStatusAndComplete() in wlanoidQueryOidInterfaceVersion() +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-14 15:51:50 GMT mtk01426 +** Add MCR read/write support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:40 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:06:31 GMT mtk01426 +** Init for develop +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "precomp.h" +#include "mgmt/rsn.h" + +#include + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ +#if CFG_ENABLE_STATISTICS_BUFFERING +static BOOLEAN IsBufferedStatisticsUsable(P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (prAdapter->fgIsStatValid == TRUE && + (kalGetTimeTick() - prAdapter->rStatUpdateTime) <= CFG_STATISTICS_VALID_CYCLE) + return TRUE; + else + return FALSE; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the supported physical layer network +* type that can be used by the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + UINT_32 u4NumItem = 0; + ENUM_PARAM_NETWORK_TYPE_T eSupportedNetworks[PARAM_NETWORK_TYPE_NUM]; + PPARAM_NETWORK_TYPE_LIST prSupported; + + /* The array of all physical layer network subtypes that the driver supports. */ + + DEBUGFUNC("wlanoidQueryNetworkTypesSupported"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + /* Init. */ + for (u4NumItem = 0; u4NumItem < PARAM_NETWORK_TYPE_NUM; u4NumItem++) + eSupportedNetworks[u4NumItem] = 0; + + u4NumItem = 0; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_DS; + u4NumItem++; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_OFDM24; + u4NumItem++; + + *pu4QueryInfoLen = + (UINT_32) OFFSET_OF(PARAM_NETWORK_TYPE_LIST, eNetworkType) + + (u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + if (u4QueryBufferLen < *pu4QueryInfoLen) + return WLAN_STATUS_INVALID_LENGTH; + + prSupported = (PPARAM_NETWORK_TYPE_LIST) pvQueryBuffer; + prSupported->NumberOfItems = u4NumItem; + kalMemCopy(prSupported->eNetworkType, eSupportedNetworks, u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + DBGLOG(OID, TRACE, "NDIS supported network type list: %u\n", prSupported->NumberOfItems); + DBGLOG_MEM8(OID, TRACE, prSupported, *pu4QueryInfoLen); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryNetworkTypesSupported */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current physical layer network +* type used by the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + /* TODO: need to check the OID handler content again!! */ + + ENUM_PARAM_NETWORK_TYPE_T rCurrentNetworkTypeInUse = PARAM_NETWORK_TYPE_OFDM24; + + DEBUGFUNC("wlanoidQueryNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) + rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkType); + else + rCurrentNetworkTypeInUse = (ENUM_PARAM_NETWORK_TYPE_T) (prAdapter->rWlanInfo.ucNetworkTypeInUse); + + *(P_ENUM_PARAM_NETWORK_TYPE_T) pvQueryBuffer = rCurrentNetworkTypeInUse; + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(OID, TRACE, "Network type in use: %d\n", rCurrentNetworkTypeInUse); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryNetworkTypeInUse */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the physical layer network type used +* by the driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns the +* amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS The given network type is supported and accepted. +* \retval WLAN_STATUS_INVALID_DATA The given network type is not in the +* supported list. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + /* TODO: need to check the OID handler content again!! */ + + ENUM_PARAM_NETWORK_TYPE_T eNewNetworkType; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_INVALID_LENGTH; + } + + eNewNetworkType = *(P_ENUM_PARAM_NETWORK_TYPE_T) pvSetBuffer; + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(OID, INFO, "New network type: %d mode\n", eNewNetworkType); + + switch (eNewNetworkType) { + + case PARAM_NETWORK_TYPE_DS: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + + case PARAM_NETWORK_TYPE_OFDM5: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; + break; + + case PARAM_NETWORK_TYPE_OFDM24: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; + break; + + case PARAM_NETWORK_TYPE_AUTOMODE: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (UINT_8) PARAM_NETWORK_TYPE_AUTOMODE; + break; + + case PARAM_NETWORK_TYPE_FH: + DBGLOG(OID, INFO, "Not support network type: %d\n", eNewNetworkType); + rStatus = WLAN_STATUS_NOT_SUPPORTED; + break; + + default: + DBGLOG(OID, INFO, "Unknown network type: %d\n", eNewNetworkType); + rStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + /* Verify if we support the new network type. */ + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(OID, WARN, "Unknown network type: %d\n", eNewNetworkType); + + return rStatus; +} /* wlanoidSetNetworkTypeInUse */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current BSSID. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryBssid"); + + ASSERT(prAdapter); + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + ASSERT(pu4QueryInfoLen); + *pu4QueryInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(u4QueryBufferLen >= MAC_ADDR_LEN); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) + kalMemCopy(pvQueryBuffer, prAdapter->rWlanInfo.rCurrBssId.arMacAddress, MAC_ADDR_LEN); + else if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS) { + PARAM_MAC_ADDRESS aucTemp; /*!< BSSID */ + + COPY_MAC_ADDR(aucTemp, prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + aucTemp[0] &= ~BIT(0); + aucTemp[1] |= BIT(1); + COPY_MAC_ADDR(pvQueryBuffer, aucTemp); + } else + rStatus = WLAN_STATUS_ADAPTER_NOT_READY; + + *pu4QueryInfoLen = MAC_ADDR_LEN; + return rStatus; +} /* wlanoidQueryBssid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the list of all BSSIDs detected by +* the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + UINT_32 i, u4BssidListExLen; + P_PARAM_BSSID_LIST_EX_T prList; + P_PARAM_BSSID_EX_T prBssidEx; + PUINT_8 cp; + + DEBUGFUNC("wlanoidQueryBssidList"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + + if (!pvQueryBuffer) + return WLAN_STATUS_INVALID_DATA; + } + + prGlueInfo = prAdapter->prGlueInfo; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in qeury BSSID list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + u4BssidListExLen = 0; + + if (prAdapter->fgIsRadioOff == FALSE) { + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) + u4BssidListExLen += ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4Length); + } + + if (u4BssidListExLen) + u4BssidListExLen += 4; /* u4NumberOfItems. */ + else + u4BssidListExLen = sizeof(PARAM_BSSID_LIST_EX_T); + + *pu4QueryInfoLen = u4BssidListExLen; + + if (u4QueryBufferLen < *pu4QueryInfoLen) + return WLAN_STATUS_INVALID_LENGTH; + + /* Clear the buffer */ + kalMemZero(pvQueryBuffer, u4BssidListExLen); + + prList = (P_PARAM_BSSID_LIST_EX_T) pvQueryBuffer; + cp = (PUINT_8) &prList->arBssid[0]; + + if (prAdapter->fgIsRadioOff == FALSE && prAdapter->rWlanInfo.u4ScanResultNum > 0) { + /* fill up for each entry */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + prBssidEx = (P_PARAM_BSSID_EX_T) cp; + + /* copy structure */ + kalMemCopy(prBssidEx, + &(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /*For WHQL test, Rssi should be in range -10 ~ -200 dBm */ + if (prBssidEx->rRssi > PARAM_WHQL_RSSI_MAX_DBM) + prBssidEx->rRssi = PARAM_WHQL_RSSI_MAX_DBM; + + if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { + /* copy IEs */ + kalMemCopy(prBssidEx->aucIEs, + prAdapter->rWlanInfo.apucScanResultIEs[i], + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + } + /* 4-bytes alignement */ + prBssidEx->u4Length = ALIGN_4(prBssidEx->u4Length); + + cp += prBssidEx->u4Length; + prList->u4NumberOfItems++; + } + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryBssidList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to perform +* scanning. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_SSID_T prSsid; + PARAM_SSID_T rSsid; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetBssidListScan()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (prAdapter->fgIsRadioOff) { + DBGLOG(OID, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + DBGLOG(OID, TRACE, "Scan\n"); + + if (pvSetBuffer != NULL && u4SetBufferLen != 0) { + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, pvSetBuffer, u4SetBufferLen); + prSsid = &rSsid; + } else { + prSsid = NULL; + } + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else { + /* reject the scan request */ + rStatus = WLAN_STATUS_FAILURE; + } + } else { + /* reject the scan request */ + rStatus = WLAN_STATUS_FAILURE; + } + } else +#endif + { + if (prAdapter->fgEnOnlineScan == TRUE) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else { + /* reject the scan request */ + rStatus = WLAN_STATUS_FAILURE; + } + } + + return rStatus; +} /* wlanoidSetBssidListScan */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to perform +* scanning with attaching information elements(IEs) specified from user space +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_SCAN_REQUEST_EXT_T prScanRequest; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_PARAM_SSID_T prSsid; + PUINT_8 pucIe; + UINT_32 u4IeLength; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_8 ucScanTime = AIS_SCN_DONE_TIMEOUT_SEC; + + DEBUGFUNC("wlanoidSetBssidListScanExt()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, ERROR, "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (prAdapter->fgTestMode) { + DBGLOG(OID, WARN, "didn't support Scan in test mode\n"); + return WLAN_STATUS_FAILURE; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)) { + DBGLOG(OID, ERROR, "u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)\n"); + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(OID, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + DBGLOG(OID, TRACE, "ScanEx\n"); + + /* clear old scan backup results if exists */ + { + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { + kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); + prBssDesc->u2RawLength = 0; + } + } + } + + if (pvSetBuffer != NULL && u4SetBufferLen != 0) { + prScanRequest = (P_PARAM_SCAN_REQUEST_EXT_T) pvSetBuffer; + prSsid = &(prScanRequest->rSsid); + pucIe = prScanRequest->pucIE; + u4IeLength = prScanRequest->u4IELength; + } else { + prScanRequest = NULL; + prSsid = NULL; + pucIe = NULL; + u4IeLength = 0; + } + +/* P_AIS_FSM_INFO_T prAisFsmInfo; */ + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + +/* #if CFG_SUPPORT_WFD */ +#if 0 + if ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.ucWfdEnable) && + ((prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings.u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(OID, TRACE, "Twice the Scan Time for WFD\n"); + ucScanTime *= 2; + } + } +#endif /* CFG_SUPPORT_WFD */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer, SEC_TO_MSEC(ucScanTime)); + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else { + /* reject the scan request */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + rStatus = WLAN_STATUS_FAILURE; + } + } else { + /* reject the scan request */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + rStatus = WLAN_STATUS_FAILURE; + } + } else +#endif + { + if (prAdapter->fgEnOnlineScan == TRUE) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else { + /* reject the scan request */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + rStatus = WLAN_STATUS_FAILURE; + DBGLOG(OID, WARN, "ScanEx fail %d!\n", prAdapter->fgEnOnlineScan); + } + } + + return rStatus; +} /* wlanoidSetBssidListScanWithIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will initiate the join procedure to attempt to associate +* with the specified BSSID. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_UINT_8 pAddr; + UINT_32 i; + INT_32 i4Idx = -1; + P_MSG_AIS_ABORT_T prAisAbortMsg; + UINT_8 ucReasonOfDisconnect; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = MAC_ADDR_LEN; + if (u4SetBufferLen != MAC_ADDR_LEN) { + *pu4SetInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_INVALID_LENGTH; + } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prGlueInfo = prAdapter->prGlueInfo; + pAddr = (P_UINT_8) pvSetBuffer; + + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) { + kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; + } else { + DBGLOG(OID, TRACE, "DisByBssid\n"); + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + } else { + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + + /* check if any scanned result matchs with the BSSID */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { + i4Idx = (INT_32) i; + break; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS + || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS *//* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + /* Set Connection Request Issued Flag */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_BSSID; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = ucReasonOfDisconnect; + + /* Update the information to CONNECTION_SETTINGS_T */ + prAdapter->rWifiVar.rConnSettings.ucSSIDLen = 0; + prAdapter->rWifiVar.rConnSettings.aucSSID[0] = '\0'; + + COPY_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr); + + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) + prAisAbortMsg->fgDelayIndication = TRUE; + else + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + + DBGLOG(OID, INFO, "SetBssid\n"); + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetBssid() */ + +WLAN_STATUS +wlanoidSetConnect(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_PARAM_CONNECT_T pParamConn; + P_CONNECTION_SETTINGS_T prConnSettings; + UINT_32 i; + /*INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN;*/ + P_MSG_AIS_ABORT_T prAisAbortMsg; + BOOLEAN fgIsValidSsid = TRUE; + BOOLEAN fgEqualSsid = FALSE; + BOOLEAN fgEqualBssid = FALSE; + const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* MSDN: + * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE + */ + if (prAdapter->fgIsRadioOff == TRUE) + prAdapter->fgIsRadioOff = FALSE; + + if (u4SetBufferLen != sizeof(PARAM_CONNECT_T)) + return WLAN_STATUS_INVALID_LENGTH; + else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + + pParamConn = (P_PARAM_CONNECT_T) pvSetBuffer; + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + + if (pParamConn->u4SsidLen > 32) { + cnmMemFree(prAdapter, prAisAbortMsg); + return WLAN_STATUS_INVALID_LENGTH; + } else if (!pParamConn->pucBssid && !pParamConn->pucSsid) { + cnmMemFree(prAdapter, prAisAbortMsg); + return WLAN_STATUS_INVALID_LENGTH; + } + + prGlueInfo = prAdapter->prGlueInfo; + kalMemZero(prConnSettings->aucSSID, sizeof(prConnSettings->aucSSID)); + kalMemZero(prConnSettings->aucBSSID, sizeof(prConnSettings->aucBSSID)); + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_ANY; + prConnSettings->fgIsConnByBssidIssued = FALSE; + + if (pParamConn->pucSsid) { + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + COPY_SSID(prConnSettings->aucSSID, + prConnSettings->ucSSIDLen, pParamConn->pucSsid, (UINT_8) pParamConn->u4SsidLen); + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamConn->pucSsid, pParamConn->u4SsidLen)) + fgEqualSsid = TRUE; + } + if (pParamConn->pucBssid) { + if (!EQUAL_MAC_ADDR(aucZeroMacAddr, pParamConn->pucBssid) && IS_UCAST_MAC_ADDR(pParamConn->pucBssid)) { + prConnSettings->eConnectionPolicy = CONNECT_BY_BSSID; + prConnSettings->fgIsConnByBssidIssued = TRUE; + COPY_MAC_ADDR(prConnSettings->aucBSSID, pParamConn->pucBssid); + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pParamConn->pucBssid)) + fgEqualBssid = TRUE; + } else + DBGLOG(OID, TRACE, "wrong bssid %pM to connect\n", pParamConn->pucBssid); + } else + DBGLOG(OID, TRACE, "No Bssid set\n"); + prConnSettings->u4FreqInKHz = pParamConn->u4CenterFreq; + + /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (fgEqualSsid) { + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_ROAMING; + if (fgEqualBssid) { + kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; + } + } else { + DBGLOG(OID, TRACE, "DisBySsid\n"); + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + } else + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; +#if 0 + /* check if any scanned result matchs with the SSID */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; + UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; + INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; + + if (EQUAL_SSID(aucSsid, ucSsidLength, pParamConn->pucSsid, pParamConn->u4SsidLen) && + i4RSSI >= i4MaxRSSI) { + i4Idx = (INT_32) i; + i4MaxRSSI = i4RSSI; + } + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, pAddr)) { + i4Idx = (INT_32) i; + break; + } + } +#endif + /* prepare message to AIS */ + if (prConnSettings->eOPMode == NET_TYPE_IBSS || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS *//* beacon period */ + prConnSettings->u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prConnSettings->u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { + if (pParamConn->u4SsidLen == ELEM_MAX_LEN_SSID) { + fgIsValidSsid = FALSE; + + for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { + if (pParamConn->pucSsid) { + if (!((0 < pParamConn->pucSsid[i]) && (pParamConn->pucSsid[i] <= 0x1F))) { + fgIsValidSsid = TRUE; + break; + } + } + } + } + } + + /* Set Connection Request Issued Flag */ + if (fgIsValidSsid) + prConnSettings->fgIsConnReqIssued = TRUE; + else + prConnSettings->fgIsConnReqIssued = FALSE; + + if (fgEqualSsid || fgEqualBssid) + prAisAbortMsg->fgDelayIndication = TRUE; + else + /* Update the information to CONNECTION_SETTINGS_T */ + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + + DBGLOG(OID, INFO, "ssid %s, bssid %pM, conn policy %d, disc reason %d\n", + prConnSettings->aucSSID, prConnSettings->aucBSSID, + prConnSettings->eConnectionPolicy, prAisAbortMsg->ucReasonOfDisconnect); + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will initiate the join procedure to attempt +* to associate with the new SSID. If the previous scanning +* result is aged, we will scan the channels at first. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_PARAM_SSID_T pParamSsid; + UINT_32 i; + INT_32 i4Idx = -1, i4MaxRSSI = INT_MIN; + P_MSG_AIS_ABORT_T prAisAbortMsg; + BOOLEAN fgIsValidSsid = TRUE; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* MSDN: + * Powering on the radio if the radio is powered off through a setting of OID_802_11_DISASSOCIATE + */ + if (prAdapter->fgIsRadioOff == TRUE) + prAdapter->fgIsRadioOff = FALSE; + + if (u4SetBufferLen < sizeof(PARAM_SSID_T) || u4SetBufferLen > sizeof(PARAM_SSID_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + pParamSsid = (P_PARAM_SSID_T) pvSetBuffer; + + if (pParamSsid->u4SsidLen > 32) + return WLAN_STATUS_INVALID_LENGTH; + + prGlueInfo = prAdapter->prGlueInfo; + + /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { + kalSetMediaStateIndicated(prGlueInfo, PARAM_MEDIA_STATE_TO_BE_INDICATED); + } else { + DBGLOG(OID, TRACE, "DisBySsid\n"); + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + } + /* check if any scanned result matchs with the SSID */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + PUINT_8 aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; + UINT_8 ucSsidLength = (UINT_8) prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; + INT_32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; + + if (EQUAL_SSID(aucSsid, ucSsidLength, pParamSsid->aucSsid, pParamSsid->u4SsidLen) && + i4RSSI >= i4MaxRSSI) { + i4Idx = (INT_32) i; + i4MaxRSSI = i4RSSI; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS + || prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS *//* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { + if (pParamSsid->u4SsidLen == ELEM_MAX_LEN_SSID) { + fgIsValidSsid = FALSE; + + for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { + if (!((0 < pParamSsid->aucSsid[i]) && (pParamSsid->aucSsid[i] <= 0x1F))) { + fgIsValidSsid = TRUE; + break; + } + } + } + } + + /* Set Connection Request Issued Flag */ + if (fgIsValidSsid) { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = TRUE; + + if (pParamSsid->u4SsidLen) { + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + } else { + /* wildcard SSID */ + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_SSID_ANY; + } + } else { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + } + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + + COPY_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, + prAdapter->rWifiVar.rConnSettings.ucSSIDLen, pParamSsid->aucSsid, (UINT_8) pParamSsid->u4SsidLen); + + prAdapter->rWifiVar.rConnSettings.u4FreqInKHz = pParamSsid->u4CenterFreq; + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { + prAisAbortMsg->fgDelayIndication = TRUE; + } else { + /* Update the information to CONNECTION_SETTINGS_T */ + prAisAbortMsg->fgDelayIndication = FALSE; + } + DBGLOG(SCN, INFO, "SSID %s\n", prAdapter->rWifiVar.rConnSettings.aucSSID); + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidSetSsid() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the currently associated SSID. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_SSID_T prAssociatedSsid; + + DEBUGFUNC("wlanoidQuerySsid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_SSID_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prAssociatedSsid = (P_PARAM_SSID_T) pvQueryBuffer; + + kalMemZero(prAssociatedSsid->aucSsid, sizeof(prAssociatedSsid->aucSsid)); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + prAssociatedSsid->u4SsidLen = prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen; + + if (prAssociatedSsid->u4SsidLen) { + kalMemCopy(prAssociatedSsid->aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, prAssociatedSsid->u4SsidLen); + } + } else { + prAssociatedSsid->u4SsidLen = 0; + + DBGLOG(OID, TRACE, "Null SSID\n"); + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQuerySsid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 network type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eOPMode; + + /* + ** According to OID_802_11_INFRASTRUCTURE_MODE + ** If there is no prior OID_802_11_INFRASTRUCTURE_MODE, + ** NDIS_STATUS_ADAPTER_NOT_READY shall be returned. + */ +#if DBG + switch (*(P_ENUM_PARAM_OP_MODE_T) pvQueryBuffer) { + case NET_TYPE_IBSS: + DBGLOG(OID, INFO, "IBSS mode\n"); + break; + case NET_TYPE_INFRA: + DBGLOG(OID, INFO, "Infrastructure mode\n"); + break; + default: + DBGLOG(OID, INFO, "Automatic mode\n"); + } +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryInfrastructureMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set mode to infrastructure or +* IBSS, or automatic switch between the two. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid +* length of the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + ENUM_PARAM_OP_MODE_T eOpMode; + + DEBUGFUNC("wlanoidSetInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + if (u4SetBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set infrastructure mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eOpMode = *(P_ENUM_PARAM_OP_MODE_T) pvSetBuffer; + /* Verify the new infrastructure mode. */ + if (eOpMode >= NET_TYPE_NUM) { + DBGLOG(OID, TRACE, "Invalid mode value %d\n", eOpMode); + return WLAN_STATUS_INVALID_DATA; + } + + /* check if possible to switch to AdHoc mode */ + if (eOpMode == NET_TYPE_IBSS || eOpMode == NET_TYPE_DEDICATED_IBSS) { + if (cnmAisIbssIsPermitted(prAdapter) == FALSE) { + DBGLOG(OID, TRACE, "Mode value %d unallowed\n", eOpMode); + return WLAN_STATUS_FAILURE; + } + } + + /* Save the new infrastructure mode setting. */ + prAdapter->rWifiVar.rConnSettings.eOPMode = eOpMode; + + /* Clean up the Tx key flag */ + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; +#if CFG_SUPPORT_WAPI + prAdapter->prGlueInfo->u2WapiAssocInfoIESz = 0; + kalMemZero(&prAdapter->prGlueInfo->aucWapiAssocInfoIEs, 42); +#endif + +#if CFG_SUPPORT_802_11W + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled = FALSE; +#endif + +#if CFG_SUPPORT_WPS2 + kalMemZero(&prAdapter->prGlueInfo->aucWSCAssocInfoIE, 200); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INFRASTRUCTURE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, 0, NULL, pvSetBuffer, u4SetBufferLen); + +} /* wlanoidSetInfrastructureMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 authentication +* mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryAuthMode"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer = prAdapter->rWifiVar.rConnSettings.eAuthMode; + +#if DBG + switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer) { + case AUTH_MODE_OPEN: + DBGLOG(OID, INFO, "Current auth mode: Open\n"); + break; + + case AUTH_MODE_SHARED: + DBGLOG(OID, INFO, "Current auth mode: Shared\n"); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(OID, INFO, "Current auth mode: Auto-switch\n"); + break; + + case AUTH_MODE_WPA: + DBGLOG(OID, INFO, "Current auth mode: WPA\n"); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(OID, INFO, "Current auth mode: WPA PSK\n"); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(OID, INFO, "Current auth mode: WPA None\n"); + break; + + case AUTH_MODE_WPA2: + DBGLOG(OID, INFO, "Current auth mode: WPA2\n"); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(OID, INFO, "Current auth mode: WPA2 PSK\n"); + break; + + default: + DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); + break; + } +#endif + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryAuthMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the IEEE 802.11 authentication mode +* to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + UINT_32 i, u4AkmSuite; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + + DEBUGFUNC("wlanoidSetAuthMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) + return WLAN_STATUS_INVALID_LENGTH; + + /* RF Test */ + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* Check if the new authentication mode is valid. */ + if (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer >= AUTH_MODE_NUM) { + DBGLOG(OID, TRACE, "Invalid auth mode %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer); + return WLAN_STATUS_INVALID_DATA; + } + + switch (*(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer) { + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + /* infrastructure mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_INFRA) + return WLAN_STATUS_NOT_ACCEPTED; + break; + + case AUTH_MODE_WPA_NONE: + /* ad hoc mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_IBSS) + return WLAN_STATUS_NOT_ACCEPTED; + break; + + default: + break; + } + + /* Save the new authentication mode. */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = *(P_ENUM_PARAM_AUTH_MODE_T) pvSetBuffer; + +#if DBG + switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { + case AUTH_MODE_OPEN: + DBGLOG(RSN, TRACE, "New auth mode: open\n"); + break; + + case AUTH_MODE_SHARED: + DBGLOG(RSN, TRACE, "New auth mode: shared\n"); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(RSN, TRACE, "New auth mode: auto-switch\n"); + break; + + case AUTH_MODE_WPA: + DBGLOG(RSN, TRACE, "New auth mode: WPA\n"); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(RSN, TRACE, "New auth mode: WPA PSK\n"); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(RSN, TRACE, "New auth mode: WPA None\n"); + break; + + case AUTH_MODE_WPA2: + DBGLOG(RSN, TRACE, "New auth mode: WPA2\n"); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(RSN, TRACE, "New auth mode: WPA2 PSK\n"); + break; + + default: + DBGLOG(RSN, TRACE, "New auth mode: unknown (%d)\n", prAdapter->rWifiVar.rConnSettings.eAuthMode); + } +#endif + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode >= AUTH_MODE_WPA) { + switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { + case AUTH_MODE_WPA: + u4AkmSuite = WPA_AKM_SUITE_802_1X; + break; + + case AUTH_MODE_WPA_PSK: + u4AkmSuite = WPA_AKM_SUITE_PSK; + break; + + case AUTH_MODE_WPA_NONE: + u4AkmSuite = WPA_AKM_SUITE_NONE; + break; + + case AUTH_MODE_WPA2: + u4AkmSuite = RSN_AKM_SUITE_802_1X; + break; + + case AUTH_MODE_WPA2_PSK: + u4AkmSuite = RSN_AKM_SUITE_PSK; + break; + + default: + u4AkmSuite = 0; + } + } else { + u4AkmSuite = 0; + } + + /* Enable the specific AKM suite only. */ + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; + + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + else + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = FALSE; +#if CFG_SUPPORT_802_11W + if (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED) { + if ((u4AkmSuite == RSN_AKM_SUITE_PSK) && + prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_PSK_SHA256) { + DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_PSK_SHA256 AKM support\n"); + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + + } + if ((u4AkmSuite == RSN_AKM_SUITE_802_1X) && + prEntry->dot11RSNAConfigAuthenticationSuite == RSN_AKM_SUITE_802_1X_SHA256) { + DBGLOG(RSN, TRACE, "Enable RSN_AKM_SUITE_802_1X_SHA256 AKM support\n"); + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = TRUE; + } + } +#endif + } + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetAuthMode */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current 802.11 privacy filter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryPrivacyFilter"); + + ASSERT(prAdapter); + + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer = prAdapter->rWlanInfo.ePrivacyFilter; + +#if DBG + switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvQueryBuffer) { + case PRIVACY_FILTER_ACCEPT_ALL: + DBGLOG(OID, INFO, "Current privacy mode: open mode\n"); + break; + + case PRIVACY_FILTER_8021xWEP: + DBGLOG(OID, INFO, "Current privacy mode: filtering mode\n"); + break; + + default: + DBGLOG(OID, INFO, "Current auth mode: %d\n", *(P_ENUM_PARAM_AUTH_MODE_T) pvQueryBuffer); + } +#endif + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryPrivacyFilter */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the IEEE 802.11 privacy filter +* to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + + DEBUGFUNC("wlanoidSetPrivacyFilter"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_PRIVACY_FILTER_T); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_PRIVACY_FILTER_T)) + return WLAN_STATUS_INVALID_LENGTH; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* Check if the new authentication mode is valid. */ + if (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer >= PRIVACY_FILTER_NUM) { + DBGLOG(OID, TRACE, "Invalid privacy filter %d\n", *(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer); + return WLAN_STATUS_INVALID_DATA; + } + + switch (*(P_ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer) { + default: + break; + } + + /* Save the new authentication mode. */ + prAdapter->rWlanInfo.ePrivacyFilter = *(ENUM_PARAM_PRIVACY_FILTER_T) pvSetBuffer; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetPrivacyFilter */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to reload the available default settings for +* the specified type field. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + UINT_32 u4Len; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetReloadDefaults"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = sizeof(PARAM_RELOAD_DEFAULTS); + + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set Reload default! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + /* Verify the available reload options and reload the settings. */ + switch (*(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer) { + case ENUM_RELOAD_WEP_KEYS: + /* Reload available default WEP keys from the permanent + storage. */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = AUTH_MODE_OPEN; + /* ENUM_ENCRYPTION_DISABLED; */ + prAdapter->rWifiVar.rConnSettings.eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; + { + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_802_11_KEY prCmdKey; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); + + kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = 0; /* (UINT_8)(prRemovedKey->u4KeyIndex & 0x000000ff); */ + kalMemCopy(prCmdKey->aucPeerAddr, aucBCAddr, MAC_ADDR_LEN); + + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); + + prCmdKey->ucKeyType = 0; + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; + } + + break; + + default: + DBGLOG(OID, TRACE, "Invalid reload option %d\n", *(P_PARAM_RELOAD_DEFAULTS) pvSetBuffer); + rStatus = WLAN_STATUS_INVALID_DATA; + } + + /* OID_802_11_RELOAD_DEFAULTS requiest to reset to auto mode */ + eNetworkType = PARAM_NETWORK_TYPE_AUTOMODE; + wlanoidSetNetworkTypeInUse(prAdapter, &eNetworkType, sizeof(eNetworkType), &u4Len); + + return rStatus; +} /* wlanoidSetReloadDefaults */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a WEP key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +#ifdef LINUX +UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; +UINT_8 aucBCAddr[] = BC_MAC_ADDR; +#endif +WLAN_STATUS +wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ +#ifndef LINUX + UINT_8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; +#endif + P_PARAM_WEP_T prNewWepKey; + P_PARAM_KEY_T prParamKey = (P_PARAM_KEY_T) keyBuffer; + UINT_32 u4KeyId, u4SetLen; + + DEBUGFUNC("wlanoidSetAddWep"); + + ASSERT(prAdapter); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + + if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)) { + ASSERT(pu4SetInfoLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set add WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewWepKey = (P_PARAM_WEP_T) pvSetBuffer; + + /* Verify the total buffer for minimum length. */ + if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + prNewWepKey->u4KeyLength) { + DBGLOG(OID, WARN, "Invalid total buffer length (%d) than minimum length (%d)\n", + (UINT_8) u4SetBufferLen, (UINT_8) OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key structure length. */ + if (prNewWepKey->u4Length > u4SetBufferLen) { + DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8) prNewWepKey->u4Length, (UINT_8) u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key material length for maximum key material length:16 */ + if (prNewWepKey->u4KeyLength > 16 /* LEGACY_KEY_MAX_LEN */) { + DBGLOG(OID, WARN, "Invalid key material length (%d) greater than maximum key material length (16)\n", + (UINT_8) prNewWepKey->u4KeyLength); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = u4SetBufferLen; + + u4KeyId = prNewWepKey->u4KeyIndex & BITS(0, 29) /* WEP_KEY_ID_FIELD */; + + /* Verify whether key index is valid or not, current version + driver support only 4 global WEP keys setting by this OID */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(OID, ERROR, "Error, invalid WEP key ID: %d\n", (UINT_8) u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + prParamKey->u4KeyIndex = u4KeyId; + + /* Transmit key */ + if (prNewWepKey->u4KeyIndex & IS_TRANSMIT_KEY) + prParamKey->u4KeyIndex |= IS_TRANSMIT_KEY; + + /* Per client key */ + if (prNewWepKey->u4KeyIndex & IS_UNICAST_KEY) + prParamKey->u4KeyIndex |= IS_UNICAST_KEY; + + prParamKey->u4KeyLength = prNewWepKey->u4KeyLength; + + kalMemCopy(prParamKey->arBSSID, aucBCAddr, MAC_ADDR_LEN); + + kalMemCopy(prParamKey->aucKeyMaterial, prNewWepKey->aucKeyMaterial, prNewWepKey->u4KeyLength); + + prParamKey->u4Length = OFFSET_OF(PARAM_KEY_T, aucKeyMaterial) + prNewWepKey->u4KeyLength; + + wlanoidSetAddKey(prAdapter, (PVOID) prParamKey, prParamKey->u4Length, &u4SetLen); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetAddWep */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to remove the WEP key +* at the specified key index. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_32 u4KeyId, u4SetLen; + PARAM_REMOVE_KEY_T rRemoveKey; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + DEBUGFUNC("wlanoidSetRemoveWep"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_KEY_INDEX); + + if (u4SetBufferLen < sizeof(PARAM_KEY_INDEX)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + u4KeyId = *(PUINT_32) pvSetBuffer; + + /* Dump PARAM_WEP content. */ + DBGLOG(OID, INFO, "Set: Dump PARAM_KEY_INDEX content\n"); + DBGLOG(OID, INFO, "Index : 0x%08x\n", u4KeyId); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4KeyId & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(OID, ERROR, "Invalid WEP key index: 0x%08x\n", u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + u4KeyId &= BITS(0, 7); + + /* Verify whether key index is valid or not. Current version + driver support only 4 global WEP keys. */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(OID, ERROR, "invalid WEP key ID %u\n", u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + rRemoveKey.u4KeyIndex = *(PUINT_32) pvSetBuffer; + + kalMemCopy(rRemoveKey.arBSSID, aucBCAddr, MAC_ADDR_LEN); + + wlanoidSetRemoveKey(prAdapter, (PVOID)&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T), &u4SetLen); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetRemoveWep */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_KEY_T prNewKey; + P_CMD_802_11_KEY prCmdKey; + UINT_8 ucCmdSeqNum; + +#if 0 + DEBUGFUNC("wlanoidSetAddKey"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } +#endif + + prNewKey = (P_PARAM_KEY_T) pvSetBuffer; + +#if 0 + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Verify the key material length for key material buffer */ + if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check */ + if (prNewKey->u4KeyIndex & 0x0fffff00) + return WLAN_STATUS_INVALID_DATA; + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) + return WLAN_STATUS_INVALID_DATA; + + if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || + prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { + if (((prNewKey->u4KeyIndex & 0xff) != 0) || + ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) + && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) + && (prNewKey->arBSSID[5] == 0xff))) { + return WLAN_STATUS_INVALID_DATA; + } + } + + *pu4SetInfoLen = u4SetBufferLen; +#endif + + /* Dump PARAM_KEY content. */ + DBGLOG(OID, TRACE, "Set: PARAM_KEY Length: 0x%08x, Key Index: 0x%08x, Key Length: 0x%08x\n", + prNewKey->u4Length, prNewKey->u4KeyIndex, prNewKey->u4KeyLength); + DBGLOG(OID, TRACE, "BSSID:\n"); + DBGLOG_MEM8(OID, TRACE, prNewKey->arBSSID, sizeof(PARAM_MAC_ADDRESS)); + DBGLOG(OID, TRACE, "Key RSC:\n"); + DBGLOG_MEM8(OID, TRACE, &prNewKey->rKeyRSC, sizeof(PARAM_KEY_RSC)); + DBGLOG(OID, TRACE, "Key Material:\n"); + DBGLOG_MEM8(OID, TRACE, prNewKey->aucKeyMaterial, prNewKey->u4KeyLength); + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { + /* Todo:: Store the legacy wep key for OID_802_11_RELOAD_DEFAULTS */ + /* Todo:: Nothing */ + } + + if (prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = TRUE; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(OID, TRACE, "ucCmdSeqNum = %d\n", ucCmdSeqNum); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); + + kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 1; /* Add */ + + prCmdKey->ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; + prCmdKey->ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; + prCmdKey->ucIsAuthenticator = ((prNewKey->u4KeyIndex & IS_AUTHENTICATOR) == IS_AUTHENTICATOR) ? 1 : 0; + + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->arBSSID, MAC_ADDR_LEN); + + prCmdKey->ucNetType = 0; /* AIS */ + + prCmdKey->ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); + + /* Note: adjust the key length for WPA-None */ + prCmdKey->ucKeyLen = (UINT_8) prNewKey->u4KeyLength; + + kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, prCmdKey->ucKeyLen); + + if (prNewKey->u4KeyLength == 5) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP40; + } else if (prNewKey->u4KeyLength == 13) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP104; + } else if (prNewKey->u4KeyLength == 16) { + if ((ucAlgorithmId != CIPHER_SUITE_CCMP) && + (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA)) + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WEP128; + else { +#if CFG_SUPPORT_802_11W + if (prCmdKey->ucKeyId >= 4) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_BIP; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + prAisSpecBssInfo->fgBipKeyInstalled = TRUE; + } else +#endif + prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; + if (rsnCheckPmkidCandicate(prAdapter)) { + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + DBGLOG(RSN, TRACE, + "Add key: Prepare a timer to indicate candidate PMKID Candidate\n"); + cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } + } else if (prNewKey->u4KeyLength == 32) { + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) + prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; + else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) { + prCmdKey->ucAlgorithmId = CIPHER_SUITE_CCMP; + prCmdKey->ucKeyLen = CCMP_KEY_LEN; + } + } else + prCmdKey->ucAlgorithmId = CIPHER_SUITE_TKIP; + } + + DBGLOG(RSN, TRACE, "prCmdKey->ucAlgorithmId=%d, key len=%d\n", + prCmdKey->ucAlgorithmId, (UINT32) prNewKey->u4KeyLength); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS +wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_KEY_T prNewKey; + + DEBUGFUNC("wlanoidSetAddKey"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewKey = (P_PARAM_KEY_T) pvSetBuffer; + + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG(OID, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Verify the key material length for key material buffer */ + if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(OID, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check */ + if (prNewKey->u4KeyIndex & 0x0fffff00) + return WLAN_STATUS_INVALID_DATA; + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { + if (((prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN) && + (prNewKey->u4KeyIndex & 0xff) != 0) || + EQUAL_MAC_ADDR(prNewKey->arBSSID, "\xff\xff\xff\xff\xff\xff")) { + return WLAN_STATUS_INVALID_DATA; + } + } else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) + return WLAN_STATUS_INVALID_DATA; + + if (!(prNewKey->u4KeyLength == WEP_40_LEN || prNewKey->u4KeyLength == WEP_104_LEN || + prNewKey->u4KeyLength == CCMP_KEY_LEN || prNewKey->u4KeyLength == TKIP_KEY_LEN)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = u4SetBufferLen; + +#if (CFG_SUPPORT_TDLS == 1) + /* + supplicant will set key before updating station & enabling the link so we need to + backup the key information and set key when link is enabled + */ + if (TdlsexKeyHandle(prAdapter, prNewKey) == TDLS_STATUS_SUCCESS) + return WLAN_STATUS_SUCCESS; +#endif /* CFG_SUPPORT_TDLS */ + + return _wlanoidSetAddKey(prAdapter, pvSetBuffer, u4SetBufferLen, TRUE, CIPHER_SUITE_NONE, pu4SetInfoLen); +} /* wlanoidSetAddKey */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request the driver to remove the key at +* the specified key index. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_REMOVE_KEY_T prRemovedKey; + P_CMD_802_11_KEY prCmdKey; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetRemoveKey"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + + if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) + return WLAN_STATUS_INVALID_LENGTH; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set remove key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; + + /* Dump PARAM_REMOVE_KEY content. */ + DBGLOG(OID, TRACE, "Set: Dump PARAM_REMOVE_KEY content\n"); + DBGLOG(OID, TRACE, "Length : 0x%08x\n", prRemovedKey->u4Length); + DBGLOG(OID, TRACE, "Key Index : 0x%08x\n", prRemovedKey->u4KeyIndex); + DBGLOG(OID, TRACE, "BSSID:\n"); + DBGLOG_MEM8(OID, TRACE, prRemovedKey->arBSSID, MAC_ADDR_LEN); + + /* Check bit 31: this bit should always 0 */ + if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); + return WLAN_STATUS_INVALID_DATA; + } + + /* Check bits 8 ~ 29 should always be 0 */ + if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { + /* Bit 31 should not be set */ + DBGLOG(OID, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); + return WLAN_STATUS_INVALID_DATA; + } + + /* Clean up the Tx key flag */ + if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); + + kalMemZero((PUINT_8) prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); + +#if CFG_SUPPORT_802_11W + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM + 2); +#else + /* ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); */ +#endif + + if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) + prCmdKey->ucKeyType = 1; + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetRemoveKey */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current encryption status. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + BOOLEAN fgTransmitKeyAvailable = TRUE; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus = 0; + + DEBUGFUNC("wlanoidQueryEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + fgTransmitKeyAvailable = prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist; + + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION3_ENABLED: + if (fgTransmitKeyAvailable) + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + else + eEncStatus = ENUM_ENCRYPTION3_KEY_ABSENT; + break; + + case ENUM_ENCRYPTION2_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + break; + } + eEncStatus = ENUM_ENCRYPTION2_KEY_ABSENT; + break; + + case ENUM_ENCRYPTION1_ENABLED: + if (fgTransmitKeyAvailable) + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + else + eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; + break; + + case ENUM_ENCRYPTION_DISABLED: + eEncStatus = ENUM_ENCRYPTION_DISABLED; + break; + + default: + DBGLOG(OID, ERROR, "Unknown Encryption Status Setting:%d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } + +#if DBG + DBGLOG(OID, INFO, + "Encryption status: %d Return:%d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, eEncStatus); +#endif + + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvQueryBuffer = eEncStatus; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryEncryptionStatus */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the encryption status to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_NOT_SUPPORTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_ENCRYPTION_STATUS_T eEewEncrypt; + + DEBUGFUNC("wlanoidSetEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set encryption status! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eEewEncrypt = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; + DBGLOG(OID, TRACE, "ENCRYPTION_STATUS %d\n", eEewEncrypt); + + switch (eEewEncrypt) { + case ENUM_ENCRYPTION_DISABLED: /* Disable WEP, TKIP, AES */ + DBGLOG(RSN, TRACE, "Disable Encryption\n"); + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION1_ENABLED: /* Enable WEP. Disable TKIP, AES */ + DBGLOG(RSN, TRACE, "Enable Encryption1\n"); + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION2_ENABLED: /* Enable WEP, TKIP. Disable AES */ + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP); + DBGLOG(RSN, TRACE, "Enable Encryption2\n"); + break; + + case ENUM_ENCRYPTION3_ENABLED: /* Enable WEP, TKIP, AES */ + secSetCipherSuite(prAdapter, + CIPHER_FLAG_WEP40 | + CIPHER_FLAG_WEP104 | CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP | CIPHER_FLAG_CCMP); + DBGLOG(RSN, TRACE, "Enable Encryption3\n"); + break; + + default: + DBGLOG(RSN, WARN, "Unacceptible encryption status: %d\n", + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer); + + rStatus = WLAN_STATUS_NOT_SUPPORTED; + } + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* Save the new encryption status. */ + prAdapter->rWifiVar.rConnSettings.eEncStatus = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T) pvSetBuffer; + + DBGLOG(RSN, TRACE, "wlanoidSetEncryptionStatus to %d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } + + return rStatus; +} /* wlanoidSetEncryptionStatus */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to test the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_802_11_TEST_T prTest; + PVOID pvTestData; + PVOID pvStatusBuffer; + UINT_32 u4StatusBufferSize; + + DEBUGFUNC("wlanoidSetTest"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + *pu4SetInfoLen = u4SetBufferLen; + + prTest = (P_PARAM_802_11_TEST_T) pvSetBuffer; + + DBGLOG(OID, TRACE, "Test - Type %u\n", prTest->u4Type); + + switch (prTest->u4Type) { + case 1: /* Type 1: generate an authentication event */ + pvTestData = (PVOID) &prTest->u.AuthenticationEvent; + pvStatusBuffer = (PVOID) prAdapter->aucIndicationEventBuffer; + u4StatusBufferSize = prTest->u4Length - 8; + if (u4StatusBufferSize > sizeof(PARAM_AUTH_EVENT_T)) { + DBGLOG(OID, TRACE, "prTest->u4Length error %u\n", u4StatusBufferSize); + ASSERT(FALSE); + } + break; + + case 2: /* Type 2: generate an RSSI status indication */ + pvTestData = (PVOID) &prTest->u.RssiTrigger; + pvStatusBuffer = (PVOID) &prAdapter->rWlanInfo.rCurrBssId.rRssi; + u4StatusBufferSize = sizeof(PARAM_RSSI); + break; + + default: + return WLAN_STATUS_INVALID_DATA; + } + + ASSERT(u4StatusBufferSize <= 180); + if (u4StatusBufferSize > 180) + return WLAN_STATUS_INVALID_LENGTH; + + /* Get the contents of the StatusBuffer from the test structure. */ + kalMemCopy(pvStatusBuffer, pvTestData, u4StatusBufferSize); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, pvStatusBuffer, u4StatusBufferSize); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetTest */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the driver's WPA2 status. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CAPABILITY_T prCap; + P_PARAM_AUTH_ENCRYPTION_T prAuthenticationEncryptionSupported; + + DEBUGFUNC("wlanoidQueryCapability"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = 4 * sizeof(UINT_32) + 14 * sizeof(PARAM_AUTH_ENCRYPTION_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) + return WLAN_STATUS_INVALID_LENGTH; + + prCap = (P_PARAM_CAPABILITY_T) pvQueryBuffer; + + prCap->u4Length = *pu4QueryInfoLen; + prCap->u4Version = 2; /* WPA2 */ + prCap->u4NoOfPMKIDs = CFG_MAX_PMKID_CACHE; + prCap->u4NoOfAuthEncryptPairsSupported = 14; + + prAuthenticationEncryptionSupported = &prCap->arAuthenticationEncryptionSupported[0]; + + /* fill 14 entries of supported settings */ + prAuthenticationEncryptionSupported[0].eAuthModeSupported = AUTH_MODE_OPEN; + + prAuthenticationEncryptionSupported[0].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[1].eAuthModeSupported = AUTH_MODE_OPEN; + prAuthenticationEncryptionSupported[1].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[2].eAuthModeSupported = AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[2].eEncryptStatusSupported = ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[3].eAuthModeSupported = AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[3].eEncryptStatusSupported = ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[4].eAuthModeSupported = AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[4].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[5].eAuthModeSupported = AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[5].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[6].eAuthModeSupported = AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[6].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[7].eAuthModeSupported = AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[7].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[8].eAuthModeSupported = AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[8].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[9].eAuthModeSupported = AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[9].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[10].eAuthModeSupported = AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[10].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[11].eAuthModeSupported = AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[11].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[12].eAuthModeSupported = AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[12].eEncryptStatusSupported = ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[13].eAuthModeSupported = AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[13].eEncryptStatusSupported = ENUM_ENCRYPTION3_ENABLED; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryCapability */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the PMKID in the PMK cache. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + UINT_32 i; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidQueryPmkid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + *pu4QueryInfoLen = OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo) + + prAisSpecBssInfo->u4PmkidCacheCount * sizeof(PARAM_BSSID_INFO_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) + return WLAN_STATUS_INVALID_LENGTH; + + prPmkid = (P_PARAM_PMKID_T) pvQueryBuffer; + + prPmkid->u4Length = *pu4QueryInfoLen; + prPmkid->u4BSSIDInfoCount = prAisSpecBssInfo->u4PmkidCacheCount; + + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + kalMemCopy(prPmkid->arBSSIDInfo[i].arBSSID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, sizeof(PARAM_MAC_ADDRESS)); + kalMemCopy(prPmkid->arBSSIDInfo[i].arPMKID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); + } + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryPmkid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the PMKID to the PMK cache in the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_32 i, j; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidSetPmkid"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = u4SetBufferLen; + + /* It's possibble BSSIDInfoCount is zero, because OS wishes to clean PMKID */ + if (u4SetBufferLen < OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + ASSERT(pvSetBuffer); + prPmkid = (P_PARAM_PMKID_T) pvSetBuffer; + + if (u4SetBufferLen < + ((prPmkid->u4BSSIDInfoCount * sizeof(PARAM_BSSID_INFO_T)) + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo))) + return WLAN_STATUS_INVALID_DATA; + + if (prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE) + return WLAN_STATUS_INVALID_DATA; + + DBGLOG(OID, TRACE, "Count %u\n", prPmkid->u4BSSIDInfoCount); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* This OID replace everything in the PMKID cache. */ + if (prPmkid->u4BSSIDInfoCount == 0) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + if ((prAisSpecBssInfo->u4PmkidCacheCount + prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE)) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + + /* + The driver can only clear its PMKID cache whenever it make a media disconnect + indication. Otherwise, it must change the PMKID cache only when set through this OID. + */ +#if CFG_RSN_MIGRATION + for (i = 0; i < prPmkid->u4BSSIDInfoCount; i++) { + /* Search for desired BSSID. If desired BSSID is found, + then set the PMKID */ + if (!rsnSearchPmkidEntry(prAdapter, (PUINT_8) prPmkid->arBSSIDInfo[i].arBSSID, &j)) { + /* No entry found for the specified BSSID, so add one entry */ + if (prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE - 1) { + j = prAisSpecBssInfo->u4PmkidCacheCount; + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prPmkid->arBSSIDInfo[i].arBSSID, sizeof(PARAM_MAC_ADDRESS)); + prAisSpecBssInfo->u4PmkidCacheCount++; + } else { + j = CFG_MAX_PMKID_CACHE; + } + } + + if (j < CFG_MAX_PMKID_CACHE) { + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID, + prPmkid->arBSSIDInfo[i].arPMKID, sizeof(PARAM_PMKID_VALUE)); + DBGLOG(RSN, TRACE, "Add BSSID %pM idx=%d PMKID value %pM\n", + (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID), (UINT_32) j, + (prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID)); + prAisSpecBssInfo->arPmkidCache[j].fgPmkidExist = TRUE; + } + } +#endif + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetPmkid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the set of supported data rates that +* the radio is capable of running +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query +* \param[in] u4QueryBufferLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number +* of bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + PARAM_RATES eRate = { + /* BSSBasicRateSet for 802.11n Non-HT rates */ + 0x8C, /* 6M */ + 0x92, /* 9M */ + 0x98, /* 12M */ + 0xA4, /* 18M */ + 0xB0, /* 24M */ + 0xC8, /* 36M */ + 0xE0, /* 48M */ + 0xEC /* 54M */ + }; + + DEBUGFUNC("wlanoidQuerySupportedRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, (PVOID) &eRate, sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQuerySupportedRates() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current desired rates. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, (PVOID) &(prAdapter->rWlanInfo.eDesiredRates), sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidQueryDesiredRates() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to Set the desired rates. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_32 i; + + DEBUGFUNC("wlanoidSetDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(PARAM_RATES); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) + return WLAN_STATUS_INVALID_LENGTH; + + kalMemCopy((PVOID) &(prAdapter->rWlanInfo.eDesiredRates), pvSetBuffer, sizeof(PARAM_RATES)); + + prAdapter->rWlanInfo.eLinkAttr.ucDesiredRateLen = PARAM_MAX_LEN_RATES; + for (i = 0; i < PARAM_MAX_LEN_RATES; i++) + prAdapter->rWlanInfo.eLinkAttr.u2DesiredRate[i] = (UINT_16) (prAdapter->rWlanInfo.eDesiredRates[i]); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_LINK_ATTRIB, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_LINK_ATTRIB), + (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); + +} /* end of wlanoidSetDesiredRates() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the maximum frame size in bytes, +* not including the header. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMaxFrameSize"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ - ETHERNET_HEADER_SZ; + *pu4QueryInfoLen = sizeof(UINT_32); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryMaxFrameSize */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the maximum total packet length +* in bytes. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMaxTotalSize"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(PUINT_32) pvQueryBuffer = ETHERNET_MAX_PKT_SZ; + *pu4QueryInfoLen = sizeof(UINT_32); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryMaxTotalSize */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the vendor ID of the NIC. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ +#if DBG + PUINT_8 cp; +#endif + DEBUGFUNC("wlanoidQueryVendorId"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, prAdapter->aucMacAddress, 3); + *((PUINT_8) pvQueryBuffer + 3) = 1; + *pu4QueryInfoLen = sizeof(UINT_32); + +#if DBG + cp = (PUINT_8) pvQueryBuffer; + DBGLOG(OID, LOUD, "Vendor ID=%02x-%02x-%02x-%02x\n", cp[0], cp[1], cp[2], cp[3]); +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryVendorId */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RSSI value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call failed due to invalid length of +* the query buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (prAdapter->fgIsLinkQualityValid == TRUE && + (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI) prAdapter->rLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ + + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } +#ifdef LINUX + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); +#else + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +#endif +} /* end of wlanoidQueryRssi() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RSSI trigger value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call failed due to invalid length of +* the query buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRssiTrigger"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_NONE) + return WLAN_STATUS_ADAPTER_NOT_READY; + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(PARAM_RSSI *) pvQueryBuffer = prAdapter->rWlanInfo.rRssiTriggerValue; + DBGLOG(OID, INFO, "RSSI trigger: %d dBm\n", *(PARAM_RSSI *) pvQueryBuffer); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryRssiTrigger */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a trigger value of the RSSI event. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns the +* amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PARAM_RSSI rRssiTriggerValue; + + DEBUGFUNC("wlanoidSetRssiTrigger"); + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_RSSI); + rRssiTriggerValue = *(PARAM_RSSI *) pvSetBuffer; + + if (rRssiTriggerValue > PARAM_WHQL_RSSI_MAX_DBM || rRssiTriggerValue < PARAM_WHQL_RSSI_MIN_DBM) + return + /* Save the RSSI trigger value to the Adapter structure */ + prAdapter->rWlanInfo.rRssiTriggerValue = rRssiTriggerValue; + + /* If the RSSI trigger value is equal to the current RSSI value, the + * indication triggers immediately. We need to indicate the protocol + * that an RSSI status indication event triggers. */ + if (rRssiTriggerValue == (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) &prAdapter->rWlanInfo.rRssiTriggerValue, sizeof(PARAM_RSSI)); + } else if (rRssiTriggerValue < (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_GREATER; + else if (rRssiTriggerValue > (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_LESS; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetRssiTrigger */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a suggested value for the number of +* bytes of received packet data that will be indicated to the protocol +* driver. We just accept the set and ignore this value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + DEBUGFUNC("wlanoidSetCurrentLookahead"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(UINT_32)) { + *pu4SetInfoLen = sizeof(UINT_32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(UINT_32); + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetCurrentLookahead */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames that the driver +* receives but does not indicate to the protocols due to errors. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvError"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryRcvError */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC +* cannot receive due to lack of NIC receive buffer space. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS If success; +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvNoBuffer"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) 0; /* @FIXME */ + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) 0; /* @FIXME */ + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvNoBuffer, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryRcvNoBuffer */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC +* received and it is CRC error. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS If success; +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvCrcError"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvCrcError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryRcvCrcError */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the current 802.11 statistics. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { + DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; + prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; + prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; + prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; + prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; + prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; + prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; + prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart = 0; + prStatistics->rTKIPICVErrors.QuadPart = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; + prStatistics->rTKIPReplays.QuadPart = 0; + prStatistics->rCCMPFormatErrors.QuadPart = 0; + prStatistics->rCCMPReplays.QuadPart = 0; + prStatistics->rCCMPDecryptErrors.QuadPart = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart = 0; + prStatistics->rWEPUndecryptableCount.QuadPart = 0; + prStatistics->rWEPICVErrorCount.QuadPart = 0; + prStatistics->rDecryptSuccessCount.QuadPart = 0; + prStatistics->rDecryptFailureCount.QuadPart = 0; + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS_PL, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryStatistics, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryStatistics */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the current 802.11 statistics. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryStatistics"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { + DBGLOG(OID, WARN, "Too short length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) pvQueryBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount = prAdapter->rStatStruct.rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount = prAdapter->rStatStruct.rMulticastTransmittedFrameCount; + prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; + prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; + prStatistics->rMultipleRetryCount = prAdapter->rStatStruct.rMultipleRetryCount; + prStatistics->rRTSSuccessCount = prAdapter->rStatStruct.rRTSSuccessCount; + prStatistics->rRTSFailureCount = prAdapter->rStatStruct.rRTSFailureCount; + prStatistics->rACKFailureCount = prAdapter->rStatStruct.rACKFailureCount; + prStatistics->rFrameDuplicateCount = prAdapter->rStatStruct.rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount = prAdapter->rStatStruct.rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount = prAdapter->rStatStruct.rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart = 0; + prStatistics->rTKIPICVErrors.QuadPart = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; + prStatistics->rTKIPReplays.QuadPart = 0; + prStatistics->rCCMPFormatErrors.QuadPart = 0; + prStatistics->rCCMPReplays.QuadPart = 0; + prStatistics->rCCMPDecryptErrors.QuadPart = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart = 0; + prStatistics->rWEPUndecryptableCount.QuadPart = 0; + prStatistics->rWEPICVErrorCount.QuadPart = 0; + prStatistics->rDecryptSuccessCount.QuadPart = 0; + prStatistics->rDecryptFailureCount.QuadPart = 0; + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryStatistics, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryStatistics */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query current media streaming status. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(P_ENUM_MEDIA_STREAM_MODE) pvQueryBuffer = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryMediaStreamMode */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to enter media streaming mode or exit media streaming mode +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ENUM_MEDIA_STREAM_MODE eStreamMode; + + DEBUGFUNC("wlanoidSetMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_MEDIA_STREAM_MODE)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + eStreamMode = *(P_ENUM_MEDIA_STREAM_MODE) pvSetBuffer; + + if (eStreamMode == ENUM_MEDIA_STREAM_OFF) + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + else + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 1; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_LINK_ATTRIB, + TRUE, + FALSE, + TRUE, + nicCmdEventSetMediaStreamMode, + nicOidCmdTimeoutCommon, + sizeof(CMD_LINK_ATTRIB), + (PUINT_8) &(prAdapter->rWlanInfo.eLinkAttr), pvSetBuffer, u4SetBufferLen); +} /* wlanoidSetMediaStreamMode */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the permanent MAC address of the NIC. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryPermanentAddr"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < MAC_ADDR_LEN) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucPermanentAddress); + *pu4QueryInfoLen = MAC_ADDR_LEN; + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryPermanentAddr */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the MAC address the NIC is currently using. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + CMD_BASIC_CONFIG rCmdBasicConfig; + + DEBUGFUNC("wlanoidQueryCurrentAddr"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < MAC_ADDR_LEN) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BASIC_CONFIG, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryAddress, + nicOidCmdTimeoutCommon, + sizeof(CMD_BASIC_CONFIG), + (PUINT_8) &rCmdBasicConfig, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryCurrentAddr */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query NIC link speed. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryLinkSpeed"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (prAdapter->fgIsLinkRateValid == TRUE && + (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + *(PUINT_32) pvQueryBuffer = prAdapter->rLinkQuality.u2LinkSpeed * 5000; /* change to unit of 100bps */ + return WLAN_STATUS_SUCCESS; + } else { + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkSpeed, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + } +} /* end of wlanoidQueryLinkSpeed() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query MCR value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; + CMD_ACCESS_REG rCmdAccessReg; + + DEBUGFUNC("wlanoidQueryMcrRead"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvQueryBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ +#if CFG_SUPPORT_SWCR + if ((prMcrRdInfo->u4McrOffset >> 16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, + SWCR_READ, + (UINT_16) (prMcrRdInfo->u4McrOffset & BITS(0, 15)), &prMcrRdInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif /* CFG_SUPPORT_SWCR */ + + /* Check if access F/W Domain MCR (due to WiFiSYS is placed from 0x6000-0000 */ + if (prMcrRdInfo->u4McrOffset & 0xFFFF0000) { + /* fill command */ + rCmdAccessReg.u4Address = prMcrRdInfo->u4McrOffset; + rCmdAccessReg.u4Data = 0; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryMcrRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvQueryBuffer, u4QueryBufferLen); + } else { + HAL_MCR_RD(prAdapter, prMcrRdInfo->u4McrOffset & BITS(2, 31), /* address is in DWORD unit */ + &prMcrRdInfo->u4McrData); + + DBGLOG(OID, TRACE, "MCR Read: Offset = %#08x, Data = %#08x\n", + prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +} /* end of wlanoidQueryMcrRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write MCR and enable specific function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrWrInfo; + CMD_ACCESS_REG rCmdAccessReg; + +#if CFG_STRESS_TEST_SUPPORT + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); + P_STA_RECORD_T prStaRec = prBssInfo->prStaRecOfAP; + UINT_32 u4McrOffset, u4McrData; +#endif + + DEBUGFUNC("wlanoidSetMcrWrite"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) pvSetBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + + /* -- Puff Stress Test Begin */ +#if CFG_STRESS_TEST_SUPPORT + + /* 0xFFFFFFFE for Control Rate */ + if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFE) { + if (prMcrWrInfo->u4McrData < FIXED_RATE_NUM && prMcrWrInfo->u4McrData > 0) + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prMcrWrInfo->u4McrData); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + DEBUGFUNC("[Stress Test]Complete Rate is Changed...\n"); + DBGLOG(OID, TRACE, + "[Stress Test] Rate is Changed to index %d...\n", prAdapter->rWifiVar.eRateSetting); + } + /* 0xFFFFFFFD for Switch Channel */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFD) { + if (prMcrWrInfo->u4McrData <= 11 && prMcrWrInfo->u4McrData >= 1) + prBssInfo->ucPrimaryChannel = prMcrWrInfo->u4McrData; + nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); + DBGLOG(OID, TRACE, "[Stress Test] Channel is switched to %d ...\n", prBssInfo->ucPrimaryChannel); + + return WLAN_STATUS_SUCCESS; + } + /* 0xFFFFFFFFC for Control RF Band and SCO */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFC) { + /* Band */ + if (prMcrWrInfo->u4McrData & 0x80000000) { + /* prBssInfo->eBand = BAND_5G; */ + /* prBssInfo->ucPrimaryChannel = 52; // Bond to Channel 52 */ + } else { + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 8; /* Bond to Channel 6 */ + } + + /* Bandwidth */ + if (prMcrWrInfo->u4McrData & 0x00010000) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + + if (prMcrWrInfo->u4McrData == 0x00010002) { + prBssInfo->eBssSCO = CHNL_EXT_SCB; /* U20 */ + prBssInfo->ucPrimaryChannel += 2; + } else if (prMcrWrInfo->u4McrData == 0x00010001) { + prBssInfo->eBssSCO = CHNL_EXT_SCA; /* L20 */ + prBssInfo->ucPrimaryChannel -= 2; + } else { + prBssInfo->eBssSCO = CHNL_EXT_SCA; /* 40 */ + } + } + + if (prMcrWrInfo->u4McrData & 0x00000000) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + } + /* 0xFFFFFFFB for HT Capability */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFB) { + /* Enable HT Capability */ + if (prMcrWrInfo->u4McrData & 0x00000001) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + DEBUGFUNC("[Stress Test]Enable HT capability...\n"); + } else { + prStaRec->u2HtCapInfo &= (~HT_CAP_INFO_HT_GF); + DEBUGFUNC("[Stress Test]Disable HT capability...\n"); + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + } + /* 0xFFFFFFFA for Enable Random Rx Reset */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFA) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_RANDOM_RX_RESET_EN, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF9 for Disable Random Rx Reset */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF9) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_RANDOM_RX_RESET_DE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF8 for Enable SAPP */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF8) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SAPP_EN, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF7 for Disable SAPP */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF7) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SAPP_DE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } + + else +#endif + /* -- Puff Stress Test End */ + + /* Check if access F/W Domain MCR */ + if (prMcrWrInfo->u4McrOffset & 0xFFFF0000) { + + /* 0x9000 - 0x9EFF reserved for FW */ +#if CFG_SUPPORT_SWCR + if ((prMcrWrInfo->u4McrOffset >> 16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, + SWCR_WRITE, + (UINT_16) (prMcrWrInfo->u4McrOffset & BITS(0, 15)), &prMcrWrInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif /* CFG_SUPPORT_SWCR */ + +#if 1 + /* low power test special command */ + if (prMcrWrInfo->u4McrOffset == 0x11111110) { + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + /* DbgPrint("Enter test mode\n"); */ + prAdapter->fgTestMode = TRUE; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111) { + /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ + + nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112) { + + /* DbgPrint("LP enter sleep\n"); */ + + /* fill command */ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } +#endif + +#if 1 + /* low power test special command */ + if (prMcrWrInfo->u4McrOffset == 0x11111110) { + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + /* DbgPrint("Enter test mode\n"); */ + prAdapter->fgTestMode = TRUE; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111) { + /* DbgPrint("nicpmSetAcpiPowerD3\n"); */ + + nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112) { + + /* DbgPrint("LP enter sleep\n"); */ + + /* fill command */ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } +#endif + /* fill command */ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (PUINT_8) &rCmdAccessReg, pvSetBuffer, u4SetBufferLen); + } else { + HAL_MCR_WR(prAdapter, (prMcrWrInfo->u4McrOffset & BITS(2, 31)), /* address is in DWORD unit */ + prMcrWrInfo->u4McrData); + + DBGLOG(OID, TRACE, "MCR Write: Offset = %#08x, Data = %#08x\n", + prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData); + + return WLAN_STATUS_SUCCESS; + } +} /* wlanoidSetMcrWrite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query SW CTRL +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + WLAN_STATUS rWlanStatus; + UINT_16 u2Id, u2SubId; + UINT_32 u4Data; + + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + + DEBUGFUNC("wlanoidQuerySwCtrlRead"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvQueryBuffer; + + u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); + u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); + u4Data = 0; + rWlanStatus = WLAN_STATUS_SUCCESS; + + switch (u2Id) { + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, SWCR_READ /* Read */ , + (UINT_16) u2SubId, &u4Data); + break; +#endif /* CFG_SUPPORT_SWCR */ + + case 0xFFFF: + { + u4Data = 0x5AA56620; + } + break; + + case 0x9000: + default: + { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + rCmdSwCtrl.u4Data = 0; + rWlanStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + FALSE, + TRUE, + TRUE, + nicCmdEventQuerySwCtrlRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8) &rCmdSwCtrl, pvQueryBuffer, u4QueryBufferLen); + } + } /* switch(u2Id) */ + + prSwCtrlInfo->u4Data = u4Data; + + return rWlanStatus; + +} + + /* end of wlanoidQuerySwCtrlRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write SW CTRL +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rWlanStatus; + UINT_16 u2Id, u2SubId; + UINT_32 u4Data; +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + P_GLUE_INFO_T prGlueInfo; + CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; +#endif + + DEBUGFUNC("wlanoidSetSwCtrlWrite"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + prGlueInfo = prAdapter->prGlueInfo; +#endif + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) pvSetBuffer; + + u2Id = (UINT_16) (prSwCtrlInfo->u4Id >> 16); + u2SubId = (UINT_16) (prSwCtrlInfo->u4Id & BITS(0, 15)); + u4Data = prSwCtrlInfo->u4Data; + rWlanStatus = WLAN_STATUS_SUCCESS; + + switch (u2Id) { + + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, SWCR_WRITE, (UINT_16) u2SubId, &u4Data); + break; +#endif /* CFG_SUPPORT_SWCR */ + + case 0x1000: + if (u2SubId == 0x8000) { + /* CTIA power save mode setting (code: 0x10008000) */ + prAdapter->u4CtiaPowerMode = u4Data; + prAdapter->fgEnCtiaPowerMode = TRUE; + + /* */ + { + PARAM_POWER_MODE ePowerMode; + + if (prAdapter->u4CtiaPowerMode == 0) + /* force to keep in CAM mode */ + ePowerMode = Param_PowerModeCAM; + else if (prAdapter->u4CtiaPowerMode == 1) + ePowerMode = Param_PowerModeMAX_PSP; + else + ePowerMode = Param_PowerModeFast_PSP; + + rWlanStatus = nicConfigPowerSaveProfile(prAdapter, + NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); + } + } + break; + case 0x1001: + if (u2SubId == 0x0) + prAdapter->fgEnOnlineScan = (BOOLEAN) u4Data; + else if (u2SubId == 0x1) + prAdapter->fgDisBcnLostDetection = (BOOLEAN) u4Data; + else if (u2SubId == 0x2) + prAdapter->rWifiVar.fgSupportUAPSD = (BOOLEAN) u4Data; + else if (u2SubId == 0x3) { + prAdapter->u4UapsdAcBmp = u4Data & BITS(0, 15); + prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpDeliveryAC = + (UINT_8) prAdapter->u4UapsdAcBmp; + prAdapter->rWifiVar.arBssInfo[u4Data >> 16].rPmProfSetupInfo.ucBmpTriggerAC = + (UINT_8) prAdapter->u4UapsdAcBmp; + } else if (u2SubId == 0x4) + prAdapter->fgDisStaAgingTimeoutDetection = (BOOLEAN) u4Data; + else if (u2SubId == 0x5) + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = (UINT_8) u4Data; + else if (u2SubId == 0x0100) + prAdapter->rWifiVar.u8SupportRxGf = (UINT_8) u4Data; + else if (u2SubId == 0x0101) { + prAdapter->rWifiVar.u8SupportRxSgi20 = (UINT_8) u4Data; + prAdapter->rWifiVar.u8SupportRxSgi40 = (UINT_8) u4Data; + } else if (u2SubId == 0x0102) + prAdapter->rWifiVar.u8SupportRxSTBC = (UINT_8) u4Data; + break; + +#if CFG_SUPPORT_SWCR + case 0x1002: + if (u2SubId == 0x0) { + if (u4Data) + u4Data = BIT(HIF_RX_PKT_TYPE_MANAGEMENT); + swCrFrameCheckEnable(prAdapter, u4Data); + } else if (u2SubId == 0x1) { + BOOLEAN fgIsEnable; + UINT_8 ucType; + UINT_32 u4Timeout; + + fgIsEnable = (BOOLEAN) (u4Data & 0xff); + ucType = 0; /* ((u4Data>>4) & 0xf); */ + u4Timeout = ((u4Data >> 8) & 0xff); + swCrDebugCheckEnable(prAdapter, fgIsEnable, ucType, u4Timeout); + } + break; +#endif + +#if CFG_SUPPORT_802_11W + case 0x2000: + DBGLOG(RSN, TRACE, "802.11w test 0x%x\n", u2SubId); + if (u2SubId == 0x0) + rsnStartSaQuery(prAdapter); + if (u2SubId == 0x1) + rsnStopSaQuery(prAdapter); + if (u2SubId == 0x2) + rsnSaQueryRequest(prAdapter, NULL); + if (u2SubId == 0x3) { + P_BSS_INFO_T prBssInfo = &(prAdapter->rWifiVar.arBssInfo[(NETWORK_TYPE_AIS_INDEX)]); + + authSendDeauthFrame(prAdapter, prBssInfo->prStaRecOfAP, NULL, 7, NULL); + } + /* wext_set_mode */ + /* + if (u2SubId == 0x3) { + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_DISABLED; + } + if (u2SubId == 0x4) { + //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_OPTIONAL; + } + if (u2SubId == 0x5) { + //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + prAdapter->prGlueInfo->rWpaInfo.u4Mfp = RSN_AUTH_MFP_REQUIRED; + } + */ + break; +#endif + case 0xFFFF: + { +/* CMD_ACCESS_REG rCmdAccessReg; */ +#if 1 /* CFG_MT6573_SMT_TEST */ + if (u2SubId == 0x0123) { + + DBGLOG(HAL, TRACE, "set smt fixed rate: %u\n", u4Data); + + if ((ENUM_REGISTRY_FIXED_RATE_T) (u4Data) < FIXED_RATE_NUM) + prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (u4Data); + else + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + + if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS) + || (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + else + /* Force Long Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + + /* abort to re-connect */ +#if 1 + DBGLOG(OID, TRACE, "DisBySwC\n"); + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); +#else + aisBssBeaconTimeout(prAdapter); +#endif + + return WLAN_STATUS_SUCCESS; + + } else if (u2SubId == 0x1234) { + /* 1. Disable On-Lin Scan */ + /* 3. Disable FIFO FULL no ack */ + /* 4. Disable Roaming */ + /* Disalbe auto tx power */ + /* 2. Keep at CAM mode */ + /* 5. Disable Beacon Timeout Detection */ + rWlanStatus = nicEnterCtiaMode(prAdapter, TRUE, TRUE); + } else if (u2SubId == 0x1235) { + /* 1. Enaable On-Lin Scan */ + /* 3. Enable FIFO FULL no ack */ + /* 4. Enable Roaming */ + /* Enable auto tx power */ + /* 2. Keep at Fast PS */ + /* 5. Enable Beacon Timeout Detection */ + rWlanStatus = nicEnterCtiaMode(prAdapter, FALSE, TRUE); + } +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + else if (u2SubId == 0x1240) { + DBGLOG(P2P, TRACE, "Disable Hotspot Optimization!\n"); + + arHotspotOptimizationCfg.fgHotspotOptimizationEn = FALSE; + arHotspotOptimizationCfg.u4Level = 0; + wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_HOTSPOT_OPTIMIZATION, + TRUE, + FALSE, + TRUE, + NULL, + NULL, + sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), + (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); + } else if (u2SubId == 0x1241) { + DBGLOG(P2P, TRACE, "Enable Hotspot Optimization!\n"); + + arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; + arHotspotOptimizationCfg.u4Level = 5; + wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_HOTSPOT_OPTIMIZATION, + TRUE, + FALSE, + TRUE, + NULL, + NULL, + sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), + (PUINT_8) &arHotspotOptimizationCfg, NULL, 0); + } +#endif /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ + else if (u2SubId == 0x1250) { + DBGLOG(OID, TRACE, "LTE_COEX: SW SET DUAL BAND\n"); + prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_NULL; + } else if (u2SubId == 0x1251) { + DBGLOG(OID, TRACE, "LTE_COEX: SW SET 2.4G BAND\n"); + prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_2G4; + } else if (u2SubId == 0x1252) { + DBGLOG(OID, TRACE, "LTE_COEX: SW SET 5G BAND\n"); + prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] = BAND_5G; + } +#endif + } + break; + + case 0x9000: + default: + { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; + rWlanStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (PUINT_8) &rCmdSwCtrl, pvSetBuffer, u4SetBufferLen); + } + } /* switch(u2Id) */ + + return rWlanStatus; +} + + /* wlanoidSetSwCtrlWrite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query EEPROM value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidQueryEepromRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvQueryBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_EEPROM, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryEepromRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_EEPROM), + (PUINT_8) &rCmdAccessEeprom, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryEepromRead */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write EEPROM value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidSetEepromWrite"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + rCmdAccessEeprom.u2Data = prEepromRwInfo->u2EepromData; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_EEPROM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_EEPROM), + (PUINT_8) &rCmdAccessEeprom, pvSetBuffer, u4SetBufferLen); + +} /* wlanoidSetEepromWrite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of the successfully transmitted +* packets. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitOk"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitOk, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryXmitOk */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of the successfully received +* packets. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvOk"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryRecvOk, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryRcvOk */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames that the driver +* fails to transmit. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitError"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryXmitError */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames successfully +* transmitted after exactly one collision. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitOneCollision"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) + (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - + prAdapter->rStatStruct.rRetryCount.QuadPart); + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) + (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - + prAdapter->rStatStruct.rRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitOneCollision, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +} /* wlanoidQueryXmitOneCollision */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames successfully +* transmitted after more than one collision. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitMoreCollisions"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) (prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitMoreCollisions, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); +} /* wlanoidQueryXmitMoreCollisions */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the number of frames +* not transmitted due to excessive collisions. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitMaxCollisions"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in query receive error! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(UINT_32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(UINT_32) + || (u4QueryBufferLen > sizeof(UINT_32) && u4QueryBufferLen < sizeof(UINT_64))) { + *pu4QueryInfoLen = sizeof(UINT_64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == TRUE) { + if (u4QueryBufferLen == sizeof(UINT_32)) { + *pu4QueryInfoLen = sizeof(UINT_32); + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rStatStruct.rFailedCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(UINT_64); + *(PUINT_64) pvQueryBuffer = (UINT_64) prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_STATISTICS, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryXmitMaxCollisions, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); +} /* wlanoidQueryXmitMaxCollisions */ + +#define MTK_CUSTOM_OID_INTERFACE_VERSION 0x00006620 /* for WPDWifi DLL */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current the OID interface version, +* which is the interface between the application and driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryOidInterfaceVersion"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *(PUINT_32) pvQueryBuffer = MTK_CUSTOM_OID_INTERFACE_VERSION; + *pu4QueryInfoLen = sizeof(UINT_32); + + DBGLOG(OID, WARN, "Custom OID interface version: %#08X\n", *(PUINT_32) pvQueryBuffer); + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryOidInterfaceVersion */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ +#ifndef LINUX + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_MAC_MCAST_ADDR, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryMcastAddr, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); +#else + return WLAN_STATUS_SUCCESS; +#endif +} /* end of wlanoidQueryMulticastList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_8 ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Caller should provide this information */ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(OID, WARN, "Invalid MC list length %u\n", u4SetBufferLen); + + *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { + DBGLOG(OID, WARN, "Too many MC addresses\n"); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucNetTypeIndex = ucNetTypeIndex; + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_MAC_MCAST_ADDR, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_MAC_MCAST_ADDR), + (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); +} /* end of wlanoidSetMulticastList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Packet Filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_32 u4NewPacketFilter; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(UINT_32)) { + *pu4SetInfoLen = sizeof(UINT_32); + DBGLOG(OID, INFO, "iput buffer is too small"); + return WLAN_STATUS_INVALID_LENGTH; + } + ASSERT(pvSetBuffer); + + /* Set the new packet filter. */ + u4NewPacketFilter = *(PUINT_32) pvSetBuffer; + + DBGLOG(OID, TRACE, "New packet filter: %#08x\n", u4NewPacketFilter); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set current packet filter! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + do { + /* Verify the bits of the new packet filter. If any bits are set that + we don't support, leave. */ + if (u4NewPacketFilter & ~(PARAM_PACKET_FILTER_SUPPORTED)) { + rStatus = WLAN_STATUS_NOT_SUPPORTED; + break; + } +#if DBG + /* Need to enable or disable promiscuous support depending on the new + filter. */ + if (u4NewPacketFilter & PARAM_PACKET_FILTER_PROMISCUOUS) + DBGLOG(OID, TRACE, "Enable promiscuous mode\n"); + else + DBGLOG(OID, TRACE, "Disable promiscuous mode\n"); + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) + DBGLOG(OID, TRACE, "Enable all-multicast mode\n"); + else if (u4NewPacketFilter & PARAM_PACKET_FILTER_MULTICAST) + DBGLOG(OID, TRACE, "Enable multicast\n"); + else + DBGLOG(OID, TRACE, "Disable multicast\n"); + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_BROADCAST) + DBGLOG(OID, TRACE, "Enable Broadcast\n"); + else + DBGLOG(OID, TRACE, "Disable Broadcast\n"); +#endif + } while (FALSE); + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* Store the packet filter */ + + prAdapter->u4OsPacketFilter &= PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RX_FILTER, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(UINT_32), + (PUINT_8) &prAdapter->u4OsPacketFilter, pvSetBuffer, u4SetBufferLen); + } else { + return rStatus; + } +} /* wlanoidSetCurrentPacketFilter */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current packet filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryCurrentPacketFilter"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen >= sizeof(UINT_32)) { + ASSERT(pvQueryBuffer); + *(PUINT_32) pvQueryBuffer = prAdapter->u4OsPacketFilter; + } + + return WLAN_STATUS_SUCCESS; +} /* wlanoidQueryCurrentPacketFilter */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query ACPI device power state. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ +#if DBG + PPARAM_DEVICE_POWER_STATE prPowerState; +#endif + + DEBUGFUNC("wlanoidQueryAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + +#if DBG + prPowerState = (PPARAM_DEVICE_POWER_STATE) pvQueryBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(OID, INFO, "Query Power State: D0\n"); + break; + case ParamDeviceStateD1: + DBGLOG(OID, INFO, "Query Power State: D1\n"); + break; + case ParamDeviceStateD2: + DBGLOG(OID, INFO, "Query Power State: D2\n"); + break; + case ParamDeviceStateD3: + DBGLOG(OID, INFO, "Query Power State: D3\n"); + break; + default: + break; + } +#endif + + /* Since we will disconnect the newwork, therefore we do not + need to check queue empty */ + *(PPARAM_DEVICE_POWER_STATE) pvQueryBuffer = ParamDeviceStateD3; + /* WARNLOG(("Ready to transition to D3\n")); */ + return WLAN_STATUS_SUCCESS; + +} /* pwrmgtQueryPower */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set ACPI device power state. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PPARAM_DEVICE_POWER_STATE prPowerState; + BOOLEAN fgRetValue = TRUE; + + DEBUGFUNC("wlanoidSetAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + + ASSERT(pvSetBuffer); + prPowerState = (PPARAM_DEVICE_POWER_STATE) pvSetBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(OID, INFO, "Set Power State: D0\n"); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD0); + fgRetValue = nicpmSetAcpiPowerD0(prAdapter); + break; + case ParamDeviceStateD1: + DBGLOG(OID, INFO, "Set Power State: D1\n"); + /* no break here */ + case ParamDeviceStateD2: + DBGLOG(OID, INFO, "Set Power State: D2\n"); + /* no break here */ + case ParamDeviceStateD3: + DBGLOG(OID, INFO, "Set Power State: D3\n"); + fgRetValue = nicpmSetAcpiPowerD3(prAdapter); + kalDevSetPowerState(prAdapter->prGlueInfo, (UINT_32) ParamDeviceStateD3); + break; + default: + break; + } + + if (fgRetValue == TRUE) + return WLAN_STATUS_SUCCESS; + else + return WLAN_STATUS_FAILURE; +} /* end of wlanoidSetAcpiDevicePowerState() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current fragmentation threshold. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryFragThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + DBGLOG(OID, LOUD, "\n"); + +#if CFG_TX_FRAGMENT + + return WLAN_STATUS_SUCCESS; + +#else + + return WLAN_STATUS_NOT_SUPPORTED; +#endif /* CFG_TX_FRAGMENT */ + +} /* end of wlanoidQueryFragThreshold() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a new fragmentation threshold to the +* driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ +#if CFG_TX_FRAGMENT + + return WLAN_STATUS_SUCCESS; + +#else + + return WLAN_STATUS_NOT_SUPPORTED; +#endif /* CFG_TX_FRAGMENT */ + +} /* end of wlanoidSetFragThreshold() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the current RTS threshold. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRtsThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + DBGLOG(OID, LOUD, "\n"); + + if (u4QueryBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + *pu4QueryInfoLen = sizeof(PARAM_RTS_THRESHOLD); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *((PARAM_RTS_THRESHOLD *) pvQueryBuffer) = prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidQueryRtsThreshold */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a new RTS threshold to the driver. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PARAM_RTS_THRESHOLD *prRtsThreshold; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_RTS_THRESHOLD); + if (u4SetBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRtsThreshold = (PARAM_RTS_THRESHOLD *) pvSetBuffer; + *prRtsThreshold = prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; + +} /* wlanoidSetRtsThreshold */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to turn radio off. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + + DEBUGFUNC("wlanoidSetDisassociate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set disassociate! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* prepare message to AIS */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + + /* indicate for disconnection */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(OID, INFO, "DisconnectByOid\n"); + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, NULL, 0); + } +#if !defined(LINUX) + prAdapter->fgIsRadioOff = TRUE; +#endif + + return WLAN_STATUS_SUCCESS; +} /* wlanoidSetDisassociate */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query the power save profile. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQuery802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen != 0) { + ASSERT(pvQueryBuffer); + +/* *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE)(prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile); */ + *(PPARAM_POWER_MODE) pvQueryBuffer = + (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_AIS_INDEX].ucPsProfile); + *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); + + /* hack for CTIA power mode setting function */ + if (prAdapter->fgEnCtiaPowerMode) { + /* set to non-zero value (to prevent MMI query 0, before it intends to set 0, */ + /* which will skip its following state machine) */ + *(PPARAM_POWER_MODE) pvQueryBuffer = (PARAM_POWER_MODE) 2; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS status; + PARAM_POWER_MODE ePowerMode; + + DEBUGFUNC("wlanoidSet802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { + /* WARNLOG(("Invalid power mode %d\n", */ + /* *(PPARAM_POWER_MODE) pvSetBuffer)); */ + return WLAN_STATUS_INVALID_DATA; + } + + ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; + + if (prAdapter->fgEnCtiaPowerMode) { + if (ePowerMode == Param_PowerModeCAM) + ; + else { + /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ + + if (prAdapter->u4CtiaPowerMode == 0) + /* force to keep in CAM mode */ + ePowerMode = Param_PowerModeCAM; + else if (prAdapter->u4CtiaPowerMode == 1) + ePowerMode = Param_PowerModeMAX_PSP; + else if (prAdapter->u4CtiaPowerMode == 2) + ePowerMode = Param_PowerModeFast_PSP; + } + } + + status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, ePowerMode, TRUE); + + switch (ePowerMode) { + case Param_PowerModeCAM: + DBGLOG(OID, INFO, "Set Wi-Fi PS mode to CAM (%d)\n", ePowerMode); + break; + case Param_PowerModeMAX_PSP: + DBGLOG(OID, INFO, "Set Wi-Fi PS mode to MAX PS (%d)\n", ePowerMode); + break; + case Param_PowerModeFast_PSP: + DBGLOG(OID, INFO, "Set Wi-Fi PS mode to FAST PS (%d)\n", ePowerMode); + break; + default: + DBGLOG(OID, INFO, "invalid Wi-Fi PS mode setting (%d)\n", ePowerMode); + break; + } + + return status; + +} /* end of wlanoidSetAcpiDevicePowerStateMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current status of AdHoc Mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryAdHocMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set AdHoc Mode. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetAdHocMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query RF frequency. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + *(PUINT_32) pvQueryBuffer = + nicChannelNum2Freq(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].ucPrimaryChannel); + } else { + *(PUINT_32) pvQueryBuffer = 0; + } + } else { + *(PUINT_32) pvQueryBuffer = nicChannelNum2Freq(prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum); + } + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryFrequency() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set RF frequency by User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_32 pu4FreqInKHz; + + DEBUGFUNC("wlanoidSetFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + pu4FreqInKHz = (PUINT_32) pvSetBuffer; + + prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(*pu4FreqInKHz); + prAdapter->rWifiVar.rConnSettings.eAdHocBand = *pu4FreqInKHz < 5000000 ? BAND_2G4 : BAND_5G; + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetFrequency() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set 802.11 channel of the radio frequency. +* This is a proprietary function call to Lunux currently. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetChannel(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ASSERT(0); /* // */ + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the Beacon Interval from User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryBeaconInterval"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) + *(PUINT_32) pvQueryBuffer = prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod; + else + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; + } else { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) + *(PUINT_32) pvQueryBuffer = 0; + else + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2BeaconPeriod; + } + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidQueryBeaconInterval() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the Beacon Interval to User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_32 pu4BeaconInterval; + + DEBUGFUNC("wlanoidSetBeaconInterval"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + pu4BeaconInterval = (PUINT_32) pvSetBuffer; + + if ((*pu4BeaconInterval < DOT11_BEACON_PERIOD_MIN) || (*pu4BeaconInterval > DOT11_BEACON_PERIOD_MAX)) { + DBGLOG(OID, TRACE, "Invalid Beacon Interval = %u\n", *pu4BeaconInterval); + return WLAN_STATUS_INVALID_DATA; + } + + prAdapter->rWlanInfo.u2BeaconPeriod = (UINT_16) *pu4BeaconInterval; + + DBGLOG(OID, INFO, "Set beacon interval: %d\n", prAdapter->rWlanInfo.u2BeaconPeriod); + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetBeaconInterval() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the ATIM window from User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) + *(PUINT_32) pvQueryBuffer = 0; + else + *(PUINT_32) pvQueryBuffer = (UINT_32) prAdapter->rWlanInfo.u2AtimWindow; + + return WLAN_STATUS_SUCCESS; + +} /* end of wlanoidQueryAtimWindow() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the ATIM window to User Settings. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_32 pu4AtimWindow; + + DEBUGFUNC("wlanoidSetAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + pu4AtimWindow = (PUINT_32) pvSetBuffer; + + prAdapter->rWlanInfo.u2AtimWindow = (UINT_16) *pu4AtimWindow; + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetAtimWindow() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to Set the MAC address which is currently used by the NIC. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ASSERT(0); /* // */ + + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetCurrentAddr() */ + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the checksum offload function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + UINT_32 i, u4CSUMFlags; + CMD_BASIC_CONFIG rCmdBasicConfig; + + DEBUGFUNC("wlanoidSetCSUMOffload"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + u4CSUMFlags = *(PUINT_32) pvSetBuffer; + + kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG)); + + for (i = 0; i < 6; i++) { /* set to broadcast address for not-specified */ + rCmdBasicConfig.rMyMacAddr[i] = 0xff; + } + + rCmdBasicConfig.ucNative80211 = 0; /* @FIXME: for Vista */ + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(2); + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(1); + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(0); + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(2); + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(1); + + if (u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(0); + + prAdapter->u4CSUMFlags = u4CSUMFlags; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BASIC_CONFIG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_BASIC_CONFIG), (PUINT_8) &rCmdBasicConfig, pvSetBuffer, u4SetBufferLen); +} +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the IP address for pattern search function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; +#if CFG_ENABLE_GTK_FRAME_FILTER + UINT_32 u4IpV4AddrListSize; + P_BSS_INFO_T prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; +#endif + + DEBUGFUNC("wlanoidSetNetworkAddress"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) + return WLAN_STATUS_INVALID_DATA; + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + /* construct payload of command packet */ + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + if (u4IpAddressCount == 0) + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + +#if CFG_ENABLE_GTK_FRAME_FILTER + u4IpV4AddrListSize = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + + (u4IpAddressCount * sizeof(IPV4_NETWORK_ADDRESS)); + if (prBssInfo->prIpV4NetAddrList) + FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); + prBssInfo->prIpV4NetAddrList = (P_IPV4_NETWORK_ADDRESS_LIST) kalMemAlloc(u4IpV4AddrListSize, VIR_MEM_TYPE); + if (prBssInfo->prIpV4NetAddrList == NULL) { + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return WLAN_STATUS_FAILURE; + } + prBssInfo->prIpV4NetAddrList->ucAddrCount = (UINT_8) u4IpAddressCount; +#endif + + /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + DBGLOG(OID, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); + + for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(UINT_32)); + +#if CFG_ENABLE_GTK_FRAME_FILTER + kalMemCopy(prBssInfo->prIpV4NetAddrList->arNetAddr[j].aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(UINT_32)); +#endif + + j++; + + pucBuf = (PUINT_8) &prNetAddrIp->in_addr; + DBGLOG(OID, INFO, + "prNetAddrIp->in_addr:%d:%d:%d:%d\n", pucBuf[0], pucBuf[1], pucBuf[2], + pucBuf[3]); + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) (prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set driver to switch into RF test mode +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, +* should be NULL +* \param[in] u4SetBufferLen The length of the set buffer, should be 0 +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_DATA +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (u4SetBufferLen == 0) { + if (prAdapter->fgTestMode == FALSE) { + /* switch to RF Test mode */ + rCmdTestCtrl.ucAction = 0; /* Switch mode */ + rCmdTestCtrl.u.u4OpMode = 1; /* RF test mode */ + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + TRUE, + TRUE, + nicCmdEventEnterRfTest, + nicOidCmdEnterRFTestTimeout, + sizeof(CMD_TEST_CTRL_T), + (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); + } else { + /* already in test mode .. */ + rStatus = WLAN_STATUS_SUCCESS; + } + } else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + DBGLOG(OID, INFO, "Enter TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", + u4SetBufferLen, prAdapter->fgTestMode, rStatus); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set driver to switch into normal operation mode from RF test mode +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* should be NULL +* \param[in] u4SetBufferLen The length of the set buffer, should be 0 +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_DATA +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (u4SetBufferLen == 0) { + if (prAdapter->fgTestMode == TRUE) { + /* switch to normal mode */ + rCmdTestCtrl.ucAction = 0; /* Switch mode */ + rCmdTestCtrl.u.u4OpMode = 0; /* normal mode */ + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + FALSE, + TRUE, + nicCmdEventLeaveRfTest, + nicOidCmdTimeoutCommon, + sizeof(CMD_TEST_CTRL_T), + (PUINT_8) &rCmdTestCtrl, pvSetBuffer, u4SetBufferLen); + } else { + /* already in normal mode .. */ + rStatus = WLAN_STATUS_SUCCESS; + } + } else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + DBGLOG(OID, INFO, "Abort TestMode, setBufLen %u, InTestMode %d, rStatus %u\n", + u4SetBufferLen, prAdapter->fgTestMode, rStatus); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief query for RF test parameter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestQueryAutoTest"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); + + if (u4QueryBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { + DBGLOG(OID, ERROR, "Invalid data. QueryBufferLen: %u.\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvQueryBuffer; + rStatus = rftestQueryATInfo(prAdapter, + prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData, pvQueryBuffer, u4QueryBufferLen); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set RF test parameter +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, + OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestSetAutoTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); + + if (u4SetBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { + DBGLOG(OID, ERROR, "Invalid data. SetBufferLen: %u.\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T) pvSetBuffer; + rStatus = rftestSetATInfo(prAdapter, prRfATInfo->u4FuncIndex, prRfATInfo->u4FuncData); + + return rStatus; +} + +/* RF test OID set handler */ +WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_TEST_MODE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 1; /* Set ATInfo */ + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS +rftestQueryATInfo(IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + UINT_8 ucCmdSeqNum; + P_EVENT_TEST_STATUS prTestStatus; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + if (u4FuncIndex == RF_AT_FUNCID_FW_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = + (prAdapter->rVerInfo.u2FwProductID << 16) | (prAdapter->rVerInfo.u2FwOwnVersion); + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } else if (u4FuncIndex == RF_AT_FUNCID_DRV_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS) pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = CFG_DRV_OWN_VERSION; + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryRfTestATInfo; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_TEST_MODE; + prCmdInfo->fgSetQuery = FALSE; + prCmdInfo->fgNeedResp = TRUE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = pvQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4QueryBufferLen; + + /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T) (prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 2; /* Get ATInfo */ + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen) +{ + CMD_TEST_CTRL_T rCmdTestCtrl; + + ASSERT(prAdapter); + + rCmdTestCtrl.ucAction = 5; /* Set Channel Frequency */ + rCmdTestCtrl.u.u4ChannelFreq = u4FreqInKHz; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_TEST_MODE, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, sizeof(CMD_TEST_CTRL_T), (PUINT_8) &rCmdTestCtrl, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + DEBUGFUNC("wlanSendSetQueryCmd"); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(OID, TRACE, "ucCmdSeqNum =%d, ucCID =%d\n", ucCmdSeqNum, ucCID); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WAPI ui to set wapi mode, which is needed to info the the driver +* to operation at WAPI mode while driver initialize. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + DEBUGFUNC("wlanoidSetWapiMode"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + /* Todo:: For support WAPI and Wi-Fi at same driver, use the set wapi assoc ie at the check point */ + /* The Adapter Connection setting fgUseWapi will cleat whil oid set mode (infra), */ + /* And set fgUseWapi True while set wapi assoc ie */ + /* policay selection, add key all depend on this flag, */ + /* The fgUseWapi may remove later */ + if (*(PUINT_32) pvSetBuffer) + prAdapter->fgUseWapi = TRUE; + else + prAdapter->fgUseWapi = FALSE; + +#if 0 + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + 4)); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + 4; + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_WAPI_MODE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + cp = (PUINT_8) (prWifiCmd->aucBuffer); + + kalMemCopy(cp, (PUINT_8) pvSetBuffer, 4); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +#else + return WLAN_STATUS_SUCCESS; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WAPI to set the assoc info, which is needed to add to +* Association request frame while join WAPI AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_WAPI_INFO_ELEM_T prWapiInfo; + PUINT_8 cp; + UINT_16 u2AuthSuiteCount = 0; + UINT_16 u2PairSuiteCount = 0; + UINT_32 u4AuthKeyMgtSuite = 0; + UINT_32 u4PairSuite = 0; + UINT_32 u4GroupSuite = 0; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetWapiAssocInfo"); + DBGLOG(OID, LOUD, "\r\n"); + + if (u4SetBufferLen < 20 /* From EID to Group cipher */) { + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; + DBGLOG(SEC, INFO, "fgWapiMode = FALSE due to u4SetBufferLen %u < 20!\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prAdapter->rWifiVar.rConnSettings.fgWapiMode = TRUE; + + /* if (prWapiInfo->ucElemId != ELEM_ID_WAPI) */ + /* DBGLOG(SEC, TRACE, ("Not WAPI IE ?!\n")); */ + + /* if (prWapiInfo->ucLength < 18) */ + /* return WLAN_STATUS_INVALID_LENGTH; */ + + *pu4SetInfoLen = u4SetBufferLen; + + prWapiInfo = (P_WAPI_INFO_ELEM_T) pvSetBuffer; + + if (prWapiInfo->ucElemId != ELEM_ID_WAPI) { + DBGLOG(SEC, INFO, "Not WAPI IE ?! u4SetBufferLen = %u\n", u4SetBufferLen); + prAdapter->rWifiVar.rConnSettings.fgWapiMode = FALSE; + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prWapiInfo->ucLength < 18) + return WLAN_STATUS_INVALID_LENGTH; + + /* Skip Version check */ + cp = (PUINT_8) &prWapiInfo->u2AuthKeyMgtSuiteCount; + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + + if (u2AuthSuiteCount > 1) + return WLAN_STATUS_INVALID_LENGTH; + + cp = (PUINT_8) &prWapiInfo->aucAuthKeyMgtSuite1[0]; + WLAN_GET_FIELD_32(cp, &u4AuthKeyMgtSuite); + + DBGLOG(SEC, TRACE, "WAPI: Assoc Info auth mgt suite [%d]: %02x-%02x-%02x-%02x\n", + u2AuthSuiteCount, + (UCHAR) (u4AuthKeyMgtSuite & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 8) & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 16) & 0x000000FF), + (UCHAR) ((u4AuthKeyMgtSuite >> 24) & 0x000000FF)); + + if (u4AuthKeyMgtSuite != WAPI_AKM_SUITE_802_1X && u4AuthKeyMgtSuite != WAPI_AKM_SUITE_PSK) + ASSERT(FALSE); + + cp += 4; + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + if (u2PairSuiteCount > 1) + return WLAN_STATUS_INVALID_LENGTH; + + cp += 2; + WLAN_GET_FIELD_32(cp, &u4PairSuite); + DBGLOG(SEC, TRACE, "WAPI: Assoc Info pairwise cipher suite [%d]: %02x-%02x-%02x-%02x\n", + u2PairSuiteCount, + (UCHAR) (u4PairSuite & 0x000000FF), + (UCHAR) ((u4PairSuite >> 8) & 0x000000FF), + (UCHAR) ((u4PairSuite >> 16) & 0x000000FF), (UCHAR) ((u4PairSuite >> 24) & 0x000000FF)); + + if (u4PairSuite != WAPI_CIPHER_SUITE_WPI) + ASSERT(FALSE); + + cp += 4; + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + DBGLOG(SEC, TRACE, "WAPI: Assoc Info group cipher suite : %02x-%02x-%02x-%02x\n", + (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); + + if (u4GroupSuite != WAPI_CIPHER_SUITE_WPI) + ASSERT(FALSE); + + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite = u4AuthKeyMgtSuite; + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher = u4PairSuite; + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher = u4GroupSuite; + + kalMemCopy(prAdapter->prGlueInfo->aucWapiAssocInfoIEs, pvSetBuffer, u4SetBufferLen); + prAdapter->prGlueInfo->u2WapiAssocInfoIESz = (UINT_16) u4SetBufferLen; + DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); + + return WLAN_STATUS_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the wpi key to the driver. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer P_PARAM_WPI_KEY, which is set by NDIS, is unpacked. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_WPI_KEY_T prNewKey; + P_CMD_802_11_KEY prCmdKey; + PUINT_8 pc; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetWapiKey"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\r\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewKey = (P_PARAM_WPI_KEY_T) pvSetBuffer; + + DBGLOG_MEM8(OID, TRACE, (PUINT_8) pvSetBuffer, 560); + pc = (PUINT_8) pvSetBuffer; + + *pu4SetInfoLen = u4SetBufferLen; + + /* Exception check */ + if (prNewKey->ucKeyID != 0x1 || prNewKey->ucKeyID != 0x0) { + prNewKey->ucKeyID = prNewKey->ucKeyID & BIT(0); + /* DBGLOG(SEC, INFO, ("Invalid WAPI key ID (%d)\r\n", prNewKey->ucKeyID)); */ + } + + /* Dump P_PARAM_WPI_KEY_T content. */ + DBGLOG(OID, TRACE, "Set: Dump P_PARAM_WPI_KEY_T content\r\n"); + DBGLOG(OID, TRACE, "TYPE : %d\r\n", prNewKey->eKeyType); + DBGLOG(OID, TRACE, "Direction : %d\r\n", prNewKey->eDirection); + DBGLOG(OID, TRACE, "KeyID : %d\r\n", prNewKey->ucKeyID); + DBGLOG(OID, TRACE, "AddressIndex:\r\n"); + DBGLOG_MEM8(OID, TRACE, prNewKey->aucAddrIndex, 12); + prNewKey->u4LenWPIEK = 16; + + DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPIEK, (UINT_8) prNewKey->u4LenWPIEK); + prNewKey->u4LenWPICK = 16; + + DBGLOG(OID, TRACE, "CK Key(%d):\r\n", (UINT_8) prNewKey->u4LenWPICK); + DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucWPICK, (UINT_8) prNewKey->u4LenWPICK); + DBGLOG(OID, TRACE, "PN:\r\n"); + if (prNewKey->eKeyType == 0) { + prNewKey->aucPN[0] = 0x5c; + prNewKey->aucPN[1] = 0x36; + prNewKey->aucPN[2] = 0x5c; + prNewKey->aucPN[3] = 0x36; + prNewKey->aucPN[4] = 0x5c; + prNewKey->aucPN[5] = 0x36; + prNewKey->aucPN[6] = 0x5c; + prNewKey->aucPN[7] = 0x36; + prNewKey->aucPN[8] = 0x5c; + prNewKey->aucPN[9] = 0x36; + prNewKey->aucPN[10] = 0x5c; + prNewKey->aucPN[11] = 0x36; + prNewKey->aucPN[12] = 0x5c; + prNewKey->aucPN[13] = 0x36; + prNewKey->aucPN[14] = 0x5c; + prNewKey->aucPN[15] = 0x36; + } + + DBGLOG_MEM8(OID, TRACE, (PUINT_8) prNewKey->aucPN, 16); + + prGlueInfo = prAdapter->prGlueInfo; + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetBufferLen)); + + if (!prCmdInfo) { + DBGLOG(OID, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_ID_ADD_REMOVE_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_AIS_INDEX; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = TRUE; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer); + + kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 1; /* Add */ + + if (prNewKey->eKeyType == ENUM_WPI_PAIRWISE_KEY) { + prCmdKey->ucTxKey = 1; + prCmdKey->ucKeyType = 1; + } + + kalMemCopy(prCmdKey->aucPeerAddr, (PUINT_8) prNewKey->aucAddrIndex, MAC_ADDR_LEN); + + prCmdKey->ucNetType = 0; /* AIS */ + + prCmdKey->ucKeyId = prNewKey->ucKeyID; + + prCmdKey->ucKeyLen = 32; + + prCmdKey->ucAlgorithmId = CIPHER_SUITE_WPI; + + kalMemCopy(prCmdKey->aucKeyMaterial, (PUINT_8) prNewKey->aucWPIEK, 16); + + kalMemCopy(prCmdKey->aucKeyMaterial + 16, (PUINT_8) prNewKey->aucWPICK, 16); + + kalMemCopy(prCmdKey->aucKeyRsc, (PUINT_8) prNewKey->aucPN, 16); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} /* wlanoidSetAddKey */ +#endif + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WSC to set the assoc info, which is needed to add to +* Association request frame while join WPS AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetWSCAssocInfo"); + DBGLOG(OID, LOUD, "\r\n"); + + if (u4SetBufferLen == 0) + return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + + kalMemCopy(prAdapter->prGlueInfo->aucWSCAssocInfoIE, pvSetBuffer, u4SetBufferLen); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = (UINT_16) u4SetBufferLen; + DBGLOG(SEC, TRACE, "Assoc Info IE sz %u\n", u4SetBufferLen); + + return WLAN_STATUS_SUCCESS; + +} +#endif + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; + + /* FIXME: + * Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN) pvSetBuffer; + + /* FIXME: + * Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + +WLAN_STATUS +wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + PUINT_32 pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidQueryEnableWakeup"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + if (u4QueryBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_BUFFER_TOO_SHORT; + + pu4WakeupEventEnable = (PUINT_32) pvQueryBuffer; + + *pu4WakeupEventEnable = prAdapter->u4WakeupEventEnable; + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_32 pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidSetEnableWakup"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + + if (u4SetBufferLen < sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + pu4WakeupEventEnable = (PUINT_32) pvSetBuffer; + prAdapter->u4WakeupEventEnable = *pu4WakeupEventEnable; + + /* FIXME: + * Send Command Event for setting wakeup-pattern / Magic Packet to firmware + * */ + + return WLAN_STATUS_FAILURE; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure PS related settings for WMM-PS test. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T prWmmPsTestInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_SET_WMM_PS_TEST_STRUCT_T rSetWmmPsTestParam; + UINT_16 u2CmdBufLen; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetWiFiWmmPsTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T); + + prWmmPsTestInfo = (P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T) pvSetBuffer; + + rSetWmmPsTestParam.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + rSetWmmPsTestParam.bmfgApsdEnAc = prWmmPsTestInfo->bmfgApsdEnAc; + rSetWmmPsTestParam.ucIsEnterPsAtOnce = prWmmPsTestInfo->ucIsEnterPsAtOnce; + rSetWmmPsTestParam.ucIsDisableUcTrigger = prWmmPsTestInfo->ucIsDisableUcTrigger; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[rSetWmmPsTestParam.ucNetTypeIndex]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + prPmProfSetupInfo->ucBmpDeliveryAC = (rSetWmmPsTestParam.bmfgApsdEnAc >> 4) & BITS(0, 3); + prPmProfSetupInfo->ucBmpTriggerAC = rSetWmmPsTestParam.bmfgApsdEnAc & BITS(0, 3); + + u2CmdBufLen = sizeof(CMD_SET_WMM_PS_TEST_STRUCT_T); + +#if 0 + /* it will apply the disable trig or not immediately */ + if (prPmInfo->ucWmmPsDisableUcPoll && prPmInfo->ucWmmPsConnWithTrig) + ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, TRUE); */ + else + ; /* NIC_PM_WMM_PS_DISABLE_UC_TRIG(prAdapter, FALSE); */ +#endif + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_WMM_PS_TEST_PARMS, TRUE, FALSE, TRUE, NULL, /* TODO? */ + NULL, u2CmdBufLen, (PUINT_8) &rSetWmmPsTestParam, NULL, 0); + + return rStatus; +} /* wlanoidSetWiFiWmmPsTest */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure enable/disable TX A-MPDU feature. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_TX_AMPDU_T rTxAmpdu; + UINT_16 u2CmdBufLen; + PBOOLEAN pfgEnable; + + DEBUGFUNC("wlanoidSetTxAmpdu"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(BOOLEAN); + + pfgEnable = (PBOOLEAN) pvSetBuffer; + + rTxAmpdu.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_TX_AMPDU_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_TX_AMPDU, + TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rTxAmpdu, NULL, 0); + + return rStatus; +} /* wlanoidSetTxAmpdu */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to configure reject/accept ADDBA Request. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_ADDBA_REJECT_T rAddbaReject; + UINT_16 u2CmdBufLen; + PBOOLEAN pfgEnable; + + DEBUGFUNC("wlanoidSetAddbaReject"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(BOOLEAN); + + pfgEnable = (PBOOLEAN) pvSetBuffer; + + rAddbaReject.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_ADDBA_REJECT_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_ADDBA_REJECT, + TRUE, FALSE, TRUE, NULL, NULL, u2CmdBufLen, (PUINT_8) &rAddbaReject, NULL, 0); + + return rStatus; +} /* wlanoidSetAddbaReject */ + +#if CFG_SLT_SUPPORT + +WLAN_STATUS +wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; + + DEBUGFUNC("wlanoidQuerySLTStatus"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvQueryBuffer); + + prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvQueryBuffer; + + prSltInfo = &(prAdapter->rWifiVar.rSltInfo); + + switch (prMtkSltInfo->rSltFuncIdx) { + case ENUM_MTK_SLT_FUNC_LP_SET: + { + P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); + + prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; + + prLpSetting->u4BcnRcvNum = prSltInfo->u4BeaconReceiveCnt; + } + break; + default: + /* TBD... */ + break; + } + + return rWlanStatus; +} /* wlanoidQuerySLTStatus */ + +WLAN_STATUS +wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_MTK_SLT_TEST_STRUCT_T prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) NULL; + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; + + /* 1. Action: Update or Initial Set + * 2. Role. + * 3. Target MAC address. + * 4. RF BW & Rate Settings + */ + + DEBUGFUNC("wlanoidUpdateSLTMode"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_MTK_SLT_TEST_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_MTK_SLT_TEST_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prMtkSltInfo = (P_PARAM_MTK_SLT_TEST_STRUCT_T) pvSetBuffer; + + prSltInfo = &(prAdapter->rWifiVar.rSltInfo); + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + switch (prMtkSltInfo->rSltFuncIdx) { + case ENUM_MTK_SLT_FUNC_INITIAL: /* Initialize */ + { + P_PARAM_MTK_SLT_INITIAL_STRUCT_T prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_INITIAL_STRUCT_T)); + + prMtkSltInit = (P_PARAM_MTK_SLT_INITIAL_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; + + if (prSltInfo->prPseudoStaRec != NULL) { + /* The driver has been initialized. */ + prSltInfo->prPseudoStaRec = NULL; + } + + prSltInfo->prPseudoBssDesc = scanSearchExistingBssDesc(prAdapter, + BSS_TYPE_IBSS, + prMtkSltInit->aucTargetMacAddr, + prMtkSltInit->aucTargetMacAddr); + + prSltInfo->u2SiteID = prMtkSltInit->u2SiteID; + + /* Bandwidth 2.4G: Channel 1~14 + * Bandwidth 5G: *36, 40, 44, 48, 52, 56, 60, 64, + * *100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, + * 149, 153, *157, 161, + * 184, 188, 192, 196, 200, 204, 208, 212, *216 + */ + prSltInfo->ucChannel2G4 = 1 + (prSltInfo->u2SiteID % 4) * 5; + + switch (prSltInfo->ucChannel2G4) { + case 1: + prSltInfo->ucChannel5G = 36; + break; + case 6: + prSltInfo->ucChannel5G = 52; + break; + case 11: + prSltInfo->ucChannel5G = 104; + break; + case 16: + prSltInfo->ucChannel2G4 = 14; + prSltInfo->ucChannel5G = 161; + break; + default: + ASSERT(FALSE); + } + + if (prSltInfo->prPseudoBssDesc == NULL) { + do { + prSltInfo->prPseudoBssDesc = scanAllocateBssDesc(prAdapter); + + if (prSltInfo->prPseudoBssDesc == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + prBssDesc = prSltInfo->prPseudoBssDesc; + } while (FALSE); + } else { + prBssDesc = prSltInfo->prPseudoBssDesc; + } + + if (prBssDesc) { + prBssDesc->eBSSType = BSS_TYPE_IBSS; + + COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prMtkSltInit->aucTargetMacAddr); + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + + prBssDesc->u2BeaconInterval = 100; + prBssDesc->u2ATIMWindow = 0; + prBssDesc->ucDTIMPeriod = 1; + + prBssDesc->u2IELength = 0; + + prBssDesc->fgIsERPPresent = TRUE; + prBssDesc->fgIsHTPresent = TRUE; + + prBssDesc->u2OperationalRateSet = BIT(RATE_36M_INDEX); + prBssDesc->u2BSSBasicRateSet = BIT(RATE_36M_INDEX); + prBssDesc->fgIsUnknownBssBasicRate = FALSE; + + prBssDesc->fgIsLargerTSF = TRUE; + + prBssDesc->eBand = BAND_2G4; + + prBssDesc->ucChannelNum = prSltInfo->ucChannel2G4; + + prBssDesc->ucPhyTypeSet = PHY_TYPE_SET_802_11ABGN; + + GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); + } + } + break; + case ENUM_MTK_SLT_FUNC_RATE_SET: /* Update RF Settings. */ + if (prSltInfo->prPseudoStaRec == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + + P_PARAM_MTK_SLT_TR_TEST_STRUCT_T prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_TR_TEST_STRUCT_T)); + + prStaRec = prSltInfo->prPseudoStaRec; + prTRSetting = (P_PARAM_MTK_SLT_TR_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; + + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { + prBssInfo->eBand = BAND_5G; + prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel5G; + } + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM24) { + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = prSltInfo->ucChannel2G4; + } + + if ((prTRSetting->u4FixedRate & FIXED_BW_DL40) != 0) { + /* RF 40 */ + /* It would controls RFBW capability in WTBL. */ + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + /* This controls RF BW, RF BW would be 40 only if */ + /* 1. PHY_TYPE_BIT_HT is TRUE. */ + /* 2. SCO is SCA/SCB. */ + prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + + /* U20/L20 Control. */ + switch (prTRSetting->u4FixedRate & 0xC000) { + case FIXED_EXT_CHNL_U20: + prBssInfo->eBssSCO = CHNL_EXT_SCB; /* +2 */ + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) + prBssInfo->ucPrimaryChannel += 2; + else { + /* For channel 1, testing L20 at channel 8. */ + if (prBssInfo->ucPrimaryChannel < 5) + prBssInfo->ucPrimaryChannel = 8; + } + break; + case FIXED_EXT_CHNL_L20: + default: /* 40M */ + prBssInfo->eBssSCO = CHNL_EXT_SCA; /* -2 */ + if (prTRSetting->rNetworkType == PARAM_NETWORK_TYPE_OFDM5) { + prBssInfo->ucPrimaryChannel -= 2; + } else { + /* For channel 11 / 14. testing U20 at channel 3. */ + if (prBssInfo->ucPrimaryChannel > 10) + prBssInfo->ucPrimaryChannel = 3; + } + break; + } + } else { + /* RF 20 */ + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + + prBssInfo->fgErpProtectMode = FALSE; + prBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; + prBssInfo->eGfOperationMode = GF_MODE_NORMAL; + + nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); + + prStaRec->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + + switch (prTRSetting->u4FixedRate & 0xFF) { + case RATE_OFDM_54M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_54M_INDEX); + break; + case RATE_OFDM_48M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_48M_INDEX); + break; + case RATE_OFDM_36M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); + break; + case RATE_OFDM_24M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_24M_INDEX); + break; + case RATE_OFDM_6M: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_6M_INDEX); + break; + case RATE_CCK_11M_LONG: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_11M_INDEX); + break; + case RATE_CCK_1M_LONG: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_1M_INDEX); + break; + case RATE_GF_MCS_0: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + break; + case RATE_MM_MCS_7: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; +#if 0 /* Only for Current Measurement Mode. */ + prStaRec->u2HtCapInfo |= (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); +#endif + break; + case RATE_GF_MCS_7: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_HT_PHY_INDEX); + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + break; + default: + prStaRec->u2DesiredNonHTRateSet = BIT(RATE_36M_INDEX); + break; + } + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + break; + case ENUM_MTK_SLT_FUNC_LP_SET: /* Reset LP Test Result. */ + { + P_PARAM_MTK_SLT_LP_TEST_STRUCT_T prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) NULL; + + ASSERT(prMtkSltInfo->u4FuncInfoLen == sizeof(PARAM_MTK_SLT_LP_TEST_STRUCT_T)); + + prLpSetting = (P_PARAM_MTK_SLT_LP_TEST_STRUCT_T) &prMtkSltInfo->unFuncInfoContent; + + if (prSltInfo->prPseudoBssDesc == NULL) { + /* Please initial SLT Mode first. */ + break; + } + prBssDesc = prSltInfo->prPseudoBssDesc; + + switch (prLpSetting->rLpTestMode) { + case ENUM_MTK_LP_TEST_NORMAL: + /* In normal mode, we would use target MAC address to be the BSSID. */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + prSltInfo->fgIsDUT = FALSE; + break; + case ENUM_MTK_LP_TEST_GOLDEN_SAMPLE: + /* 1. Lower AIFS of BCN queue. + * 2. Fixed Random Number tobe 0. + */ + prSltInfo->fgIsDUT = FALSE; + /* In LP test mode, we would use MAC address of Golden Sample to be the BSSID. */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssInfo->aucOwnMacAddr); + break; + case ENUM_MTK_LP_TEST_DUT: + /* 1. Enter Sleep Mode. + * 2. Fix random number a large value & enlarge AIFN of BCN queue. + */ + COPY_MAC_ADDR(prBssDesc->aucBSSID, prBssDesc->aucSrcAddr); + prSltInfo->u4BeaconReceiveCnt = 0; + prSltInfo->fgIsDUT = TRUE; + break; + } + + } + + break; + default: + break; + } + + return WLAN_STATUS_FAILURE; + + return rWlanStatus; +} /* wlanoidUpdateSLTMode */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query NVRAM value. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + UINT_16 u2Data; + BOOLEAN fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryNvramRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvQueryBuffer; + + if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_READ) { + /* change to byte offset */ + fgStatus = kalCfgDataRead16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, + &u2Data); + + if (fgStatus) { + prNvramRwInfo->u2EepromData = u2Data; + DBGLOG(OID, INFO, "NVRAM Read: index=%#X, data=%#02X\r\n", + prNvramRwInfo->ucEepromIndex, u2Data); + } else { + DBGLOG(OID, ERROR, "NVRAM Read Failed: index=%#x.\r\n", prNvramRwInfo->ucEepromIndex); + rStatus = WLAN_STATUS_FAILURE; + } + } else if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_GETSIZE) { + prNvramRwInfo->u2EepromData = CFG_FILE_WIFI_REC_SIZE; + DBGLOG(OID, INFO, "EEPROM size =%d\r\n", prNvramRwInfo->u2EepromData); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + return rStatus; +} /* wlanoidQueryNvramRead */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to write NVRAM value. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + BOOLEAN fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetNvramWrite"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T) pvSetBuffer; + + /* change to byte offset */ + fgStatus = kalCfgDataWrite16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, + prNvramRwInfo->u2EepromData); + + if (fgStatus == FALSE) { + DBGLOG(OID, ERROR, "NVRAM Write Failed.\r\n"); + rStatus = WLAN_STATUS_FAILURE; + } + + return rStatus; +} /* wlanoidSetNvramWrite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(ENUM_CFG_SRC_TYPE_T); + + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE) + *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_NVRAM; + else + *(P_ENUM_CFG_SRC_TYPE_T) pvQueryBuffer = CFG_SRC_TYPE_EEPROM; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(P_ENUM_EEPROM_TYPE_T); + +#if CFG_SUPPORT_NIC_CAPABILITY + if (prAdapter->fgIsEepromUsed == TRUE) + *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_PRESENT; + else + *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; +#else + *(P_ENUM_EEPROM_TYPE_T) pvQueryBuffer = EEPROM_TYPE_NO; +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get the config data source type. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_8 pucCountry; + UINT_16 u2CountryCode; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(u4SetBufferLen == 2); + + *pu4SetInfoLen = 2; + + pucCountry = pvSetBuffer; + u2CountryCode = (((UINT_16) pucCountry[0]) << 8) | ((UINT_16) pucCountry[1]); + + /* previous country code == FF : ignore country code, current country code == FE : resume */ + if (prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup == COUNTRY_CODE_FF) { + if (u2CountryCode != COUNTRY_CODE_FE) { + DBGLOG(OID, INFO, "Skip country code cmd (0x%04x)\n", u2CountryCode); + return WLAN_STATUS_SUCCESS; + } + DBGLOG(OID, INFO, "Resume handle country code cmd (0x%04x)\n", u2CountryCode); + } + + prAdapter->rWifiVar.rConnSettings.u2CountryCode = u2CountryCode; + prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + DBGLOG(OID, LOUD, "u2CountryCodeBakup=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCodeBakup); + + /* Force to re-search country code in country domains */ + prAdapter->prDomainInfo = NULL; + rlmDomainSendCmd(prAdapter, TRUE); + + /* Update supported channel list in channel table based on current country domain */ + wlanUpdateChannelTable(prAdapter->prGlueInfo); + + return WLAN_STATUS_SUCCESS; +} + +#if 0 +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; + CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; + + DEBUGFUNC("wlanoidSetNoaParam"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); + rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; + rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; + rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), + (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); +} + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; + CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; + + DEBUGFUNC("wlanoidSetOppPsParam"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_OPPPS_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); +} + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; + CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetUApsdParam"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; + prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; + + rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; + rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; + rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; + rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; + prPmProfSetupInfo->ucBmpDeliveryAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); + prPmProfSetupInfo->ucBmpTriggerAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); + + rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; + prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set BT profile or BT information and the +* driver will set the built-in PTA configuration into chip. +* +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + + P_PTA_IPC_T prPtaIpc; + + DEBUGFUNC("wlanoidSetBT.\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PTA_IPC_T); + if (u4SetBufferLen != sizeof(PTA_IPC_T)) { + WARNLOG(("Invalid length %u\n", u4SetBufferLen)); + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail to set BT profile because of ACPI_D3\n"); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prPtaIpc = (P_PTA_IPC_T) pvSetBuffer; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(OID, INFO, + "BCM BWCS CMD: BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", + prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], + prPtaIpc->u.aucBTPParams[3]; + +#endif + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BWCS, + TRUE, FALSE, FALSE, NULL, NULL, sizeof(PTA_IPC_T), (PUINT_8) prPtaIpc, NULL, 0); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query current BT profile and BTCR values +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvQueryBuffer Pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBT(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ +/* P_PARAM_PTA_IPC_T prPtaIpc; */ +/* UINT_32 u4QueryBuffLen; */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PTA_IPC_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(PTA_IPC_T)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); +/* prPtaIpc = (P_PTA_IPC_T)pvQueryBuffer; */ +/* prPtaIpc->ucCmd = BT_CMD_PROFILE; */ +/* prPtaIpc->ucLen = sizeof(prPtaIpc->u); */ +/* nicPtaGetProfile(prAdapter, (PUINT_8)&prPtaIpc->u, &u4QueryBuffLen); */ + + return WLAN_STATUS_SUCCESS; +} + +#if 0 +WLAN_STATUS +wlanoidQueryBtSingleAntenna(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PTA_INFO_T prPtaInfo; + PUINT_32 pu4SingleAntenna; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(UINT_32)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + prPtaInfo = &prAdapter->rPtaInfo; + pu4SingleAntenna = (PUINT_32) pvQueryBuffer; + + if (prPtaInfo->fgSingleAntenna) { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 1\r\n")); */ + *pu4SingleAntenna = 1; + } else { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Q Single Ant = 0\r\n")); */ + *pu4SingleAntenna = 0; + } + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetBtSingleAntenna(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + + PUINT_32 pu4SingleAntenna; + UINT_32 u4SingleAntenna; + P_PTA_INFO_T prPtaInfo; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + prPtaInfo = &prAdapter->rPtaInfo; + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen != sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + if (IS_ARB_IN_RFTEST_STATE(prAdapter)) + return WLAN_STATUS_SUCCESS; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail to set antenna because of ACPI_D3\n"); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + pu4SingleAntenna = (PUINT_32) pvSetBuffer; + u4SingleAntenna = *pu4SingleAntenna; + + if (u4SingleAntenna == 0) { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 0\r\n")); */ + prPtaInfo->fgSingleAntenna = FALSE; + } else { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Single Ant = 1\r\n")); */ + prPtaInfo->fgSingleAntenna = TRUE; + } + ptaFsmRunEventSetConfig(prAdapter, &prPtaInfo->rPtaParam); + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS +WLAN_STATUS +wlanoidQueryPta(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PTA_INFO_T prPtaInfo; + PUINT_32 pu4Pta; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(UINT_32)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + + prPtaInfo = &prAdapter->rPtaInfo; + pu4Pta = (PUINT_32) pvQueryBuffer; + + if (prPtaInfo->fgEnabled) { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 1\r\n")); */ + *pu4Pta = 1; + } else { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"PTA = 0\r\n")); */ + *pu4Pta = 0; + } + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetPta(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + PUINT_32 pu4PtaCtrl; + UINT_32 u4PtaCtrl; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(UINT_32); + if (u4SetBufferLen != sizeof(UINT_32)) + return WLAN_STATUS_INVALID_LENGTH; + + if (IS_ARB_IN_RFTEST_STATE(prAdapter)) + return WLAN_STATUS_SUCCESS; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(OID, WARN, "Fail to set BT setting because of ACPI_D3\n"); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + pu4PtaCtrl = (PUINT_32) pvSetBuffer; + u4PtaCtrl = *pu4PtaCtrl; + + if (u4PtaCtrl == 0) { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 0\r\n")); */ + nicPtaSetFunc(prAdapter, FALSE); + } else { + /* DBGLOG(OID, INFO, (KERN_WARNING DRV_NAME"Set Pta= 1\r\n")); */ + nicPtaSetFunc(prAdapter, TRUE); + } + + return WLAN_STATUS_SUCCESS; +} +#endif + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Tx power profile. +* +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + /* P_SET_TXPWR_CTRL_T pTxPwr = (P_SET_TXPWR_CTRL_T)pvSetBuffer; */ + /* UINT_32 i; */ + WLAN_STATUS rStatus; + + DEBUGFUNC("wlanoidSetTxPower"); + DBGLOG(OID, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + +#if 0 + DBGLOG(OID, INFO, "c2GLegacyStaPwrOffset=%d\n", pTxPwr->c2GLegacyStaPwrOffset); + DBGLOG(OID, INFO, "c2GHotspotPwrOffset=%d\n", pTxPwr->c2GHotspotPwrOffset); + DBGLOG(OID, INFO, "c2GP2pPwrOffset=%d\n", pTxPwr->c2GP2pPwrOffset); + DBGLOG(OID, INFO, "c2GBowPwrOffset=%d\n", pTxPwr->c2GBowPwrOffset); + DBGLOG(OID, INFO, "c5GLegacyStaPwrOffset=%d\n", pTxPwr->c5GLegacyStaPwrOffset); + DBGLOG(OID, INFO, "c5GHotspotPwrOffset=%d\n", pTxPwr->c5GHotspotPwrOffset); + DBGLOG(OID, INFO, "c5GP2pPwrOffset=%d\n", pTxPwr->c5GP2pPwrOffset); + DBGLOG(OID, INFO, "c5GBowPwrOffset=%d\n", pTxPwr->c5GBowPwrOffset); + DBGLOG(OID, INFO, "ucConcurrencePolicy=%d\n", pTxPwr->ucConcurrencePolicy); + + for (i = 0; i < 14; i++) + DBGLOG(OID, INFO, "acTxPwrLimit2G[%d]=%d\n", i, pTxPwr->acTxPwrLimit2G[i]); + + for (i = 0; i < 4; i++) + DBGLOG(OID, INFO, "acTxPwrLimit5G[%d]=%d\n", i, pTxPwr->acTxPwrLimit5G[i]); +#endif + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_TXPWR_CTRL, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + TRUE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + u4SetBufferLen, /* u4SetQueryInfoLen */ + (PUINT_8) pvSetBuffer, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + return rStatus; + +} + +WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen) +{ + P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; + P_CMD_DUMP_MEM prCmdDumpMem; + CMD_DUMP_MEM rCmdDumpMem; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4MemSize = PARAM_MEM_DUMP_MAX_SIZE; + + UINT_32 u4RemainLeng = 0; + UINT_32 u4CurAddr = 0; + UINT_8 ucFragNum = 0; + + prCmdDumpMem = &rCmdDumpMem; + prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; + + u4RemainLeng = prMemDumpInfo->u4RemainLength; + u4CurAddr = prMemDumpInfo->u4Address + prMemDumpInfo->u4Length; + ucFragNum = prMemDumpInfo->ucFragNum + 1; + + /* Query. If request length is larger than max length, do it as ping pong. + * Send a command and wait for a event. Send next command while the event is received. + * + */ + do { + UINT_32 u4CurLeng = 0; + + if (u4RemainLeng > u4MemSize) { + u4CurLeng = u4MemSize; + u4RemainLeng -= u4MemSize; + } else { + u4CurLeng = u4RemainLeng; + u4RemainLeng = 0; + } + + prCmdDumpMem->u4Address = u4CurAddr; + prCmdDumpMem->u4Length = u4CurLeng; + prCmdDumpMem->u4RemainLength = u4RemainLeng; + prCmdDumpMem->ucFragNum = ucFragNum; + + DBGLOG(OID, TRACE, "[%d] 0x%X, len %u, remain len %u\n", + ucFragNum, + prCmdDumpMem->u4Address, prCmdDumpMem->u4Length, prCmdDumpMem->u4RemainLength); + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_DUMP_MEM, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryMemDump, + nicOidCmdTimeoutCommon, + sizeof(CMD_DUMP_MEM), + (PUINT_8) prCmdDumpMem, pvQueryBuffer, u4QueryBufferLen); + + } while (FALSE); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to dump memory. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; + + DEBUGFUNC("wlanoidQueryMemDump"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_32); + + prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) pvQueryBuffer; + DBGLOG(OID, TRACE, "Dump 0x%X, len %u\n", prMemDumpInfo->u4Address, prMemDumpInfo->u4Length); + + prMemDumpInfo->u4RemainLength = prMemDumpInfo->u4Length; + prMemDumpInfo->u4Length = 0; + prMemDumpInfo->ucFragNum = 0; + + return wlanSendMemDumpCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen); + +} /* end of wlanoidQueryMcrRead() */ + +#if CFG_ENABLE_WIFI_DIRECT +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the p2p mode. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_PARAM_CUSTOM_P2P_SET_STRUCT_T prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) NULL; + /* P_MSG_P2P_NETDEV_REGISTER_T prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T)NULL; */ + DEBUGFUNC("wlanoidSetP2pMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T); + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T)) { + DBGLOG(OID, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T) pvSetBuffer; + + DBGLOG(P2P, INFO, "Set P2P enable %p [%u] mode[%u]\n", prSetP2P, prSetP2P->u4Enable, prSetP2P->u4Mode); + + /* + * enable = 1, mode = 0 => init P2P network + * enable = 1, mode = 1 => init Soft AP network + * enable = 0 => uninit P2P/AP network + */ + + if (prSetP2P->u4Enable) { + p2pSetMode((prSetP2P->u4Mode == 1) ? TRUE : FALSE); + + if (p2pLaunch(prAdapter->prGlueInfo)) + ASSERT(prAdapter->fgIsP2PRegistered); + + } else { + DBGLOG(P2P, TRACE, "prAdapter->fgIsP2PRegistered = %d\n", prAdapter->fgIsP2PRegistered); + + if (prAdapter->fgIsP2PRegistered) { + DBGLOG(P2P, INFO, "p2pRemove\n"); + p2pRemove(prAdapter->prGlueInfo); + } + + } + +#if 0 + prP2pNetdevRegMsg = (P_MSG_P2P_NETDEV_REGISTER_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + (sizeof(MSG_P2P_NETDEV_REGISTER_T))); + + if (prP2pNetdevRegMsg == NULL) { + ASSERT(FALSE); + status = WLAN_STATUS_RESOURCES; + return status; + } + + prP2pNetdevRegMsg->rMsgHdr.eMsgId = MID_MNY_P2P_NET_DEV_REGISTER; + prP2pNetdevRegMsg->fgIsEnable = (prSetP2P->u4Enable == 1) ? TRUE : FALSE; + prP2pNetdevRegMsg->ucMode = (UINT_8) prSetP2P->u4Mode; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pNetdevRegMsg, MSG_SEND_METHOD_BUF); +#endif + + return status; +} +#endif + +#if CFG_SUPPORT_BUILD_DATE_CODE +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query build date code information from firmware +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + CMD_GET_BUILD_DATE_CODE rCmdGetBuildDateCode; + + DEBUGFUNC("wlanoidQueryBuildDateCode"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(UINT_8) * 16; + + if (u4QueryBufferLen < sizeof(UINT_8) * 16) + return WLAN_STATUS_INVALID_LENGTH; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_BUILD_DATE_CODE, + FALSE, + TRUE, + TRUE, + nicCmdEventBuildDateCode, + nicOidCmdTimeoutCommon, + sizeof(CMD_GET_BUILD_DATE_CODE), + (PUINT_8) &rCmdGetBuildDateCode, pvQueryBuffer, u4QueryBufferLen); + +} /* end of wlanoidQueryBuildDateCode() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query BSS info from firmware +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + EVENT_AIS_BSS_INFO_T rCmdBSSInfo; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); + + if (u4QueryBufferLen < sizeof(EVENT_AIS_BSS_INFO_T)) + return WLAN_STATUS_INVALID_LENGTH; + kalMemZero(&rCmdBSSInfo, sizeof(EVENT_AIS_BSS_INFO_T)); + /* + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_BSS_INFO, + FALSE, + TRUE, + TRUE, + nicCmdEventGetBSSInfo, + nicOidCmdTimeoutCommon, + sizeof(P_EVENT_AIS_BSS_INFO_T), + (PUINT_8) &rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); + */ + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_BSS_INFO, + FALSE, + TRUE, + TRUE, + nicCmdEventGetBSSInfo, + nicOidCmdTimeoutCommon, + sizeof(EVENT_AIS_BSS_INFO_T), + (PUINT_8) & rCmdBSSInfo, pvQueryBuffer, u4QueryBufferLen); + + return rStatus; +} /* wlanoidSetWiFiWmmPsTest */ + +#if CFG_SUPPORT_BATCH_SCAN + +#define CMD_WLS_BATCHING "WLS_BATCHING" + +#define BATCHING_SET "SET" +#define BATCHING_GET "GET" +#define BATCHING_STOP "STOP" + +#define PARAM_SCANFREQ "SCANFREQ" +#define PARAM_MSCAN "MSCAN" +#define PARAM_BESTN "BESTN" +#define PARAM_CHANNEL "CHANNEL" +#define PARAM_RTT "RTT" + +WLAN_STATUS +batchSetCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4WritenLen) +{ + P_CHANNEL_INFO_T prRfChannelInfo; + CMD_BATCH_REQ_T rCmdBatchReq; + + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PCHAR head, p, p2; + UINT_32 tokens; + INT_32 scanfreq, mscan, bestn, rtt; + + DBGLOG(SCN, TRACE, "[BATCH] command=%s, len=%u\n", (PCHAR) pvSetBuffer, (UINT_32) u4SetBufferLen); + + if (!pu4WritenLen) + return -EINVAL; + *pu4WritenLen = 0; + + if (u4SetBufferLen < kalStrLen(CMD_WLS_BATCHING)) { + DBGLOG(SCN, TRACE, "[BATCH] invalid len %u\n", (UINT_32) u4SetBufferLen); + return -EINVAL; + } + + head = pvSetBuffer + kalStrLen(CMD_WLS_BATCHING) + 1; + kalMemSet(&rCmdBatchReq, 0, sizeof(CMD_BATCH_REQ_T)); + + if (!kalStrnCmp(head, BATCHING_SET, kalStrLen(BATCHING_SET))) { + + DBGLOG(SCN, TRACE, "XXX Start Batch Scan XXX\n"); + + head += kalStrLen(BATCHING_SET) + 1; + + /* SCANFREQ, MSCAN, BESTN */ + tokens = kalSScanf(head, "SCANFREQ=%d MSCAN=%d BESTN=%d", &scanfreq, &mscan, &bestn); + if (tokens != 3) { + DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, SCANFREQ=%d MSCAN=%d BESTN=%d\n", + (UINT_32) tokens, scanfreq, mscan, bestn); + return -EINVAL; + } + /* RTT */ + p = kalStrStr(head, PARAM_RTT); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse RTT fail. head=%s\n", head); + return -EINVAL; + } + tokens = kalSScanf(p, "RTT=%d", &rtt); + if (tokens != 1) { + DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%u, rtt=%d\n", (UINT_32) tokens, rtt); + return -EINVAL; + } + /* CHANNEL */ + p = kalStrStr(head, PARAM_CHANNEL); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(1)\n"); + return -EINVAL; + } + head = p; + p = kalStrChr(head, '>'); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(2)\n"); + return -EINVAL; + } + /* else { + *p = '.'; // remove '>' because sscanf can not parse <%s> + }*/ + /*tokens = kalSScanf(head, "CHANNEL=<%s", c_channel); + if (tokens != 1) { + DBGLOG(SCN, TRACE, ("[BATCH] Parse fail: tokens=%d, CHANNEL=<%s>\n", + tokens, c_channel)); + return -EINVAL; + } */ + rCmdBatchReq.ucChannelType = SCAN_CHANNEL_SPECIFIED; + rCmdBatchReq.ucChannelListNum = 0; + prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; + p = head + kalStrLen(PARAM_CHANNEL) + 2; /* c_channel; */ + while ((p2 = kalStrSep((char **)&p, ",")) != NULL) { + if (p2 == NULL || *p2 == 0) + break; + if (*p2 == '\0') + continue; + if (*p2 == 'A') { + rCmdBatchReq.ucChannelType = + rCmdBatchReq.ucChannelType == + SCAN_CHANNEL_2G4 ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_5G; + } else if (*p2 == 'B') { + rCmdBatchReq.ucChannelType = + rCmdBatchReq.ucChannelType == + SCAN_CHANNEL_5G ? SCAN_CHANNEL_FULL : SCAN_CHANNEL_2G4; + } else { + + /* Translate Freq from MHz to channel number. */ + prRfChannelInfo->ucChannelNum = kalStrtol(p2, NULL, 0); + DBGLOG(SCN, TRACE, "Scanning Channel:%u, freq: %d\n", + (UINT_32) prRfChannelInfo->ucChannelNum, + (UINT_32) nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); + prRfChannelInfo->ucBand = prRfChannelInfo->ucChannelNum < 15 ? BAND_2G4 : BAND_5G; + + rCmdBatchReq.ucChannelListNum++; + if (rCmdBatchReq.ucChannelListNum >= 32) + break; + prRfChannelInfo++; + } + } + + /* set channel for test */ +#if 0 + rCmdBatchReq.ucChannelType = 4; /* SCAN_CHANNEL_SPECIFIED; */ + rCmdBatchReq.ucChannelListNum = 0; + prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; + for (i = 1; i <= 14; i++) { + + /* filter out some */ + if (i == 1 || i == 5 || i == 11) + continue; + + /* Translate Freq from MHz to channel number. */ + prRfChannelInfo->ucChannelNum = i; + DBGLOG(SCN, TRACE, "Scanning Channel:%d, freq: %d\n", + prRfChannelInfo->ucChannelNum, + nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); + prRfChannelInfo->ucBand = BAND_2G4; + + rCmdBatchReq.ucChannelListNum++; + prRfChannelInfo++; + } +#endif +#if 0 + rCmdBatchReq.ucChannelType = 0; /* SCAN_CHANNEL_FULL; */ +#endif + + rCmdBatchReq.u4Scanfreq = scanfreq; + rCmdBatchReq.ucMScan = mscan > CFG_BATCH_MAX_MSCAN ? CFG_BATCH_MAX_MSCAN : mscan; + rCmdBatchReq.ucBestn = bestn; + rCmdBatchReq.ucRtt = rtt; + DBGLOG(SCN, TRACE, "[BATCH] SCANFREQ=%u MSCAN=%u BESTN=%u RTT=%u\n", + (UINT_32) rCmdBatchReq.u4Scanfreq, + (UINT_32) rCmdBatchReq.ucMScan, + (UINT_32) rCmdBatchReq.ucBestn, (UINT_32) rCmdBatchReq.ucRtt; + + if (rCmdBatchReq.ucChannelType != SCAN_CHANNEL_SPECIFIED) { + DBGLOG(SCN, TRACE, "[BATCH] CHANNELS = %s\n", + rCmdBatchReq.ucChannelType == SCAN_CHANNEL_FULL ? "FULL" : + rCmdBatchReq.ucChannelType == SCAN_CHANNEL_2G4 ? "2.4G all" : "5G all"); + } else { + DBGLOG(SCN, TRACE, "[BATCH] CHANNEL list\n"); + prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; + for (tokens = 0; tokens < rCmdBatchReq.ucChannelListNum; tokens++) { + DBGLOG(SCN, TRACE, "[BATCH] %s, %d\n", + prRfChannelInfo->ucBand == BAND_2G4 ? "2.4G" : "5G", + prRfChannelInfo->ucChannelNum); + prRfChannelInfo++; + } + } + + rCmdBatchReq.ucSeqNum = 1; + rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_START; + + *pu4WritenLen = kalSnprintf(pvSetBuffer, 3, "%d", rCmdBatchReq.ucMScan); + + } else if (!kalStrnCmp(head, BATCHING_STOP, kalStrLen(BATCHING_STOP))) { + + DBGLOG(SCN, TRACE, "XXX Stop Batch Scan XXX\n"); + + rCmdBatchReq.ucSeqNum = 1; + rCmdBatchReq.ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_STOP; + } else { + return -EINVAL; + } + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BATCH_REQ, + TRUE, FALSE, TRUE, NULL, NULL, sizeof(CMD_BATCH_REQ_T), (PUINT_8) &rCmdBatchReq, NULL, 0); + + /* kalMemSet(pvSetBuffer, 0, u4SetBufferLen); */ + /* rStatus = kalSnprintf(pvSetBuffer, 2, "%s", "OK"); */ + + return rStatus; +} + +WLAN_STATUS +batchGetCmd(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + CMD_BATCH_REQ_T rCmdBatchReq; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_EVENT_BATCH_RESULT_T prEventBatchResult; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pvQueryBuffer; + + DBGLOG(SCN, TRACE, "XXX Get Batch Scan Result (%u) XXX\n", (UINT_32) prEventBatchResult->ucScanCount); + + *pu4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); + + rCmdBatchReq.ucSeqNum = 2; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_RESULT; + rCmdBatchReq.ucMScan = prEventBatchResult->ucScanCount; /* Get which round result */ + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BATCH_REQ, + FALSE, + TRUE, + TRUE, + nicCmdEventBatchScanResult, + nicOidCmdTimeoutCommon, + sizeof(CMD_BATCH_REQ_T), + (PUINT_8) &rCmdBatchReq, (PVOID) pvQueryBuffer, u4QueryBufferLen); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + return batchSetCmd(prAdapter, pvSetBuffer, u4SetBufferLen, pu4SetInfoLen); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + return batchGetCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen, pu4QueryInfoLen); + +} /* end of wlanoidQueryBatchScanResult() */ + +#endif /* CFG_SUPPORT_BATCH_SCAN */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request starting of schedule scan +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; + + DEBUGFUNC("wlanoidSetStartSchedScan()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(SCN, WARN, "Fail in set scheduled scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (u4SetBufferLen != sizeof(PARAM_SCHED_SCAN_REQUEST)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + return WLAN_STATUS_INVALID_DATA; + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED && + prAdapter->fgEnOnlineScan == FALSE) { + return WLAN_STATUS_FAILURE; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) pvSetBuffer; + + if (scnFsmSchedScanRequest(prAdapter, + (UINT_8) (prSchedScanRequest->u4SsidNum), + prSchedScanRequest->arSsid, + prSchedScanRequest->u4IELength, + prSchedScanRequest->pucIE, prSchedScanRequest->u2ScanInterval) == TRUE) { + return WLAN_STATUS_SUCCESS; + } else { + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request termination of schedule scan +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ASSERT(prAdapter); + + /* ask SCN module to stop scan request */ + if (scnFsmSchedScanStopRequest(prAdapter) == TRUE) + return WLAN_STATUS_SUCCESS; + else + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a periodically scan action +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_CMD_SET_PSCAN_ENABLE prCmdPscnAction; + P_SCAN_INFO_T prScanInfo; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + DBGLOG(SCN, TRACE, "wlanoidSetGSCNAction\n"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4SetBufferLen != sizeof(CMD_SET_PSCAN_ENABLE)) + return WLAN_STATUS_INVALID_LENGTH; + else if (pvSetBuffer == NULL) + return WLAN_STATUS_INVALID_DATA; + + if (prAdapter->fgIsRadioOff) { + DBGLOG(SCN, WARN, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prCmdPscnAction = (P_CMD_SET_PSCAN_ENABLE) pvSetBuffer; + + if (prCmdPscnAction->ucPscanAct == ENABLE) { +#if 0 + DBGLOG(OID, INFO, "set PCSN ENABLE\n"); + if (scnFsmPSCNAction(prAdapter, (UINT_8) (prCmdPscnAction->ucPscanAct)) == TRUE) { + + DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); + return WLAN_STATUS_PENDING; + } + DBGLOG(OID, INFO, "wlanoidSetGSCNAction < ---\n"); + return WLAN_STATUS_FAILURE; + +#endif + scnPSCNFsm(prAdapter, PSCN_SCANNING, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE, TRUE); + } else if (prCmdPscnAction->ucPscanAct == DISABLE) { +#if 0 + DBGLOG(OID, INFO, "disable PCSN\n"); + scnFsmPSCNAction(prAdapter, (UINT_8) DISABLE); + + DBGLOG(OID, TRACE, "set new PCSN\n"); + scnCombineParamsIntoPSCN(prAdapter, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE); + + DBGLOG(OID, INFO, "ENABLE or disable PCSN\n"); + if (!prScanInfo->fgPscnOnnning) { + DBGLOG(OID, INFO, "ENABLE PCSN\n"); + scnFsmPSCNAction(prAdapter, ENABLE); + } else { + DBGLOG(OID, INFO, "All PCSN is disabled...\n"); + } +#endif + scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, FALSE, FALSE, TRUE, FALSE); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a periodically scan action +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam; + /*UINT_8 i, j = 0;*/ + DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam v1\n"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { + DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(P_PARAM_WIFI_GSCAN_CMD_PARAMS))\n"); + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); + return WLAN_STATUS_INVALID_DATA; + } + if (prAdapter->fgIsRadioOff) { + DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prCmdGscnParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; + /* KC-XXX memcpy(prCmdGscnParam, */ + /* (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer, */ + /* sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS) ); */ + DBGLOG(SCN, INFO, + "prCmdGscnParam : base_period[%u], max_ap_per_scan[%u] num_buckets[%u], report_threshold[%u]\n", + prCmdGscnParam->base_period, prCmdGscnParam->max_ap_per_scan, prCmdGscnParam->num_buckets, + prCmdGscnParam->report_threshold); +#if 0 + for (i = 0; i < prCmdGscnParam->num_buckets; i++) { + + DBGLOG(OID, INFO, + "prCmdGscnParam->buckets : band[%u], bucket[%u] num_buckets[%u], period[%u] report_events[%u]\n", + prCmdGscnParam->buckets[i].band, prCmdGscnParam->buckets[i].bucket, + prCmdGscnParam->buckets[i].num_channels, prCmdGscnParam->buckets[i].period, + prCmdGscnParam->buckets[i].report_events)); + DBGLOG(OID, INFO, "prCmdGscnParam->buckets[%d] has channel: ", i); + for (j = 0; j < prCmdGscnParam->buckets[i].num_channels; j++) + DBGLOG(OID, INFO, " %d, ", prCmdGscnParam->buckets[i].channels[j].channel); + DBGLOG(OID, INFO, "\n"); + } +#endif + if (scnSetGSCNParam(prAdapter, prCmdGscnParam) == TRUE) { + DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); + return WLAN_STATUS_PENDING; + } else { + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set configure gscan PARAMs +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnScnConfigParam; + CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; + + DBGLOG(SCN, INFO, "wlanoidSetGSCNAConfig v1\n"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)) { + DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); + return WLAN_STATUS_INVALID_DATA; + } + if (prAdapter->fgIsRadioOff) { + DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS)pvSetBuffer\n"); + prCmdGscnScnConfigParam = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer; + memcpy(prCmdGscnScnConfigParam, (P_PARAM_WIFI_GSCAN_CMD_PARAMS) pvSetBuffer, + sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + DBGLOG(SCN, INFO, "prCmdGscnScnConfigParam assign prCmdGscnScnConfig\n"); + rCmdGscnScnConfig.u4BufferThreshold = prCmdGscnScnConfigParam->report_threshold; + rCmdGscnScnConfig.ucNumApPerScn = prCmdGscnScnConfigParam->max_ap_per_scan; + rCmdGscnScnConfig.u4NumScnToCache = prCmdGscnScnConfigParam->num_scans; + DBGLOG(SCN, INFO, " report_threshold %d report_threshold %d num_scans %d\n", + rCmdGscnScnConfig.u4BufferThreshold, + rCmdGscnScnConfig.ucNumApPerScn, rCmdGscnScnConfig.u4NumScnToCache); + if (scnFsmSetGSCNConfig(prAdapter, &rCmdGscnScnConfig) == TRUE) { + DBGLOG(SCN, INFO, "wlanoidSetGSCNAParam --->scnSetGSCNParam\n"); + return WLAN_STATUS_PENDING; + } else { + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get a gscan result +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +* +* \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS prGetGscnScnResultParm; + CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; + + DEBUGFUNC("wlanoidGetGSCNResult()"); + DBGLOG(SCN, INFO, "wlanoidGetGSCNResult v1\n"); + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(SCN, WARN, "Fail in set Periodically Scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4SetBufferLen != sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS)) { + DBGLOG(SCN, WARN, "(u4SetBufferLen != sizeof(CMD_GSCN_SCN_COFIG_T))\n"); + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + DBGLOG(SCN, WARN, "(pvSetBuffer == NULL)\n"); + return WLAN_STATUS_INVALID_DATA; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(SCN, INFO, "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prGetGscnScnResultParm = (P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) pvSetBuffer; + /* memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultParm, sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS) ); */ + + rGetGscnScnResultCmd.u4Num = prGetGscnScnResultParm->get_num; + rGetGscnScnResultCmd.ucFlush = prGetGscnScnResultParm->flush; + rGetGscnScnResultCmd.ucVersion = PSCAN_VERSION; + kalMemZero(rGetGscnScnResultCmd.aucReserved, sizeof(rGetGscnScnResultCmd.aucReserved)); + + if (scnFsmGetGSCNResult(prAdapter, &rGetGscnScnResultCmd) == TRUE) { + DBGLOG(SCN, INFO, "wlanoidGetGSCNResult --->scnFsmGetGSCNResult\n"); + return WLAN_STATUS_PENDING; + } else { + return WLAN_STATUS_FAILURE; + } + +} + +#if CFG_SUPPORT_HOTSPOT_2_0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by HS2.0 to set the assoc info, which is needed to add to +* Association request frame while join HS2.0 AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_IE_HS20_INDICATION_T prHS20IndicationIe; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetHS20AssocInfo"); + DBGLOG(OID, LOUD, "\r\n"); + + if (u4SetBufferLen == 0) + return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + + prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pvSetBuffer; + + prAdapter->prGlueInfo->ucHotspotConfig = prHS20IndicationIe->ucHotspotConfig; + prAdapter->prGlueInfo->fgConnectHS20AP = TRUE; + + DBGLOG(SEC, TRACE, "HS20 IE sz %u\n", u4SetBufferLen); + + kalMemCopy(prAdapter->prGlueInfo->aucHS20AssocInfoIE, pvSetBuffer, u4SetBufferLen); + prAdapter->prGlueInfo->u2HS20AssocInfoIELen = (UINT_16) u4SetBufferLen; + DBGLOG(SEC, TRACE, "HS20 Assoc Info IE sz %u\n", u4SetBufferLen); + + return WLAN_STATUS_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WSC to set the assoc info, which is needed to add to +* Association request frame while join WPS AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ +#if 0 + P_HS20_INFO_T prHS20Info = NULL; + P_IE_INTERWORKING_T prInterWorkingIe; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prHS20Info = &(prAdapter->rWifiVar.rHS20Info); + + DEBUGFUNC("wlanoidSetInterworkingInfo"); + DBGLOG(OID, TRACE, "\r\n"); + + if (u4SetBufferLen == 0) + return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + prInterWorkingIe = (P_IE_INTERWORKING_T) pvSetBuffer; + + prHS20Info->ucAccessNetworkOptions = prInterWorkingIe->ucAccNetOpt; + prHS20Info->ucVenueGroup = prInterWorkingIe->ucVenueGroup; + prHS20Info->ucVenueType = prInterWorkingIe->ucVenueType; + COPY_MAC_ADDR(prHS20Info->aucHESSID, prInterWorkingIe->aucHESSID); + + DBGLOG(SEC, TRACE, "IW IE sz %ld\n", u4SetBufferLen); +#endif + return WLAN_STATUS_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called by WSC to set the Roaming Consortium IE info, which is needed to +* add to Association request frame while join WPS AP. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ +#if 0 + P_HS20_INFO_T prHS20Info = NULL; + P_PARAM_HS20_ROAMING_CONSORTIUM_INFO prRCInfo; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prHS20Info = &(prAdapter->rWifiVar.rHS20Info); + + /* DEBUGFUNC("wlanoidSetRoamingConsortiumInfo"); */ + /* DBGLOG(HS2, TRACE, ("\r\n")); */ + + if (u4SetBufferLen == 0) + return WLAN_STATUS_INVALID_LENGTH; + + *pu4SetInfoLen = u4SetBufferLen; + prRCInfo = (P_PARAM_HS20_ROAMING_CONSORTIUM_INFO) pvSetBuffer; + + kalMemCopy(&(prHS20Info->rRCInfo), prRCInfo, sizeof(PARAM_HS20_ROAMING_CONSORTIUM_INFO)); + + /* DBGLOG(HS2, TRACE, ("RoamingConsortium IE sz %ld\n", u4SetBufferLen)); */ +#endif + return WLAN_STATUS_SUCCESS; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set_bssid_pool +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + if (u4SetBufferLen < sizeof(PARAM_HS20_SET_BSSID_POOL)) { + *pu4SetInfoLen = sizeof(PARAM_HS20_SET_BSSID_POOL); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + rWlanStatus = hs20SetBssidPool(prAdapter, pvSetBuffer, NETWORK_TYPE_AIS_INDEX); + + return rWlanStatus; +} /* end of wlanoidSendHS20GASRequest() */ + +#endif + +#if CFG_SUPPORT_ROAMING_ENC +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the MAC address the NIC is currently using. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + CMD_ROAMING_INFO_T *prCmdRoamingInfo; + + DEBUGFUNC("wlanoidSetRoamingInfo"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_ROAMING_INFO_T); + + if (u4SetBufferLen < sizeof(CMD_ROAMING_INFO_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + prCmdRoamingInfo = (CMD_ROAMING_INFO_T *) pvSetBuffer; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_ROAMING_INFO, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ROAMING_INFO_T), (PUINT_8) prCmdRoamingInfo, NULL, 0); +} +#endif /* CFG_SUPPORT_ROAMING_ENC */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set chip +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; + CMD_CHIP_CONFIG_T rCmdChipConfig; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DATA_STRUCT_INSPECTING_ASSERT(sizeof(prChipConfigInfo->aucCmd) == CHIP_CONFIG_RESP_SIZE); + DEBUGFUNC("wlanoidSetChipConfig"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prChipConfigInfo = (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T) pvSetBuffer; + kalMemZero(&rCmdChipConfig, sizeof(rCmdChipConfig)); + + rCmdChipConfig.u2Id = prChipConfigInfo->u2Id; + rCmdChipConfig.ucType = prChipConfigInfo->ucType; + rCmdChipConfig.ucRespType = prChipConfigInfo->ucRespType; + rCmdChipConfig.u2MsgSize = prChipConfigInfo->u2MsgSize; + if (rCmdChipConfig.u2MsgSize > CHIP_CONFIG_RESP_SIZE) { + DBGLOG(OID, INFO, "Chip config Msg Size %u is not valid (set)\n", rCmdChipConfig.u2MsgSize); + rCmdChipConfig.u2MsgSize = CHIP_CONFIG_RESP_SIZE; + } + kalMemCopy(rCmdChipConfig.aucCmd, prChipConfigInfo->aucCmd, rCmdChipConfig.u2MsgSize); + + DBGLOG(OID, TRACE, "rCmdChipConfig.aucCmd=%s\n", rCmdChipConfig.aucCmd); +#if 1 + rWlanStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_CHIP_CONFIG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CHIP_CONFIG_T), + (PUINT_8) &rCmdChipConfig, pvSetBuffer, u4SetBufferLen); +#endif + return rWlanStatus; +} /* wlanoidSetChipConfig */ + +WLAN_STATUS +wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_CMD_WFD_DEBUG_MODE_INFO_T prCmdWfdDebugModeInfo; + + DEBUGFUNC("wlanoidSetWFDDebugMode"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_WFD_DEBUG_MODE_INFO_T); + + if (u4SetBufferLen < sizeof(CMD_WFD_DEBUG_MODE_INFO_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + prCmdWfdDebugModeInfo = (CMD_WFD_DEBUG_MODE_INFO_T *) pvSetBuffer; + + DBGLOG(OID, INFO, "New WFD Debug: %d mode and period=0x%x\n", prCmdWfdDebugModeInfo->ucDebugMode, + prCmdWfdDebugModeInfo->u2PeriodInteval); + + prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode = (UINT_8) prCmdWfdDebugModeInfo->ucDebugMode; + prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.u2WfdSNShowPeiroid = + (UINT_16) prCmdWfdDebugModeInfo->u2PeriodInteval; + + return WLAN_STATUS_SUCCESS; +} /*wlanoidSetWfdDebugMode */ + + +#if (CFG_SUPPORT_TXR_ENC == 1) +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the MAC address the NIC is currently using. +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvQueryBuf A pointer to the buffer that holds the result of the +* query buffer +* \param[in] u4QueryBufLen The length of the query buffer +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_BUFFER_TOO_SHORT +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxRateInfo( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen) +{ + CMD_RLM_INFO_T *prCmdTxRInfo; + + DEBUGFUNC("wlanoidSetTxRateInfo"); + DBGLOG(OID, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_RLM_INFO_T); + + if (u4SetBufferLen < sizeof(CMD_RLM_INFO_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + prCmdTxRInfo = (CMD_RLM_INFO_T *)pvSetBuffer; + + DBGLOG(OID, INFO, " command = %u %u %u %u %d %u %u\n", + prCmdTxRInfo->u4Version, + prCmdTxRInfo->fgIsErrRatioEnhanceApplied, + prCmdTxRInfo->ucErrRatio2LimitMinRate, + prCmdTxRInfo->ucMinLegacyRateIdx, + prCmdTxRInfo->cMinRssiThreshold, + prCmdTxRInfo->fgIsRtsApplied, + prCmdTxRInfo->ucRecoverTime)); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_TX_AR_ERR_CONFIG, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_RLM_INFO_T), + (PUINT_8)prCmdTxRInfo, + NULL, + 0 + ); +} +#endif /* CFG_SUPPORT_TXR_ENC */ + +WLAN_STATUS +wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WIFI_SYSTEM_SUSPEND_CMD_T rSuspendCmd; + + if (!prAdapter || !pvSetBuffer) + return WLAN_STATUS_INVALID_DATA; + + rSuspendCmd.fgIsSystemSuspend = *(PBOOLEAN)pvSetBuffer; + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_SYSTEM_SUSPEND, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(BOOLEAN), + (PUINT_8)&rSuspendCmd, + NULL, + 0); +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c new file mode 100644 index 0000000000000..7ca7ee48922e1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/common/wlan_p2p.c @@ -0,0 +1,1654 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/common/wlan_p2p.c#8 +*/ + +/*! \file wlan_bow.c + \brief This file contains the Wi-Fi Direct commands processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_p2p.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support + * for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channel Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 23 2011 yuche.tsai + * NULL + * Fix Multicast Issue of P2P. + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 17 2011 wh.su + * [WCXRP00000571] [MT6620 Wi-Fi] [Driver] Not check the p2p role during set key + * Skip the p2p role for adding broadcast key issue. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * fixed compiling error while enable dbg. + * + * 03 08 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format + * issue[WCXRP00000509] [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix SD Request Query Length issue. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Service Discovery Request. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Wlan OID related function. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface + * for supporting Wi-Fi Direct Service Discovery ioctl implementations for P2P Service Discovery + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to + * ease physically continuous memory demands separate kalMemAlloc() into virtually-continuous + * and physically-continuous type to ease slab system pressure + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface + * for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T + * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * . + * + * 08 16 2010 george.huang + * NULL + * support wlanoidSetP2pPowerSaveProfile() in P2P + * + * 08 16 2010 george.huang + * NULL + * Support wlanoidSetNetworkAddress() for P2P + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * +** +*/ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ +#include "precomp.h" +#include "gl_p2p_ioctl.h" + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief command packet generation utility +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucCID Command ID +* \param[in] fgSetQuery Set or Query +* \param[in] fgNeedResp Need for response +* \param[in] pfCmdDoneHandler Function pointer when command is done +* \param[in] u4SetQueryInfoLen The length of the set/query buffer +* \param[in] pucInfoBuffer Pointer to set/query buffer +* +* +* \retval WLAN_STATUS_PENDING +* \retval WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + DEBUGFUNC("wlanoidSendSetQueryP2PCmd"); + DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + if (!prCmdInfo) { + DBGLOG(P2P, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = NETWORK_TYPE_P2P_INDEX; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set a key to Wi-Fi Direct driver +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + CMD_802_11_KEY rCmdKey; + P_PARAM_KEY_T prNewKey; + + DEBUGFUNC("wlanoidSetAddP2PKey"); + DBGLOG(REQ, INFO, "\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prNewKey = (P_PARAM_KEY_T) pvSetBuffer; + + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG(REQ, WARN, "Invalid key structure length (%d) greater than total buffer length (%d)\n", + (UINT_8) prNewKey->u4Length, (UINT_8) u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + /* Verify the key material length for key material buffer */ + else if (prNewKey->u4KeyLength > prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(REQ, WARN, "Invalid key material length (%d)\n", (UINT_8) prNewKey->u4KeyLength); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + /* Exception check */ + else if (prNewKey->u4KeyIndex & 0x0fffff00) + return WLAN_STATUS_INVALID_DATA; + /* Exception check, pairwise key must with transmit bit enabled */ + else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) { + return WLAN_STATUS_INVALID_DATA; + } else if (!(prNewKey->u4KeyLength == CCMP_KEY_LEN) && !(prNewKey->u4KeyLength == TKIP_KEY_LEN)) { + return WLAN_STATUS_INVALID_DATA; + } + /* Exception check, pairwise key must with transmit bit enabled */ + else if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { + if (((prNewKey->u4KeyIndex & 0xff) != 0) || + ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && (prNewKey->arBSSID[2] == 0xff) + && (prNewKey->arBSSID[3] == 0xff) && (prNewKey->arBSSID[4] == 0xff) + && (prNewKey->arBSSID[5] == 0xff))) { + return WLAN_STATUS_INVALID_DATA; + } + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* fill CMD_802_11_KEY */ + kalMemZero(&rCmdKey, sizeof(CMD_802_11_KEY)); + rCmdKey.ucAddRemove = 1; /* add */ + rCmdKey.ucTxKey = ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; + rCmdKey.ucKeyType = ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; + if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ + rCmdKey.ucIsAuthenticator = 0; + } else { /* group owner */ + rCmdKey.ucIsAuthenticator = 1; + } + COPY_MAC_ADDR(rCmdKey.aucPeerAddr, prNewKey->arBSSID); + rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; + if (prNewKey->u4KeyLength == CCMP_KEY_LEN) + rCmdKey.ucAlgorithmId = CIPHER_SUITE_CCMP; /* AES */ + else if (prNewKey->u4KeyLength == TKIP_KEY_LEN) + rCmdKey.ucAlgorithmId = CIPHER_SUITE_TKIP; /* TKIP */ + rCmdKey.ucKeyId = (UINT_8) (prNewKey->u4KeyIndex & 0xff); + rCmdKey.ucKeyLen = (UINT_8) prNewKey->u4KeyLength; + kalMemCopy(rCmdKey.aucKeyMaterial, (PUINT_8) prNewKey->aucKeyMaterial, rCmdKey.ucKeyLen); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + NULL, + sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to request Wi-Fi Direct driver to remove keys +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + CMD_802_11_KEY rCmdKey; + P_PARAM_REMOVE_KEY_T prRemovedKey; + + DEBUGFUNC("wlanoidSetRemoveP2PKey"); + ASSERT(prAdapter); + + if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + prRemovedKey = (P_PARAM_REMOVE_KEY_T) pvSetBuffer; + + /* Check bit 31: this bit should always 0 */ + if (prRemovedKey->u4KeyIndex & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); + return WLAN_STATUS_INVALID_DATA; + } + + /* Check bits 8 ~ 29 should always be 0 */ + if (prRemovedKey->u4KeyIndex & BITS(8, 29)) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, "invalid key index: 0x%08x\n", prRemovedKey->u4KeyIndex); + return WLAN_STATUS_INVALID_DATA; + } + + /* There should not be any key operation for P2P Device */ + if (kalP2PGetRole(prAdapter->prGlueInfo) == 0) + ; /* return WLAN_STATUS_NOT_ACCEPTED; */ + + kalMemZero((PUINT_8) &rCmdKey, sizeof(CMD_802_11_KEY)); + + rCmdKey.ucAddRemove = 0; /* remove */ + if (kalP2PGetRole(prAdapter->prGlueInfo) == 1) { /* group client */ + rCmdKey.ucIsAuthenticator = 0; + } else { /* group owner */ + rCmdKey.ucIsAuthenticator = 1; + } + kalMemCopy(rCmdKey.aucPeerAddr, (PUINT_8) prRemovedKey->arBSSID, MAC_ADDR_LEN); + rCmdKey.ucNetType = NETWORK_TYPE_P2P_INDEX; + rCmdKey.ucKeyId = (UINT_8) (prRemovedKey->u4KeyIndex & 0x000000ff); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_ADD_REMOVE_KEY, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + NULL, + sizeof(CMD_802_11_KEY), (PUINT_8) &rCmdKey, pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setting the IP address for pattern search function. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +* \return WLAN_STATUS_ADAPTER_NOT_READY +* \return WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + + DEBUGFUNC("wlanoidSetP2pNetworkAddress"); + DBGLOG(P2P, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) + return WLAN_STATUS_INVALID_DATA; + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + /* construct payload of command packet */ + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + + /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(UINT_32)); + + j++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to query the power save profile. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuf A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen != 0) { + ASSERT(pvQueryBuffer); + + *(PPARAM_POWER_MODE) pvQueryBuffer = + (PARAM_POWER_MODE) (prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile); + *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS status; + PARAM_POWER_MODE ePowerMode; + + DEBUGFUNC("wlanoidSetP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { + DBGLOG(REQ, WARN, "Invalid length %u\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } else if (*(PPARAM_POWER_MODE) pvSetBuffer >= Param_PowerModeMax) { + WARNLOG(("Invalid power mode %d\n", *(PPARAM_POWER_MODE) pvSetBuffer)); + return WLAN_STATUS_INVALID_DATA; + } + + ePowerMode = *(PPARAM_POWER_MODE) pvSetBuffer; + + if (prAdapter->fgEnCtiaPowerMode) { + if (ePowerMode == Param_PowerModeCAM) { + /*Todo:: Nothing*/ + /*Todo:: Nothing*/ + } else { + /* User setting to PS mode (Param_PowerModeMAX_PSP or Param_PowerModeFast_PSP) */ + + if (prAdapter->u4CtiaPowerMode == 0) { + /* force to keep in CAM mode */ + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (prAdapter->u4CtiaPowerMode == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + } + } + + status = nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_P2P_INDEX, ePowerMode, TRUE); + return status; +} /* end of wlanoidSetP2pPowerSaveProfile() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the power save profile. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = (P_PARAM_NETWORK_ADDRESS_LIST) pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + UINT_32 u4IpAddressCount, u4CmdSize; + PUINT_8 pucBuf = (PUINT_8) pvSetBuffer; + + DEBUGFUNC("wlanoidSetP2pSetNetworkAddress"); + DBGLOG(P2P, TRACE, "\n"); + DBGLOG(P2P, INFO, "wlanoidSetP2pSetNetworkAddress (%d)\n", (INT_16) u4SetBufferLen); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) + return WLAN_STATUS_INVALID_DATA; + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress))); + } + + /* construct payload of command packet */ + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + if (u4IpAddressCount == 0) + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST) kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) + return WLAN_STATUS_FAILURE; + + /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (UINT_8) u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + DBGLOG(P2P, INFO, "u4IpAddressCount (%u)\n", u4IpAddressCount); + for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j].aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(UINT_32)); + + j++; + + pucBuf = (PUINT_8) &prNetAddrIp->in_addr; + DBGLOG(P2P, INFO, "prNetAddrIp->in_addr:%d:%d:%d:%d\n", + (UINT_8) pucBuf[0], (UINT_8) pucBuf[1], + (UINT_8) pucBuf[2], (UINT_8) pucBuf[3]); + } + + prNetworkAddress = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prNetworkAddress + + (ULONG) (prNetworkAddress->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + rStatus = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_IP_ADDRESS, + TRUE, + FALSE, + TRUE, + nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, + u4CmdSize, (PUINT_8) prCmdNetworkAddressList, pvSetBuffer, u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} /* end of wlanoidSetP2pSetNetworkAddress() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Multicast Address List. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(REQ, WARN, "Invalid MC list length %u\n", u4SetBufferLen); + + *pu4SetInfoLen = (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if ((u4SetBufferLen / MAC_ADDR_LEN) > MAX_NUM_GROUP_ADDR) { + DBGLOG(REQ, WARN, "Too many MC addresses\n"); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + /* This CMD response is no need to complete the OID. Or the event would unsync. */ + return wlanoidSendSetQueryP2PCmd(prAdapter, CMD_ID_MAC_MCAST_ADDR, TRUE, FALSE, FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_MAC_MCAST_ADDR), + (PUINT_8) &rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); + +} /* end of wlanoidSetP2PMulticastList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send GAS frame for P2P Service Discovery Request +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_REQUEST)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } +/* rWlanStatus = p2pFsmRunEventSDRequest(prAdapter, (P_PARAM_P2P_SEND_SD_REQUEST)pvSetBuffer); */ + + return rWlanStatus; +} /* end of wlanoidSendP2PSDRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send GAS frame for P2P Service Discovery Response +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_RESPONSE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } +/* rWlanStatus = p2pFsmRunEventSDResponse(prAdapter, (P_PARAM_P2P_SEND_SD_RESPONSE)pvSetBuffer); */ + + return rWlanStatus; +} /* end of wlanoidGetP2PSDRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get GAS frame for P2P Service Discovery Request +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /*PUINT_8 pucPacketBuffer = NULL, pucTA = NULL;*/ +/* PUINT_8 pucChannelNum = NULL; */ + /*PUINT_16 pu2PacketLength = NULL;*/ + /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ + /*UINT_8 ucVersionNum = 0;*/ +/* UINT_8 ucChannelNum = 0, ucSeqNum = 0; */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_REQUEST)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, "Get Service Discovery Request\n"); +#if 0 + ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); + if (ucVersionNum == 0) { + P_PARAM_P2P_GET_SD_REQUEST prP2pGetSdReq = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; + + pucPacketBuffer = prP2pGetSdReq->aucPacketContent; + pu2PacketLength = &prP2pGetSdReq->u2PacketLength; + pucTA = &prP2pGetSdReq->rTransmitterAddr; + } else { + P_PARAM_P2P_GET_SD_REQUEST_EX prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST_EX) NULL; + + prP2pGetSdReqEx = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; + pucPacketBuffer = prP2pGetSdReqEx->aucPacketContent; + pu2PacketLength = &prP2pGetSdReqEx->u2PacketLength; + pucTA = &prP2pGetSdReqEx->rTransmitterAddr; + pucChannelNum = &prP2pGetSdReqEx->ucChannelNum; + ucSeqNum = prP2pGetSdReqEx->ucSeqNum; + } + + rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, + pucPacketBuffer, + (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_REQUEST)), + (PUINT_32) pu2PacketLength, pucChannelNum, ucSeqNum); +#else + *pu4QueryInfoLen = 0; + return rWlanStatus; +#endif + /* + prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketBuffer; + + kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); + + if (pu4QueryInfoLen) { + if (ucVersionNum == 0) + *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST) + (*pu2PacketLength)); + else + *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_REQUEST_EX) + (*pu2PacketLength)); + + } + + return rWlanStatus; + */ +} /* end of wlanoidGetP2PSDRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get GAS frame for P2P Service Discovery Response +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /*P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL;*/ + /* UINT_8 ucSeqNum = 0, */ + /*UINT_8 ucVersionNum = 0;*/ + /*PUINT_8 pucPacketContent = (PUINT_8) NULL, pucTA = (PUINT_8) NULL;*/ + /*PUINT_16 pu2PacketLength = (PUINT_16) NULL;*/ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_RESPONSE)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, "Get Service Discovery Response\n"); + +#if 0 + ucVersionNum = p2pFuncGetVersionNumOfSD(prAdapter); + if (ucVersionNum == 0) { + P_PARAM_P2P_GET_SD_RESPONSE prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_RESPONSE) NULL; + + prP2pGetSdRsp = (P_PARAM_P2P_GET_SD_REQUEST) pvQueryBuffer; + pucPacketContent = prP2pGetSdRsp->aucPacketContent; + pucTA = &prP2pGetSdRsp->rTransmitterAddr; + pu2PacketLength = &prP2pGetSdRsp->u2PacketLength; + } else { + P_PARAM_P2P_GET_SD_RESPONSE_EX prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) NULL; + + prP2pGetSdRspEx = (P_PARAM_P2P_GET_SD_RESPONSE_EX) pvQueryBuffer; + pucPacketContent = prP2pGetSdRspEx->aucPacketContent; + pucTA = &prP2pGetSdRspEx->rTransmitterAddr; + pu2PacketLength = &prP2pGetSdRspEx->u2PacketLength; + ucSeqNum = prP2pGetSdRspEx->ucSeqNum; + } + +/* rWlanStatus = p2pFuncGetServiceDiscoveryFrame(prAdapter, */ +/* pucPacketContent, */ +/* (u4QueryBufferLen - sizeof(PARAM_P2P_GET_SD_RESPONSE)), */ +/* (PUINT_32)pu2PacketLength, */ +/* NULL, */ +/* ucSeqNum); */ +#else + *pu4QueryInfoLen = 0; + return rWlanStatus; +#endif + /* + prWlanHdr = (P_WLAN_MAC_HEADER_T) pucPacketContent; + + kalMemCopy(pucTA, prWlanHdr->aucAddr2, MAC_ADDR_LEN); + + if (pu4QueryInfoLen) { + if (ucVersionNum == 0) + *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE) + *pu2PacketLength); + else + *pu4QueryInfoLen = (UINT_32) (sizeof(PARAM_P2P_GET_SD_RESPONSE_EX) + *pu2PacketLength); + } + + return rWlanStatus; + */ +} /* end of wlanoidGetP2PSDResponse() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to terminate P2P Service Discovery Phase +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_P2P_TERMINATE_SD_PHASE prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) NULL; + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) + break; + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) + break; + + if (u4SetBufferLen < sizeof(PARAM_P2P_TERMINATE_SD_PHASE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_TERMINATE_SD_PHASE); + rWlanStatus = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE) pvSetBuffer; + + if (EQUAL_MAC_ADDR(prP2pTerminateSD->rPeerAddr, aucNullAddr)) { + DBGLOG(P2P, TRACE, "Service Discovery Version 2.0\n"); +/* p2pFuncSetVersionNumOfSD(prAdapter, 2); */ + } + /* rWlanStatus = p2pFsmRunEventSDAbort(prAdapter); */ + + } while (FALSE); + + return rWlanStatus; +} /* end of wlanoidSetP2PTerminateSDPhase() */ + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) + ASSERT(pvSetBuffer); + + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SEC_CHECK, + FALSE, + TRUE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + u4SetBufferLen, (PUINT_8) pvSetBuffer, pvSetBuffer, u4SetBufferLen); + +} /* end of wlanoidSetSecCheckRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[out] pvQueryBuffer A pointer to the buffer that holds the result of +* the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_ADAPTER_NOT_READY +* \retval WLAN_STATUS_MULTICAST_FULL +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /* P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; */ + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = prAdapter->prGlueInfo; + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + if (u4QueryBufferLen > 256) + u4QueryBufferLen = 256; + + *pu4QueryInfoLen = u4QueryBufferLen; + +#if DBG + DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); +#endif + kalMemCopy((PUINT_8) (pvQueryBuffer + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer)), + prGlueInfo->prP2PInfo->aucSecCheckRsp, u4QueryBufferLen); + + return rWlanStatus; +} /* end of wlanoidGetSecCheckResponse() */ +#endif + +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; + CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; + + DEBUGFUNC("wlanoidSetNoaParam"); + DBGLOG(P2P, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); + rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; + rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; + rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), + (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); +#else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), + (PUINT_8) &rCmdNoaParam, pvSetBuffer, u4SetBufferLen); + +#endif + +} + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; + CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; + + DEBUGFUNC("wlanoidSetOppPsParam"); + DBGLOG(P2P, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + rCmdOppPsParam.u4CTwindowMs = prOppPsParam->u4CTwindowMs; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_OPPPS_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); +#else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_NOA_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdOppPsParam, pvSetBuffer, u4SetBufferLen); + +#endif + +} + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; + CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetUApsdParam"); + DBGLOG(P2P, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvSetBuffer); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T) pvSetBuffer; + + kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; + prAdapter->rWifiVar.fgSupportUAPSD = prUapsdParam->fgEnAPSD; + + rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; + rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; + rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; + rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; + prPmProfSetupInfo->ucBmpDeliveryAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); + prPmProfSetupInfo->ucBmpTriggerAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | (prUapsdParam->fgEnAPSD_AcVo << 3)); + + rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; + prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; + +#if 0 + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); +#else + return wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_UAPSD_PARAM, + TRUE, + FALSE, + TRUE, + NULL, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (PUINT_8) &rCmdUapsdParam, pvSetBuffer, u4SetBufferLen); + +#endif +} + +WLAN_STATUS +wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; +/* PUINT_8 pucOpChnl = (PUINT_8)pvQueryBuffer; */ + + do { + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) + break; + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) + break; + + if (u4QueryBufferLen < sizeof(UINT_8)) { + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } +#if 0 + if (!p2pFuncGetCurrentOpChnl(prAdapter, pucOpChnl)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } +#else + rResult = WLAN_STATUS_INVALID_DATA; + break; +#endif + /* + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_SUCCESS; + */ + + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pOpChannel */ + +WLAN_STATUS +wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; +/* PUINT_8 pucVersionNum = (PUINT_8)pvQueryBuffer; */ + + do { + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) + break; + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) + break; + + if (u4QueryBufferLen < sizeof(UINT_8)) { + *pu4QueryInfoLen = sizeof(UINT_8); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + } while (FALSE); + + return rResult; +} /* wlanoidQueryP2pVersion */ + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + UINT_8 ucVersionNum; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { + + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + *pu4SetInfoLen = sizeof(UINT_8); + + if (u4SetBufferLen < sizeof(UINT_8)) { + rResult = WLAN_STATUS_INVALID_LENGTH; + break; + } + + ucVersionNum = *((PUINT_8) pvSetBuffer); + + rResult = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rResult; +} /* wlanoidSetP2pSupplicantVersion */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set the WPS mode. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS status; + UINT_32 u4IsWPSmode = 0; + + DEBUGFUNC("wlanoidSetP2pWPSmode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (pvSetBuffer) + u4IsWPSmode = *(PUINT_32) pvSetBuffer; + else + u4IsWPSmode = 0; + + if (u4IsWPSmode) + prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 1; + else + prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = 0; + + status = nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + return status; +} /* end of wlanoidSetP2pWPSmode() */ + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryP2pRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) + ASSERT(pvQueryBuffer); + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Too short length %u\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->fgIsP2pLinkQualityValid == TRUE && + (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) <= CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI) prAdapter->rP2pLinkQuality.cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ + + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } +#ifdef LINUX + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, + *pu4QueryInfoLen, pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); +#else + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_LINK_QUALITY, + FALSE, + TRUE, + TRUE, + nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, u4QueryBufferLen); + +#endif +} /* wlanoidQueryP2pRssi */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h new file mode 100644 index 0000000000000..89de18c89c1cc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/CFG_Wifi_File.h @@ -0,0 +1,238 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/CFG_Wifi_File.h#1 +*/ + +/*! \file CFG_Wifi_File.h + \brief Collection of NVRAM structure used for YuSu project + + In this file we collect all compiler flags and detail the driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +/* +** Log: CFG_Wifi_File.h + * + * 09 08 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 08 09 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * update NVRAM data structure definition. + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition + * follow-up for CMD_5G_PWR_OFFSET_T definition change + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * +*/ + +#ifndef _CFG_WIFI_FILE_H +#define _CFG_WIFI_FILE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/* duplicated from nic_cmd_event.h to avoid header dependency */ +typedef struct _TX_PWR_PARAM_T { + INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ + INT_8 acReserved[3]; /* form MT6628 acReserved[0]=cTxPwr2G4Dsss */ + INT_8 cTxPwr2G4OFDM_BPSK; + INT_8 cTxPwr2G4OFDM_QPSK; + INT_8 cTxPwr2G4OFDM_16QAM; + INT_8 cTxPwr2G4OFDM_Reserved; + INT_8 cTxPwr2G4OFDM_48Mbps; + INT_8 cTxPwr2G4OFDM_54Mbps; + + INT_8 cTxPwr2G4HT20_BPSK; + INT_8 cTxPwr2G4HT20_QPSK; + INT_8 cTxPwr2G4HT20_16QAM; + INT_8 cTxPwr2G4HT20_MCS5; + INT_8 cTxPwr2G4HT20_MCS6; + INT_8 cTxPwr2G4HT20_MCS7; + + INT_8 cTxPwr2G4HT40_BPSK; + INT_8 cTxPwr2G4HT40_QPSK; + INT_8 cTxPwr2G4HT40_16QAM; + INT_8 cTxPwr2G4HT40_MCS5; + INT_8 cTxPwr2G4HT40_MCS6; + INT_8 cTxPwr2G4HT40_MCS7; + + INT_8 cTxPwr5GOFDM_BPSK; + INT_8 cTxPwr5GOFDM_QPSK; + INT_8 cTxPwr5GOFDM_16QAM; + INT_8 cTxPwr5GOFDM_Reserved; + INT_8 cTxPwr5GOFDM_48Mbps; + INT_8 cTxPwr5GOFDM_54Mbps; + + INT_8 cTxPwr5GHT20_BPSK; + INT_8 cTxPwr5GHT20_QPSK; + INT_8 cTxPwr5GHT20_16QAM; + INT_8 cTxPwr5GHT20_MCS5; + INT_8 cTxPwr5GHT20_MCS6; + INT_8 cTxPwr5GHT20_MCS7; + + INT_8 cTxPwr5GHT40_BPSK; + INT_8 cTxPwr5GHT40_QPSK; + INT_8 cTxPwr5GHT40_16QAM; + INT_8 cTxPwr5GHT40_MCS5; + INT_8 cTxPwr5GHT40_MCS6; + INT_8 cTxPwr5GHT40_MCS7; +} TX_PWR_PARAM_T, *P_TX_PWR_PARAM_T; + +typedef struct _PWR_5G_OFFSET_T { + INT_8 cOffsetBand0; /* 4.915-4.980G */ + INT_8 cOffsetBand1; /* 5.000-5.080G */ + INT_8 cOffsetBand2; /* 5.160-5.180G */ + INT_8 cOffsetBand3; /* 5.200-5.280G */ + INT_8 cOffsetBand4; /* 5.300-5.340G */ + INT_8 cOffsetBand5; /* 5.500-5.580G */ + INT_8 cOffsetBand6; /* 5.600-5.680G */ + INT_8 cOffsetBand7; /* 5.700-5.825G */ +} PWR_5G_OFFSET_T, *P_PWR_5G_OFFSET_T; + +typedef struct _PWR_PARAM_T { + UINT_32 au4Data[28]; + UINT_32 u4RefValue1; + UINT_32 u4RefValue2; +} PWR_PARAM_T, *P_PWR_PARAM_T; + +typedef struct _MT6620_CFG_PARAM_STRUCT { + /* 256 bytes of MP data */ + UINT_16 u2Part1OwnVersion; + UINT_16 u2Part1PeerVersion; + UINT_8 aucMacAddress[6]; + UINT_8 aucCountryCode[2]; + TX_PWR_PARAM_T rTxPwr; + UINT_8 aucEFUSE[144]; + UINT_8 ucTxPwrValid; + UINT_8 ucSupport5GBand; + UINT_8 fg2G4BandEdgePwrUsed; + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + + UINT_8 ucRegChannelListMap; + UINT_8 ucRegChannelListIndex; + UINT_8 aucRegSubbandInfo[36]; + + UINT_8 aucReserved2[256 - 240]; + + /* 256 bytes of function data */ + UINT_16 u2Part2OwnVersion; + UINT_16 u2Part2PeerVersion; + UINT_8 uc2G4BwFixed20M; + UINT_8 uc5GBwFixed20M; + UINT_8 ucEnable5GBand; + UINT_8 aucPreTailReserved; + UINT_8 uc2GRssiCompensation; + UINT_8 uc5GRssiCompensation; + UINT_8 fgRssiCompensationValidbit; + UINT_8 ucRxAntennanumber; + UINT_8 aucTailReserved[256 - 12]; +} MT6620_CFG_PARAM_STRUCT, *P_MT6620_CFG_PARAM_STRUCT, WIFI_CFG_PARAM_STRUCT, *P_WIFI_CFG_PARAM_STRUCT; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifndef DATA_STRUCT_INSPECTING_ASSERT +#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ +{ \ + switch (0) {case 0: case (expr): default:; } \ +} +#endif + +#define CFG_FILE_WIFI_REC_SIZE sizeof(WIFI_CFG_PARAM_STRUCT) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +static inline VOID nvramOffsetCheck(VOID) +{ + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion) == 256); + + DATA_STRUCT_INSPECTING_ASSERT(sizeof(WIFI_CFG_PARAM_STRUCT) == 512); + + DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) & 0x0001) == 0); + + DATA_STRUCT_INSPECTING_ASSERT((OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) & 0x0001) == 0); +} +#endif + +#endif /* _CFG_WIFI_FILE_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h new file mode 100644 index 0000000000000..a52053d5752db --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/config.h @@ -0,0 +1,1628 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/config.h#2 +*/ + +/*! \file "config.h" + \brief This file includes the various configurable parameters for customers + + This file ncludes the configurable parameters except the parameters indicate the turning-on/off of some features +*/ + +/* +** Log: config.h + * + * 07 13 2012 cp.wu + * [WCXRP00001259] [MT6620 Wi-Fi][Driver][Firmware] Send a signal to firmware for + * termination after SDIO error has happened + * [driver domain] add force reset by host-to-device interrupt mechanism + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 06 05 2012 tsaiyuan.hsu + * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" + * resolve build waring for "WNM_UNIT_TEST not defined".. + * + * 06 04 2012 cp.wu + * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development + * discussed with WH, privacy bit in associate response is not necessary to be checked, + * and identified as association failure when mismatching with beacon/probe response + * + * 05 11 2012 cp.wu + * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience + * show MAC address & source while initiliazation + * + * 04 20 2012 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * correct macro + * + * 04 12 2012 terry.wu + * NULL + * Add AEE message support + * 1) Show AEE warning(red screen) if SDIO access error occurs + * + * 03 29 2012 eason.tsai + * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define + * add conditional define. + * + * 03 02 2012 terry.wu + * NULL + * Enable CFG80211 Support. + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 11 23 2011 cp.wu + * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection + * add compile option to disable beacon content change detection. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 10 28 2011 cp.wu + * [MT6620 Wi-Fi][Win32 Driver] Enable 5GHz support as default + * enable 5GHz as default for DaVinci trunk and V2.1 driver release . + * + * 10 18 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * surpress compiler warning for MT6628 build + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * enable divided firmware downloading. + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware download path in divided scatters. + * + * 10 03 2011 cp.wu + * [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware downloading aggregated path. + * + * 09 28 2011 tsaiyuan.hsu + * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX + * enlarge window size only by 4. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * reuse firmware download logic of MT6620 for MT6628. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 08 15 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. + * + * 08 12 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. + * + * 08 09 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS definition for MT6620. + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 22 2011 jeffrey.chang + * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time + * modify driver to set OSC stable time after f/w download + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Refine compile flag. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add wifi direct connection enhancement method I, II & VI. + * + * 06 24 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * increase RX buffer number to have a 2:1 ping-pong ratio + * + * 06 23 2011 eddie.chen + * [WCXRP00000810] [MT5931][DRV/FW] Adjust TxRx Buffer number and Rx buffer size + * 1. Different TX RX buffer + * 2. Enlarge RX buffer and increase the number 8->11 + * 3. Separate the WINSZIE and RX buffer number + * 4. Fix RX maximum size in MAC + * + * 06 20 2011 terry.wu + * NULL + * Add BoW Rate Limitation. + * + * 06 17 2011 terry.wu + * NULL + * . + * + * 06 17 2011 terry.wu + * NULL + * Add BoW 11N support. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Add compile flag for persistent group support. + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Limit AIS to fixed channel same with BOW + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * Enable RX STBC capability + * + * 04 11 2011 george.huang + * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF + * . + * + * 04 08 2011 pat.lu + * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver + * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver + * + * 04 08 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * 1. correction: RX aggregation is not limited to SDIO but for all host interface options + * 2. add forward declarations for DBG-only symbols + * + * 04 06 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port + * 2. update perm_addr as well for MAC address + * 3. not calling check_mem_region() anymore for eHPI + * 4. correct MSC_CS macro for 0-based notation + * + * 04 01 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface + * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR + * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 + * + * 03 29 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with + * user space process for RESET_START and RESET_END events + * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism + * + * 03 22 2011 pat.lu + * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build + * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. + * + * 03 18 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the Anti_piracy check at driver . + * + * 03 17 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * enable roaming feature. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one + * to reduce physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 03 01 2011 george.huang + * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames + * Fix compile issue + * + * 02 25 2011 george.huang + * [WCXRP00000497] [MT6620 Wi-Fi][FW] Change default UAPSD AC assignment + * Assign all AC default to be U-APSD enabled. + * + * 02 14 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * Let the privacy check at hotspot mode default enable. + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 02 08 2011 cp.wu + * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number + * change version number to v1.2.0.0 for preparing v1.2 software package release. + * + * 02 01 2011 yarco.yang + * [WCXRP00000417] [MT6620 Driver] Change CFG_HANDLE_IST_IN_SDIO_CALLBACK from 1 to 0 for Interoperability + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 19 2011 wh.su + * [WCXRP00000370] [MT6620 Wi-Fi][Driver] Disable Rx RDG for workaround pre-N ccmp issue + * Not announce support Rx RDG for wokaround pre-N ccmp construct AAD issue.. + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause + * hardware header translation needs such information + * fill mac header length information for 802.1x frames. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support BOW only for Linux. + * + * 01 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Enable BOW and 4 physical links. + * + * 01 08 2011 yuche.tsai + * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, + * but the SSID length is still invalid. + * Modify CFG_SLT_SUPPORT default value. + * + * 01 08 2011 yuche.tsai + * [WCXRP00000341] [MT6620][SLT] Create Branch for SLT SW. + * Update configure flag. + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 15 2010 yuche.tsai + * NULL + * Update SLT Descriptor number configure in driver. + * + * 12 13 2010 chinglan.wang + * NULL + * Add WPS 1.0 feature flag to enable the WPS 1.0 function. + * + * 11 23 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Enable PM function by default + * + * 11 15 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * use config.mk WAPI config define. + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * use the config.mk define. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add option for enable/disable TX PWR gain adjustment (default: off) + * + * 10 20 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * enable the WAPI compiling flag as default + * + * 10 19 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 14 2010 wh.su + * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * Add a define CFG_TEST_ANDROID_DIRECT_GO compiling flag + * + * 10 08 2010 cm.chang + * NULL + * Remove unused compiling flags (TX_RDG and TX_SGI) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 05 2010 yarco.yang + * [WCXRP00000082] [MT6620 Wi-Fi][Driver]High throughput performance tuning + * Change CFG_IST_LOOP_COUNT from 2 to 1 to reduce unnecessary SDIO bus access + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 20 2010 cm.chang + * NULL + * Disable RX STBC by BB HEC based on MT6620E1_PHY_BUG v05.docx + * + * 09 17 2010 chinglan.wang + * NULL + * Add performance test option + * + * 09 10 2010 chinglan.wang + * NULL + * Modify for Software Migration Phase 2.10 for E2 FPGA + * + * 09 07 2010 yuche.tsai + * NULL + * Add a CFG for max common IE buffer size. + * + * 09 01 2010 cp.wu + * NULL + * restore configuration as before. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 chinglan.wang + * NULL + * Enable the MT6620_FPGA_BWCS value. + * + * 08 30 2010 chinglan.wang + * NULL + * Disable the FW encryption. + * + * 08 27 2010 chinglan.wang + * NULL + * Update configuration for MT6620_E1_PRE_ALPHA_1832_0827_2010 + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 cp.wu + * NULL + * add option for enabling AIS 5GHz scan + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cp.wu + * NULL + * 1) initialize variable for enabling short premable/short time slot. + * 2) add compile option for disabling online scan + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 23 2010 chinghwa.yu + * NULL + * Disable BOW Test. + * + * 08 23 2010 jeffrey.chang + * NULL + * fix config.h typo + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 21 2010 jeffrey.chang + * NULL + * 1) add sdio two setting + * 2) bug fix of sdio glue + * + * 08 09 2010 wh.su + * NULL + * let the firmware download default enabled. + * + * 08 07 2010 wh.su + * NULL + * adding the privacy related code for P2P network + * + * 08 05 2010 yuche.tsai + * NULL + * Add a configure flag for P2P unitest. + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 cp.wu + * + * 1) enable Ad-Hoc + * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 yuche.tsai + * + * Add for SLT support. + * + * 07 16 2010 cp.wu + * + * remove work-around in case SCN is not available. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor + * underflow under concurrent network operation + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * for first connection, if connecting failed do not enter into scan state. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add SCN compilation option. + * 2) when SCN is not turned on, BSSID_SCAN will generate a fake entry for 1st connection + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * set default compiling flag for security disable. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add config option for cfg80211. + * + * 05 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * set ATIMwindow default value to zero. + * + * 05 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add option for FPGA_BWCS & FPGA_V5 + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) enable CMD/EVENT ver 0.9 definition. + * 2) abandon use of ENUM_MEDIA_STATE + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change firmware name to WIFI_RAM_CODE. + * + * 05 07 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * disable bt-over-wifi configuration, turn it on after firmware finished implementation + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * re-enable power management + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable TCP/IP checksum offloading by default. + * + * 04 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * set CFG_ENABLE_FULL_PM to 1 as default to + * 1) acquire own before hardware access + * 2) set own back after hardware access + * + * 04 15 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * change firmware name + * + * 04 07 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * disable RX-enhanced response temporally, it seems the CQ is not resolved yet. + * + * 04 06 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * re-enable RX enhanced mode as WPD00003827 is resolved. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * turn off RX_ENHANCE mode by default. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) eliminate unused definitions + * * 2) ready bit will be polled for limited iteration + * + * 04 02 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * firmware download: Linux uses different firmware path + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load address & start address are now configured from config.h + * * due to the different configurations on FPGA and ASIC + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add options for full PM support. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * turn on FW-DOWNLOAD as default for release. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 05 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * change CFG_NUM_OF_QM_RX_PKT_NUM to 120 + * + * 03 04 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * . + * + * 03 04 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * increase RX buffer number to avoid RX buffer starvation. + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed the number of STA_RECs to 20 + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * and result is retrieved by get ATInfo instead + * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-16 22:12:28 GMT mtk02752 +** enable interrupt enhanced response, TX/RX Aggregation as default +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:38:43 GMT mtk02752 +** eliminate compile options which are obsolete or for emulation purpose +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 13:56:26 GMT MTK02468 +** Added RX buffer reordering configurations +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-12-04 12:09:09 GMT mtk02752 +** once enhanced intr/rx response is taken, RX must be access in aggregated basis +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 17:54:50 GMT mtk02752 +** correct a typo +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:47 GMT mtk01084 +** add defines +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:33:37 GMT mtk02752 +** add coalescing buffer definition for SD1_SD3_DATAPATH_INTEGRATION +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 20:32:40 GMT mtk02752 +** add CFG_TX_MAX_PKT_NUM for limiting queued TX packet +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 13:34:44 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION define for source control +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-13 13:54:11 GMT mtk01084 +** enable INT enhance mode by default +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-30 18:17:14 GMT mtk01084 +** add new define +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-10-29 19:47:36 GMT mtk01084 +** not use HIF loopback mode +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-10-13 21:58:33 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-09-09 17:26:08 GMT mtk01084 +** add CFG_TEST_WITH_MT5921 +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:02:30 GMT mtk01426 +** Update CFG_RX_COALESCING_BUFFER_SIZE +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-21 09:35:51 GMT mtk01461 +** Add CFG_TX_DBG_MGT_BUF to debug MGMT Buffer depth +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:52:21 GMT mtk01426 +** Add OOB_DATA_PRE_FIXED_LEN define +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-08 16:51:08 GMT mtk01084 +** update for FW download part +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:33:37 GMT mtk01461 +** Add SW pre test flag CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 00:29:18 GMT mtk01461 +** Fix CFG_COALESCING_BUFFER_SIZE if enable the CFG_TX_FRAGMENT +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-18 20:58:34 GMT mtk01426 +** Add CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-17 20:17:36 GMT mtk01426 +** Add CMD/Response related configure +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:21 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:21 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#ifdef MT6620 +#undef MT6620 +#endif + +#ifndef MT6628 +#define MT6628 +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* 2 Flags for OS capability */ + +#define MTK_WCN_SINGLE_MODULE 0 /* 1: without WMT */ + +#ifdef LINUX +#ifdef CONFIG_X86 +#define MTK_WCN_HIF_SDIO 0 +#else +#define MTK_WCN_HIF_SDIO 0 /* samp */ +#endif +#else +#define MTK_WCN_HIF_SDIO 0 +#endif + +#if (CFG_SUPPORT_AEE == 1) +#define CFG_ENABLE_AEE_MSG 1 +#else +#define CFG_ENABLE_AEE_MSG 0 +#endif + +#if CFG_ENABLE_AEE_MSG +#include +#endif + +/* 2 Flags for Driver Features */ +#define CFG_TX_FRAGMENT 1 /*!< 1: Enable TX fragmentation + 0: Disable */ +#define CFG_SUPPORT_PERFORMANCE_TEST 0 /*Only for performance Test */ + +#define CFG_COUNTRY_CODE NULL /* "US" */ + +#ifndef LINUX +#define CFG_FW_FILENAME L"WIFI_RAM_CODE" +#define CFG_FW_FILENAME_E6 L"WIFI_RAM_CODE_E6" +#else +#define CFG_FW_FILENAME "WIFI_RAM_CODE" +#endif +#ifndef LINUX +#define CFG_SUPPORT_CFG_FILE 0 +#else +#define CFG_SUPPORT_CFG_FILE 1 +#endif + +#define CFG_SUPPORT_CE_FCC_TXPWR_LIMIT 0 /* Support CE FCC Tx Power limit */ + +#define CFG_SUPPORT_802_11D 1 /*!< 1(default): Enable 802.11d + 0: Disable */ + +#define CFG_SUPPORT_RRM 0 /* Radio Reasource Measurement (802.11k) */ +#define CFG_SUPPORT_DFS 1 /* DFS (802.11h) */ + +#if (CFG_SUPPORT_DFS == 1) /* Add by Enlai */ +#define CFG_SUPPORT_QUIET 1 /* Quiet (802.11h) */ +#define CFG_SUPPORT_SPEC_MGMT 1 /* Spectrum Management (802.11h): TPC and DFS */ +#else +#define CFG_SUPPORT_QUIET 0 /* Quiet (802.11h) */ +#define CFG_SUPPORT_SPEC_MGMT 0 /* Spectrum Management (802.11h): TPC and DFS */ +#endif + +#define CFG_SUPPORT_RX_RDG 0 /* 11n feature. RX RDG capability */ +#define CFG_SUPPORT_MFB 0 /* 802.11n MCS Feedback responder */ +#define CFG_SUPPORT_RX_STBC 1 /* 802.11n RX STBC (1SS) */ +#define CFG_SUPPORT_RX_SGI 1 /* 802.11n RX short GI for both 20M and 40M BW */ +#define CFG_SUPPORT_RX_HT_GF 1 /* 802.11n RX HT green-field capability */ + +#define CFG_SUPPORT_ROAMING_ENC 0 /* enahnced roaming */ + +#define CFG_SUPPORT_TDLS 1 /* IEEE802.11z TDLS */ +#define CFG_SUPPORT_TDLS_DBG 0 /* TDLS debug */ +#define CFG_SUPPORT_STATISTICS 1 +#define CFG_SUPPORT_DBG_POWERMODE 1 /* for debugging power always active mode */ + +#define CFG_SUPPORT_GSCN 1 + +#define CFG_SUPPORT_TXR_ENC 0 /* enhanced tx rate switch */ + +#define CFG_SUPPORT_PERSIST_NETDEV 0 /* create NETDEV when system bootup */ + +#define CFG_FORCE_USE_20BW 1 +/*------------------------------------------------------------------------------ + * SLT Option + *------------------------------------------------------------------------------ + */ +#define CFG_SLT_SUPPORT 0 + +#define MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE 0 + +#if defined(MTK_AUTO_CHANNEL_SEL_SUPPORT_ENABLE) +#define CFG_AUTO_CHANNEL_SEL_SUPPORT 1 +#else +#define CFG_AUTO_CHANNEL_SEL_SUPPORT 0 +#endif + +#ifdef NDIS60_MINIPORT +#define CFG_NATIVE_802_11 1 + +#define CFG_TX_MAX_PKT_SIZE 2304 +#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 /* !< 1: Enable TCP/IP header checksum offload + 0: Disable */ +#define CFG_TCP_IP_CHKSUM_OFFLOAD 0 +#define CFG_WHQL_DOT11_STATISTICS 1 +#define CFG_WHQL_ADD_REMOVE_KEY 1 +#define CFG_WHQL_CUSTOM_IE 1 +#define CFG_WHQL_SAFE_MODE_ENABLED 1 + +#else +#define CFG_TCP_IP_CHKSUM_OFFLOAD 1 /* !< 1: Enable TCP/IP header checksum offload + 0: Disable */ +#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 +#define CFG_TX_MAX_PKT_SIZE 1600 +#define CFG_NATIVE_802_11 0 +#endif + +/* 2 Flags for Driver Parameters */ +/*------------------------------------------------------------------------------ + * Flags for EHPI Interface in Colibri Platform + *------------------------------------------------------------------------------ + */ +#define CFG_EHPI_FASTER_BUS_TIMING 0 /*!< 1: Do workaround for faster bus timing + 0(default): Disable */ + +/*------------------------------------------------------------------------------ + * Flags for HIFSYS Interface + *------------------------------------------------------------------------------ + */ +#ifdef _lint +#define _HIF_SDIO 0 /* samp */ +#endif + +#define CFG_SDIO_INTR_ENHANCE 1 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode + 0: Disable */ +#define CFG_SDIO_RX_ENHANCE 0 /*!< 1(default): Enable SDIO ISR & TX/RX status enhance mode + 0: Disable */ +#define CFG_SDIO_TX_AGG 1 /*!< 1: Enable SDIO TX enhance + mode(Multiple frames in single BLOCK CMD) + 0(default): Disable */ + +#define CFG_SDIO_RX_AGG 1 /*!< 1: Enable SDIO RX enhance + mode(Multiple frames in single BLOCK CMD) + 0(default): Disable */ + +#if (CFG_SDIO_RX_AGG == 1) && (CFG_SDIO_INTR_ENHANCE == 0) +#error "CFG_SDIO_INTR_ENHANCE should be 1 once CFG_SDIO_RX_AGG equals to 1" +#elif (CFG_SDIO_INTR_ENHANCE == 1 || CFG_SDIO_RX_ENHANCE == 1) && (CFG_SDIO_RX_AGG == 0) +#error "CFG_SDIO_RX_AGG should be 1 once CFG_SDIO_INTR_ENHANCE and/or CFG_SDIO_RX_ENHANCE equals to 1" +#endif + +#define CFG_SDIO_MAX_RX_AGG_NUM 0 /*!< 1: Setting the maximum RX aggregation number + 0(default): no limited */ + +#ifdef WINDOWS_CE +#define CFG_SDIO_PATHRU_MODE 1 /*!< 1: Support pass through (PATHRU) mode + 0: Disable */ +#else +#define CFG_SDIO_PATHRU_MODE 0 /*!< 0: Always disable if WINDOWS_CE is not defined */ +#endif + +#define CFG_MAX_RX_ENHANCE_LOOP_COUNT 3 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Integration + *------------------------------------------------------------------------------ + */ +#if defined(MT6620) +#define MT6620_FPGA_BWCS 0 +#define MT6620_FPGA_V5 0 + +#if (MT6620_FPGA_BWCS == 1) && (MT6620_FPGA_V5 == 1) +#error +#endif + +#if (MTK_WCN_HIF_SDIO == 1) +#define CFG_MULTI_ECOVER_SUPPORT 1 +#elif !defined(LINUX) +#define CFG_MULTI_ECOVER_SUPPORT 1 +#else +#define CFG_MULTI_ECOVER_SUPPORT 0 +#endif + +#define CFG_ENABLE_CAL_LOG 0 +#define CFG_REPORT_RFBB_VERSION 0 + +#elif defined(MT6628) + +#define CFG_MULTI_ECOVER_SUPPORT 0 + +#define CFG_ENABLE_CAL_LOG 1 +#define CFG_REPORT_RFBB_VERSION 1 + +#endif + +#define CFG_CHIP_RESET_SUPPORT 1 + +#if defined(MT6628) +#define CFG_EMBED_FIRMWARE_BUILD_DATE_CODE 1 +#endif + +/*------------------------------------------------------------------------------ + * Flags for workaround + *------------------------------------------------------------------------------ + */ +#if defined(MT6620) && (MT6620_FPGA_BWCS == 0) && (MT6620_FPGA_V5 == 0) +#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 +#else +#define MT6620_E1_ASIC_HIFSYS_WORKAROUND 0 +#endif + +/* SPM issue: suspend current is higher than deep idle */ +#define CFG_SPM_WORKAROUND_FOR_HOTSPOT 1 + +/*------------------------------------------------------------------------------ + * Flags for driver version + *------------------------------------------------------------------------------ + */ +#define CFG_DRV_OWN_VERSION \ + ((UINT_16)((NIC_DRIVER_MAJOR_VERSION << 8) | (NIC_DRIVER_MINOR_VERSION))) +#define CFG_DRV_PEER_VERSION ((UINT_16)0x0000) + +/*------------------------------------------------------------------------------ + * Flags for TX path which are OS dependent + *------------------------------------------------------------------------------ + */ +/*! NOTE(Kevin): If the Network buffer is non-scatter-gather like structure(without + * NETIF_F_FRAGLIST in LINUX), then we can set CFG_TX_BUFFER_IS_SCATTER_LIST to "0" + * for zero copy TX packets. + * For scatter-gather like structure, we set "1", driver will do copy frame to + * internal coalescing buffer before write it to FIFO. + */ +#if defined(LINUX) +#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 /*!< 1: Do frame copy before write to TX FIFO. + Used when Network buffer is scatter-gather. + 0(default): Do not copy frame */ +#else /* WINDOWS/WINCE */ +#define CFG_TX_BUFFER_IS_SCATTER_LIST 1 +#endif /* LINUX */ + +#if CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST +#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE * NIC_TX_BUFF_SUM) +#else +#define CFG_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE) +#endif /* CFG_SDIO_TX_AGG || CFG_TX_BUFFER_IS_SCATTER_LIST */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for TX path + *------------------------------------------------------------------------------ + */ + +/*! Maximum number of SW TX packet queue */ +#define CFG_TX_MAX_PKT_NUM 512 /* 256 must >= CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD * 2; + or wmm will fail when queue is full */ + +/*! Maximum number of SW TX CMD packet buffer */ +#define CFG_TX_MAX_CMD_PKT_NUM 32 + +/*! Maximum number of associated STAs */ +#define CFG_NUM_OF_STA_RECORD 20 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for RX path + *------------------------------------------------------------------------------ + */ + +/*! Max. descriptor number - sync. with firmware */ +#if CFG_SLT_SUPPORT +#define CFG_NUM_OF_RX0_HIF_DESC 42 +#else +#define CFG_NUM_OF_RX0_HIF_DESC 16 +#endif +#define CFG_NUM_OF_RX1_HIF_DESC 2 + +/*! Max. buffer hold by QM */ +#define CFG_NUM_OF_QM_RX_PKT_NUM 120 + +/*! Maximum number of SW RX packet buffer */ +#define CFG_RX_MAX_PKT_NUM ((CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC) * 3 \ + + CFG_NUM_OF_QM_RX_PKT_NUM) + +#define CFG_RX_REORDER_Q_THRESHOLD 8 + +#ifndef LINUX +#define CFG_RX_RETAINED_PKT_THRESHOLD \ + (CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC + CFG_NUM_OF_QM_RX_PKT_NUM) +#else +#define CFG_RX_RETAINED_PKT_THRESHOLD 0 +#endif + +/*! Maximum RX packet size, if exceed this value, drop incoming packet */ +/* 7.2.3 Maganement frames */ +#define CFG_RX_MAX_PKT_SIZE (28 + 2312 + 12 /*HIF_RX_HEADER_T*/) /* TODO: it should be + 4096 under emulation mode */ + +/*! Minimum RX packet size, if lower than this value, drop incoming packet */ +#define CFG_RX_MIN_PKT_SIZE 10 /*!< 802.11 Control Frame is 10 bytes */ + +#if CFG_SDIO_RX_AGG + /* extra size for CS_STATUS and enhanced response */ +#define CFG_RX_COALESCING_BUFFER_SIZE ((CFG_NUM_OF_RX0_HIF_DESC + 1) \ + * CFG_RX_MAX_PKT_SIZE) +#else +#define CFG_RX_COALESCING_BUFFER_SIZE (CFG_RX_MAX_PKT_SIZE) +#endif + +/*! RX BA capability */ +#define CFG_NUM_OF_RX_BA_AGREEMENTS 8 +#define CFG_RX_BA_MAX_WINSIZE 16 +#define CFG_RX_BA_INC_SIZE 4 +#define CFG_RX_MAX_BA_TID_NUM 8 +#define CFG_RX_REORDERING_ENABLED 1 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for CMD/RESPONSE + *------------------------------------------------------------------------------ + */ +#define CFG_RESPONSE_POLLING_TIMEOUT 512 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Protocol Stack + *------------------------------------------------------------------------------ + */ +/*! Maximum number of BSS in the SCAN list */ +#define CFG_MAX_NUM_BSS_LIST 64 + +#define CFG_MAX_COMMON_IE_BUF_LEN ((1500 * CFG_MAX_NUM_BSS_LIST) / 3) + +/*! Maximum size of Header buffer of each SCAN record */ +#define CFG_RAW_BUFFER_SIZE 1024 + +/*! Maximum size of IE buffer of each SCAN record */ +#define CFG_IE_BUFFER_SIZE 512 + +/*! Maximum number of STA records */ +#define CFG_MAX_NUM_STA_RECORD 32 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Power management + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FULL_PM 1 +#define CFG_ENABLE_WAKEUP_ON_LAN 0 +#if defined(CONFIG_ARCH_MT6755) || defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || \ + defined(CONFIG_ARCH_MT6753) || defined(CONFIG_ARCH_MT6580) +#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 1 /* debug which packet wake up host */ +#else +#define CFG_SUPPORT_WAKEUP_REASON_DEBUG 0 /* debug which packet wake up host */ +#endif +#define CFG_INIT_POWER_SAVE_PROF ENUM_PSP_FAST_SWITCH + +#define CFG_INIT_ENABLE_PATTERN_FILTER_ARP 0 + +#define CFG_INIT_UAPSD_AC_BMP 0 /* (BIT(3) | BIT(2) | BIT(1) | BIT(0)) */ + +/* #define CFG_SUPPORT_WAPI 0 */ +#define CFG_SUPPORT_WPS 1 +#define CFG_SUPPORT_WPS2 1 + +/*------------------------------------------------------------------------------ + * 802.11i RSN Pre-authentication PMKID cahce maximun number + *------------------------------------------------------------------------------ + */ +#define CFG_MAX_PMKID_CACHE 16 /*!< max number of PMKID cache + 16(default) : The Max PMKID cache */ +/*------------------------------------------------------------------------------ + * Auto Channel Selection Maximun Channel Number + *------------------------------------------------------------------------------ + */ + +#define MAX_AUTO_CHAL_NUM 23 /* Ch1~Ch14,Ch36,Ch40,Ch44, + Ch48,Ch149,Ch153,Ch157,Ch161 */ +/*------------------------------------------------------------------------------ + * FAST SCAN + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FAST_SCAN 0 +#define CFG_CN_SUPPORT_CLASS121 0 /* Add Class 121, 5470-5725MHz, support for China domain */ +#if CFG_ENABLE_FAST_SCAN + #define CFG_FAST_SCAN_DWELL_TIME 40 + #define CFG_FAST_SCAN_REG_DOMAIN_DEF_IDX 10 +#endif +/*------------------------------------------------------------------------------ + * Flags and Parameters for Ad-Hoc + *------------------------------------------------------------------------------ + */ +#define CFG_INIT_ADHOC_FREQ (2462000) +#define CFG_INIT_ADHOC_MODE AD_HOC_MODE_MIXED_11BG +#define CFG_INIT_ADHOC_BEACON_INTERVAL (100) +#define CFG_INIT_ADHOC_ATIM_WINDOW (0) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Maximum Scan SSID number + *------------------------------------------------------------------------------ + */ +#define CFG_SCAN_SSID_MAX_NUM (4) +#define CFG_SCAN_SSID_MATCH_MAX_NUM (16) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Load Setup Default + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags for enable 802.11A Band setting + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Interrupt Process + *------------------------------------------------------------------------------ + */ +#if defined(_HIF_SDIO) && defined(WINDOWS_CE) +#define CFG_IST_LOOP_COUNT 8 +#else +#define CFG_IST_LOOP_COUNT 8 +#endif /* _HIF_SDIO */ + +#define CFG_INT_WRITE_CLEAR 0 + +#if defined(LINUX) +#define CFG_DBG_GPIO_PINS 0 /* if 1, use MT6516 GPIO pin to log TX behavior */ +#endif + +/* 2 Flags for Driver Debug Options */ +/*------------------------------------------------------------------------------ + * Flags of TX Debug Option. NOTE(Kevin): Confirm with SA before modifying following flags. + *------------------------------------------------------------------------------ + */ +#define CFG_DBG_MGT_BUF 1 /*!< 1: Debug statistics usage of MGMT Buffer + 0: Disable */ + +#define CFG_HIF_STATISTICS 0 + +#define CFG_HIF_RX_STARVATION_WARNING 0 + +#define CFG_STARTUP_DEBUG 0 + +#define CFG_RX_PKTS_DUMP 1 + +/*------------------------------------------------------------------------------ + * Flags of Firmware Download Option. + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FW_DOWNLOAD 1 + +#define CFG_ENABLE_FW_DOWNLOAD_ACK 1 +#define CFG_ENABLE_FW_ENCRYPTION 1 + +#if defined(MT6628) +#define CFG_ENABLE_FW_DOWNLOAD_AGGREGATION 0 +#define CFG_ENABLE_FW_DIVIDED_DOWNLOAD 1 +#endif + +#if defined(MT6620) +#if MT6620_FPGA_BWCS +#define CFG_FW_LOAD_ADDRESS 0x10014000 +#define CFG_OVERRIDE_FW_START_ADDRESS 0 +#define CFG_FW_START_ADDRESS 0x10014001 +#elif MT6620_FPGA_V5 +#define CFG_FW_LOAD_ADDRESS 0x10008000 +#define CFG_OVERRIDE_FW_START_ADDRESS 0 +#define CFG_FW_START_ADDRESS 0x10008001 +#else +#define CFG_FW_LOAD_ADDRESS 0x10008000 +#define CFG_OVERRIDE_FW_START_ADDRESS 0 +#define CFG_FW_START_ADDRESS 0x10008001 +#endif +#elif defined(MT6628) +#define CFG_FW_LOAD_ADDRESS 0x00060000 +#define CFG_OVERRIDE_FW_START_ADDRESS 1 +#define CFG_FW_START_ADDRESS 0x00060000 +#define CFG_START_ADDRESS_IS_1ST_SECTION_ADDR 1 +#endif + +/*------------------------------------------------------------------------------ + * Flags of Bluetooth-over-WiFi (BT 3.0 + HS) support + *------------------------------------------------------------------------------ + */ + +#ifdef LINUX +#ifdef CONFIG_X86 +#define CFG_ENABLE_BT_OVER_WIFI 0 +#else +#define CFG_ENABLE_BT_OVER_WIFI 1 +#endif +#else +#define CFG_ENABLE_BT_OVER_WIFI 0 +#endif + +#define CFG_BOW_SEPARATE_DATA_PATH 1 + +#define CFG_BOW_PHYSICAL_LINK_NUM 4 + +#define CFG_BOW_TEST 0 + +#define CFG_BOW_LIMIT_AIS_CHNL 1 + +#define CFG_BOW_SUPPORT_11N 0 + +#define CFG_BOW_RATE_LIMITATION 1 + +/*------------------------------------------------------------------------------ + * Flags of Wi-Fi Direct support + *------------------------------------------------------------------------------ + */ +#ifdef LINUX +#ifdef CONFIG_X86 +#define CFG_ENABLE_WIFI_DIRECT 0 +#define CFG_SUPPORT_802_11W 0 +#else +#define CFG_ENABLE_WIFI_DIRECT 1 +#define CFG_SUPPORT_802_11W 0 /*!< 0(default): Disable 802.11W */ +#endif +#else +#define CFG_ENABLE_WIFI_DIRECT 0 +#define CFG_SUPPORT_802_11W 0 /* Not support at WinXP */ +#endif + +#define CFG_SUPPORT_PERSISTENT_GROUP 0 + +#define CFG_TEST_WIFI_DIRECT_GO 0 + +#define CFG_TEST_ANDROID_DIRECT_GO 0 + +#define CFG_UNITEST_P2P 0 + +/* + * Enable cfg80211 option after Android 2.2(Froyo) is suggested, + * cfg80211 on linux 2.6.29 is not mature yet + */ +#define CFG_ENABLE_WIFI_DIRECT_CFG_80211 1 + +#define CFG_SUPPORT_HOTSPOT_OPTIMIZATION 1 +#define CFG_HOTSPOT_OPTIMIZATION_BEACON_INTERVAL 300 +#define CFG_HOTSPOT_OPTIMIZATION_DTIM 1 + +/*------------------------------------------------------------------------------ + * Configuration Flags (Linux Only) + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_EXT_CONFIG 0 + +/*------------------------------------------------------------------------------ + * Statistics Buffering Mechanism + *------------------------------------------------------------------------------ + */ +#if CFG_SUPPORT_PERFORMANCE_TEST +#define CFG_ENABLE_STATISTICS_BUFFERING 1 +#else +#define CFG_ENABLE_STATISTICS_BUFFERING 0 +#endif +#define CFG_STATISTICS_VALID_CYCLE 2000 +#define CFG_LINK_QUALITY_VALID_PERIOD 5000 + +/*------------------------------------------------------------------------------ + * Migration Option + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_ADHOC 0 +#define CFG_SUPPORT_AAA 1 + +#define CFG_SUPPORT_BCM 0 +#define CFG_SUPPORT_BCM_BWCS 0 +#define CFG_SUPPORT_BCM_BWCS_DEBUG 0 + +#define CFG_SUPPORT_RDD_TEST_MODE 0 + +#define CFG_SUPPORT_PWR_MGT 1 + +#define CFG_RSN_MIGRATION 1 + +#define CFG_PRIVACY_MIGRATION 1 + +#define CFG_ENABLE_HOTSPOT_PRIVACY_CHECK 1 + +#define CFG_MGMT_FRAME_HANDLING 1 + +#define CFG_MGMT_HW_ACCESS_REPLACEMENT 0 + +#if CFG_SUPPORT_PERFORMANCE_TEST + +#else + +#endif + +#define CFG_SUPPORT_AIS_5GHZ 1 +#define CFG_SUPPORT_BEACON_CHANGE_DETECTION 0 + +/*------------------------------------------------------------------------------ + * Option for NVRAM and Version Checking + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_NVRAM 1 +#define CFG_NVRAM_EXISTENCE_CHECK 1 +#define CFG_SW_NVRAM_VERSION_CHECK 1 +#define CFG_SUPPORT_NIC_CAPABILITY 1 + +/*------------------------------------------------------------------------------ + * CONFIG_TITLE : Stress Test Option + * OWNER : Puff Wen + * Description : For stress test only. DO NOT enable it while normal operation + *------------------------------------------------------------------------------ + */ +#define CFG_STRESS_TEST_SUPPORT 0 + +/*------------------------------------------------------------------------------ + * Flags for LINT + *------------------------------------------------------------------------------ + */ +#define LINT_SAVE_AND_DISABLE /*lint -save -e* */ + +#define LINT_RESTORE /*lint -restore */ + +#define LINT_EXT_HEADER_BEGIN LINT_SAVE_AND_DISABLE + +#define LINT_EXT_HEADER_END LINT_RESTORE + +/*------------------------------------------------------------------------------ + * Flags of Features + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_QOS 1 /* Enable/disable QoS TX, AMPDU */ +#define CFG_SUPPORT_AMPDU_TX 1 +#define CFG_SUPPORT_AMPDU_RX 1 +#define CFG_SUPPORT_TSPEC 0 /* Enable/disable TS-related Action frames handling */ +#define CFG_SUPPORT_UAPSD 1 +#define CFG_SUPPORT_UL_PSMP 0 + +#define CFG_SUPPORT_ROAMING 1 /* Roaming System */ +#define CFG_SUPPORT_SWCR 1 + +#define CFG_SUPPORT_ANTI_PIRACY 1 + +#define CFG_SUPPORT_OSC_SETTING 1 + +#define CFG_SUPPORT_P2P_RSSI_QUERY 0 + +#define CFG_SHOW_MACADDR_SOURCE 1 + +#define CFG_SUPPORT_802_11V 0 /* Support 802.11v Wireless Network Management */ +#define CFG_SUPPORT_802_11V_TIMING_MEASUREMENT 0 +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (CFG_SUPPORT_802_11V == 0) +#error "CFG_SUPPORT_802_11V should be 1 once CFG_SUPPORT_802_11V_TIMING_MEASUREMENT equals to 1" +#endif +#if (CFG_SUPPORT_802_11V == 0) +#define WNM_UNIT_TEST 0 +#endif + +#define CFG_DRIVER_COMPOSE_ASSOC_REQ 1 + +#define CFG_STRICT_CHECK_CAPINFO_PRIVACY 0 + +#define CFG_SUPPORT_WFD 1 + +#define CFG_SUPPORT_WFD_COMPOSE_IE 1 + +/*------------------------------------------------------------------------------ + * Flags of Packet Lifetime Profiling Mechanism + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_PKT_LIFETIME_PROFILE 1 + +#define CFG_ENABLE_PER_STA_STATISTICS 1 + +#define CFG_PRINT_RTP_PROFILE 0 /* If want to enable WFD Debug, please change it to 1. */ +#define CFG_PRINT_RTP_SN_SKIP 0 + +#define CFG_SUPPORT_PWR_LIMIT_COUNTRY 1 +/*------------------------------------------------------------------------------ + * Flags of bus error tolerance + *------------------------------------------------------------------------------ + */ +#define CFG_FORCE_RESET_UNDER_BUS_ERROR 0 + +/*------------------------------------------------------------------------------ + * Build Date Code Integration + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_BUILD_DATE_CODE 1 + +/*------------------------------------------------------------------------------ + * Flags for prepare the FW compile flag + *------------------------------------------------------------------------------ + */ +#define COMPILE_FLAG0_GET_STA_LINK_STATUS (1<<0) +#define COMPILE_FLAG0_WFD_ENHANCEMENT_PROTECT (1<<1) + +/*------------------------------------------------------------------------------ + * Flags of Batch Scan SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_BATCH_SCAN 0 +#define CFG_BATCH_MAX_MSCAN 2 + +/*------------------------------------------------------------------------------ + * Flags of Channel Environment SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_GET_CH_ENV 1 + +/*------------------------------------------------------------------------------ + * Flags of THERMO_THROTTLING SUPPORT + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_THERMO_THROTTLING 1 +#define WLAN_INCLUDE_PROC 1 + +#define CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE 1 +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONFIG_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h new file mode 100644 index 0000000000000..af586063c21af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/debug.h @@ -0,0 +1,466 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/debug.h#1 +*/ + +/*! \file debug.h + \brief Definition of SW debugging level. + + In this file, it describes the definition of various SW debugging levels and + assert functions. +*/ + +/* +** Log: debug.h + * + * 12 16 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * fixed the Windows DDK free build compiling error. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 07 2011 wh.su + * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * . + * + * 09 23 2010 cp.wu + * NULL + * add BOW index for debugging message and passing compilation + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add one more debug moduel for P2P. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add debug module index for cnm and ais. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add CFG_STARTUP_DEBUG for debugging starting up issue. + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-29 19:47:50 GMT mtk01084 +** add emu category +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-17 18:12:04 GMT mtk01426 +** Don't use dynamic memory allocate for debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:29 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _DEBUG_H +#define _DEBUG_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#ifndef BUILD_QA_DBG +#define BUILD_QA_DBG 0 +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +extern UINT_8 aucDebugModule[]; +extern UINT_32 u4DebugModule; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Define debug category (class): + * (1) ERROR (2) WARN (3) STATE (4) EVENT (5) TRACE (6) INFO (7) LOUD (8) TEMP + */ +#define DBG_CLASS_ERROR BIT(0) +#define DBG_CLASS_WARN BIT(1) +#define DBG_CLASS_STATE BIT(2) +#define DBG_CLASS_EVENT BIT(3) +#define DBG_CLASS_TRACE BIT(4) +#define DBG_CLASS_INFO BIT(5) +#define DBG_CLASS_LOUD BIT(6) +#define DBG_CLASS_TEMP BIT(7) +#define DBG_CLASS_MASK BITS(0, 7) + +#if defined(LINUX) +#define DBG_PRINTF_64BIT_DEC "lld" + +#else /* Windows */ +#define DBG_PRINTF_64BIT_DEC "I64d" + +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Define debug module index */ +typedef enum _ENUM_DBG_MODULE_T { + DBG_INIT_IDX = 0, /* For driver initial */ + DBG_HAL_IDX, /* For HAL(HW) Layer */ + DBG_INTR_IDX, /* For Interrupt */ + DBG_REQ_IDX, + DBG_TX_IDX, + DBG_RX_IDX, + DBG_RFTEST_IDX, /* For RF test mode */ + DBG_EMU_IDX, /* Developer specific */ + + DBG_SW1_IDX, /* Developer specific */ + DBG_SW2_IDX, /* Developer specific */ + DBG_SW3_IDX, /* Developer specific */ + DBG_SW4_IDX, /* Developer specific */ + + DBG_HEM_IDX, /* HEM */ + DBG_AIS_IDX, /* AIS */ + DBG_RLM_IDX, /* RLM */ + DBG_MEM_IDX, /* RLM */ + DBG_CNM_IDX, /* CNM */ + DBG_RSN_IDX, /* RSN */ + DBG_BSS_IDX, /* BSS */ + DBG_SCN_IDX, /* SCN */ + DBG_SAA_IDX, /* SAA */ + DBG_AAA_IDX, /* AAA */ + DBG_P2P_IDX, /* P2P */ + DBG_QM_IDX, /* QUE_MGT */ + DBG_SEC_IDX, /* SEC */ + DBG_BOW_IDX, /* BOW */ + DBG_WAPI_IDX, /* WAPI */ + DBG_ROAMING_IDX, /* ROAMING */ + DBG_TDLS_IDX, /* TDLS *//* CFG_SUPPORT_TDLS */ + DBG_OID_IDX, + DBG_NIC_IDX, + + DBG_MODULE_NUM /* Notice the XLOG check */ +} ENUM_DBG_MODULE_T; + +/* XLOG */ +/* #define XLOG_DBG_MODULE_IDX 28 */ /* DBG_MODULE_NUM */ +/* #if (XLOG_DBG_MODULE_IDX != XLOG_DBG_MODULE_IDX) */ +/* #error "Please modify the DBG_MODULE_NUM and make sure this include at XLOG" */ +/* #endif */ + +/* Define who owns developer specific index */ +#define DBG_YARCO_IDX DBG_SW1_IDX +#define DBG_KEVIN_IDX DBG_SW2_IDX +#define DBG_CMC_IDX DBG_SW3_IDX +#define DBG_GEORGE_IDX DBG_SW4_IDX + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Debug print format string for the OS system time */ +#define OS_SYSTIME_DBG_FORMAT "0x%08x" + +/* Debug print argument for the OS system time */ +#define OS_SYSTIME_DBG_ARGUMENT(systime) (systime) + +/* Debug print format string for the MAC Address */ +#define MACSTR "%pM" +/* "%02x:%02x:%02x:%02x:%02x:%02x" */ + +/* Debug print argument for the MAC Address */ +#define MAC2STR(a) a +/* ((PUINT_8)a)[0], ((PUINT_8)a)[1], ((PUINT_8)a)[2], ((PUINT_8)a)[3], ((PUINT_8)a)[4], ((PUINT_8)a)[5] */ + +/* The pre-defined format to dump the value of a varaible with its name shown. */ +#define DUMPVAR(variable, format) (#variable " = " format "\n", variable) + +/* The pre-defined format to dump the MAC type value with its name shown. */ +#define DUMPMACADDR(addr) (#addr " = %pM\n", (addr)) + +/* Basiclly, we just do renaming of KAL functions although they should + * be defined as "Nothing to do" if DBG=0. But in some compiler, the macro + * syntax does not support #define LOG_FUNC(x,...) + * + * A caller shall not invoke these three macros when DBG=0. + */ + +/*LOG_FUNC("[wlan]%s:(" #_Module " " #_Class ") "_Fmt, __func__, ##__VA_ARGS__);*/ + +#define LOG_FUNC kalPrint + +#if defined(LINUX) +#define DBGLOG(_Module, _Class, _Fmt, ...) \ + do { \ + if ((aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) == 0) \ + break; \ + LOG_FUNC("%s:(" #_Module " " #_Class ")"_Fmt, __func__, ##__VA_ARGS__); \ + } while (0) +#else +#define DBGLOG(_Module, _Class, _Fmt) +#endif + +#if DBG + +#define TMP_BUF_LEN 256 +#define TMP_WBUF_LEN (TMP_BUF_LEN * 2) + +extern PINT_16 g_wbuf_p; +extern PINT_8 g_buf_p; + + /* If __FUNCTION__ is already defined by compiler, we just use it. */ +#if defined(__func__) +#define DEBUGFUNC(_Func) +#else +#define DEBUGFUNC(_Func) \ + static const char __func__[] = _Func +#endif + +#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ + LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ + dumpMemory8((PUINT_8) (_StartAddr), (UINT_32) (_Length)); \ + } \ + } + +#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_##_Module##_IDX] & DBG_CLASS_##_Class) { \ + LOG_FUNC("%s: (" #_Module " " #_Class ")\n", __func__); \ + dumpMemory32((PUINT_32) (_StartAddr), (UINT_32) (_Length)); \ + } \ + } + /*lint -restore */ + + /*lint -save -e961 use of '#undef' is discouraged */ +#undef ASSERT + /*lint -restore */ + +#ifdef _lint +#define ASSERT(_exp) \ + { \ + if (!(_exp)) { \ + do {} while (1); \ + } \ + } +#else +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ + kalBreakPoint(); \ + } \ + } +#endif /* _lint */ + +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + kalBreakPoint(); \ + } \ + } + +#define DISP_STRING(_str) _str + +#else /* !DBG */ + +#define DEBUGFUNC(_Func) +#define INITLOG(_Fmt) +#define ERRORLOG(_Fmt) +#define WARNLOG(_Fmt) + +#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) +#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) + +#undef ASSERT + +#if BUILD_QA_DBG +#if defined(LINUX) /* For debugging in Linux w/o GDB */ +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ + kalBreakPoint(); \ + } \ + } + +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + kalBreakPoint(); \ + } \ + } +#else +#ifdef WINDOWS_CE +#define UNICODE_TEXT(_msg) TEXT(_msg) +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), \ + __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } + +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), \ + __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } +#else +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + kalBreakPoint(); \ + } \ + } + +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + kalBreakPoint(); \ + } \ + } +#endif /* WINDOWS_CE */ +#endif /* LINUX */ +#else +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ + } \ + } + +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Warning at %s:%d (%s)\n", __func__, __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + } \ + } +#endif /* BUILD_QA_DBG */ + +#define DISP_STRING(_str) "" + +#endif /* DBG */ + +#if CFG_STARTUP_DEBUG +#if defined(LINUX) +#define DBGPRINTF kalPrint +#else +#define DBGPRINTF DbgPrint +#endif +#else +#define DBGPRINTF(...) +#endif + +/* The following macro is used for debugging packed structures. */ +#ifndef DATA_STRUCT_INSPECTING_ASSERT +#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ +{ \ + switch (0) {case 0: case (expr): default:; } \ +} +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID dumpMemory8(IN PUINT_8 pucStartAddr, IN UINT_32 u4Length); + +VOID dumpMemory32(IN PUINT_32 pu4StartAddr, IN UINT_32 u4Length); + +VOID wlanDebugInit(VOID); +VOID wlanDebugUninit(VOID); +VOID wlanTraceReleaseTcRes(P_ADAPTER_T prAdapter, PUINT_8 aucTxRlsCnt, UINT_8 ucAvailable); +VOID wlanTraceTxCmd(P_CMD_INFO_T prCmd); +VOID wlanDumpTcResAndTxedCmd(PUINT_8 pucBuf, UINT_32 maxLen); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _DEBUG_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h new file mode 100644 index 0000000000000..108860c80e2d4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/link.h @@ -0,0 +1,368 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/link.h#1 +*/ + +/*! \file link.h + \brief Definition for simple doubly linked list operations. + + In this file we define the simple doubly linked list data structure and its + operation MACROs and INLINE functions. +*/ + +/* +** Log: link.h + * + * 08 05 2010 yuche.tsai + * NULL + * Modify a MACRO of LINK_FOR_EACH_SAFE for compile error. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833] [MT6620 and MT5931] Driver migration + * . + * + * + * + * + * May 4 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * add WIFI to BORA source control +** \main\maintrunk.MT5921\8 2008-10-16 15:57:11 GMT mtk01461 +** Update driver to fix lint warning +** \main\maintrunk.MT5921\7 2008-08-10 18:47:53 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\6 2007-12-11 00:09:00 GMT mtk01461 +** Add macro for checking valid list +** \main\maintrunk.MT5921\5 2007-11-13 14:27:01 GMT mtk01461 +** Add LINK_IS_INVALID macro +** Revision 1.1.1.1 2007/06/22 08:09:05 MTK01461 +** no message +** +*/ + +#ifndef _LINK_H +#define _LINK_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* May cause page fault & unalignment issue (data abort) */ +#define INVALID_LINK_POISON1 ((VOID *) 0x00100101) +/* Used to verify that nonbody uses non-initialized link entries. */ +#define INVALID_LINK_POISON2 ((VOID *) 0x00100201) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Simple Doubly Linked List Structures - Entry Part */ +typedef struct _LINK_ENTRY_T { + struct _LINK_ENTRY_T *prNext, *prPrev; +} LINK_ENTRY_T, *P_LINK_ENTRY_T; + +/* Simple Doubly Linked List Structures - List Part */ +typedef struct _LINK_T { + P_LINK_ENTRY_T prNext; + P_LINK_ENTRY_T prPrev; + UINT_32 u4NumElem; +} LINK_T, *P_LINK_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#if 0 /* No one use it, temporarily mark it for [Lint - Info 773] */ +#define LINK_ADDR(rLink) { (P_LINK_ENTRY_T)(&(rLink)), (P_LINK_ENTRY_T)(&(rLink)), 0 } + +#define LINK_DECLARATION(rLink) \ + struct _LINK_T rLink = LINK_ADDR(rLink) +#endif + +#define LINK_INITIALIZE(prLink) \ + do { \ + ((P_LINK_T)(prLink))->prNext = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->prPrev = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->u4NumElem = 0; \ + } while (0) + +#define LINK_ENTRY_INITIALIZE(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)NULL; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)NULL; \ + } while (0) + +#define LINK_ENTRY_INVALID(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)INVALID_LINK_POISON1; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)INVALID_LINK_POISON2; \ + } while (0) + +#define LINK_IS_EMPTY(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)(prLink)) + +/* NOTE: We should do memory zero before any LINK been initiated, so we can check + * if it is valid before parsing the LINK. + */ +#define LINK_IS_INVALID(prLink) (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)NULL) + +#define LINK_IS_VALID(prLink) (((P_LINK_T)(prLink))->prNext != (P_LINK_ENTRY_T)NULL) + +#define LINK_ENTRY(ptr, type, member) ENTRY_OF(ptr, type, member) + +/* Insert an entry into a link list's head */ +#define LINK_INSERT_HEAD(prLink, prEntry) \ + { \ + linkAdd(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + +/* Append an entry into a link list's tail */ +#define LINK_INSERT_TAIL(prLink, prEntry) \ + { \ + linkAddTail(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + +/* Peek head entry, but keep still in link list */ +#define LINK_PEEK_HEAD(prLink, _type, _member) \ + ( \ + LINK_IS_EMPTY(prLink) ? \ + NULL : LINK_ENTRY((prLink)->prNext, _type, _member) \ + ) + +/* Peek tail entry, but keep still in link list */ +#define LINK_PEEK_TAIL(prLink, _type, _member) \ + ( \ + LINK_IS_EMPTY(prLink) ? \ + NULL : LINK_ENTRY((prLink)->prPrev, _type, _member) \ + ) + +/* Get first entry from a link list */ +/* NOTE: We assume the link entry located at the beginning of "prEntry Type", + * so that we can cast the link entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define LINK_REMOVE_HEAD(prLink, prEntry, _P_TYPE) \ + { \ + ASSERT(prLink); \ + if (LINK_IS_EMPTY(prLink)) { \ + prEntry = (_P_TYPE)NULL; \ + } \ + else { \ + prEntry = (_P_TYPE)(((P_LINK_T)(prLink))->prNext); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } \ + } + +/* Assume the link entry located at the beginning of prEntry Type. + * And also decrease the total entry count. + */ +#define LINK_REMOVE_KNOWN_ENTRY(prLink, prEntry) \ + { \ + ASSERT(prLink); \ + ASSERT(prEntry); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } + +/* Iterate over a link list */ +#define LINK_FOR_EACH(prEntry, prLink) \ + for (prEntry = (prLink)->prNext; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prNext) + +/* Iterate over a link list backwards */ +#define LINK_FOR_EACH_PREV(prEntry, prLink) \ + for (prEntry = (prLink)->prPrev; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prPrev) + +/* Iterate over a link list safe against removal of link entry */ +#define LINK_FOR_EACH_SAFE(prEntry, prNextEntry, prLink) \ + for (prEntry = (prLink)->prNext, prNextEntry = prEntry->prNext; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = prNextEntry, prNextEntry = prEntry->prNext) + +/* Iterate over a link list of given type */ +#define LINK_FOR_EACH_ENTRY(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember)) + +/* Iterate backwards over a link list of given type */ +#define LINK_FOR_EACH_ENTRY_PREV(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prPrev, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prPrev, _TYPE, rMember)) + +/* Iterate over a link list of given type safe against removal of link entry */ +#define LINK_FOR_EACH_ENTRY_SAFE(prObj, prNextObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember), \ + prNextObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = prNextObj, \ + prNextObj = LINK_ENTRY(prNextObj->rMember.prNext, _TYPE, rMember)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is only for internal link list manipulation. +* +* \param[in] prNew Pointer of new link head +* \param[in] prPrev Pointer of previous link head +* \param[in] prNext Pointer of next link head +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID __linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) +{ + prNext->prPrev = prNew; + prNew->prNext = prNext; + prNew->prPrev = prPrev; + prPrev->prNext = prNew; + +} /* end of __linkAdd() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will add a new entry after the specified link head. +* +* \param[in] prNew New entry to be added +* \param[in] prHead Specified link head to add it after +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) +{ + __linkAdd(prNew, (P_LINK_ENTRY_T) prLink, prLink->prNext); + +} /* end of linkAdd() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will add a new entry before the specified link head. +* +* \param[in] prNew New entry to be added +* \param[in] prHead Specified link head to add it before +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID linkAddTail(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) +{ + __linkAdd(prNew, prLink->prPrev, (P_LINK_ENTRY_T) prLink); + +} /* end of linkAddTail() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is only for internal link list manipulation. +* +* \param[in] prPrev Pointer of previous link head +* \param[in] prNext Pointer of next link head +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID __linkDel(IN P_LINK_ENTRY_T prPrev, IN P_LINK_ENTRY_T prNext) +{ + prNext->prPrev = prPrev; + prPrev->prNext = prNext; + +} /* end of __linkDel() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list. +* NOTE: the entry is in an initial state. +* +* \param prEntry Specified link head(entry) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID linkDel(IN P_LINK_ENTRY_T prEntry) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + + LINK_ENTRY_INITIALIZE(prEntry); + +} /* end of linkDel() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list and then add it +* after the specified link head. +* +* \param[in] prEntry Specified link head(entry) +* \param[in] prOtherHead Another link head to add it after +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID linkMove(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAdd(prEntry, prLink); + +} /* end of linkMove() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will delete a specified entry from link list and then add it +* before the specified link head. +* +* \param[in] prEntry Specified link head(entry) +* \param[in] prOtherHead Another link head to add it before +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID linkMoveTail(IN P_LINK_ENTRY_T prEntry, IN P_LINK_T prLink) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAddTail(prEntry, prLink); + +} /* end of linkMoveTail() */ + +#endif /* _LINK_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h new file mode 100644 index 0000000000000..fd83c79ffe103 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/aa_fsm.h @@ -0,0 +1,188 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/aa_fsm.h#1 +*/ + +/*! \file aa_fsm.h + \brief Declaration of functions and finite state machine for SAA/AAA Module. + + Declaration of functions and finite state machine for SAA/AAA Module. +*/ + +/* +** Log: aa_fsm.h + * + * 10 13 2011 cp.wu + * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS + * 1. short join failure count limit to 2 + * 2. treat join timeout as kind of join failure as well + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _AA_FSM_H +#define _AA_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Retry interval for retransmiting authentication-request MMPDU. */ +#define TX_AUTHENTICATION_RETRY_TIMEOUT_TU 100 /* TU. */ + +/* Retry interval for retransmiting association-request MMPDU. */ +#define TX_ASSOCIATION_RETRY_TIMEOUT_TU 100 /* TU. */ + +/* Wait for a response to a transmitted authentication-request MMPDU. */ +#define DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ + +/* Wait for a response to a transmitted association-request MMPDU. */ +#define DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ + +/* The maximum time to wait for JOIN process complete. */ +#define JOIN_FAILURE_TIMEOUT_BEACON_INTERVAL 20 /* Beacon Interval, 20 * 100TU = 2 sec. */ + +/* Retry interval for next JOIN request. */ +#define JOIN_RETRY_INTERVAL_SEC 10 /* Seconds */ + +/* Maximum Retry Count for accept a JOIN request. */ +#define JOIN_MAX_RETRY_FAILURE_COUNT 2 /* Times */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_AA_STATE_T { + AA_STATE_IDLE = 0, + SAA_STATE_SEND_AUTH1, + SAA_STATE_WAIT_AUTH2, + SAA_STATE_SEND_AUTH3, + SAA_STATE_WAIT_AUTH4, + SAA_STATE_SEND_ASSOC1, + SAA_STATE_WAIT_ASSOC2, + AAA_STATE_SEND_AUTH2, + AAA_STATE_SEND_AUTH4, /* We may not use, because P2P GO didn't support WEP and 11r */ + AAA_STATE_SEND_ASSOC2, + AA_STATE_RESOURCE, /* A state for debugging the case of out of msg buffer. */ + AA_STATE_NUM +} ENUM_AA_STATE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in saa_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmSteps(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb); + +WLAN_STATUS +saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, + WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb); + +VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +WLAN_STATUS +saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +/*----------------------------------------------------------------------------*/ +/* Routines in aaa_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AA_FSM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h new file mode 100644 index 0000000000000..b771bdacf2c62 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/ais_fsm.h @@ -0,0 +1,573 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/ais_fsm.h#1 +*/ + +/*! \file ais_fsm.h + \brief Declaration of functions and finite state machine for AIS Module. + + Declaration of functions and finite state machine for AIS Module. +*/ + +/* +** Log: ais_fsm.h + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition + * from synchronous to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS + * is in Normal TR state without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 04 25 2011 cp.wu + * [WCXRP00000676] [MT6620 Wi-Fi][Driver] AIS to reduce request channel period from 5 seconds to 2 seconds + * channel interval for joining is shortened to 2 seconds to avoid interruption of concurrent operating network. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 02 22 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with + * a queue-based approach to improve response time for scanning request + * handle SCAN and RECONNECT with a FIFO approach. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 14 2011 cp.wu + * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent + * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. + * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 25 2010 cp.wu + * NULL + * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, RLM/CNM will handle + * the channel switching when BSS information is updated + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 26 2010 cp.wu + * + * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, + * just pend it til 5-sec. period finishes + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 cp.wu + * + * separate AIS-FSM states into different cases of channel request. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Refine AIS-FSM by divided into more states + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, + * other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 23 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * reduce the background ssid idle time min and max value + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * and will send Null frame to diagnose connection + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Support dynamic channel selection + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Media disconnect indication and related postpone functions + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmRunEventJoinComplete() + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Virtual CMD & RESP for testing CMD PATH + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * add aisFsmInitializeConnectionSettings() + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_MGMT_FSM for aisFsmTest() + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function prototype of aisFsmInit() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _AIS_FSM_H +#define _AIS_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define AIS_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ +#define AIS_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ + +#define AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4 2 /* 2.4G scan need about 0.5s, so delay 2s to reconnect is enough */ +#define AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND 5 /* 2.4G scan need about 3.3s, so delay 5s to reconnect is enough */ + +#define AIS_IBSS_ALONE_TIMEOUT_SEC 20 /* seconds */ + +#define AIS_BEACON_TIMEOUT_COUNT_ADHOC 30 +#define AIS_BEACON_TIMEOUT_COUNT_INFRA 10 +#define AIS_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ + +#define AIS_BEACON_MAX_TIMEOUT_TU 100 +#define AIS_BEACON_MIN_TIMEOUT_TU 5 +#define AIS_BEACON_MAX_TIMEOUT_VALID TRUE +#define AIS_BEACON_MIN_TIMEOUT_VALID TRUE + +#define AIS_BMC_MAX_TIMEOUT_TU 100 +#define AIS_BMC_MIN_TIMEOUT_TU 5 +#define AIS_BMC_MAX_TIMEOUT_VALID TRUE +#define AIS_BMC_MIN_TIMEOUT_VALID TRUE + +#define AIS_JOIN_CH_GRANT_THRESHOLD 10 +#define AIS_JOIN_CH_REQUEST_INTERVAL 3000 + +#define AIS_SCN_DONE_TIMEOUT_SEC 30 /* 15 for 2.4G + 5G */ /* 5 */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_AIS_STATE_T { + AIS_STATE_IDLE = 0, + AIS_STATE_SEARCH, + AIS_STATE_SCAN, + AIS_STATE_ONLINE_SCAN, + AIS_STATE_LOOKING_FOR, + AIS_STATE_WAIT_FOR_NEXT_SCAN, + AIS_STATE_REQ_CHANNEL_JOIN, + AIS_STATE_JOIN, + AIS_STATE_IBSS_ALONE, + AIS_STATE_IBSS_MERGE, + AIS_STATE_NORMAL_TR, + AIS_STATE_DISCONNECTING, + AIS_STATE_REQ_REMAIN_ON_CHANNEL, + AIS_STATE_REMAIN_ON_CHANNEL, + AIS_STATE_NUM +} ENUM_AIS_STATE_T; + +typedef struct _MSG_AIS_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucReasonOfDisconnect; + BOOLEAN fgDelayIndication; +} MSG_AIS_ABORT_T, *P_MSG_AIS_ABORT_T; + +typedef struct _MSG_AIS_IBSS_PEER_FOUND_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + BOOLEAN fgIsMergeIn; /* TRUE: Merge In, FALSE: Merge Out */ + P_STA_RECORD_T prStaRec; +} MSG_AIS_IBSS_PEER_FOUND_T, *P_MSG_AIS_IBSS_PEER_FOUND_T; + +typedef enum _ENUM_AIS_REQUEST_TYPE_T { + AIS_REQUEST_SCAN, + AIS_REQUEST_RECONNECT, + AIS_REQUEST_ROAMING_SEARCH, + AIS_REQUEST_ROAMING_CONNECT, + AIS_REQUEST_REMAIN_ON_CHANNEL, + AIS_REQUEST_NUM +} ENUM_AIS_REQUEST_TYPE_T; + +typedef struct _AIS_REQ_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_AIS_REQUEST_TYPE_T eReqType; +} AIS_REQ_HDR_T, *P_AIS_REQ_HDR_T; + +typedef struct _AIS_REQ_CHNL_INFO { + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eSco; + UINT_8 ucChannelNum; + UINT_32 u4DurationMs; + UINT_64 u8Cookie; +} AIS_REQ_CHNL_INFO, *P_AIS_REQ_CHNL_INFO; + +typedef struct _AIS_MGMT_TX_REQ_INFO_T { + BOOLEAN fgIsMgmtTxRequested; + P_MSDU_INFO_T prMgmtTxMsdu; + UINT_64 u8Cookie; +} AIS_MGMT_TX_REQ_INFO_T, *P_AIS_MGMT_TX_REQ_INFO_T; + +typedef struct _AIS_FSM_INFO_T { + ENUM_AIS_STATE_T ePreviousState; + ENUM_AIS_STATE_T eCurrentState; + + BOOLEAN fgTryScan; + + BOOLEAN fgIsInfraChannelFinished; + BOOLEAN fgIsChannelRequested; + BOOLEAN fgIsChannelGranted; + +#if CFG_SUPPORT_ROAMING + BOOLEAN fgIsRoamingScanPending; +#endif /* CFG_SUPPORT_ROAMING */ + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + + P_BSS_DESC_T prTargetBssDesc; /* For destination */ + + P_STA_RECORD_T prTargetStaRec; /* For JOIN Abort */ + + UINT_32 u4SleepInterval; + + TIMER_T rBGScanTimer; + + TIMER_T rIbssAloneTimer; + + TIMER_T rIndicationOfDisconnectTimer; + + TIMER_T rJoinTimeoutTimer; + + TIMER_T rChannelTimeoutTimer; + + TIMER_T rScanDoneTimer; + + TIMER_T rDeauthDoneTimer; + + UINT_8 ucSeqNumOfReqMsg; + UINT_8 ucSeqNumOfChReq; + UINT_8 ucSeqNumOfScanReq; + + UINT_32 u4ChGrantedInterval; + + UINT_8 ucConnTrialCount; + + UINT_8 ucScanSSIDLen; + UINT_8 aucScanSSID[ELEM_MAX_LEN_SSID]; + + UINT_32 u4ScanIELength; + UINT_8 aucScanIEBuf[MAX_IE_LENGTH]; + + /* Pending Request List */ + LINK_T rPendingReqList; + + /* Join Request Timestamp */ + OS_SYSTIME rJoinReqTime; + + /* for cfg80211 REMAIN_ON_CHANNEL support */ + AIS_REQ_CHNL_INFO rChReqInfo; + + /* Mgmt tx related. */ + AIS_MGMT_TX_REQ_INFO_T rMgmtTxInfo; + + /* Packet filter for AIS module. */ + UINT_32 u4AisPacketFilter; + +} AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define aisChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState = (_eNewMediaState)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); + +VOID aisFsmInit(IN P_ADAPTER_T prAdapter); + +VOID aisFsmUninit(IN P_ADAPTER_T prAdapter); + +VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter); + +VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication); + +VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter); + +VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter); + +VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter); + +VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter); +#if 0 +VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState); +#endif +VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +/*----------------------------------------------------------------------------*/ +/* Handling for Ad-Hoc Network */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter); + +VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* Handling of Incoming Mailbox Message from CNM */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +/*----------------------------------------------------------------------------*/ +/* Generating Outgoing Mailbox Message to CNM */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Event Indication */ +/*----------------------------------------------------------------------------*/ +VOID +aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); + +VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb); + +VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter); + +VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); + +WLAN_STATUS +aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +/*----------------------------------------------------------------------------*/ +/* Disconnection Handling */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication); + +/*----------------------------------------------------------------------------*/ +/* Event Handling */ +/*----------------------------------------------------------------------------*/ +VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter); + +VOID aisBssSecurityChanged(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +#if CFG_SUPPORT_ROAMING +VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan); + +ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter); + +VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec); + +VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); +#endif /*CFG_SUPPORT_ROAMING */ + +/*----------------------------------------------------------------------------*/ +/* Timeout Handling */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength); + +/*----------------------------------------------------------------------------*/ +/* Internal State Checking */ +/*----------------------------------------------------------------------------*/ +BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove); + +P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter); + +BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType); + +VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); + +VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +VOID aisTest(VOID); +#endif /* CFG_TEST_MGMT_FSM */ +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AIS_FSM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h new file mode 100644 index 0000000000000..70b32bca102bc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/assoc.h @@ -0,0 +1,112 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/assoc.h#1 +*/ + +/*! \file assoc.h + \brief This file contains the ASSOC REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: assoc.h + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add assocCheckTxReAssocRespFrame() proto type for P2P usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _ASSOC_H +#define _ASSOC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in assoc.c */ +/*----------------------------------------------------------------------------*/ +UINT_16 assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); + +WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode); + +WLAN_STATUS +assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); + +WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); + +WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ASSOC_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h new file mode 100644 index 0000000000000..4f76f03324dde --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/auth.h @@ -0,0 +1,125 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/auth.h#1 +*/ + +/*! \file auth.h + \brief This file contains the authentication REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: auth.h + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _AUTH_H +#define _AUTH_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in auth.c */ +/*----------------------------------------------------------------------------*/ +VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo); + +#if !CFG_SUPPORT_AAA +WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum); +#else +WLAN_STATUS +authSendAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode); +#endif /* CFG_SUPPORT_AAA */ + +WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum); + +WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode); + +VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr); + +WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +authSendDeauthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode); + +WLAN_STATUS +authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucExpectedBSSID[], + IN UINT_16 u2ExpectedAuthAlgNum, + IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _AUTH_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h new file mode 100644 index 0000000000000..5995d133a6cdf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bow_fsm.h @@ -0,0 +1,184 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/bow_fsm.h#1 +*/ + +/*! \file bow_fsm.h + \brief Declaration of functions and finite state machine for BOW Module. + + Declaration of functions and finite state machine for BOW Module. +*/ + +/* +** Log: bow_fsm.h + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Submit missing BoW header files. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add channel previledge into _BOW_FSM_INFO_T. + * + * 09 16 2010 chinghwa.yu + * NULL + * update bowChangeMediaState. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + */ + +#ifndef _BOW_FSM_H +#define _BOW_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define BOW_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ +#define BOW_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ + +#define BOW_DELAY_TIME_OF_DISCONNECT_SEC 10 + +#define BOW_BEACON_TIMEOUT_COUNT_STARTING 10 +#define BOW_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ + +#define BOW_BEACON_MAX_TIMEOUT_TU 100 +#define BOW_BEACON_MIN_TIMEOUT_TU 5 +#define BOW_BEACON_MAX_TIMEOUT_VALID TRUE +#define BOW_BEACON_MIN_TIMEOUT_VALID TRUE + +#define BOW_BMC_MAX_TIMEOUT_TU 100 +#define BOW_BMC_MIN_TIMEOUT_TU 5 +#define BOW_BMC_MAX_TIMEOUT_VALID TRUE +#define BOW_BMC_MIN_TIMEOUT_VALID TRUE + +#define BOW_JOIN_CH_GRANT_THRESHOLD 10 +#define BOW_JOIN_CH_REQUEST_INTERVAL 2000 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_BOW_STATE_T { + BOW_STATE_IDLE = 0, + BOW_STATE_SEARCH, + BOW_STATE_SCAN, + BOW_STATE_ONLINE_SCAN, + BOW_STATE_LOOKING_FOR, + BOW_STATE_WAIT_FOR_NEXT_SCAN, + BOW_STATE_REQ_CHANNEL_JOIN, + BOW_STATE_REQ_CHANNEL_ALONE, + BOW_STATE_REQ_CHANNEL_MERGE, + BOW_STATE_JOIN, + BOW_STATE_IBSS_ALONE, + BOW_STATE_IBSS_MERGE, + BOW_STATE_NORMAL_TR, + BOW_STATE_NUM +} ENUM_BOW_STATE_T; + +typedef struct _BOW_FSM_INFO_T { + ENUM_BOW_STATE_T ePreviousState; + ENUM_BOW_STATE_T eCurrentState; + + BOOLEAN fgTryScan; + + /* Channel Privilege */ + + BOOLEAN fgIsInfraChannelFinished; + BOOLEAN fgIsChannelRequested; + BOOLEAN fgIsChannelGranted; + BOOLEAN fgIsScanPending; + UINT_32 u4ChGrantedInterval; + + UINT_8 ucPrimaryChannel; + ENUM_BAND_T eBand; + UINT_16 u2BeaconInterval; + + ENUM_BOW_STATE_T eReturnState; /* Return state after current activity finished or abort. */ + ENUM_BOW_STATE_T eForwardState; /* Step to next state if ACTION frame is TX successfully. */ + + P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ + + P_STA_RECORD_T prTargetStaRec; + P_BSS_DESC_T prTargetBssDesc; /* For destination */ + + UINT_8 aucPeerAddress[6]; + + UINT_8 ucRole; + + BOOLEAN fgSupportQoS; + + BOOLEAN fgIsRsponseProbe; /* Indicate if BOW can response probe request frame. */ + + /* Sequence number of requested message. */ + UINT_8 ucSeqNumOfChReq; + UINT_8 ucSeqNumOfReqMsg; + UINT_8 ucSeqNumOfScnMsg; + UINT_8 ucSeqNumOfScanReq; + + UINT_8 ucSeqNumOfCancelMsg; + + UINT_8 ucDialogToken; + + /* Timer */ + TIMER_T rStartingBeaconTimer; /* For device discovery time of each discovery request from user. */ + TIMER_T rStartingDiscoveryTimer; + TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ + TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ + TIMER_T rIndicationOfDisconnectTimer; + TIMER_T rChGrantedTimer; + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + +} BOW_FSM_INFO_T, *P_BOW_FSM_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define bowChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].eConnectionState = (_eNewMediaState)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h new file mode 100644 index 0000000000000..0597132b970ef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/bss.h @@ -0,0 +1,265 @@ +/* +** Id: @(#) bss.h +*/ + +/*! \file "bss.h" + \brief In this file we define the function prototype used in BSS/IBSS. + + The file contains the function declarations and defines for used in BSS/IBSS. +*/ + +/* +** Log: bss.h + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 09 14 2011 yuche.tsai + * NULL + * Add P2P IE in assoc response. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Make assoc req to append P2P IE if wifi direct is enabled. + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 02 23 2011 eddie.chen + * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap + * Fix parsing WMM INFO and bmp delivery bitmap definition. + * + * 01 31 2011 george.huang + * [WCXRP00000333] [MT5931][FW] support SRAM power control drivers + * Extend TIM PVB, from 2 to 3 octets. + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for + * initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 12 2010 kevin.huang + * NULL + * Update bssProcessProbeRequest() and bssSendBeaconProbeResponse() declarations + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add CTRL FLAGS for Probe Response. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Remove unused typedef. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix file merge error + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * and will send Null frame to diagnose connection + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add DTIM count update while TX Beacon + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +#ifndef _BSS_H +#define _BSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* NOTE(Kevin): change define for george */ +/* #define MAX_LEN_TIM_PARTIAL_BMP (((MAX_ASSOC_ID + 1) + 7) / 8) */ /* Required bits = (MAX_ASSOC_ID + 1) */ +#define MAX_LEN_TIM_PARTIAL_BMP ((CFG_STA_REC_NUM + 7) / 8) +/* reserve length greater than maximum size of STA_REC */ /* obsoleted: Assume we only use AID:1~15 */ + +/* CTRL FLAGS for Probe Response */ +#define BSS_PROBE_RESP_USE_P2P_DEV_ADDR BIT(0) +#define BSS_PROBE_RESP_INCLUDE_P2P_IE BIT(1) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define bssAssignAssocID(_prStaRec) ((_prStaRec)->ucIndex + 1) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc); + +VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec); + +VOID +bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP); + +WLAN_STATUS +bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +WLAN_STATUS +bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID +bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr); + +VOID +bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, + IN PUINT_8 pucDestAddr, + IN PUINT_8 pucOwnMACAddress, + IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo); + +WLAN_STATUS +bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags); + +WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); + +VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +VOID +ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI); + +WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate); + +VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId); + +P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr); + +/*link function to p2p module for txBcnIETable*/ + +/* WMM-2.2.2 WMM ACI to AC coding */ +typedef enum _ENUM_ACI_T { + ACI_BE = 0, + ACI_BK = 1, + ACI_VI = 2, + ACI_VO = 3, + ACI_NUM +} ENUM_ACI_T, *P_ENUM_ACI_T; + +typedef enum _ENUM_AC_PRIORITY_T { + AC_BK_PRIORITY = 0, + AC_BE_PRIORITY, + AC_VI_PRIORITY, + AC_VO_PRIORITY +} ENUM_AC_PRIORITY_T, *P_ENUM_AC_PRIORITY_T; + +#endif /* _BSS_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h new file mode 100644 index 0000000000000..81b16b5888672 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm.h @@ -0,0 +1,258 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm.h#1 +*/ + +/*! \file "cnm.h" + \brief +*/ + +/* +** Log: cnm.h + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 01 12 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Provide function to decide if BSS can be activated or not + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 13 2010 cm.chang + * + * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Need bandwidth info when requesting channel privilege + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add a new function to send abort message + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support partial part about cmd basic configuration + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add prototype of cnmFsmEventInit() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_H +#define _CNM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_CH_REQ_TYPE_T { + CH_REQ_TYPE_JOIN, + CH_REQ_TYPE_P2P_LISTEN, + + CH_REQ_TYPE_NUM +} ENUM_CH_REQ_TYPE_T, *P_ENUM_CH_REQ_TYPE_T; + +typedef struct _MSG_CH_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; + UINT_32 u4MaxInterval; /* In unit of ms */ + UINT_8 aucBSSID[6]; + UINT_8 aucReserved[2]; +} MSG_CH_REQ_T, *P_MSG_CH_REQ_T; + +typedef struct _MSG_CH_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; +} MSG_CH_ABORT_T, *P_MSG_CH_ABORT_T; + +typedef struct _MSG_CH_GRANT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; + UINT_32 u4GrantInterval; /* In unit of ms */ +} MSG_CH_GRANT_T, *P_MSG_CH_GRANT_T; + +typedef struct _MSG_CH_REOCVER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CH_REQ_TYPE_T eReqType; +} MSG_CH_RECOVER_T, *P_MSG_CH_RECOVER_T; + +typedef struct _CNM_INFO_T { + UINT_32 u4Reserved; +} CNM_INFO_T, *P_CNM_INFO_T; + +#if CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +typedef struct _DEVICE_TYPE_T { + UINT_16 u2CategoryId; /* Category ID */ + UINT_8 aucOui[4]; /* OUI */ + UINT_16 u2SubCategoryId; /* Sub Category ID */ +} __KAL_ATTRIB_PACKED__ DEVICE_TYPE_T, *P_DEVICE_TYPE_T; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID cnmInit(P_ADAPTER_T prAdapter); + +VOID cnmUninit(P_ADAPTER_T prAdapter); + +VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent); + +BOOLEAN +cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO); + +BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); + +VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter); + +BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter); + +BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter); + +BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter); + +BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); +#if CFG_P2P_LEGACY_COEX_REVISE +BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +static inline VOID cnmMsgDataTypeCheck(VOID) +{ + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == 0); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == OFFSET_OF(MSG_CH_RECOVER_T, rMsgHdr)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucNetTypeIndex) == + OFFSET_OF(MSG_CH_RECOVER_T, ucNetTypeIndex)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucTokenID) == OFFSET_OF(MSG_CH_RECOVER_T, ucTokenID)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucPrimaryChannel) == + OFFSET_OF(MSG_CH_RECOVER_T, ucPrimaryChannel)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfSco) == OFFSET_OF(MSG_CH_RECOVER_T, eRfSco)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfBand) == OFFSET_OF(MSG_CH_RECOVER_T, eRfBand)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eReqType) == OFFSET_OF(MSG_CH_RECOVER_T, eReqType)); + +} +#endif /* _lint */ + +#endif /* _CNM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h new file mode 100644 index 0000000000000..c8f25b1b29a9f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_mem.h @@ -0,0 +1,1164 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_mem.h#1 +*/ + +/*! \file "cnm_mem.h" + \brief In this file we define the structure of the control unit of + packet buffer and MGT/MSG Memory Buffer. +*/ + +/* +** Log: cnm_mem.h + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 03 17 2011 yuche.tsai + * NULL + * Resize the Secondary Device Type array when WiFi Direct is enabled. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Add per STA flow control when STA is in PS mode + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for + * initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD + * when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 12 2010 cp.wu + * + * SAA will take a record for tracking request sequence number. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error for P2P related defination. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related fields. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [BORA00000678] [MT6620]WiFi LP integration + * 1. add u8TimeStamp in MSDU_INFO + * 2. move fgIsRxTSFUpdated/fgIsTxTSFUpdated from static to BSS_INFO + * 3. add new member for supporting PM in STA_RECORD, which is for AP PS mode + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support checking of duplicated buffer free + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 19 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fixed MAC RX Desc be overwritten issue + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 10 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support Rx header translation for A-MSDU subframe + * + * 05 07 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * add more sanity check about setting timer + * + * 04 29 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * modify the compiling flag for RAM usage + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Modified some MQM-related data structures (SN counter, TX/RX BA table) + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Added new TX/RX BA tables in STA_REC + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 09 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * [BORA00000644] WiFi phase 4 integration + * Added per-TID SN cache in STA_REC + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support power control + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 11 2010 yuche.tsai + * [BORA00000343][MT6620] Emulation For TX + * . + * + * 03 05 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove Emulation definition + * + * 03 04 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * eliminate HIF_EMULATION in cnm_mem.h + * + * 03 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add cnmStaRecChangeState() declaration. + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning for some emulation flags + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, + * and modify the security related callback function prototype. + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * To store field AMPDU Parameters in STA_REC + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsWmmSupported in STA_RECORD_T. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsUapsdSupported in STA_RECORD_T + * + * 02 13 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added arTspecTable in STA_REC for TSPEC management + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable mgmt buffer debug by default + * + * 02 12 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added BUFFER_SOURCE_BCN + * + * 02 10 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Renamed MSDU_INFO.ucFixedRateIndex as MSDU_INFO.ucFixedRateCode + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 02 02 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added SN info in MSDU_INFO_T + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h + * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem + * 3) use cnmMemAlloc() instead to allocate SRAM buffer + * + * 12 31 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) surpress debug message emitted from hal_hif.c + * 2) add two set of field for recording buffer process time + * + * 12 31 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1. move wifi task initialization from wifi_task.c(rom) to wifi_init.c (TCM) for integrating F/W download later + * * * * * 2. WIFI_Event_Dispatcher() prototype changed to return to suspend mode from normal operation mode + * * * * * 2. HIF emulation logic revised + * + * 12 29 2009 yuche.tsai + * [BORA00000343][MT6620] Emulation For TX + * .Using global buffer declaring by SD1 instead of using another one. + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * MQM: BA handling + * * TXM: Macros updates + * * RXM: Macros/Duplicate Removal updates + * + * 12 24 2009 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 23 2009 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * allocating SRAM for emulation purpose by ruducing MEM_BANK3_BUF_SZ + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove individual DATA_BUF_BLOCK_NUM definition for emulation compiling flagsu1rwduu`wvpghlqg|fh+fmdkb + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support several data buffer banks. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * .For new FPGA memory size + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 17 2009 george.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 17 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Modified the DATA_BLOCK_SIZE from 1620 to 2048 + * + * Dec 16 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_SEC_EMULATION flag + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add HT cap to sta record + * + * Dec 9 2009 mtk02752 + * [BORA00000368] Integrate HIF part into BORA + * add cnmDataPktFree() for emulation loopback purpose + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the buffer for key handshake 1x and cmd key order issue + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * move the tx call back function proto type to typedef.h + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add cnmGetStaRecByAddress() and modify variable in STA_RECORD_T + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the port block flag + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add variables to STA_RECORD_T for assoc/auth + * + * Nov 23 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed the value of STA_WAIT_QUEUE_NUM (from 7 to 5) + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed u2FrameLength from SW_RFB + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed indenting + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Updated MSDU_INFO and SW_RFB + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * update the variable for security + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove the variable to make the compiler ok + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the variable for security module + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo in define of MSG_BUF_BLOCK_SIZE + * + * Nov 13 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Let typedef STA_REC_T precede typedef MSDU_INFO_T and SW_RFB_T + * + * Nov 13 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Modified MSDU_INFO and STA_REC for TXM and MQM + * + * Nov 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename STA_REC_T to STA_RECORD_T and add ucIndex member + * + * Nov 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Make sure ucBufferSource the same offset in MSDU_INFO and SW_RFB + * + * Nov 6 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Nov 5 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comment + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add draft content of MSDU_INFO_T and SW_RFB_T + * + * Oct 30 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 21 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_RX_EMULATION flag + * + * Oct 20 2009 mtk01426 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 9 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added field ucTC to MSDU_INFO_T and field pucHifRxPacket to SW_RFB_T + * + * Oct 8 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_MEM_H +#define _CNM_MEM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#ifndef POWER_OF_2 +#define POWER_OF_2(n) BIT(n) +#endif + +/* Size of a basic management buffer block in power of 2 */ +#define MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2 7 /* 7 to the power of 2 = 128 */ +#define MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2 5 /* 5 to the power of 2 = 32 */ + +/* Size of a basic management buffer block */ +#define MGT_BUF_BLOCK_SIZE POWER_OF_2(MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCK_SIZE POWER_OF_2(MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Total size of (n) basic management buffer blocks */ +#define MGT_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCKS_SIZE(n) ((UINT_32)(n) << MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Number of management buffer block */ +#define MAX_NUM_OF_BUF_BLOCKS 32 /* Range: 1~32 */ + +/* Size of overall management frame buffer */ +#define MGT_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MGT_BUF_BLOCK_SIZE) +#define MSG_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * MSG_BUF_BLOCK_SIZE) + +/* STA_REC related definitions */ +#define STA_REC_INDEX_BMCAST 0xFF +#define STA_REC_INDEX_NOT_FOUND 0xFE +#define STA_WAIT_QUEUE_NUM 5 /* Number of SW queues in each STA_REC: AC0~AC4 */ +#define SC_CACHE_INDEX_NUM 5 /* Number of SC caches in each STA_REC: AC0~AC4 */ + +/* P2P related definitions */ +#ifdef CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ +#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if ((MAX_NUM_OF_BUF_BLOCKS > 32) || (MAX_NUM_OF_BUF_BLOCKS <= 0)) +#error > #define MAX_NUM_OF_MGT_BUF_BLOCKS : Out of boundary ! +#elif MAX_NUM_OF_BUF_BLOCKS > 16 +typedef UINT_32 BUF_BITMAP; +#elif MAX_NUM_OF_BUF_BLOCKS > 8 +typedef UINT_16 BUF_BITMAP; +#else +typedef UINT_8 BUF_BITMAP; +#endif /* MAX_NUM_OF_MGT_BUF_BLOCKS */ + +/* Control variable of TX management memory pool */ +typedef struct _BUF_INFO_T { + PUINT_8 pucBuf; + +#if CFG_DBG_MGT_BUF + UINT_32 u4AllocCount; + UINT_32 u4FreeCount; + UINT_32 u4AllocNullCount; +#endif /* CFG_DBG_MGT_BUF */ + + BUF_BITMAP rFreeBlocksBitmap; + UINT_8 aucAllocatedBlockNum[MAX_NUM_OF_BUF_BLOCKS]; +} BUF_INFO_T, *P_BUF_INFO_T; + +/* Wi-Fi divides RAM into three types + * MSG: Mailbox message (Small size) + * BUF: HW DMA buffers (HIF/MAC) + */ +typedef enum _ENUM_RAM_TYPE_T { + RAM_TYPE_MSG = 0, + RAM_TYPE_BUF +} ENUM_RAM_TYPE_T, P_ENUM_RAM_TYPE_T; + +typedef enum _ENUM_BUFFER_SOURCE_T { + BUFFER_SOURCE_HIF_TX0 = 0, + BUFFER_SOURCE_HIF_TX1, + BUFFER_SOURCE_MAC_RX, + BUFFER_SOURCE_MNG, + BUFFER_SOURCE_BCN, + BUFFER_SOURCE_NUM +} ENUM_BUFFER_SOURCE_T, *P_ENUM_BUFFER_SOURCE_T; + +typedef enum _ENUM_SEC_STATE_T { + SEC_STATE_INIT, + SEC_STATE_INITIATOR_PORT_BLOCKED, + SEC_STATE_RESPONDER_PORT_BLOCKED, + SEC_STATE_CHECK_OK, + SEC_STATE_SEND_EAPOL, + SEC_STATE_SEND_DEAUTH, + SEC_STATE_COUNTERMEASURE, + SEC_STATE_NUM +} ENUM_SEC_STATE_T; + +typedef struct _TSPEC_ENTRY_T { + UINT_8 ucStatus; + UINT_8 ucToken; /* Dialog Token in ADDTS_REQ or ADDTS_RSP */ + UINT_16 u2MediumTime; + UINT_32 u4TsInfo; + /* PARAM_QOS_TS_INFO rParamTsInfo; */ + /* Add other retained QoS parameters below */ +} TSPEC_ENTRY_T, *P_TSPEC_ENTRY_T, TSPEC_TABLE_ENTRY_T, *P_TSPEC_TABLE_ENTRY_T; + +typedef struct _SEC_INFO_T { + + ENUM_SEC_STATE_T ePreviousState; + ENUM_SEC_STATE_T eCurrentState; + + BOOLEAN fg2nd1xSend; + BOOLEAN fgKeyStored; + + UINT_8 aucStoredKey[64]; + + BOOLEAN fgAllowOnly1x; +} SEC_INFO_T, *P_SEC_INFO_T; + +#define MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS 3 + +#define UPDATE_BSS_RSSI_INTERVAL_SEC 3 /* Seconds */ + +/* Fragment information structure */ +typedef struct _FRAG_INFO_T { + UINT_16 u2NextFragSeqCtrl; + PUINT_8 pucNextFragStart; + P_SW_RFB_T pr1stFrag; + OS_SYSTIME rReceiveLifetimeLimit; /* The receive time of 1st fragment */ +} FRAG_INFO_T, *P_FRAG_INFO_T; + +typedef struct _STAT_CNT_INFO_FW_T { + UINT32 u4NumOfTx; /* number of packets sent from host */ + UINT32 u4NumOfTxOK; /* number of packets sent to air OK */ + UINT32 u4NumOfTxRetry; /* number of packets sent to air RETRY */ + UINT32 u4TxDoneAirTimeMax; /* maximum tx done air time */ + + UINT32 u4NumOfPtiRspTxOk; /* number of PTI RSP sent to air OK */ + UINT32 u4NumOfPtiRspTxErr; /* number of PTI RSP sent to air ERROR */ + + UINT32 u4NumOfTxErr; /* number of packets sent to air ERROR */ + + UINT32 u4NumOfRx; /* number of received packets */ + UINT32 u4NumOfPtiRspRx; /* number of PTI RSP rcv */ + +#define STAT_CNT_INFO_TX_ERR_FLUSHED 0x00000001 +#define STAT_CNT_INFO_TX_ERR_AGE_TIMEOUT 0x00000002 +#define STAT_CNT_INFO_TX_ERR_MPDU 0x00000004 +#define STAT_CNT_INFO_TX_ERR_RTS 0x00000010 +#define STAT_CNT_INFO_TX_ERR_LIFETIME 0x00000020 +#define STAT_CNT_INFO_TX_ERR_UNKNOWN 0x80000000 + UINT32 u4TxErrBitmap; /* TX error type */ + +#define STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM 10 /* TX OK history */ + UINT8 aucTxRateOkHis[STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM][2]; + UINT32 u4TxRateOkHisId; + +#define STAT_CNT_INFO_MAX_RATE_ID (32) /* MCS0 ~ MCS31 */ + UINT32 aucTxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; + UINT32 aucRxRateMap[STAT_CNT_INFO_MAX_RATE_ID]; + + UINT8 aucStateHis[100][3]; /* State history */ + UINT32 u4StateHisId; /* history ID */ +} STAT_CNT_INFO_FW_T; + +typedef struct _STAT_CNT_INFO_DRV_T { + + UINT32 u4NumOfTxFromOs; /* number of packets sent from OS */ + UINT32 u4NumOfTxQueFull; /* number of packets dropped due to queue full */ + UINT32 u4NumOfTxToFw; /* number of packets sent to firmware */ + + STAT_CNT_INFO_FW_T rFw; +} STAT_CNT_INFO_DRV_T; + +/* Define STA record structure */ +struct _STA_RECORD_T { + LINK_ENTRY_T rLinkEntry; + UINT_8 ucIndex; /* Not modify it except initializing */ + + BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 aucMacAddr[MAC_ADDR_LEN]; /* MAC address */ + + /* SAA/AAA */ + ENUM_AA_STATE_T eAuthAssocState; /* Store STATE Value used in SAA/AAA */ + UINT_8 ucAuthAssocReqSeqNum; + + ENUM_STA_TYPE_T eStaType; /* Indicate the role of this STA in + * the network (for example, P2P GO) + */ + + UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ + + UINT_8 ucStaState; /* STATE_1,2,3 */ + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (may deduced from received BSS_DESC_T) + */ + UINT_8 ucDesiredPhyTypeSet; /* The match result by AND operation of peer's + * PhyTypeSet and ours. + */ + BOOLEAN fgHasBasicPhyType; /* A flag to indicate a Basic Phy Type which + * is used to generate some Phy Attribute IE + * (e.g. capability, MIB) during association. + */ + UINT_8 ucNonHTBasicPhyType; /* The Basic Phy Type chosen among the + * ucDesiredPhyTypeSet. + */ + + UINT_16 u2CapInfo; /* For Infra Mode, to store Capability Info. from Association Resp(SAA). + * For AP Mode, to store Capability Info. from Association Req(AAA). + */ + UINT_16 u2AssocId; /* For Infra Mode, to store AID from Association Resp(SAA). + * For AP Mode, to store the Assigned AID(AAA). + */ + + UINT_16 u2ListenInterval; /* Listen Interval from STA(AAA) */ + + UINT_16 u2DesiredNonHTRateSet; /* Our Current Desired Rate Set after + * match with STA's Operational Rate Set + */ + + UINT_16 u2OperationalRateSet; /* Operational Rate Set of peer BSS */ + UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of peer BSS */ + + BOOLEAN fgIsMerging; /* For IBSS Mode, to indicate that Merge is ongoing */ + + BOOLEAN fgDiagnoseConnection; /* For Infra/AP Mode, to diagnose the Connection with + * this peer by sending ProbeReq/Null frame */ + + /*------------------------------------------------------------------------------------------*/ + /* 802.11n HT capabilities when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) is true */ + /* They have the same definition with fields of information element */ + /*------------------------------------------------------------------------------------------*/ + UINT_8 ucMcsSet; /* MCS0~7 rate set of peer BSS */ + BOOLEAN fgSupMcs32; /* MCS32 is supported by peer BSS */ + UINT_16 u2HtCapInfo; /* HT cap info field by HT cap IE */ + UINT_8 ucAmpduParam; /* Field A-MPDU Parameters in HT cap IE */ + UINT_16 u2HtExtendedCap; /* HT extended cap field by HT cap IE */ + UINT_32 u4TxBeamformingCap; /* TX beamforming cap field by HT cap IE */ + UINT_8 ucAselCap; /* ASEL cap field by HT cap IE */ + + UINT_8 ucRCPI; /* RCPI of peer */ + + UINT_8 ucDTIMPeriod; /* Target BSS's DTIM Period, we use this + * value for setup Listen Interval + * TODO(Kevin): TBD + */ + UINT_8 ucAuthAlgNum; /* For Infra/AP Mode, the Auth Algorithm Num used in Authentication(SAA/AAA) */ + BOOLEAN fgIsReAssoc; /* For Infra/AP Mode, to indicate ReAssoc Frame was in used(SAA/AAA) */ + + UINT_8 ucTxAuthAssocRetryCount; /* For Infra Mode, the Retry Count of TX Auth/Assod Frame(SAA) */ + UINT_8 ucTxAuthAssocRetryLimit; /* For Infra Mode, the Retry Limit of TX Auth/Assod Frame(SAA) */ + + UINT_16 u2StatusCode; /* Status of Auth/Assoc Req */ + UINT_16 u2ReasonCode; /* Reason that been Deauth/Disassoc */ + + P_IE_CHALLENGE_TEXT_T prChallengeText; /* Point to an allocated buffer for storing Challenge Text + * for Shared Key Authentication + */ + + TIMER_T rTxReqDoneOrRxRespTimer; /* For Infra Mode, a timer used to send a timeout event + * while waiting for TX request done or RX response. + */ + + /*------------------------------------------------------------------------------------------*/ + /* Power Management related fields (for STA/ AP/ P2P/ BOW power saving mode) */ + /*------------------------------------------------------------------------------------------*/ + BOOLEAN fgSetPwrMgtBit; /* For Infra Mode, to indicate that outgoing frame need toggle + * the Pwr Mgt Bit in its Frame Control Field. + */ + + BOOLEAN fgIsInPS; /* For AP Mode, to indicate the client PS state(PM). + * TRUE: In PS Mode; FALSE: In Active Mode. */ + + BOOLEAN fgIsInPsPollSP; /* For Infra Mode, to indicate we've sent a PS POLL to AP and start + * the PS_POLL Service Period(LP) + */ + + BOOLEAN fgIsInTriggerSP; /* For Infra Mode, to indicate we've sent a Trigger Frame to AP and start + * the Delivery Service Period(LP) + */ + + UINT_8 ucBmpDeliveryAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + UINT_8 ucBmpTriggerAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + UINT_8 ucUapsdSp; /* Max SP length */ + + /*------------------------------------------------------------------------------------------*/ + + BOOLEAN fgIsRtsEnabled; + + OS_SYSTIME rUpdateTime; /* (4) System Timestamp of Successful TX and RX */ + + OS_SYSTIME rLastJoinTime; /* (4) System Timestamp of latest JOIN process */ + + UINT_8 ucJoinFailureCount; /* Retry Count of JOIN process */ + + LINK_T arStaWaitQueue[STA_WAIT_QUEUE_NUM]; /* For TXM to defer pkt forwarding to MAC TX DMA */ + + UINT_16 au2CachedSeqCtrl[TID_NUM + 1]; /* Duplicate removal for HT STA on a per-TID basis + * ("+1" is for MMPDU and non-QoS) + */ + +#if 0 + /* RXM */ + P_RX_BA_ENTRY_T aprRxBaTable[TID_NUM]; + + /* TXM */ + P_TX_BA_ENTRY_T aprTxBaTable[TID_NUM]; +#endif + + FRAG_INFO_T rFragInfo[MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS]; + + SEC_INFO_T rSecInfo; /* The security state machine */ + + BOOLEAN fgPortBlock; /* The 802.1x Port Control flag */ + + BOOLEAN fgTransmitKeyExist; /* Unicast key exist for this STA */ + + UINT_8 ucWTEntry; + + BOOLEAN fgTxAmpduEn; /* Enable TX AMPDU for this Peer */ + BOOLEAN fgRxAmpduEn; /* Enable RX AMPDU for this Peer */ + + PUINT_8 pucAssocReqIe; + UINT_16 u2AssocReqIeLen; + /*------------------------------------------------------------------------------------------*/ + /* WMM/QoS related fields */ + /*------------------------------------------------------------------------------------------*/ + BOOLEAN fgIsQoS; /* If the STA is associated as a QSTA or QAP (for TX/RX) */ + BOOLEAN fgIsWmmSupported; /* If the peer supports WMM, set to TRUE (for association) */ + BOOLEAN fgIsUapsdSupported; /* Set according to the scan result (for association) */ + + /*------------------------------------------------------------------------------------------*/ + /* P2P related fields */ + /*------------------------------------------------------------------------------------------*/ +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 u2DevNameLen; + UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; + + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + + UINT_16 u2ConfigMethods; + + UINT_8 ucDeviceCap; + + UINT_8 ucSecondaryDevTypeCount; + + DEVICE_TYPE_T rPrimaryDevTypeBE; + + DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT]; +#endif /* CFG_SUPPORT_P2P */ + + /*------------------------------------------------------------------------------------------*/ + /* QM related fields */ + /*------------------------------------------------------------------------------------------*/ + + UINT_8 ucFreeQuota; /* Per Sta flow controal. Valid when fgIsInPS is TRUE. + Change it for per Queue flow control */ + /* UINT_8 aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]; */ /* used in future */ + UINT_8 ucFreeQuotaForDelivery; + UINT_8 ucFreeQuotaForNonDelivery; +#if CFG_ENABLE_PKT_LIFETIME_PROFILE && CFG_ENABLE_PER_STA_STATISTICS + UINT_32 u4TotalTxPktsNumber; + UINT_32 u4TotalTxPktsTime; + UINT_32 u4TotalTxPktsHifTime; + + UINT_32 u4MaxTxPktsTime; + UINT_32 u4MaxTxPktsHifTime; + + UINT_32 u4ThresholdCounter; + UINT_32 u4EnqeueuCounter; + UINT_32 u4DeqeueuCounter; + UINT_32 u4PrevIntCount; + UINT_32 u4ThisIntCount; + UINT_32 u4NoTcResource; +#endif + +#if 1 + /*------------------------------------------------------------------------------------------*/ + /* To be removed, this is to make que_mgt compilation success only */ + /*------------------------------------------------------------------------------------------*/ + /* When this STA_REC is in use, set to TRUE. */ + BOOLEAN fgIsValid; + + /* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ + QUE_T arTxQueue[NUM_OF_PER_STA_TX_QUEUES]; + + /* When this STA is in PS Mode, set to TRUE. */ + /* BOOLEAN fgIsPS; */ + + /* When this STA enters Power-Saving, FW will notify the driver with a Session ID */ + UINT_8 ucPsSessionID; + + BOOLEAN fgIsAp; + + /* Reorder Parameter reference table */ + P_RX_BA_ENTRY_T aprRxReorderParamRefTbl[CFG_RX_MAX_BA_TID_NUM]; +#endif + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + TIMINGMSMT_PARAM_T rWNMTimingMsmt; +#endif + +#if (CFG_SUPPORT_TDLS == 1) + BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ + BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ + + BOOLEAN flgTdlsIsInitiator; /* TRUE: the peer is the initiator */ + IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ + BOOLEAN fgTdlsInSecurityMode; /* TRUE: security mode */ + PARAM_KEY_T rTdlsKeyTemp; /* temp to queue the key information */ + +#define TDLS_SETUP_TIMEOUT_SEC 5 /* unit: second */ + OS_SYSTIME rTdlsSetupStartTime; /* time when link setup is started */ + + OS_SYSTIME rTdlsTxQuotaEmptyTime; /* time when TX quota is 0 */ + + STAT_CNT_INFO_DRV_T rTdlsStatistics; +#endif /* CFG_SUPPORT_TDLS */ + +#if (CFG_SUPPORT_STATISTICS == 1) +#define STATS_ENV_TIMEOUT_SEC 10 /* unit: second */ + OS_SYSTIME rStatsEnvTxPeriodLastTime; + +#define STATS_ENV_TX_CNT_REPORT_TRIGGER 2500 /* 6Mbps */ +#define STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC 5 /* unit: second */ + OS_SYSTIME rStatsEnvTxLastTime; + UINT32 u4StatsEnvTxCnt; + + UINT32 u4NumOfNoTxQuota; + + UINT32 u4RxReorderFallAheadCnt; + UINT32 u4RxReorderFallBehindCnt; + UINT32 u4RxReorderHoleCnt; + UINT32 u4RxReorderHoleTimeoutCnt; + + UINT32 u4StatsRxPassToOsCnt; + + /* delay from HIF to pass to OS: us */ +#define STATS_STAY_INT_BYTE_THRESHOLD 500 + UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; + + UINT8 ucStatsGenDisplayCnt; +#endif /* CFG_SUPPORT_STATISTICS */ +}; + +#if 0 +/* use nic_tx.h instead */ +/* MSDU_INFO and SW_RFB structure */ +typedef struct _MSDU_INFO_T { + + /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ + + LINK_ENTRY_T rLinkEntry; + PUINT_8 pucBuffer; /* Pointer to the associated buffer */ + + UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ + UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ + UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ + UINT_8 ucTID; /* Traffic Identification */ + + BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ + UINT_8 ucMacHeaderLength; + UINT_16 u2PayloadLength; + PUINT_8 pucMacHeader; /* 802.11 header */ + PUINT_8 pucPayload; /* 802.11 payload */ + + OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ + P_STA_RECORD_T prStaRec; + +#if CFG_PROFILE_BUFFER_TRACING + ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; + UINT_32 rActivityTime[2]; +#endif +#if DBG && CFG_BUFFER_FREE_CHK + BOOLEAN fgBufferInSource; +#endif + + UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ + + /* 4 -----------------------Non-Common ------------------------- */ + /* TODO: move flags to ucControlFlag */ + + BOOLEAN fgIs1xFrame; /* Set to TRUE for 802.1x frame */ + + /* TXM: For TX Done handling, callback function & parameter (5) */ + BOOLEAN fgIsTxFailed; /* Set to TRUE if transmission failure */ + + PFN_TX_DONE_HANDLER pfTxDoneHandler; + + UINT_64 u8TimeStamp; /* record the TX timestamp */ + + /* TXM: For PS forwarding control (per-STA flow control) */ + UINT_8 ucPsForwardingType; /* Delivery-enabled, non-delivery-enabled, non-PS */ + UINT_8 ucPsSessionID; /* The Power Save session id for PS forwarding control */ + + /* TXM: For MAC TX DMA operations */ + UINT_8 ucMacTxQueIdx; /* MAC TX queue: AC0-AC6, BCM, or BCN */ + BOOLEAN fgNoAck; /* Set to true if Ack is not required for this packet */ + BOOLEAN fgBIP; /* Set to true if BIP is used for this packet */ + UINT_8 ucFragTotalCount; + UINT_8 ucFragFinishedCount; + UINT_16 u2FragThreshold; /* Fragmentation threshold without WLAN Header & FCS */ + BOOLEAN fgFixedRate; /* If a fixed rate is used, set to TRUE. */ + UINT_8 ucFixedRateCode; /* The rate code copied to MAC TX Desc */ + UINT_8 ucFixedRateRetryLimit; /* The retry limit when a fixed rate is used */ + BOOLEAN fgIsBmcQueueEnd; /* Set to true if this packet is the end of BMC */ + + /* TXM: For flushing ACL frames */ + UINT_16 u2PalLLH; /* 802.11 PAL LLH */ + /* UINT_16 u2LLH; */ + UINT_16 u2ACLSeq; /* u2LLH+u2ACLSeq for AM HCI flush ACL frame */ + + /* TXM for retransmitting a flushed packet */ + BOOLEAN fgIsSnAssigned; + UINT_16 u2SequenceNumber; /* To remember the Sequence Control field of this MPDU */ + +} MSDU_INFO_T, *P_MSDU_INFO_T; +#endif + +#if 0 +/* nic_rx.h */ +typedef struct _SW_RFB_T { + + /* 4 ----------------MSDU_INFO and SW_RFB Common Fields------------------ */ + + LINK_ENTRY_T rLinkEntry; + PUINT_8 pucBuffer; /* Pointer to the associated buffer */ + + UINT_8 ucBufferSource; /* HIF TX0, HIF TX1, MAC RX, or MNG Pool */ + UINT_8 ucNetworkTypeIndex; /* Network type index that this TX packet is assocaited with */ + UINT_8 ucTC; /* 0 to 5 (used by HIF TX to increment the corresponding TC counter) */ + UINT_8 ucTID; /* Traffic Identification */ + + BOOLEAN fgIs802_11Frame; /* Set to TRUE for 802.11 frame */ + UINT_8 ucMacHeaderLength; + UINT_16 u2PayloadLength; + PUINT_8 pucMacHeader; /* 802.11 header */ + PUINT_8 pucPayload; /* 802.11 payload */ + + OS_SYSTIME rArrivalTime; /* System Timestamp (4) */ + P_STA_RECORD_T prStaRec; + +#if CFG_PROFILE_BUFFER_TRACING + ENUM_BUFFER_ACTIVITY_TYPE_T eActivity[2]; + UINT_32 rActivityTime[2]; +#endif +#if DBG && CFG_BUFFER_FREE_CHK + BOOLEAN fgBufferInSource; +#endif + + UINT_8 ucControlFlag; /* For specify some Control Flags, e.g. Basic Rate */ + + /* 4 -----------------------Non-Common ------------------------- */ + + /* For composing the HIF RX Header (TODO: move flags to ucControlFlag) */ + PUINT_8 pucHifRxPacket; /* Pointer to the Response packet to HIF RX0 or RX1 */ + UINT_16 u2HifRxPacketLength; + UINT_8 ucHeaderOffset; + UINT_8 ucHifRxPortIndex; + + UINT_16 u2SequenceControl; + BOOLEAN fgIsA4Frame; /* (For MAC RX packet parsing) set to TRUE if 4 addresses are present */ + BOOLEAN fgIsBAR; + BOOLEAN fgIsQoSData; + BOOLEAN fgIsAmsduSubframe; /* Set to TRUE for A-MSDU Subframe */ + + /* For HIF RX DMA Desc */ + BOOLEAN fgTUChecksumCheckRequired; + BOOLEAN fgIPChecksumCheckRequired; + UINT_8 ucEtherTypeOffset; + +} SW_RFB_T, *P_SW_RFB_T; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +P_MSDU_INFO_T cnmMgtPktAlloc(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); + +VOID cnmMgtPktFree(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID cnmMemInit(IN P_ADAPTER_T prAdapter); + +PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length); + +VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory); + +VOID cnmStaRecInit(IN P_ADAPTER_T prAdapter); + +VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter); + +P_STA_RECORD_T cnmStaRecAlloc(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex); + +VOID cnmStaRecFree(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSyncToChip); + +VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip); + +P_STA_RECORD_T cnmGetStaRecByIndex(IN P_ADAPTER_T prAdapter, IN UINT_8 ucIndex); + +P_STA_RECORD_T cnmGetStaRecByAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIndex, IN UINT_8 aucPeerMACAddress[]); + +VOID cnmStaRecResetStatus(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +VOID cnmStaRecChangeState(IN P_ADAPTER_T prAdapter, IN OUT P_STA_RECORD_T prStaRec, IN UINT_8 ucNewState); + +P_STA_RECORD_T +cnmStaTheTypeGet(P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +static inline VOID cnmMemDataTypeCheck(VOID) +{ +#if 0 + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == 0); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rLinkEntry) == OFFSET_OF(SW_RFB_T, rLinkEntry)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucBuffer) == OFFSET_OF(SW_RFB_T, pucBuffer)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucBufferSource) == OFFSET_OF(SW_RFB_T, ucBufferSource)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucMacHeader) == OFFSET_OF(SW_RFB_T, pucMacHeader)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucMacHeaderLength) == + OFFSET_OF(SW_RFB_T, ucMacHeaderLength)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, pucPayload) == OFFSET_OF(SW_RFB_T, pucPayload)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, u2PayloadLength) == OFFSET_OF(SW_RFB_T, u2PayloadLength)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, prStaRec) == OFFSET_OF(SW_RFB_T, prStaRec)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucNetworkTypeIndex) == + OFFSET_OF(SW_RFB_T, ucNetworkTypeIndex)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTID) == OFFSET_OF(SW_RFB_T, ucTID)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgIs802_11Frame) == OFFSET_OF(SW_RFB_T, fgIs802_11Frame)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucControlFlag) == OFFSET_OF(SW_RFB_T, ucControlFlag)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rArrivalTime) == OFFSET_OF(SW_RFB_T, rArrivalTime)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, ucTC) == OFFSET_OF(SW_RFB_T, ucTC)); + +#if CFG_PROFILE_BUFFER_TRACING + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, eActivity[0]) == OFFSET_OF(SW_RFB_T, eActivity[0])); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, rActivityTime[0]) == + OFFSET_OF(SW_RFB_T, rActivityTime[0])); +#endif + +#if DBG && CFG_BUFFER_FREE_CHK + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSDU_INFO_T, fgBufferInSource) == + OFFSET_OF(SW_RFB_T, fgBufferInSource)); +#endif + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(STA_RECORD_T, rLinkEntry) == 0); + + return; +#endif +} +#endif /* _lint */ + +#endif /* _CNM_MEM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h new file mode 100644 index 0000000000000..cc5d0fa1adfca --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_scan.h @@ -0,0 +1,169 @@ +/* +** Id: @(#) +*/ + +/*! \file "cnm_scan.h" + \brief + +*/ + +/* +** Log: cnm_scan.h + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * remove unused definitions. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function prototype of cnmScanInit() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_SCAN_H +#define _CNM_SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define SCN_CHANNEL_DWELL_TIME_MIN_MSEC 12 +#define SCN_CHANNEL_DWELL_TIME_EXT_MSEC 98 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_FULL 3 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_FULL 1 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_PARTIAL 2 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_PARTIAL 1 + +#define SCN_INTERLACED_CHANNEL_GROUPS_NUM 3 /* Used by partial scan */ + +#define SCN_PARTIAL_SCAN_NUM 3 + +#define SCN_PARTIAL_SCAN_IDLE_MSEC 100 + +#define MAXIMUM_OPERATION_CHANNEL_LIST 46 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* The type of Scan Source */ +typedef enum _ENUM_SCN_REQ_SOURCE_T { + SCN_REQ_SOURCE_HEM = 0, + SCN_REQ_SOURCE_NET_FSM, + SCN_REQ_SOURCE_ROAMING, /* ROAMING Module is independent of AIS FSM */ + SCN_REQ_SOURCE_OBSS, /* 2.4G OBSS scan */ + SCN_REQ_SOURCE_NUM +} ENUM_SCN_REQ_SOURCE_T, *P_ENUM_SCN_REQ_SOURCE_T; + +typedef enum _ENUM_SCAN_PROFILE_T { + SCAN_PROFILE_FULL = 0, + SCAN_PROFILE_PARTIAL, + SCAN_PROFILE_VOIP, + SCAN_PROFILE_FULL_2G4, + SCAN_PROFILE_NUM +} ENUM_SCAN_PROFILE_T, *P_ENUM_SCAN_PROFILE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 +VOID cnmScanInit(VOID); + +VOID cnmScanRunEventScanRequest(IN P_MSG_HDR_T prMsgHdr); + +BOOLEAN cnmScanRunEventScanAbort(IN P_MSG_HDR_T prMsgHdr); + +VOID cnmScanProfileSelection(VOID); + +VOID cnmScanProcessStart(VOID); + +VOID cnmScanProcessStop(VOID); + +VOID cnmScanRunEventReqAISAbsDone(IN P_MSG_HDR_T prMsgHdr); + +VOID cnmScanRunEventCancelAISAbsDone(IN P_MSG_HDR_T prMsgHdr); + +VOID cnmScanPartialScanTimeout(UINT_32 u4Param); + +VOID cnmScanRunEventScnFsmComplete(IN P_MSG_HDR_T prMsgHdr); +#endif + +#endif /* _CNM_SCAN_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h new file mode 100644 index 0000000000000..a2ed9cd02fedf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/cnm_timer.h @@ -0,0 +1,235 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/cnm_timer.h#1 +*/ + +/*! \file cnm_timer.h + \brief Declaration of timer obj and related timer macro for setup time out + event. + + In this file we declare the timer object and provide several macro for + Protocol functional blocks to setup their own time out event. +*/ + +/* +** Log: cnm_timer.h + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Return timer token back to COS when entering wait off state + * + * 01 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb + * + * 01 06 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix system time is 32KHz instead of 1ms + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * add the copy time function + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix LINT warnning + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +#ifndef _CNM_TIMER_H +#define _CNM_TIMER_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#undef MSEC_PER_SEC +#define MSEC_PER_SEC 1000 +#undef USEC_PER_MSEC +#define USEC_PER_MSEC 1000 +#define USEC_PER_TU 1024 /* microsecond */ + +#define MSEC_PER_MIN (60 * MSEC_PER_SEC) + +#define MGMT_MAX_TIMEOUT_INTERVAL ((UINT_32)0x7fffffff) + +#define WAKE_LOCK_MAX_TIME 5 /* Unit: sec */ + +/* If WAKE_LOCK_MAX_TIME is too large, the whole system may always keep awake + * because of periodic timer of OBSS scanning + */ +#if (WAKE_LOCK_MAX_TIME >= OBSS_SCAN_MIN_INTERVAL) +#error WAKE_LOCK_MAX_TIME is too large +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef VOID(*PFN_MGMT_TIMEOUT_FUNC) (P_ADAPTER_T, ULONG); + +typedef struct _TIMER_T { + LINK_ENTRY_T rLinkEntry; + OS_SYSTIME rExpiredSysTime; + UINT_16 u2Minutes; + UINT_16 u2Reserved; + ULONG ulData; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; +} TIMER_T, *P_TIMER_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Check if time "a" is before time "b" */ +/* In 32-bit variable, 0x00000001~0x7fffffff -> positive number, + * 0x80000000~0xffffffff -> negative number + */ +#define TIME_BEFORE_64bit(a, b) (a < b) + +#define TIME_BEFORE(a, b) ((UINT_32)((UINT_32)(a) - (UINT_32)(b)) > 0x7fffffff) + +/* #define TIME_BEFORE(a,b) ((INT_32)((INT_32)(b) - (INT_32)(a)) > 0) + * may cause UNexpect result between Free build and Check build for WinCE + */ + +#define TIME_AFTER(a, b) TIME_BEFORE(b, a) + +#define SYSTIME_TO_SEC(_systime) ((_systime) / KAL_HZ) +#define SEC_TO_SYSTIME(_sec) ((_sec) * KAL_HZ) + +/* The macros to convert second & millisecond */ +#define MSEC_TO_SEC(_msec) ((_msec) / MSEC_PER_SEC) +#define SEC_TO_MSEC(_sec) ((UINT_32)(_sec) * MSEC_PER_SEC) + +/* The macros to convert millisecond & microsecond */ +#define USEC_TO_MSEC(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_USEC(_msec) ((UINT_32)(_msec) * USEC_PER_MSEC) + +/* The macros to convert TU & microsecond, TU & millisecond */ +#define TU_TO_USEC(_tu) ((_tu) * USEC_PER_TU) +#define TU_TO_MSEC(_tu) USEC_TO_MSEC(TU_TO_USEC(_tu)) + +/* The macros to convert TU & & OS system time, round up by 0.5 */ +#define TU_TO_SYSTIME(_tu) MSEC_TO_SYSTIME(TU_TO_MSEC(_tu)) +#define SYSTIME_TO_TU(_systime) \ + ((SYSTIME_TO_USEC(_systime) + ((USEC_PER_TU / 2) - 1)) / USEC_PER_TU) + +/* The macros to convert OS system time & microsecond */ +#define SYSTIME_TO_USEC(_systime) (SYSTIME_TO_MSEC(_systime) * USEC_PER_MSEC) + +/* The macro to get the current OS system time */ +#define GET_CURRENT_SYSTIME(_systime_p) {*(_systime_p) = kalGetTimeTick(); } + +/* The macro to copy the system time */ +#define COPY_SYSTIME(_destTime, _srcTime) {(_destTime) = (_srcTime); } + +/* The macro to get the system time difference between t1 and t2 (t1 - t2) */ +/* #define GET_SYSTIME_DIFFERENCE(_time1, _time2, _diffTime) \ + (_diffTime) = (_time1) - (_time2) */ + +/* The macro to check for the expiration, if TRUE means _currentTime >= _expirationTime */ +#define CHECK_FOR_EXPIRATION(_currentTime, _expirationTime) \ + (((UINT_32)(_currentTime) - (UINT_32)(_expirationTime)) <= 0x7fffffffUL) + +/* The macro to check for the timeout */ +#define CHECK_FOR_TIMEOUT(_currentTime, _timeoutStartingTime, _timeout) \ + CHECK_FOR_EXPIRATION((_currentTime), ((_timeoutStartingTime) + (_timeout))) + +/* The macro to set the expiration time with a specified timeout *//* Watch out for round up. */ +#define SET_EXPIRATION_TIME(_expirationTime, _timeout) \ + { \ + GET_CURRENT_SYSTIME(&(_expirationTime)); \ + (_expirationTime) += (OS_SYSTIME)(_timeout); \ + } + +#define timerRenewTimer(adapter, tmr, interval) \ + timerStartTimer(adapter, tmr, interval, (tmr)->function, (tmr)->data) + +#define MGMT_INIT_TIMER(_adapter_p, _timer, _callbackFunc) \ + timerInitTimer(_adapter_p, &(_timer), (ULONG)(_callbackFunc)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter); + +VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter); + +VOID +cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData); + +VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer); + +VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs); + +VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +static inline INT_32 timerPendingTimer(IN P_TIMER_T prTimer) +{ + ASSERT(prTimer); + + return prTimer->rLinkEntry.prNext != NULL; +} + +#endif /* _CNM_TIMER_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h new file mode 100644 index 0000000000000..868de4a6c40ac --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hem_mbox.h @@ -0,0 +1,446 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/hem_mbox.h#2 +*/ + +/*! \file hem_mbox.h + \brief + +*/ + +/* +** Log: hem_mbox.h +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for + * more than one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID + * support as well as uProbeDelay in NDIS 6.x driver model + * + * 06 07 2011 yuche.tsai + * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. + * cnm_timer[WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Add invitation support. + * + * 06 02 2011 cp.wu + * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction + * eliminate unused parameters for SAA-FSM + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 09 16 2010 cm.chang + * NULL + * Remove unused message ID + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some message ID for P2P FSM under provisioning phase. + * + * 08 11 2010 yuche.tsai + * NULL + * Add Message Event ID for P2P Module. + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 04 2010 cp.wu + * NULL + * remove unused mailbox message definitions. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * message table should not be commented out by compilation option without modifying header file + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_QOS_ACTION_FRAME + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_BA_ACTION_FRAME + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Develop partial DPD code + * + * 02 11 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added MID_RXM_MQM_QOS_ACTION_FRAME for RXM to indicate QoS Action frames to MQM + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename the parameter of mboxDummy() + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added MID_RXM_MQM_BA_ACTION_FRAME + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove Dummy MSG ID + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add JOIN REQ related MSG ID + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add AIS ABORT MSG ID + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add SCN MSG IDs + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _HEM_MBOX_H +#define _HEM_MBOX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Message IDs */ +typedef enum _ENUM_MSG_ID_T { + MID_MNY_CNM_CH_REQ, /* MANY notify CNM to obtain channel privilege */ + MID_MNY_CNM_CH_ABORT, /* MANY notify CNM to abort/release channel privilege */ + + MID_CNM_AIS_CH_GRANT, /* CNM notify AIS for indicating channel granted */ + MID_CNM_P2P_CH_GRANT, /* CNM notify P2P for indicating channel granted */ + MID_CNM_BOW_CH_GRANT, /* CNM notify BOW for indicating channel granted */ + + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_AIS_SCN_SCAN_REQ, /* AIS notify SCN for starting scan */ + MID_AIS_SCN_SCAN_REQ_V2, /* AIS notify SCN for starting scan with multiple SSID support */ + MID_AIS_SCN_SCAN_CANCEL, /* AIS notify SCN for cancelling scan */ + MID_P2P_SCN_SCAN_REQ, /* P2P notify SCN for starting scan */ + MID_P2P_SCN_SCAN_REQ_V2, /* P2P notify SCN for starting scan with multiple SSID support */ + MID_P2P_SCN_SCAN_CANCEL, /* P2P notify SCN for cancelling scan */ + MID_BOW_SCN_SCAN_REQ, /* BOW notify SCN for starting scan */ + MID_BOW_SCN_SCAN_REQ_V2, /* BOW notify SCN for starting scan with multiple SSID support */ + MID_BOW_SCN_SCAN_CANCEL, /* BOW notify SCN for cancelling scan */ + MID_RLM_SCN_SCAN_REQ, /* RLM notify SCN for starting scan (OBSS-SCAN) */ + MID_RLM_SCN_SCAN_REQ_V2, /* RLM notify SCN for starting scan (OBSS-SCAN) with multiple SSID support */ + MID_RLM_SCN_SCAN_CANCEL, /* RLM notify SCN for cancelling scan (OBSS-SCAN) */ + MID_SCN_AIS_SCAN_DONE, /* SCN notify AIS for scan completion */ + MID_SCN_P2P_SCAN_DONE, /* SCN notify P2P for scan completion */ + MID_SCN_BOW_SCAN_DONE, /* SCN notify BOW for scan completion */ + MID_SCN_RLM_SCAN_DONE, /* SCN notify RLM for scan completion (OBSS-SCAN) */ + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_OID_AIS_FSM_JOIN_REQ, /* OID/IOCTL notify AIS for join */ + MID_OID_AIS_FSM_ABORT, /* OID/IOCTL notify AIS for abort */ + MID_AIS_SAA_FSM_START, /* AIS notify SAA for Starting authentication/association fsm */ + MID_AIS_SAA_FSM_ABORT, /* AIS notify SAA for Aborting authentication/association fsm */ + MID_SAA_AIS_JOIN_COMPLETE, /* SAA notify AIS for indicating join complete */ + +#if CFG_ENABLE_BT_OVER_WIFI + /*--------------------------------------------------*/ + /* BOW Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_BOW_SAA_FSM_START, /* BOW notify SAA for Starting authentication/association fsm */ + MID_BOW_SAA_FSM_ABORT, /* BOW notify SAA for Aborting authentication/association fsm */ + MID_SAA_BOW_JOIN_COMPLETE, /* SAA notify BOW for indicating join complete */ +#endif + +#if CFG_ENABLE_WIFI_DIRECT + /*--------------------------------------------------*/ + /* P2P Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_P2P_SAA_FSM_START, /* P2P notify SAA for Starting authentication/association fsm */ + MID_P2P_SAA_FSM_ABORT, /* P2P notify SAA for Aborting authentication/association fsm */ + MID_SAA_P2P_JOIN_COMPLETE, /* SAA notify P2P for indicating join complete */ + + MID_MNY_P2P_FUN_SWITCH, /* Enable P2P FSM. */ + MID_MNY_P2P_DEVICE_DISCOVERY, /* Start device discovery. */ + MID_MNY_P2P_CONNECTION_REQ, /* Connection request. */ + MID_MNY_P2P_CONNECTION_ABORT, /* Abort connection request, P2P FSM return to IDLE. */ + MID_MNY_P2P_BEACON_UPDATE, + MID_MNY_P2P_STOP_AP, + MID_MNY_P2P_CHNL_REQ, + MID_MNY_P2P_CHNL_ABORT, + MID_MNY_P2P_MGMT_TX, + MID_MNY_P2P_GROUP_DISSOLVE, + MID_MNY_P2P_MGMT_FRAME_REGISTER, + MID_MNY_P2P_NET_DEV_REGISTER, + MID_MNY_P2P_START_AP, + MID_MNY_P2P_MGMT_FRAME_UPDATE, + MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, +#if CFG_SUPPORT_WFD + MID_MNY_P2P_WFD_CFG_UPDATE, +#endif +#endif + +#if CFG_SUPPORT_ADHOC + MID_SCN_AIS_FOUND_IBSS, /* SCN notify AIS that an IBSS Peer has been found and can merge into */ +#endif /* CFG_SUPPORT_ADHOC */ + + MID_SAA_AIS_FSM_ABORT, /* SAA notify AIS for indicating deauthentication/disassociation */ + + /*--------------------------------------------------*/ + /* AIS MGMT-TX Support */ + /*--------------------------------------------------*/ + MID_MNY_AIS_REMAIN_ON_CHANNEL, + MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, + MID_MNY_AIS_MGMT_TX, + + MID_TOTAL_NUM +} ENUM_MSG_ID_T, *P_ENUM_MSG_ID_T; + +/* Message header of inter-components */ +struct _MSG_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_MSG_ID_T eMsgId; +}; + +typedef VOID(*PFN_MSG_HNDL_FUNC) (P_ADAPTER_T, P_MSG_HDR_T); + +typedef struct _MSG_HNDL_ENTRY { + ENUM_MSG_ID_T eMsgId; + PFN_MSG_HNDL_FUNC pfMsgHndl; +} MSG_HNDL_ENTRY_T, *P_MSG_HNDL_ENTRY_T; + +typedef enum _EUNM_MSG_SEND_METHOD_T { + MSG_SEND_METHOD_BUF = 0, /* Message is put in the queue and will be + executed when mailbox is checked. */ + MSG_SEND_METHOD_UNBUF /* The handler function is called immediately + in the same context of the sender */ +} EUNM_MSG_SEND_METHOD_T, *P_EUNM_MSG_SEND_METHOD_T; + +typedef enum _ENUM_MBOX_ID_T { + MBOX_ID_0 = 0, + MBOX_ID_TOTAL_NUM +} ENUM_MBOX_ID_T, *P_ENUM_MBOX_ID_T; + +/* Define Mailbox structure */ +typedef struct _MBOX_T { + LINK_T rLinkHead; +} MBOX_T, *P_MBOX_T; + +typedef struct _MSG_SAA_FSM_START_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_START_T, *P_MSG_SAA_FSM_START_T; + +typedef struct _MSG_SAA_FSM_COMP_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + WLAN_STATUS rJoinStatus; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prSwRfb; +} MSG_SAA_FSM_COMP_T, *P_MSG_SAA_FSM_COMP_T; + +typedef struct _MSG_SAA_FSM_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_ABORT_T, *P_MSG_SAA_FSM_ABORT_T; + +typedef struct _MSG_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucNetTypeIndex; +} MSG_CONNECTION_ABORT_T, *P_MSG_CONNECTION_ABORT_T; + +typedef struct _MSG_REMAIN_ON_CHANNEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eSco; + UINT_8 ucChannelNum; + UINT_32 u4DurationMs; + UINT_64 u8Cookie; +} MSG_REMAIN_ON_CHANNEL_T, *P_MSG_REMAIN_ON_CHANNEL_T; + +typedef struct _MSG_CANCEL_REMAIN_ON_CHANNEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_64 u8Cookie; +} MSG_CANCEL_REMAIN_ON_CHANNEL_T, *P_MSG_CANCEL_REMAIN_ON_CHANNEL_T; + +typedef struct _MSG_MGMT_TX_REQUEST_T { + MSG_HDR_T rMsgHdr; + P_MSDU_INFO_T prMgmtMsduInfo; + UINT_64 u8Cookie; /* For indication. */ + BOOLEAN fgNoneCckRate; + BOOLEAN fgIsWaitRsp; +} MSG_MGMT_TX_REQUEST_T, *P_MSG_MGMT_TX_REQUEST_T; + +/* specific message data types */ +typedef MSG_SAA_FSM_START_T MSG_JOIN_REQ_T, *P_MSG_JOIN_REQ_T; +typedef MSG_SAA_FSM_COMP_T MSG_JOIN_COMP_T, *P_MSG_JOIN_COMP_T; +typedef MSG_SAA_FSM_ABORT_T MSG_JOIN_ABORT_T, *P_MSG_JOIN_ABORT_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); + +VOID +mboxSendMsg(IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod); + +VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); + +VOID mboxInitialize(IN P_ADAPTER_T prAdapter); + +VOID mboxDestroy(IN P_ADAPTER_T prAdapter); + +VOID mboxDummy(IN P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _HEM_MBOX_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h new file mode 100644 index 0000000000000..88b99222133f4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/hs20.h @@ -0,0 +1,148 @@ +/* +** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/include/mgmt/hs20.h#2 +*/ + +/*! \file hs20.h + \brief This file contains the function declaration for hs20.c. +*/ + +/* +** Log: + * + */ + +#ifndef _HS20_H +#define _HS20_H + +#if CFG_SUPPORT_HOTSPOT_2_0 +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define BSSID_POOL_MAX_SIZE 8 +#define HS20_SIGMA_SCAN_RESULT_TIMEOUT 30 /* sec */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CFG_ENABLE_GTK_FRAME_FILTER +/*For GTK Frame Filter*/ +typedef struct _IPV4_NETWORK_ADDRESS_LIST { + UINT_8 ucAddrCount; + IPV4_NETWORK_ADDRESS arNetAddr[1]; +} IPV4_NETWORK_ADDRESS_LIST, *P_IPV4_NETWORK_ADDRESS_LIST; +#endif + +/* Entry of BSSID Pool - For SIGMA Test */ +typedef struct _BSSID_ENTRY_T { + UINT_8 aucBSSID[MAC_ADDR_LEN]; +} BSSID_ENTRY_T, P_HS20_BSSID_POOL_ENTRY_T; + +struct _HS20_INFO_T { + + /*Hotspot 2.0 Information */ + UINT_8 aucHESSID[MAC_ADDR_LEN]; + UINT_8 ucAccessNetworkOptions; + UINT_8 ucVenueGroup; /* VenueInfo - Group */ + UINT_8 ucVenueType; + UINT_8 ucHotspotConfig; + + /*Roaming Consortium Information */ + /* PARAM_HS20_ROAMING_CONSORTIUM_INFO rRCInfo; */ + + /*Hotspot 2.0 dummy AP Info */ + + /*Time Advertisement Information */ + /* UINT_32 u4UTCOffsetTime; */ + /* UINT_8 aucTimeZone[ELEM_MAX_LEN_TIME_ZONE]; */ + /* UINT_8 ucLenTimeZone; */ + + /* For SIGMA Test */ + /* BSSID Pool */ + BSSID_ENTRY_T arBssidPool[BSSID_POOL_MAX_SIZE]; + UINT_8 ucNumBssidPoolEntry; + BOOLEAN fgIsHS2SigmaMode; + +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*For GTK Frame Filter*/ +#if DBG +#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ + { \ + UINT_32 u4Size = OFFSET_OF(IPV4_NETWORK_ADDRESS_LIST, arNetAddr) + \ + (((_prAddrList)->ucAddrCount) * sizeof(IPV4_NETWORK_ADDRESS)); \ + kalMemFree((_prAddrList), VIR_MEM_TYPE, u4Size); \ + (_prAddrList) = NULL; \ + } +#else +#define FREE_IPV4_NETWORK_ADDR_LIST(_prAddrList) \ + { \ + kalMemFree((_prAddrList), VIR_MEM_TYPE, 0); \ + (_prAddrList) = NULL; \ + } +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); + +VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); + +VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo); + +VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); + +VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); + +VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE); + +UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID); + +WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE); + +BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); + +BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb); + +#if CFG_ENABLE_GTK_FRAME_FILTER +BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); +#endif + +BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb); + +BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx); + +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h new file mode 100644 index 0000000000000..cb89fd8793ee4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/mib.h @@ -0,0 +1,153 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/mib.h#1 +*/ + +/*! \file mib.h + \brief This file contains the IEEE 802.11 family related MIB definition + for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: mib.h + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +#ifndef _MIB_H +#define _MIB_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Entry in SMT AuthenticationAlgorithms Table: dot11AuthenticationAlgorithmsEntry */ +typedef struct _DOT11_AUTHENTICATION_ALGORITHMS_ENTRY { + BOOLEAN dot11AuthenticationAlgorithmsEnable; /* dot11AuthenticationAlgorithmsEntry 3 */ +} DOT11_AUTHENTICATION_ALGORITHMS_ENTRY, *P_DOT11_AUTHENTICATION_ALGORITHMS_ENTRY; + +/* Entry in SMT dot11RSNAConfigPairwiseCiphersTalbe Table: dot11RSNAConfigPairwiseCiphersEntry */ +typedef struct _DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY { + UINT_32 dot11RSNAConfigPairwiseCipher; /* dot11RSNAConfigPairwiseCiphersEntry 2 */ + BOOLEAN dot11RSNAConfigPairwiseCipherEnabled; /* dot11RSNAConfigPairwiseCiphersEntry 3 */ +} DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY, *P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY; + +/* Entry in SMT dot11RSNAConfigAuthenticationSuitesTalbe Table: dot11RSNAConfigAuthenticationSuitesEntry */ +typedef struct _DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY { + UINT_32 dot11RSNAConfigAuthenticationSuite; /* dot11RSNAConfigAuthenticationSuitesEntry 2 */ + BOOLEAN dot11RSNAConfigAuthenticationSuiteEnabled; /* dot11RSNAConfigAuthenticationSuitesEntry 3 */ +} DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY, *P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY; + +/* ----- IEEE 802.11 MIB Major sections ----- */ +typedef struct _IEEE_802_11_MIB_T { + /* dot11PrivacyTable (dot11smt 5) */ + UINT_8 dot11WEPDefaultKeyID; /* dot11PrivacyEntry 2 */ + BOOLEAN dot11TranmitKeyAvailable; + UINT_32 dot11WEPICVErrorCount; /* dot11PrivacyEntry 5 */ + UINT_32 dot11WEPExcludedCount; /* dot11PrivacyEntry 6 */ + + /* dot11RSNAConfigTable (dot11smt 8) */ + UINT_32 dot11RSNAConfigGroupCipher; /* dot11RSNAConfigEntry 4 */ + + /* dot11RSNAConfigPairwiseCiphersTable (dot11smt 9) */ + DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY dot11RSNAConfigPairwiseCiphersTable[MAX_NUM_SUPPORTED_CIPHER_SUITES]; + + /* dot11RSNAConfigAuthenticationSuitesTable (dot11smt 10) */ + DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY + dot11RSNAConfigAuthenticationSuitesTable[MAX_NUM_SUPPORTED_AKM_SUITES]; + +#if 0 /* SUPPORT_WAPI */ + BOOLEAN fgWapiKeyInstalled; + PARAM_WPI_KEY_T rWapiPairwiseKey[2]; + BOOLEAN fgPairwiseKeyUsed[2]; + UINT_8 ucWpiActivedPWKey; /* Must be 0 or 1, by wapi spec */ + PARAM_WPI_KEY_T rWapiGroupKey[2]; + BOOLEAN fgGroupKeyUsed[2]; +#endif +} IEEE_802_11_MIB_T, *P_IEEE_802_11_MIB_T; + +/* ------------------ IEEE 802.11 non HT PHY characteristics ---------------- */ +typedef const struct _NON_HT_PHY_ATTRIBUTE_T { + UINT_16 u2SupportedRateSet; + + BOOLEAN fgIsShortPreambleOptionImplemented; + + BOOLEAN fgIsShortSlotTimeOptionImplemented; + +} NON_HT_PHY_ATTRIBUTE_T, *P_NON_HT_PHY_ATTRIBUTE_T; + +typedef const struct _NON_HT_ADHOC_MODE_ATTRIBUTE_T { + + ENUM_PHY_TYPE_INDEX_T ePhyTypeIndex; + + UINT_16 u2BSSBasicRateSet; + +} NON_HT_ADHOC_MODE_ATTRIBUTE_T, *P_NON_HT_ADHOC_MODE_ATTRIBUTE_T; + +typedef NON_HT_ADHOC_MODE_ATTRIBUTE_T NON_HT_AP_MODE_ATTRIBUTE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[]; +extern NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[]; +extern NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[]; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MIB_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h new file mode 100644 index 0000000000000..11145c31dbfae --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_assoc.h @@ -0,0 +1,55 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_assoc.h#1 +*/ + +/*! \file p2p_assoc.h + \brief This file contains the Wi-Fi Direct ASSOC REQ/RESP of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +#ifndef _P2P_ASSOC_H +#define _P2P_ASSOC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h new file mode 100644 index 0000000000000..869d7bf0ee614 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_bss.h @@ -0,0 +1,56 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_bss.h#2 +*/ + +/*! \file "p2p_bss.h" + \brief In this file we define the function prototype used in p2p BSS/IBSS. + + The file contains the function declarations and defines for used in BSS/IBSS. +*/ + +#ifndef _P2P_BSS_H +#define _P2P_BSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +UINT_32 p2pGetTxProbRspIeTableSize(VOID); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h new file mode 100644 index 0000000000000..2541e1d2883e8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_fsm.h @@ -0,0 +1,2190 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_fsm.h#23 +*/ + +/*! \file p2p_fsm.h + \brief Declaration of functions and finite state machine for P2P Module. + + Declaration of functions and finite state machine for P2P Module. +*/ + +/* +** Log: p2p_fsm.h +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 14 2012 yuche.tsai +** NULL +** Fix compile error. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 18 2012 yuche.tsai + * NULL + * add one file. + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve class 3 error issue under AP mode. + * + * data frame may TX before Assoc Response TX. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix default device name issue. + * + * 11 09 2011 yuche.tsai + * [WCXRP00001093] [Need Patch][Volunteer Patch] Service Discovery 2.0 state transition issue. + * Fix SD2.0 issue which may cause KE. (Monkey test) + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version + * query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channel Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 09 01 2011 yuche.tsai + * NULL + * Fix channel stay interval. + * Sync channel stay interval & channel request interval under AP mode.. + * + * 08 30 2011 yuche.tsai + * [WCXRP00000953] [Volunteer Patch][Driver] Hot Spot Channel ASSERT issue. + * Fix hot spot FW assert issue when under concurrent case. (DBG enable only) + * + * 08 16 2011 cp.wu + * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence + * auto channel decision for 2.4GHz hot spot mode + * + * 08 16 2011 yuche.tsai + * NULL + * Fix scan policy for Active LISTEN scan. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, + * TX deauth to a disconnecting device issue. + * Support TX Deauth Issue. + * + * 07 26 2011 yuche.tsai + * [WCXRP00000875] [Volunteer Patch][WiFi Direct][Driver] MT6620 IOT issue with realtek test bed solution. + * Turn off persistent group support for V2.0 release. + * + * 07 18 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Fix compile error. + * + * 07 18 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Fix MT6620 WiFi Direct IOT Issue with BCM solution. + * + * 07 11 2011 yuche.tsai + * [WCXRP00000845] [Volunteer Patch][WiFi Direct] WiFi Direct Device Connection Robustness + * Enhance Connection Robustness. + * + * 07 08 2011 yuche.tsai + * [WCXRP00000841] [Volunteer Patch][WiFi Direct] Group Owner Setting. + * Update GO configure parameter. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Disable enhancement II for debugging. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Refine compile flag. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add wifi direct connection enhancement method I, II & VI. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix connection indication twice issue. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Fix RX SD request under AP mode issue. + * + * 05 04 2011 yuche.tsai + * NULL + * Support partial persistent group function. + * + * 04 20 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove CFG_WIFI_DIRECT_MOVED. + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 22 2011 yuche.tsai + * NULL + * 1.Shorten the LISTEN interval. + * 2. Fix IF address issue when we are GO + * 3. Fix LISTEN channel issue. + * + * 03 21 2011 yuche.tsai + * NULL + * Change P2P Connection Request Flow. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 07 2011 yuche.tsai + * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the ioctl setting that index not map to spec defined config method. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC IE BE format issue. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 11 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add two function prototype. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Support Disassoc & Deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. + +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. + +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 25 2011 terry.wu + * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter + * Add a new module parameter to indicate current runnig mode, P2P or AP. + * + * 01 19 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Null NOA attribute setting when no related parameters. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify some behavior of AP mode. + * + * 12 22 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Compile Error. + * + * 12 15 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Refine Connection Flow. + * + * 12 08 2010 yuche.tsai + * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. + * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client + * by checking the P2P IE in assoc req frame. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation & Provision Discovery. + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 30 2010 yuche.tsai + * NULL + * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ + * + * 11 29 2010 yuche.tsai + * NULL + * Update P2P related function for INVITATION & PROVISION DISCOVERY. + * + * 11 26 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Update P2P PS for NOA function. + * + * 11 25 2010 yuche.tsai + * NULL + * Update Code for Invitation Related Function. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] + * Set the Tx lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at WinXP. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 26 2010 yuche.tsai + * NULL + * Add connection abort message event prototype. + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 16 2010 yuche.tsai + * NULL + * Fix P2P Intended Interface Address Bug. + * Extend GO Nego Timeout Time. + * + * 08 16 2010 yuche.tsai + * NULL + * Extend Listen Interval default value & remove deprecated variable. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Add function prototype for join complete. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some function proto type for P2P FSM under provisioning phase.. + * + * 08 11 2010 yuche.tsai + * NULL + * Change P2P data structure for supporting + * 1. P2P Device discovery. + * 2. P2P Group Negotiation. + * 3. P2P JOIN + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Update P2P FSM header file. + * + * 07 23 2010 cp.wu + * + * P2P/RSN/WAPI IEs need to be declared with compact structure. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Update P2P FSM header file. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix some P2P function prototype. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename CFG flag for P2P + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify parameter of p2pStartGO + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add Wi-Fi Direct SSID and P2P GO Test Mode + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +#ifndef _P2P_FSM_H +#define _P2P_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CID52_53_54 0 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_P2P_STATE_T { + P2P_STATE_IDLE = 0, + P2P_STATE_SCAN, + P2P_STATE_AP_CHANNEL_DETECT, + P2P_STATE_REQING_CHANNEL, + P2P_STATE_CHNL_ON_HAND, /* Requesting Channel to Send Specific Frame. */ + P2P_STATE_GC_JOIN, /* Sending Specific Frame. May extending channel by other event. */ + P2P_STATE_NUM +} ENUM_P2P_STATE_T, *P_ENUM_P2P_STATE_T; + +enum _ENUM_P2P_DEV_EXT_LISTEN_T { + P2P_DEV_NOT_EXT_LISTEN, + P2P_DEV_EXT_LISTEN_ING, + P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT, + P2P_DEV_EXT_LISTEN_NUM +}; + +typedef enum _ENUM_CHANNEL_REQ_TYPE_T { + CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL, + CHANNEL_REQ_TYPE_GC_JOIN_REQ, + CHANNEL_REQ_TYPE_GO_START_BSS +} ENUM_CHANNEL_REQ_TYPE_T, *P_ENUM_CHANNEL_REQ_TYPE_T; + +typedef enum _ENUM_BUFFER_TYPE_T { + ENUM_FRAME_TYPE_EXTRA_IE_BEACON, + ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP, + ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP, + ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE, + ENUM_FRAME_TYPE_BEACON_TEMPLATE, + ENUM_FRAME_IE_NUM +} ENUM_BUFFER_TYPE_T, *P_ENUM_BUFFER_TYPE_T; + +typedef enum _ENUM_HIDDEN_SSID_TYPE_T { + ENUM_HIDDEN_SSID_NONE, + ENUM_HIDDEN_SSID_LEN, + ENUM_HIDDEN_SSID_ZERO_CONTENT, + ENUM_HIDDEN_SSID_NUM +} ENUM_HIDDEN_SSID_TYPE_T, *P_ENUM_HIDDEN_SSID_TYPE_T; + +typedef struct _P2P_SSID_STRUCT_T { + UINT_8 aucSsid[32]; + UINT_8 ucSsidLen; +} P2P_SSID_STRUCT_T, *P_P2P_SSID_STRUCT_T; + +typedef struct _P2P_STATION_INFO_T { + UINT_32 u4InactiveTime; + UINT_32 u4RxBytes; /* TODO: */ + UINT_32 u4TxBytes; /* TODO: */ + UINT_32 u4RxPackets; /* TODO: */ + UINT_32 u4TxPackets; /* TODO: */ + /* TODO: Add more for requirement. */ +} P2P_STATION_INFO_T, *P_P2P_STATION_INFO_T; + +typedef struct _AP_CRYPTO_SETTINGS_T { + UINT_32 u4WpaVersion; + UINT_32 u4CipherGroup; + INT_32 i4NumOfCiphers; + UINT_32 aucCiphersPairwise[5]; + INT_32 i4NumOfAkmSuites; + UINT_32 aucAkmSuites[2]; + BOOLEAN fgIsControlPort; + UINT_16 u2ControlPortBE; + BOOLEAN fgIsControlPortEncrypt; +} AP_CRYPTO_SETTINGS_T, *P_AP_CRYPTO_SETTINGS_T; + +/*-------------------- P2P FSM ACTION STRUCT ---------------------*/ +typedef struct _P2P_CHNL_REQ_INFO_T { + BOOLEAN fgIsChannelRequested; + UINT_8 ucSeqNumOfChReq; + UINT_64 u8Cookie; + UINT_8 ucReqChnlNum; + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eChnlSco; + UINT_32 u4MaxInterval; + ENUM_CHANNEL_REQ_TYPE_T eChannelReqType; + + UINT_8 ucOriChnlNum; + ENUM_BAND_T eOriBand; + ENUM_CHNL_EXT_T eOriChnlSco; + UINT_32 NFC_BEAM; /*NFC Beam + Indication */ +} P2P_CHNL_REQ_INFO_T, *P_P2P_CHNL_REQ_INFO_T; + +typedef struct _P2P_SCAN_REQ_INFO_T { + ENUM_SCAN_TYPE_T eScanType; + ENUM_SCAN_CHANNEL eChannelSet; + UINT_16 u2PassiveDewellTime; + UINT_8 ucSeqNumOfScnMsg; + BOOLEAN fgIsAbort; + BOOLEAN fgIsScanRequest; + UINT_8 ucNumChannelList; + RF_CHANNEL_INFO_T arScanChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; + P2P_SSID_STRUCT_T rSsidStruct; /* Currently we can only take one SSID scan request */ + BOOLEAN fgIsGOInitialDone; +} P2P_SCAN_REQ_INFO_T, *P_P2P_SCAN_REQ_INFO_T; + +typedef struct _P2P_CONNECTION_REQ_INFO_T { + + BOOLEAN fgIsConnRequest; + P2P_SSID_STRUCT_T rSsidStruct; + UINT_8 aucBssid[MAC_ADDR_LEN]; + /* For ASSOC Req. */ + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; +} P2P_CONNECTION_REQ_INFO_T, *P_P2P_CONNECTION_REQ_INFO_T; + +typedef struct _P2P_MGMT_TX_REQ_INFO_T { + BOOLEAN fgIsMgmtTxRequested; + P_MSDU_INFO_T prMgmtTxMsdu; + UINT_64 u8Cookie; +} P2P_MGMT_TX_REQ_INFO_T, *P_P2P_MGMT_TX_REQ_INFO_T; + +struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T { + MSG_HDR_T rMsgHdr; + UINT_32 wait; /* interval supplicant expected to stay in listen interval */ +}; + +typedef struct _P2P_BEACON_UPDATE_INFO_T { + PUINT_8 pucBcnHdr; + UINT_32 u4BcnHdrLen; + PUINT_8 pucBcnBody; + UINT_32 u4BcnBodyLen; +} P2P_BEACON_UPDATE_INFO_T, *P_P2P_BEACON_UPDATE_INFO_T; + +typedef struct _P2P_PROBE_RSP_UPDATE_INFO_T { + P_MSDU_INFO_T prProbeRspMsduTemplate; +} P2P_PROBE_RSP_UPDATE_INFO_T, *P_P2P_PROBE_RSP_UPDATE_INFO_T; + +typedef struct _P2P_ASSOC_RSP_UPDATE_INFO_T { + PUINT_8 pucAssocRspExtIE; + UINT_16 u2AssocIELen; +} P2P_ASSOC_RSP_UPDATE_INFO_T, *P_P2P_ASSOC_RSP_UPDATE_INFO_T; + +typedef struct _P2P_JOIN_INFO_T { + UINT_32 ucSeqNumOfReqMsg; + UINT_8 ucAvailableAuthTypes; + P_STA_RECORD_T prTargetStaRec; + P2P_SSID_STRUCT_T rSsidStruct; + BOOLEAN fgIsJoinComplete; + /* For ASSOC Rsp. */ + UINT_32 u4BufLength; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; +} P2P_JOIN_INFO_T, *P_P2P_JOIN_INFO_T; + +#if CFG_SUPPORT_WFD + +#define WFD_FLAGS_DEV_INFO_VALID BIT(0) /* 1. WFD_DEV_INFO, 2. WFD_CTRL_PORT, 3. WFD_MAT_TP. */ +#define WFD_FLAGS_SINK_INFO_VALID BIT(1) /* 1. WFD_SINK_STATUS, 2. WFD_SINK_MAC. */ +#define WFD_FLAGS_ASSOC_MAC_VALID BIT(2) /* 1. WFD_ASSOC_MAC. */ +#define WFD_FLAGS_EXT_CAPABILITY_VALID BIT(3) /* 1. WFD_EXTEND_CAPABILITY. */ + +struct _WFD_CFG_SETTINGS_T { + UINT_32 u4WfdCmdType; + UINT_8 ucWfdEnable; + UINT_8 ucWfdCoupleSinkStatus; + UINT_8 ucWfdSessionAvailable; /* 0: NA 1:Set 2:Clear */ + UINT_8 ucWfdSigmaMode; + UINT_16 u2WfdDevInfo; + UINT_16 u2WfdControlPort; + UINT_16 u2WfdMaximumTp; + UINT_16 u2WfdExtendCap; + UINT_8 aucWfdCoupleSinkAddress[MAC_ADDR_LEN]; + UINT_8 aucWfdAssociatedBssid[MAC_ADDR_LEN]; + UINT_8 aucWfdVideoIp[4]; + UINT_8 aucWfdAudioIp[4]; + UINT_16 u2WfdVideoPort; + UINT_16 u2WfdAudioPort; + UINT_32 u4WfdFlag; + UINT_32 u4WfdPolicy; + UINT_32 u4WfdState; + UINT_8 aucWfdSessionInformationIE[24 * 8]; + UINT_16 u2WfdSessionInformationIELen; + UINT_8 aucReserved1[2]; + UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; + UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; + UINT_32 u4WfdAdvancedFlag; + /* Group 1 64 bytes */ + UINT_8 aucWfdLocalIp[4]; + UINT_16 u2WfdLifetimeAc2; /* Unit is 2 TU */ + UINT_16 u2WfdLifetimeAc3; /* Unit is 2 TU */ + UINT_16 u2WfdCounterThreshold; /* Unit is ms */ + UINT_8 aucReverved2[54]; + /* Group 2 64 bytes */ + UINT_8 aucReverved3[64]; + /* Group 3 64 bytes */ + UINT_8 aucReverved4[64]; + +}; + +struct _WFD_DBG_CFG_SETTINGS_T { + UINT_8 ucWfdDebugMode; + UINT_16 u2WfdSNShowPeiroid; + UINT_8 Reserved; + +}; + +#endif + +struct _P2P_FSM_INFO_T { + /* State related. */ + ENUM_P2P_STATE_T ePreviousState; + ENUM_P2P_STATE_T eCurrentState; + + /* Channel related. */ + P2P_CHNL_REQ_INFO_T rChnlReqInfo; + + /* Scan related. */ + P2P_SCAN_REQ_INFO_T rScanReqInfo; + + /* Connection related. */ + P2P_CONNECTION_REQ_INFO_T rConnReqInfo; + + /* Mgmt tx related. */ + P2P_MGMT_TX_REQ_INFO_T rMgmtTxInfo; + + /* Beacon related. */ + P2P_BEACON_UPDATE_INFO_T rBcnContentInfo; + + /* Probe Response related. */ + P2P_PROBE_RSP_UPDATE_INFO_T rProbeRspContentInfo; + + /* Assoc Rsp related. */ + P2P_ASSOC_RSP_UPDATE_INFO_T rAssocRspContentInfo; + + /* GC Join related. */ + P2P_JOIN_INFO_T rJoinInfo; + + /* FSM Timer */ +/* TIMER_T rP2pFsmTimeoutTimer; */ + + /* GC Target BSS. */ + P_BSS_DESC_T prTargetBss; + + /* GC Connection Request. */ + BOOLEAN fgIsConnectionRequested; + + BOOLEAN fgIsApMode; + + /* Channel grant interval. */ + UINT_32 u4GrantInterval; + + /* Packet filter for P2P module. */ + UINT_32 u4P2pPacketFilter; + + /* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Prepare for use vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ + /* Msg event queue. */ + LINK_T rMsgEventQueue; + +#if CFG_SUPPORT_WFD + WFD_CFG_SETTINGS_T rWfdConfigureSettings; + WFD_DBG_CFG_SETTINGS_T rWfdDebugSetting; +#endif + + BOOLEAN fgIsWPSMode; + + enum _ENUM_P2P_DEV_EXT_LISTEN_T eListenExted; +}; + +/*---------------- Messages -------------------*/ +typedef struct _MSG_P2P_SCAN_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P_P2P_SSID_STRUCT_T prSSID; + INT_32 i4SsidNum; + UINT_32 u4NumChannel; + PUINT_8 pucIEBuf; + UINT_32 u4IELen; + BOOLEAN fgIsAbort; + RF_CHANNEL_INFO_T arChannelListInfo[1]; +} MSG_P2P_SCAN_REQUEST_T, *P_MSG_P2P_SCAN_REQUEST_T; + +typedef struct _MSG_P2P_CHNL_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_64 u8Cookie; + UINT_32 u4Duration; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; +} MSG_P2P_CHNL_REQUEST_T, *P_MSG_P2P_CHNL_REQUEST_T; + +typedef struct _MSG_P2P_CHNL_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_64 u8Cookie; +} MSG_P2P_CHNL_ABORT_T, *P_MSG_P2P_CHNL_ABORT_T; + +typedef struct _MSG_P2P_CONNECTION_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P2P_SSID_STRUCT_T rSsid; + UINT_8 aucBssid[MAC_ADDR_LEN]; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; + UINT_32 u4IELen; + UINT_8 aucIEBuf[1]; + /* TODO: Auth Type, OPEN, SHARED, FT, EAP... */ +} MSG_P2P_CONNECTION_REQUEST_T, *P_MSG_P2P_CONNECTION_REQUEST_T; + +typedef struct _MSG_P2P_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member. */ + UINT_8 aucTargetID[MAC_ADDR_LEN]; + UINT_16 u2ReasonCode; + BOOLEAN fgSendDeauth; +} MSG_P2P_CONNECTION_ABORT_T, *P_MSG_P2P_CONNECTION_ABORT_T; + +typedef struct _MSG_P2P_MGMT_TX_REQUEST_T { + MSG_HDR_T rMsgHdr; + P_MSDU_INFO_T prMgmtMsduInfo; + UINT_64 u8Cookie; /* For indication. */ + BOOLEAN fgNoneCckRate; + BOOLEAN fgIsWaitRsp; +} MSG_P2P_MGMT_TX_REQUEST_T, *P_MSG_P2P_MGMT_TX_REQUEST_T; + +typedef struct _MSG_P2P_START_AP_T { + MSG_HDR_T rMsgHdr; + UINT_32 u4DtimPeriod; + UINT_32 u4BcnInterval; + UINT_8 aucSsid[32]; + UINT_16 u2SsidLen; + UINT_8 ucHiddenSsidType; + BOOLEAN fgIsPrivacy; + AP_CRYPTO_SETTINGS_T rEncryptionSettings; + INT_32 i4InactiveTimeout; +} MSG_P2P_START_AP_T, *P_MSG_P2P_START_AP_T; + +typedef struct _MSG_P2P_BEACON_UPDATE_T { + MSG_HDR_T rMsgHdr; + UINT_32 u4BcnHdrLen; + UINT_32 u4BcnBodyLen; + PUINT_8 pucBcnHdr; + PUINT_8 pucBcnBody; + UINT_8 aucBuffer[1]; /* Header & Body are put here. */ +} MSG_P2P_BEACON_UPDATE_T, *P_MSG_P2P_BEACON_UPDATE_T; + +typedef struct _MSG_P2P_MGMT_FRAME_UPDATE_T { + MSG_HDR_T rMsgHdr; + ENUM_BUFFER_TYPE_T eBufferType; + UINT_32 u4BufferLen; + UINT_8 aucBuffer[1]; +} MSG_P2P_MGMT_FRAME_UPDATE_T, *P_MSG_P2P_MGMT_FRAME_UPDATE_T; + +typedef struct _MSG_P2P_SWITCH_OP_MODE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + ENUM_OP_MODE_T eOpMode; +} MSG_P2P_SWITCH_OP_MODE_T, *P_MSG_P2P_SWITCH_OP_MODE_T; + +typedef struct _MSG_P2P_MGMT_FRAME_REGISTER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_16 u2FrameType; + BOOLEAN fgIsRegister; +} MSG_P2P_MGMT_FRAME_REGISTER_T, *P_MSG_P2P_MGMT_FRAME_REGISTER_T; + +typedef struct _MSG_P2P_NETDEV_REGISTER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + BOOLEAN fgIsEnable; + UINT_8 ucMode; +} MSG_P2P_NETDEV_REGISTER_T, *P_MSG_P2P_NETDEV_REGISTER_T; + +#if CFG_SUPPORT_WFD +typedef struct _MSG_WFD_CONFIG_SETTINGS_CHANGED_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P_WFD_CFG_SETTINGS_T prWfdCfgSettings; +} MSG_WFD_CONFIG_SETTINGS_CHANGED_T, *P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T; +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +WLAN_STATUS +p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +#if CFG_SUPPORT_WFD +VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); +#endif + +#if 0 +/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////////////////////////////////// */ +#endif + +/* 3 --------------- WFA P2P DEFAULT PARAMETERS --------------- */ +#define P2P_WILDCARD_SSID "DIRECT-" +#define P2P_WILDCARD_SSID_LEN 7 +#define P2P_GROUP_ID_LEN 9 + +#define P2P_DRIVER_VERSION 2 /* Update when needed. */ + +#define P2P_DEFAULT_DEV_NAME "Wireless Client" +#define P2P_DEFAULT_DEV_NAME_LEN 15 +#define P2P_DEFAULT_PRIMARY_CATEGORY_ID 10 +#define P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID 5 +#define P2P_DEFAULT_CONFIG_METHOD \ + (WPS_ATTRI_CFG_METHOD_PUSH_BUTTON | WPS_ATTRI_CFG_METHOD_KEYPAD | WPS_ATTRI_CFG_METHOD_DISPLAY) +#define P2P_DEFAULT_LISTEN_CHANNEL 1 + +#define P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT 0 /* NOTE(Kevin): Shall <= 16 */ +#define P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT 13 + +#define P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE 51 /* Contains 6 sub-band. */ + +#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ + +#define P2P_MAXIMUM_CLIENT_COUNT 8 +#define P2P_MAXIMUM_NOA_COUNT 8 + +#define P2P_MAXIMUM_ATTRIBUTE_LEN 251 + +#define P2P_CTWINDOW_DEFAULT 25 /* in TU=(1024usec) */ + +#define P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE 768 + +/* P2P 3.1.2.1.3 - Find Phase */ +#define P2P_MAX_DISCOVERABLE_INTERVAL 8 /* 3 */ +#define P2P_MIN_DISCOVERABLE_INTERVAL 5 /* 1 */ + +#define P2P_LISTEN_SCAN_UNIT 100 /* MS */ + +/* FSM Time Related constrain. */ +#define P2P_SERACH_STATE_PERIOD_MS 1000 /* Deprecated. */ + +#define P2P_GO_CHANNEL_STAY_INTERVAL 1000 + +#define P2P_GO_NEGO_TIMEOUT_MS 500 +#define P2P_CONNECTION_TIMEOUT_SEC 120 + +#define P2P_INVITAION_TIMEOUT_MS 500 /* Timeout Wait Invitation Resonse. */ +#define P2P_PROVISION_DISCOVERY_TIMEOUT_MS 500 /* Timeout Wait Provision Discovery Resonse. */ + +/* 3 --------------- WFA P2P IE --------------- */ +/* P2P 4.1.1 - P2P IE format */ +#define P2P_OUI_TYPE_LEN 4 +#define P2P_IE_OUI_HDR (ELEM_HDR_LEN + P2P_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, + aucP2PAttributes[0]) */ + +/* P2P 4.1.1 - General P2P Attribute */ +#define P2P_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ +#define P2P_ATTRI_LEN_NOTICE_OF_ABSENCE (P2P_ATTRI_HDR_LEN + 2) /* 5 */ + +/* P2P 4.1.1 - P2P Attribute ID definitions */ +#define P2P_ATTRI_ID_STATUS 0 +#define P2P_ATTRI_ID_REASON_CODE 1 +#define P2P_ATTRI_ID_P2P_CAPABILITY 2 +#define P2P_ATTRI_ID_P2P_DEV_ID 3 +#define P2P_ATTRI_ID_GO_INTENT 4 +#define P2P_ATTRI_ID_CFG_TIMEOUT 5 +#define P2P_ATTRI_ID_LISTEN_CHANNEL 6 +#define P2P_ATTRI_ID_P2P_GROUP_BSSID 7 +#define P2P_ATTRI_ID_EXT_LISTEN_TIMING 8 +#define P2P_ATTRI_ID_INTENDED_P2P_IF_ADDR 9 +#define P2P_ATTRI_ID_P2P_MANAGEABILITY 10 +#define P2P_ATTRI_ID_CHANNEL_LIST 11 +#define P2P_ATTRI_ID_NOTICE_OF_ABSENCE 12 +#define P2P_ATTRI_ID_P2P_DEV_INFO 13 +#define P2P_ATTRI_ID_P2P_GROUP_INFO 14 +#define P2P_ATTRI_ID_P2P_GROUP_ID 15 +#define P2P_ATTRI_ID_P2P_INTERFACE 16 +#define P2P_ATTRI_ID_OPERATING_CHANNEL 17 +#define P2P_ATTRI_ID_INVITATION_FLAG 18 +#define P2P_ATTRI_ID_VENDOR_SPECIFIC 221 + +/* Maximum Length of P2P Attributes */ +#define P2P_ATTRI_MAX_LEN_STATUS 1 /* 0 */ +#define P2P_ATTRI_MAX_LEN_REASON_CODE 1 /* 1 */ +#define P2P_ATTRI_MAX_LEN_P2P_CAPABILITY 2 /* 2 */ +#define P2P_ATTRI_MAX_LEN_P2P_DEV_ID 6 /* 3 */ +#define P2P_ATTRI_MAX_LEN_GO_INTENT 1 /* 4 */ +#define P2P_ATTRI_MAX_LEN_CFG_TIMEOUT 2 /* 5 */ +#if CID52_53_54 +#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ +#else +#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ +#endif +#define P2P_ATTRI_MAX_LEN_P2P_GROUP_BSSID 6 /* 7 */ +#define P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING 4 /* 8 */ +#define P2P_ATTRI_MAX_LEN_INTENDED_P2P_IF_ADDR 6 /* 9 */ +#define P2P_ATTRI_MAX_LEN_P2P_MANAGEABILITY 1 /* 10 */ +/* #define P2P_ATTRI_MAX_LEN_CHANNEL_LIST 3 + (n* (2 + num_of_ch)) */ /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_LIST 3 /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_ENTRY 2 /* 11 */ + +/* #define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE 2 + (n* (13)) */ /* 12 */ +#define P2P_ATTRI_MAX_LEN_NOTICE_OF_ABSENCE (2 + (P2P_MAXIMUM_NOA_COUNT*(13))) /* 12 */ + +#define P2P_ATTRI_MAX_LEN_P2P_DEV_INFO (17 + (8 * (8)) + 36) /* 13 */ +/* #define P2P_ATTRI_MAX_LEN_P2P_GROUP_INFO n* (25 + (m* (8)) + 32) */ /* 14 */ +#define P2P_ATTRI_MAX_LEN_P2P_GROUP_ID 38 /* 15 */ +#define P2P_ATTRI_MAX_LEN_P2P_INTERFACE 253 /* 7 + 6* [0~41] */ /* 16 */ +#if CID52_53_54 +#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ +#else +#define P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL 5 /* 17 */ +#endif +#define P2P_ATTRI_MAX_LEN_INVITATION_FLAGS 1 /* 18 */ + +/* P2P 4.1.2 - P2P Status definitions */ +#define P2P_STATUS_SUCCESS 0 +#define P2P_STATUS_FAIL_INFO_IS_CURRENTLY_UNAVAILABLE 1 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 2 +#define P2P_STATUS_FAIL_LIMIT_REACHED 3 +#define P2P_STATUS_FAIL_INVALID_PARAM 4 +#define P2P_STATUS_FAIL_UNABLE_ACCOMMODATE_REQ 5 +#define P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR 6 +#define P2P_STATUS_FAIL_NO_COMMON_CHANNELS 7 +#define P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP 8 +#define P2P_STATUS_FAIL_SAME_INTENT_VALUE_15 9 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVISION_METHOD 10 +#define P2P_STATUS_FAIL_REJECTED_BY_USER 11 + +/* P2P 4.1.3 - P2P Minor Reason Code definitions */ +#define P2P_REASON_SUCCESS 0 +#define P2P_REASON_DISASSOCIATED_DUE_CROSS_CONNECTION 1 +#define P2P_REASON_DISASSOCIATED_DUE_UNMANAGEABLE 2 +#define P2P_REASON_DISASSOCIATED_DUE_NO_P2P_COEXIST_PARAM 3 +#define P2P_REASON_DISASSOCIATED_DUE_MANAGEABLE 4 + +/* P2P 4.1.4 - Device Capability Bitmap definitions */ +#define P2P_DEV_CAPABILITY_SERVICE_DISCOVERY BIT(0) +#define P2P_DEV_CAPABILITY_CLIENT_DISCOVERABILITY BIT(1) +#define P2P_DEV_CAPABILITY_CONCURRENT_OPERATION BIT(2) +#define P2P_DEV_CAPABILITY_P2P_INFRA_MANAGED BIT(3) +#define P2P_DEV_CAPABILITY_P2P_DEVICE_LIMIT BIT(4) +#define P2P_DEV_CAPABILITY_P2P_INVITATION_PROCEDURE BIT(5) + +/* P2P 4.1.4 - Group Capability Bitmap definitions */ +#define P2P_GROUP_CAPABILITY_P2P_GROUP_OWNER BIT(0) +#define P2P_GROUP_CAPABILITY_PERSISTENT_P2P_GROUP BIT(1) +#define P2P_GROUP_CAPABILITY_P2P_GROUP_LIMIT BIT(2) +#define P2P_GROUP_CAPABILITY_INTRA_BSS_DISTRIBUTION BIT(3) +#define P2P_GROUP_CAPABILITY_CROSS_CONNECTION BIT(4) +#define P2P_GROUP_CAPABILITY_PERSISTENT_RECONNECT BIT(5) +#define P2P_GROUP_CAPABILITY_GROUP_FORMATION BIT(6) + +/* P2P 4.1.6 - GO Intent field definitions */ +#define P2P_GO_INTENT_TIE_BREAKER_FIELD BIT(0) +#define P2P_GO_INTENT_VALUE_MASK BITS(1, 7) +#define P2P_GO_INTENT_VALUE_OFFSET 1 + +/* P2P 4.1.12 - Manageability Bitmap definitions */ +#define P2P_DEVICE_MANAGEMENT BIT(0) + +/* P2P 4.1.14 - CTWindow and OppPS Parameters definitions */ +#define P2P_CTW_OPPPS_PARAM_OPPPS_FIELD BIT(7) +#define P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK BITS(0, 6) + +#define ELEM_MAX_LEN_P2P_FOR_PROBE_REQ \ + (P2P_OUI_TYPE_LEN + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_ID) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_OPERATING_CHANNEL)) + +#define ELEM_MAX_LEN_P2P_FOR_ASSOC_REQ \ + (P2P_OUI_TYPE_LEN + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_CAPABILITY) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING) + \ + (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_P2P_DEV_INFO)) + +/* P2P 4.1.16 - P2P Client Infor Descriptor */ +#define P2P_CLIENT_INFO_DESC_HDR_LEN 1 /* Length(1 octets) */ + +/* P2P 4.1.20 - P2P Invitation Flags Attribute*/ +#define P2P_INVITATION_FLAGS_INVITATION_TYPE BIT(0) +#define P2P_INVITATION_TYPE_INVITATION 0 +#define P2P_INVITATION_TYPE_REINVOKE 1 +/* 3 --------------- WPS Data Element Definitions --------------- */ +/* P2P 4.2.2 - General WSC Attribute */ +#define WSC_ATTRI_HDR_LEN 4 /* ID(2 octet) + Length(2 octets) */ +#define WSC_ATTRI_MAX_LEN_VERSION 1 +#define WSC_ATTRI_MAX_LEN_DEVICE_PASSWORD_ID 2 +#define WSC_ATTRI_LEN_CONFIG_METHOD 2 + +/* WPS 11 - Data Element Definitions */ +#define WPS_ATTRI_ID_VERSION 0x104A +#define WPS_ATTRI_ID_CONFIGURATION_METHODS 0x1008 +#define WPS_ATTRI_ID_DEVICE_PASSWORD 0x1012 +#define WPS_ATTRI_ID_DEVICE_NAME 0x1011 +#define WPS_ATTRI_ID_PRI_DEVICE_TYPE 0x1054 +#define WPS_ATTRI_ID_SEC_DEVICE_TYPE 0x1055 + +#define WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE 300 + +#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ + +#define WPS_ATTRI_CFG_METHOD_USBA BIT(0) +#define WPS_ATTRI_CFG_METHOD_ETHERNET BIT(1) +#define WPS_ATTRI_CFG_METHOD_LABEL BIT(2) +#define WPS_ATTRI_CFG_METHOD_DISPLAY BIT(3) +#define WPS_ATTRI_CFG_METHOD_EXT_NFC BIT(4) +#define WPS_ATTRI_CFG_METHOD_INT_NFC BIT(5) +#define WPS_ATTRI_CFG_METHOD_NFC_IF BIT(6) +#define WPS_ATTRI_CFG_METHOD_PUSH_BUTTON BIT(7) +#define WPS_ATTRI_CFG_METHOD_KEYPAD BIT(8) + +#define P2P_FLAGS_PROVISION_COMPLETE 0x00000001 +#define P2P_FLAGS_PROVISION_DISCOVERY_COMPLETE 0x00000002 +#define P2P_FLAGS_PROVISION_DISCOVERY_WAIT_RESPONSE 0x00000004 +#define P2P_FLAGS_PROVISION_DISCOVERY_RESPONSE_WAIT 0x00000008 +#define P2P_FLAGS_MASK_PROVISION 0x00000017 +#define P2P_FLAGS_MASK_PROVISION_COMPLETE 0x00000015 +#define P2P_FLAGS_PROVISION_DISCOVERY_INDICATED 0x00000010 +#define P2P_FLAGS_INVITATION_TOBE_GO 0x00000100 +#define P2P_FLAGS_INVITATION_TOBE_GC 0x00000200 +#define P2P_FLAGS_INVITATION_SUCCESS 0x00000400 +#define P2P_FLAGS_INVITATION_WAITING_TARGET 0x00000800 +#define P2P_FLAGS_MASK_INVITATION 0x00000F00 +#define P2P_FLAGS_FORMATION_ON_GOING 0x00010000 +#define P2P_FLAGS_FORMATION_LOCAL_PWID_RDY 0x00020000 +#define P2P_FLAGS_FORMATION_TARGET_PWID_RDY 0x00040000 +#define P2P_FLAGS_FORMATION_COMPLETE 0x00080000 +#define P2P_FLAGS_MASK_FORMATION 0x000F0000 +#define P2P_FLAGS_DEVICE_DISCOVER_REQ 0x00100000 +#define P2P_FLAGS_DEVICE_DISCOVER_DONE 0x00200000 +#define P2P_FLAGS_DEVICE_INVITATION_WAIT 0x00400000 +#define P2P_FLAGS_DEVICE_SERVICE_DISCOVER_WAIT 0x00800000 +#define P2P_FLAGS_MASK_DEVICE_DISCOVER 0x00F00000 + +#define P2P_FLAGS_DEVICE_FORMATION_REQUEST 0x01000000 + +/* MACRO for flag operation */ +#define SET_FLAGS(_FlagsVar, _BitsToSet) \ + {(_FlagsVar) = ((_FlagsVar) | (_BitsToSet))} + +#define TEST_FLAGS(_FlagsVar, _BitsToCheck) \ + (((_FlagsVar) & (_BitsToCheck)) == (_BitsToCheck)) + +#define CLEAR_FLAGS(_FlagsVar, _BitsToClear) \ + {(_FlagsVar) &= ~(_BitsToClear)} + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_I 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_II 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_III 0 + +#define CFG_DISABLE_WIFI_DIRECT_ENHANCEMENT_IV 0 + +#define CFG_DISABLE_DELAY_PROVISION_DISCOVERY 0 + +#define CFG_CONNECTION_POLICY_2_0 0 + +/* Device Password ID */ +enum wps_dev_password_id { + DEV_PW_DEFAULT = 0x0000, + DEV_PW_USER_SPECIFIED = 0x0001, + DEV_PW_MACHINE_SPECIFIED = 0x0002, + DEV_PW_REKEY = 0x0003, + DEV_PW_PUSHBUTTON = 0x0004, + DEV_PW_REGISTRAR_SPECIFIED = 0x0005 +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack(1) +#endif + +/* 3 --------------- WFA P2P IE and Attributes --------------- */ + +/* P2P 4.1.1 - P2P Information Element */ +typedef struct _IE_P2P_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 aucP2PAttributes[1]; /* P2P Attributes */ +} __KAL_ATTRIB_PACKED__ IE_P2P_T, *P_IE_P2P_T; + +/* P2P 4.1.1 - General P2P Attribute */ +typedef struct _P2P_ATTRIBUTE_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRIBUTE_T, ATTRIBUTE_HDR_T, *P_P2P_ATTRIBUTE_T, *P_ATTRIBUTE_HDR_T; + +/* P2P 4.1.2 - P2P Status Attribute */ +typedef struct _P2P_ATTRI_STATUS_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucStatusCode; /* Status Code */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_STATUS_T, *P_P2P_ATTRI_STATUS_T; + +/* P2P 4.1.3 - P2P Minor Reason Code Attribute */ +typedef struct _P2P_ATTRI_REASON_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucMinorReasonCode; /* Minor Reason Code */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_REASON_T, *P_P2P_ATTRI_REASON_T; + +/* P2P 4.1.4 - P2P Capability Attribute */ +typedef struct _P2P_ATTRI_CAPABILITY_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucDeviceCap; /* Device Capability Bitmap */ + UINT_8 ucGroupCap; /* Group Capability Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CAPABILITY_T, *P_P2P_ATTRI_CAPABILITY_T; + +/* P2P 4.1.5 - P2P Device ID Attribute */ +typedef struct _P2P_ATTRI_DEV_ID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_ID_T, *P_P2P_ATTRI_DEV_ID_T; + +/* P2P 4.1.6 - Group Owner Intent Attribute */ +typedef struct _P2P_ATTRI_GO_INTENT_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucGOIntent; /* Group Owner Intent */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GO_INTENT_T, *P_P2P_ATTRI_GO_INTENT_T; + +/* P2P 4.1.7 - Configuration Timeout Attribute */ +typedef struct _P2P_ATTRI_CFG_TIMEOUT_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucGOCfgTimeout; /* GO Configuration Timeout */ + UINT_8 ucClientCfgTimeout; /* Client Configuration Timeout */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CFG_TIMEOUT_T, *P_P2P_ATTRI_CFG_TIMEOUT_T; + +/* P2P 4.1.8 - Listen Channel Attribute */ +typedef struct _P2P_ATTRI_LISTEN_CHANNEL_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ + UINT_8 ucChannelNumber; /* Channel Number */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_LISTEN_CHANNEL_T, *P_P2P_ATTRI_LISTEN_CHANNEL_T; + +/* P2P 4.1.9 - P2P Group BSSID Attribute */ +typedef struct _P2P_ATTRI_GROUP_BSSID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBssid[MAC_ADDR_LEN]; /* P2P Group BSSID */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_BSSID_T, *P_P2P_ATTRI_GROUP_BSSID_T; + +/* P2P 4.1.10 - Extended Listen Timing Attribute */ +typedef struct _P2P_ATTRI_EXT_LISTEN_TIMING_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2AvailPeriod; /* Availability Period */ + UINT_16 u2AvailInterval; /* Availability Interval */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_EXT_LISTEN_TIMING_T, *P_P2P_ATTRI_EXT_LISTEN_TIMING_T; + +/* P2P 4.1.11 - Intended P2P Interface Address Attribute */ +typedef struct _P2P_ATTRI_INTENDED_IF_ADDR_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTENDED_IF_ADDR_T, *P_P2P_ATTRI_INTENDED_IF_ADDR_T; + +/* P2P 4.1.12 - P2P Manageability Attribute */ +typedef struct _P2P_ATTRI_MANAGEABILITY_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucManageability; /* P2P Manageability Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_MANAGEABILITY_T, *P_P2P_ATTRI_MANAGEABILITY_T; + +/* P2P 4.1.13 - Channel List Attribute */ +typedef struct _P2P_ATTRI_CHANNEL_LIST_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 aucChannelEntry[1]; /* Channel Entry List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_CHANNEL_T, *P_P2P_ATTRI_CHANNEL_T; + +typedef struct _CHANNEL_ENTRY_FIELD_T { + UINT_8 ucRegulatoryClass; /* Regulatory Class */ + UINT_8 ucNumberOfChannels; /* Number Of Channels */ + UINT_8 aucChannelList[1]; /* Channel List */ +} __KAL_ATTRIB_PACKED__ CHANNEL_ENTRY_FIELD_T, *P_CHANNEL_ENTRY_FIELD_T; + +/* P2P 4.1.14 - Notice of Absence Attribute */ +typedef struct _P2P_ATTRI_NOA_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucIndex; /* Index */ + UINT_8 ucCTWOppPSParam; /* CTWindow and OppPS Parameters */ + UINT_8 aucNoADesc[1]; /* NoA Descriptor */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_NOA_T, *P_P2P_ATTRI_NOA_T; + +typedef struct _NOA_DESCRIPTOR_T { + UINT_8 ucCountType; /* Count/Type */ + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} __KAL_ATTRIB_PACKED__ NOA_DESCRIPTOR_T, *P_NOA_DESCRIPTOR_T; + +typedef struct _P2P_ATTRI_DEV_INFO_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_16 u2ConfigMethodsBE; /* Config Method */ + DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ + UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ + DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_DEV_INFO_T, *P_P2P_ATTRI_DEV_INFO_T; + +/* WPS 7.1 & 11 WPS TLV Data Format - Device Name */ +typedef struct _DEVICE_NAME_TLV_T { + UINT_16 u2Id; /* WPS Attribute Type */ + UINT_16 u2Length; /* Data Length */ + UINT_8 aucName[32]; /* Device Name */ /* TODO: Fixme */ +} __KAL_ATTRIB_PACKED__ DEVICE_NAME_TLV_T, *P_DEVICE_NAME_TLV_T; + +/* P2P 4.1.16 - P2P Group Info Attribute */ +typedef struct _P2P_CLIENT_INFO_DESC_T { + UINT_8 ucLength; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 aucIfAddr[MAC_ADDR_LEN]; /* P2P Interface Address */ + UINT_8 ucDeviceCap; /* Device Capability Bitmap */ + UINT_16 u2ConfigMethodsBE; /* Config Method */ + DEVICE_TYPE_T rPrimaryDevTypeBE; /* Primary Device Type */ + UINT_8 ucNumOfSecondaryDevType; /* Number of Secondary Device Types */ + DEVICE_TYPE_T arSecondaryDevTypeListBE[1]; /* Secondary Device Type List */ +} __KAL_ATTRIB_PACKED__ P2P_CLIENT_INFO_DESC_T, *P_P2P_CLIENT_INFO_DESC_T; + +typedef struct _P2P_ATTRI_GROUP_INFO_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + P2P_CLIENT_INFO_DESC_T arClientDesc[1]; /* P2P Client Info Descriptors */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_INFO_T, *P_P2P_ATTRI_GROUP_INFO_T; + +/* P2P 4.1.17 - P2P Group ID Attribute */ +typedef struct _P2P_ATTRI_GROUP_ID_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_GROUP_ID_T, *P_P2P_ATTRI_GROUP_ID_T; + +/* P2P 4.1.18 - P2P Interface Attribute */ +typedef struct _P2P_ATTRI_INTERFACE_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + UINT_8 ucIfAddrCount; /* P2P Interface Address Count */ + UINT_8 aucIfAddrList[MAC_ADDR_LEN]; /* P2P Interface Address List */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INTERFACE_T, *P_P2P_ATTRI_INTERFACE_T; + +/* P2P 4.1.19 - Operating Channel Attribute */ +typedef struct _P2P_ATTRI_OPERATING_CHANNEL_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucCountryString[3]; /* Country String */ + UINT_8 ucOperatingClass; /* Operating Class from 802.11 Annex J/P802.11 REVmb 3.0 */ + UINT_8 ucChannelNumber; /* Channel Number */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_OPERATING_CHANNEL_T, *P_P2P_ATTRI_OPERATING_CHANNEL_T; + +/* P2P 4.1.20 - Invitation Flags Attribute */ +typedef struct _P2P_ATTRI_INVITATION_FLAG_T { + UINT_8 ucId; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucInviteFlagsBitmap; /* Invitation Flags Bitmap */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_INVITATION_FLAG_T, *P_P2P_ATTRI_INVITATION_FLAG_T; + +/* P2P 4.1.1 - General WSC Attribute */ +typedef struct _WSC_ATTRIBUTE_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRIBUTE_T, *P_WSC_ATTRIBUTE_T; + +/* WSC 1.0 Table 28 */ +typedef struct _WSC_ATTRI_VERSION_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_8 ucVersion; /* Version 1.0 or 1.1 */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_VERSION_T, *P_WSC_ATTRI_VERSION_T; + +typedef struct _WSC_ATTRI_DEVICE_PASSWORD_ID_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2DevPasswordId; /* Device Password ID */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_DEVICE_PASSWORD_ID_T, *P_WSC_ATTRI_DEVICE_PASSWORD_ID_T; + +typedef struct _WSC_ATTRI_CONFIGURATION_METHOD_T { + UINT_16 u2Id; /* Attribute ID */ + UINT_16 u2Length; /* Length */ + UINT_16 u2ConfigMethods; /* Configure Methods */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRI_CONFIGURATION_METHOD_T, *P_WSC_ATTRI_CONFIGURATION_METHOD_T; + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack() +#endif + +/* 3 --------------- WFA P2P Attributes Handler prototype --------------- */ +typedef UINT_32(*PFN_APPEND_ATTRI_FUNC) (P_ADAPTER_T, BOOLEAN, PUINT_16, PUINT_8, UINT_16); + +typedef VOID(*PFN_HANDLE_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T); + +typedef VOID(*PFN_VERIFY_ATTRI_FUNC) (P_SW_RFB_T, P_P2P_ATTRIBUTE_T, PUINT_16); + +typedef UINT_32(*PFN_CALCULATE_VAR_ATTRI_LEN_FUNC) (P_ADAPTER_T, P_STA_RECORD_T); + +typedef struct _APPEND_VAR_ATTRI_ENTRY_T { + UINT_16 u2EstimatedFixedAttriLen; /* For fixed length */ + PFN_CALCULATE_VAR_ATTRI_LEN_FUNC pfnCalculateVariableAttriLen; + PFN_APPEND_ATTRI_FUNC pfnAppendAttri; +} APPEND_VAR_ATTRI_ENTRY_T, *P_APPEND_VAR_ATTRI_ENTRY_T; + +typedef enum _ENUM_CONFIG_METHOD_SEL { + ENUM_CONFIG_METHOD_SEL_AUTO, + ENUM_CONFIG_METHOD_SEL_USER, + ENUM_CONFIG_METHOD_SEL_NUM +} ENUM_CONFIG_METHOD_SEL, *P_ENUM_CONFIG_METHOD_SEL; + +typedef enum _ENUM_P2P_FORMATION_POLICY { + ENUM_P2P_FORMATION_POLICY_AUTO = 0, + ENUM_P2P_FORMATION_POLICY_PASSIVE, /* Device would wait GO NEGO REQ instead of sending it actively. */ + ENUM_P2P_FORMATION_POLICY_NUM +} ENUM_P2P_FORMATION_POLICY, P_ENUM_P2P_FORMATION_POLICY; + +typedef enum _ENUM_P2P_INVITATION_POLICY { + ENUM_P2P_INVITATION_POLICY_USER = 0, + ENUM_P2P_INVITATION_POLICY_ACCEPT_FIRST, + ENUM_P2P_INVITATION_POLICY_DENY_ALL, + ENUM_P2P_INVITATION_POLICY_NUM +} ENUM_P2P_INVITATION_POLICY, P_ENUM_P2P_INVITATION_POLICY; + +/* 3 --------------- Data Structure for P2P Operation --------------- */ +/* 3 Session for CONNECTION SETTINGS of P2P */ +struct _P2P_CONNECTION_SETTINGS_T { + UINT_8 ucDevNameLen; + UINT_8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; + + DEVICE_TYPE_T rPrimaryDevTypeBE; + + ENUM_P2P_FORMATION_POLICY eFormationPolicy; /* Formation Policy. */ + + /*------------WSC Related Param---------------*/ + UINT_16 u2ConfigMethodsSupport; /* Preferred configure method. + * Some device may not have keypad. + */ + ENUM_CONFIG_METHOD_SEL eConfigMethodSelType; + UINT_16 u2TargetConfigMethod; /* Configure method selected by user or auto. */ + UINT_16 u2LocalConfigMethod; /* Configure method of target. */ + BOOLEAN fgIsPasswordIDRdy; + /*------------WSC Related Param---------------*/ + + UINT_8 ucClientConfigTimeout; + UINT_8 ucGoConfigTimeout; + + UINT_8 ucSecondaryDevTypeCount; +#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT + DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT]; +#endif + +#if 0 + UINT_8 ucRfChannelListCount; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT + UINT_8 aucChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering + depends on 802.11mb Annex J. */ + +#endif +#else + UINT_8 ucRfChannelListSize; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE + UINT_8 aucChannelEntriesField[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE]; +#endif +#endif + + /* Go Intent */ + UINT_8 ucTieBreaker; + UINT_8 ucGoIntent; + + /* For Device Capability */ + BOOLEAN fgSupportServiceDiscovery; + BOOLEAN fgSupportClientDiscoverability; + BOOLEAN fgSupportConcurrentOperation; + BOOLEAN fgSupportInfraManaged; + BOOLEAN fgSupportInvitationProcedure; + + /* For Group Capability */ + BOOLEAN fgSupportPersistentP2PGroup; + BOOLEAN fgSupportIntraBSSDistribution; + BOOLEAN fgSupportCrossConnection; + BOOLEAN fgSupportPersistentReconnect; + + BOOLEAN fgP2pGroupLimit; + + BOOLEAN fgSupportOppPS; + UINT_16 u2CTWindow; + + BOOLEAN fgIsScanReqIssued; + BOOLEAN fgIsServiceDiscoverIssued; + + /*============ Target Device Connection Settings ============*/ + + /* Discover Target Device Info. */ + BOOLEAN fgIsDevId; + BOOLEAN fgIsDevType; + + /* Encryption mode of Target Device */ + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + /* SSID + * 1. AP Mode, this is the desired SSID user specified. + * 2. Client Mode, this is the target SSID to be connected to. + */ + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + UINT_8 ucSSIDLen; + + /* Operating channel requested. */ + UINT_8 ucOperatingChnl; + ENUM_BAND_T eBand; + + /* Linten channel requested. */ + UINT_8 ucListenChnl; + + /* For device discover address/type. */ + UINT_8 aucTargetDevAddr[MAC_ADDR_LEN]; /* P2P Device Address, for P2P Device Discovery & P2P Connection. */ + +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_DEVICE_DESC_T prTargetP2pDesc; +#endif + + UINT_8 ucLastStatus; /* P2P FSM would append status attribute according to this field. */ + +#if !CFG_DISABLE_DELAY_PROVISION_DISCOVERY + UINT_8 ucLastDialogToken; + UINT_8 aucIndicateDevAddr[MAC_ADDR_LEN]; +#endif + +#if 0 + UINT_8 ucTargetRfChannelListCount; +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT + UINT_8 aucTargetChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_COUNT]; /* Channel Numbering + depends on 802.11mb Annex J. */ +#endif +#endif + +}; + +typedef struct _NOA_TIMING_T { + BOOLEAN fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 ucCount; /* Count */ + + UINT_8 aucReserved[2]; + + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} NOA_TIMING_T, *P_NOA_TIMING_T; + +typedef enum _ENUM_P2P_IOCTL_T { + P2P_IOCTL_IDLE = 0, + P2P_IOCTL_DEV_DISCOVER, + P2P_IOCTL_INVITATION_REQ, + P2P_IOCTL_SERV_DISCOVER, + P2P_IOCTL_WAITING, + P2P_IOCTL_NUM +} ENUM_P2P_IOCTL_T; + +/*---------------- Service Discovery Related -------------------*/ +typedef enum _ENUM_SERVICE_TX_TYPE_T { + ENUM_SERVICE_TX_TYPE_BY_DA, + ENUM_SERVICE_TX_TYPE_BY_CHNL, + ENUM_SERVICE_TX_TYPE_NUM +} ENUM_SERVICE_TX_TYPE_T; + +typedef struct _SERVICE_DISCOVERY_FRAME_DATA_T { + QUE_ENTRY_T rQueueEntry; + P_MSDU_INFO_T prSDFrame; + ENUM_SERVICE_TX_TYPE_T eServiceType; + UINT_8 ucSeqNum; + union { + + UINT_8 ucChannelNum; + UINT_8 aucPeerAddr[MAC_ADDR_LEN]; + } uTypeData; + BOOLEAN fgIsTxDoneIndicate; +} SERVICE_DISCOVERY_FRAME_DATA_T, *P_SERVICE_DISCOVERY_FRAME_DATA_T; + +struct _P2P_FSM_INFO_T_DEPRECATED { + /* P2P FSM State */ + ENUM_P2P_STATE_T eCurrentState; + + /* Channel */ + BOOLEAN fgIsChannelRequested; + + ENUM_P2P_STATE_T ePreviousState; + + ENUM_P2P_STATE_T eReturnState; /* Return state after current activity finished or abort. */ + + UINT_8 aucTargetIfAddr[PARAM_MAC_ADDR_LEN]; + P_BSS_DESC_T prTargetBss; /* BSS of target P2P Device. For Connection/Service Discovery */ + + P_STA_RECORD_T prTargetStaRec; + + BOOLEAN fgIsRsponseProbe; /* Indicate if P2P FSM can response probe request frame. */ + + /* Sequence number of requested message. */ + UINT_8 ucSeqNumOfReqMsg; /* Used for SAA FSM request message. */ + + /* Channel Privilege */ + UINT_8 ucSeqNumOfChReq; /* Used for Channel Request message. */ + + UINT_8 ucSeqNumOfScnMsg; /* Used for SCAN FSM request message. */ + UINT_8 ucSeqNumOfCancelMsg; + + UINT_8 ucDialogToken; + UINT_8 ucRxDialogToken; + + /* Timer */ + TIMER_T rDeviceDiscoverTimer; /* For device discovery time of each discovery request from user. */ + TIMER_T rOperationListenTimer; /* For Find phase under operational state. */ + TIMER_T rFSMTimer; /* A timer used for Action frame timeout usage. */ + + TIMER_T rRejoinTimer; /* A timer used for Action frame timeout usage. */ + + /* Flag to indicate Provisioning */ + BOOLEAN fgIsConnectionRequested; + + /* Current IOCTL. */ + ENUM_P2P_IOCTL_T eP2pIOCTL; + + UINT_8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + + /*--------SERVICE DISCOVERY--------*/ + QUE_T rQueueGASRx; /* Input Request/Response. */ + QUE_T rQueueGASTx; /* Output Response. */ + P_SERVICE_DISCOVERY_FRAME_DATA_T prSDRequest; + UINT_8 ucVersionNum; /* GAS packet sequence number for...Action Frame? */ + UINT_8 ucGlobalSeqNum; /* Sequence Number of RX SD packet. */ + /*--------Service DISCOVERY--------*/ + + /*--------DEVICE DISCOVERY---------*/ + UINT_8 aucTargetGroupID[PARAM_MAC_ADDR_LEN]; + UINT_16 u2TargetGroupSsidLen; + UINT_8 aucTargetSsid[32]; + UINT_8 aucSearchingP2pDevice[PARAM_MAC_ADDR_LEN]; + UINT_8 ucDLToken; + /*----------------------------------*/ + + /* Indicating Peer Status. */ + UINT_32 u4Flags; + + /*Indicating current running mode. */ + BOOLEAN fgIsApMode; + + /*------------INVITATION------------*/ + ENUM_P2P_INVITATION_POLICY eInvitationRspPolicy; + /*----------------------------------*/ + +}; + +struct _P2P_SPECIFIC_BSS_INFO_T { + /* For GO(AP) Mode - Compose TIM IE */ + UINT_16 u2SmallestAID; + UINT_16 u2LargestAID; + UINT_8 ucBitmapCtrl; + /* UINT_8 aucPartialVirtualBitmap[MAX_LEN_TIM_PARTIAL_BMP]; */ + + /* For GC/GO OppPS */ + BOOLEAN fgEnableOppPS; + UINT_16 u2CTWindow; + + /* For GC/GO NOA */ + UINT_8 ucNoAIndex; + UINT_8 ucNoATimingCount; /* Number of NoA Timing */ + NOA_TIMING_T arNoATiming[P2P_MAXIMUM_NOA_COUNT]; + + BOOLEAN fgIsNoaAttrExisted; + + /* For P2P Device */ + UINT_8 ucRegClass; /* Regulatory Class for channel. */ + UINT_8 ucListenChannel; /* Linten Channel only on channels 1, 6 and 11 in the 2.4 GHz. */ + + UINT_8 ucPreferredChannel; /* Operating Channel, should be one of channel list + in p2p connection settings. */ + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + + /* Extended Listen Timing. */ + UINT_16 u2AvailabilityPeriod; + UINT_16 u2AvailabilityInterval; + +#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ + UINT_16 u2IELenForBCN; + UINT_8 aucBeaconIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + +/* UINT_16 u2IELenForProbeRsp; */ +/* UINT_8 aucProbeRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; */ + + UINT_16 u2IELenForAssocRsp; + UINT_8 aucAssocRspIECache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE + WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + +#else + UINT_16 u2AttributeLen; + UINT_8 aucAttributesCache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + + UINT_16 u2WscAttributeLen; + UINT_8 aucWscAttributesCache[WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; +#endif + UINT_8 aucGroupID[MAC_ADDR_LEN]; + UINT_16 u2GroupSsidLen; + UINT_8 aucGroupSsid[ELEM_MAX_LEN_SSID]; + + PARAM_CUSTOM_NOA_PARAM_STRUCT_T rNoaParam; + PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T rOppPsParam; + + UINT_16 u2WpaIeLen; + UINT_8 aucWpaIeBuffer[ELEM_HDR_LEN + ELEM_MAX_LEN_WPA]; +}; + +typedef struct _MSG_P2P_DEVICE_DISCOVER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_32 u4DevDiscoverTime; /* 0: Infinite, 1~X: in unit of MS. */ + BOOLEAN fgIsSpecificType; +#if CFG_ENABLE_WIFI_DIRECT + P2P_DEVICE_TYPE_T rTargetDeviceType; +#endif + UINT_8 aucTargetDeviceID[MAC_ADDR_LEN]; +} MSG_P2P_DEVICE_DISCOVER_T, *P_MSG_P2P_DEVICE_DISCOVER_T; + +typedef struct _MSG_P2P_INVITATION_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 aucDeviceID[MAC_ADDR_LEN]; /* Target Device ID to be invited. */ +} MSG_P2P_INVITATION_REQUEST_T, *P_MSG_P2P_INVITATION_REQUEST_T; + +typedef struct _MSG_P2P_FUNCTION_SWITCH_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + BOOLEAN fgIsFuncOn; +} MSG_P2P_FUNCTION_SWITCH_T, *P_MSG_P2P_FUNCTION_SWITCH_T; + +typedef struct _MSG_P2P_SERVICE_DISCOVERY_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 aucDeviceID[MAC_ADDR_LEN]; + BOOLEAN fgNeedTxDoneIndicate; + UINT_8 ucSeqNum; +} MSG_P2P_SERVICE_DISCOVERY_REQUEST_T, *P_MSG_P2P_SERVICE_DISCOVERY_REQUEST_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define p2pChangeMediaState(_prAdapter, _eNewMediaState) \ +do { \ + (_prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState = (_eNewMediaState));\ + wfdChangeMediaState((_prAdapter), NETWORK_TYPE_P2P_INDEX, (_eNewMediaState)); \ +} while (0) + +#define ATTRI_ID(_fp) (((P_P2P_ATTRIBUTE_T) _fp)->ucId) +#define ATTRI_LEN(_fp) \ + (((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[0]) | \ + ((UINT_16) ((PUINT_8)&((P_P2P_ATTRIBUTE_T) _fp)->u2Length)[1] << 8)) + +#define ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + ATTRI_LEN(_fp)) + +#define P2P_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += ATTRI_SIZE(_pucAttriBuf))) + +#define P2P_IE(_fp) ((P_IE_P2P_T) _fp) + +#define WSC_ATTRI_ID(_fp) \ + (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[0] << 8) | \ + ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Id)[1])) + +#define WSC_ATTRI_LEN(_fp) \ + (((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ + ((UINT_16) ((PUINT_8)&((P_WSC_ATTRIBUTE_T) _fp)->u2Length)[1])) + +#define WSC_ATTRI_SIZE(_fp) (WSC_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) + +#define WSC_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += WSC_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WSC_ATTRI_SIZE(_pucAttriBuf))) + +#define WSC_IE(_fp) ((P_IE_P2P_T) _fp) + +#define WFD_ATTRI_ID(_fp) (((P_WFD_ATTRIBUTE_T) _fp)->ucElemID) + +#define WFD_ATTRI_LEN(_fp) \ + (((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[0] << 8) | \ + ((UINT_16) ((PUINT_8)&((P_WFD_ATTRIBUTE_T) _fp)->u2Length)[1])) + +#define WFD_ATTRI_SIZE(_fp) (WFD_ATTRI_HDR_LEN + WFD_ATTRI_LEN(_fp)) + +#define WFD_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += WFD_ATTRI_SIZE(_pucAttriBuf), ((_pucAttriBuf) += WFD_ATTRI_SIZE(_pucAttriBuf))) + +#if DBG +#define ASSERT_BREAK(_exp) \ + { \ + if (!(_exp)) { \ + ASSERT(FALSE); \ + break; \ + } \ + } + +#else +#define ASSERT_BREAK(_exp) +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*======P2P State======*/ +VOID +p2pStateInit_LISTEN(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prSP2pBssInfo, IN UINT_8 ucListenChannel); + +VOID p2pStateAbort_LISTEN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); + +VOID p2pStateAbort_SEARCH_SCAN(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtenstion); + +VOID p2pStateAbort_GO_OPERATION(IN P_ADAPTER_T prAdapter); + +VOID p2pStateAbort_GC_OPERATION(IN P_ADAPTER_T prAdapter); + +VOID +p2pStateInit_CONFIGURATION(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecBssInfo); + +VOID p2pStateAbort_CONFIGURATION(IN P_ADAPTER_T prAdapter); + +VOID p2pStateInit_JOIN(IN P_ADAPTER_T prAdapter); + +VOID p2pStateAbort_JOIN(IN P_ADAPTER_T prAdapter); + +/*====== P2P Functions ======*/ + +VOID p2pFuncInitGO(IN P_ADAPTER_T prAdapter); + +VOID +p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); + +VOID +p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW); + +VOID p2pFuncRunEventProvisioningComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +WLAN_STATUS p2pFuncSetGroupID(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucGroupID, IN PUINT_8 pucSsid, IN UINT_8 ucSsidLen); + +WLAN_STATUS +p2pFuncSendDeviceDiscoverabilityReqFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); + +WLAN_STATUS +p2pFuncSendDeviceDiscoverabilityRspFrame(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDestAddr[], IN UINT_8 ucDialogToken); + +UINT_8 p2pFuncGetVersionNumOfSD(IN P_ADAPTER_T prAdapter); + +/*====== P2P FSM ======*/ +VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventDeviceDiscoveryRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventDeviceDiscoveryAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventRxGroupNegotiationReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationRequestTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationResponseTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS +p2pFsmRunEventGroupNegotiationConfirmTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS +p2pFsmRunEventProvisionDiscoveryRequestTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS +p2pFsmRunEventProvisionDiscoveryResponseTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS +p2pFsmRunEventInvitationRequestTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); + +VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); + +VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +#if 1 +#endif + +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/*======Mail Box Event Message=====*/ + +VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventConnectionTrigger(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventP2PFunctionSwitch(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventConnectionPause(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID +p2pIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + IN ENUM_PARAM_MEDIA_STATE_T eConnectionState, IN UINT_8 aucTargetAddr[]); + +VOID p2pUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); + +/*======Mail Box Event Message=====*/ + +VOID p2pFsmInit(IN P_ADAPTER_T prAdapter); + +VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter); + +VOID p2pFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_P2P_STATE_T eNextState); + +VOID p2pStartGO(IN P_ADAPTER_T prAdapter); + +VOID p2pAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); + +VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID p2pFsmRunEventIOReqTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); + +VOID p2pFsmRunEventSearchPeriodTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param); + +VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG u4Param); + +VOID p2pFsmRunEventRejoinTimeout(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Parm); + +/*=============== P2P Function Related ================*/ + +/*=============== P2P Function Related ================*/ + +#if CFG_TEST_WIFI_DIRECT_GO +VOID p2pTest(IN P_ADAPTER_T prAdapter); +#endif /* CFG_TEST_WIFI_DIRECT_GO */ + +VOID p2pGenerateP2P_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID p2pGenerateP2P_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID +p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pCalculateP2P_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pCalculateP2P_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pGenerateWSC_IEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID +p2pGenerateWSC_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_16 p2pCalculateWSC_IELenForProbeReq(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +UINT_32 +p2pCalculateWSC_IELenForProbeResp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pAppendAttriStatus(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriCapability(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriGoIntent(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriCfgTimeout(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriGroupBssid(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriDeviceIDForBeacon(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriDeviceIDForProbeReq(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriDeviceIDForDeviceDiscoveryReq(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriListenChannel(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriIntendP2pIfAddr(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriChannelList(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 p2pCalculateAttriLenChannelList(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pAppendAttriNoA(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriDeviceInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 p2pCalculateAttriLenDeviceInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pAppendAttriGroupInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 p2pCalculateAttriLenGroupInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +UINT_32 +p2pAppendAttriP2pGroupID(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriOperatingChannel(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriInvitationFlag(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +VOID +p2pGenerateWscIE(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); + +UINT_32 +p2pAppendAttriWSCConfigMethod(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriWSCVersion(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriWSCGONegReqDevPasswordId(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pAppendAttriWSCGONegRspDevPasswordId(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +WLAN_STATUS +p2pGetWscAttriList(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); + +WLAN_STATUS +p2pGetAttriList(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); + +VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS p2pSendProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +BOOLEAN p2pFsmRunEventRxProbeRequestFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc); + +WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID p2pFsmRunEventRxGroupNegotiationRspFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID p2pFsmRunEventRxGroupNegotiationCfmFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +#if 0 /* frog */ +BOOLEAN scanMatchFilterOfP2P(IN P_SW_RFB_T prSWRfb, IN PP_BSS_DESC_T pprBssDesc); +#endif /* frog */ + +VOID +p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); + +VOID p2pFuncCompleteIOCTL(IN P_ADAPTER_T prAdapter, IN WLAN_STATUS rWlanStatus); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifndef _lint +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +static inline VOID p2pDataTypeCheck(VOID) +{ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(IE_P2P_T) == (2 + 4 + 1)); /* all UINT_8 */ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRIBUTE_T) == (3 + 1)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_STATUS_T) == (3 + 1)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_REASON_T) == (3 + 1)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CAPABILITY_T) == (3 + 2)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_ID_T) == (3 + 6)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GO_INTENT_T) == (3 + 1)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CFG_TIMEOUT_T) == (3 + 2)); +#if CID52_53_54 + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); +#else + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_LISTEN_CHANNEL_T) == (3 + 5)); +#endif + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_BSSID_T) == (3 + 6)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_EXT_LISTEN_TIMING_T) == (3 + 4)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTENDED_IF_ADDR_T) == (3 + 6)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_MANAGEABILITY_T) == (3 + 1)); + + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_CHANNEL_T) == (3 + 4)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(CHANNEL_ENTRY_FIELD_T) == 3); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_NOA_T) == (3 + 3)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(NOA_DESCRIPTOR_T) == 13); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_TYPE_T) == 8); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_DEV_INFO_T) == (3 + 6 + 2 + 8 + 1 + 8)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(DEVICE_NAME_TLV_T) == (4 + 32)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_CLIENT_INFO_DESC_T) == (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_INFO_T) == (3 + (1 + 6 + 6 + 1 + 2 + 8 + 1 + 8))); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_GROUP_ID_T) == (3 + 38)); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_INTERFACE_T) == (3 + 13)); +#if CID52_53_54 + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); +#else + DATA_STRUCT_INSPECTING_ASSERT(sizeof(P2P_ATTRI_OPERATING_CHANNEL_T) == (3 + 5)); +#endif + +} +#endif /* _lint */ + +#endif /* _P2P_FSM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h new file mode 100644 index 0000000000000..1ac1770debcab --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_func.h @@ -0,0 +1,155 @@ +#ifndef _P2P_FUNC_H +#define _P2P_FUNC_H + +#define P2P_EXT_LISTEN_TIME_MS 600 +#define P2P_OFF_CHNL_TX_DEFAULT_TIME_MS 1000 + +VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +VOID +p2pFuncStartGO(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucSsidBuf, + IN UINT_8 ucSsidLen, + IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP); + +VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo); + +BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo); + +VOID +p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb); + +WLAN_STATUS +p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie); + +WLAN_STATUS +p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen); + +BOOLEAN +p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); + +BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); + +VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings); + +BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); + +BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); + +VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +VOID +p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen); + +P_BSS_DESC_T +p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID +p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter); + +VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter); + +VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo); + +BOOLEAN +p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen); + +P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu); + +#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ +UINT_32 +p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +#else +UINT_32 +p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +#endif +UINT_32 +p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); + +VOID +p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize); + +UINT_32 +p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +VOID +p2pFuncDissolve(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); + +P_IE_HDR_T +p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore); + +P_ATTRIBUTE_HDR_T +p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID); + +WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, + IN ENUM_PARAM_MEDIA_STATE_T eConnectionState); +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h new file mode 100644 index 0000000000000..efb75855695f9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_ie.h @@ -0,0 +1,156 @@ +#ifndef _P2P_IE_H +#define _P2P_IE_H + +#if CFG_SUPPORT_WFD + +#define ELEM_MAX_LEN_WFD 62 /* TODO: Move to appropriate place */ + +/*---------------- WFD Data Element Definitions ----------------*/ +/* WFD 4.1.1 - WFD IE format */ +#define WFD_OUI_TYPE_LEN 4 +#define WFD_IE_OUI_HDR (ELEM_HDR_LEN + WFD_OUI_TYPE_LEN) /* == OFFSET_OF(IE_P2P_T, + aucP2PAttributes[0]) */ + +/* WFD 4.1.1 - General WFD Attribute */ +#define WFD_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ + +/* WFD Attribute Code */ +#define WFD_ATTRI_ID_DEV_INFO 0 +#define WFD_ATTRI_ID_ASSOC_BSSID 1 +#define WFD_ATTRI_ID_COUPLED_SINK_INFO 6 +#define WFD_ATTRI_ID_EXT_CAPABILITY 7 +#define WFD_ATTRI_ID_SESSION_INFO 9 +#define WFD_ATTRI_ID_ALTER_MAC_ADDRESS 10 + +/* Maximum Length of WFD Attributes */ +#define WFD_ATTRI_MAX_LEN_DEV_INFO 6 /* 0 */ +#define WFD_ATTRI_MAX_LEN_ASSOC_BSSID 6 /* 1 */ +#define WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO 7 /* 6 */ +#define WFD_ATTRI_MAX_LEN_EXT_CAPABILITY 2 /* 7 */ +#define WFD_ATTRI_MAX_LEN_SESSION_INFO 0 /* 9 */ /* 24 * #Clients */ +#define WFD_ATTRI_MAX_LEN_ALTER_MAC_ADDRESS 6 /* 10 */ + +/* WFD 1.10 5.1.1 */ +typedef struct _IE_WFD_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 aucWFDAttributes[1]; /* WFD Subelement */ +} __KAL_ATTRIB_PACKED__ IE_WFD_T, *P_IE_WFD_T; + +typedef struct _WFD_ATTRIBUTE_T { + UINT_8 ucElemID; /* Subelement ID */ + UINT_16 u2Length; /* Length */ + UINT_8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ WFD_ATTRIBUTE_T, *P_WFD_ATTRIBUTE_T; + +typedef struct _WFD_DEVICE_INFORMATION_IE_T { + UINT_8 ucElemID; + UINT_16 u2Length; + UINT_16 u2WfdDevInfo; + UINT_16 u2SessionMgmtCtrlPort; + UINT_16 u2WfdDevMaxSpeed; +} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_IE_T, *P_WFD_DEVICE_INFORMATION_IE_T; + +typedef struct _WFD_ASSOCIATED_BSSID_IE_T { + UINT_8 ucElemID; + UINT_16 u2Length; + UINT_8 aucAssocBssid[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WFD_ASSOCIATED_BSSID_IE_T, *P_WFD_ASSOCIATED_BSSID_IE_T; + +typedef struct _WFD_COUPLE_SINK_INFORMATION_IE_T { + UINT_8 ucElemID; + UINT_16 u2Length; + UINT_8 ucCoupleSinkStatusBp; + UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WFD_COUPLE_SINK_INFORMATION_IE_T, *P_WFD_COUPLE_SINK_INFORMATION_IE_T; + +typedef struct _WFD_EXTENDED_CAPABILITY_IE_T { + UINT_8 ucElemID; + UINT_16 u2Length; + UINT_16 u2WfdExtCapabilityBp; +} __KAL_ATTRIB_PACKED__ WFD_EXTENDED_CAPABILITY_IE_T, *P_WFD_EXTENDED_CAPABILITY_IE_T; + +typedef struct _WFD_SESSION_INFORMATION_IE_T { + UINT_8 ucElemID; + UINT_16 u2Length; + PUINT_8 pucWfdDevInfoDesc[1]; +} __KAL_ATTRIB_PACKED__ WFD_SESSION_INFORMATION_IE_T, *P_WFD_SESSION_INFORMATION_IE_T; + +typedef struct _WFD_DEVICE_INFORMATION_DESCRIPTOR_T { + UINT_8 ucLength; + UINT_8 aucDevAddr[MAC_ADDR_LEN]; + UINT_8 aucAssocBssid[MAC_ADDR_LEN]; + UINT_16 u2WfdDevInfo; + UINT_16 u2WfdDevMaxSpeed; + UINT_8 ucCoupleSinkStatusBp; + UINT_8 aucCoupleSinkMac[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_DESCRIPTOR_T, *P_WFD_DEVICE_INFORMATION_DESCRIPTOR_T; + +#endif + +UINT_32 +p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +#if CFG_SUPPORT_WFD + +UINT_32 +wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +UINT_32 +wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize); + +UINT_32 +wfdFuncCalculateWfdIELenForProbeResp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID wfdFuncGenerateWfdIEForProbeResp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +wfdFuncCalculateWfdIELenForAssocReq(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID wfdFuncGenerateWfdIEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 +wfdFuncCalculateWfdIELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +VOID wfdFuncGenerateWfdIEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +#endif + +UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec); + +VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h new file mode 100644 index 0000000000000..32bc14c109591 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm.h @@ -0,0 +1,74 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm.h#1 +*/ + +/*! \file "rlm.h" + \brief +*/ + +#ifndef _P2P_RLM_H +#define _P2P_RLM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); + +VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter); + +VOID +rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, + IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize); + +UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum); + +BOOLEAN +rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCheckChnl, + IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel); + +ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h new file mode 100644 index 0000000000000..5b6e756f48dd4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_rlm_obss.h @@ -0,0 +1,64 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_rlm_obss.h#1 +*/ + +/*! \file "rlm_obss.h" + \brief +*/ + +#ifndef _P2P_RLM_OBSS_H +#define _P2P_RLM_OBSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); + +UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); + +VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h new file mode 100644 index 0000000000000..8db6aa5c31e0c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_scan.h @@ -0,0 +1,81 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/mgmt/p2p_scan.h#1 +*/ + +/*! \file "scan.h" + \brief + +*/ + +#ifndef _P2P_SCAN_H +#define _P2P_SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); + +P_P2P_DEVICE_DESC_T +scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc); + +P_P2P_DEVICE_DESC_T +scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound); + +P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum); + +BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +VOID +scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); + +VOID scanRemoveAllP2pBssDesc(P_ADAPTER_T prAdapter); + +VOID scanRemoveP2pBssDesc(P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +P_BSS_DESC_T +scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h new file mode 100644 index 0000000000000..8f0c4c1564a85 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/p2p_state.h @@ -0,0 +1,43 @@ +#ifndef _P2P_STATE_H +#define _P2P_STATE_H + +BOOLEAN +p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState); + +VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +VOID +p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID +p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +VOID +p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID +p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState); + +VOID +p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc); + +VOID +p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h new file mode 100644 index 0000000000000..c80430ae4eb54 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/privacy.h @@ -0,0 +1,230 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/privacy.h#1 +*/ + +/*! \file privacy.h + \brief This file contains the function declaration for privacy.c. +*/ + +/* +** Log: privacy.h + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 25 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * For support the WHQL test, do the remove key code refine. + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the cmd return type + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for auth mode and encryption status setting from build connection command + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for wapi + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the tx done callback handle function + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function declaration for mac header privacy bit setting + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the structure for parsing the EAPoL frame + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the class error function parameter + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security function declaration + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the ap selection structure + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +#ifndef _PRIVACY_H +#define _PRIVACY_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_KEY_NUM 4 +#define WEP_40_LEN 5 +#define WEP_104_LEN 13 +#define LEGACY_KEY_MAX_LEN 16 +#define CCMP_KEY_LEN 16 +#define TKIP_KEY_LEN 32 +#define MAX_KEY_LEN 32 +#define MIC_RX_KEY_OFFSET 16 +#define MIC_TX_KEY_OFFSET 24 +#define MIC_KEY_LEN 8 + +#define WEP_KEY_ID_FIELD BITS(0, 29) +#define KEY_ID_FIELD BITS(0, 7) + +#define IS_TRANSMIT_KEY BIT(31) +#define IS_UNICAST_KEY BIT(30) +#define IS_AUTHENTICATOR BIT(28) + +#define CIPHER_SUITE_NONE 0 +#define CIPHER_SUITE_WEP40 1 +#define CIPHER_SUITE_TKIP 2 +#define CIPHER_SUITE_TKIP_WO_MIC 3 +#define CIPHER_SUITE_CCMP 4 +#define CIPHER_SUITE_WEP104 5 +#define CIPHER_SUITE_BIP 6 +#define CIPHER_SUITE_WEP128 7 +#define CIPHER_SUITE_WPI 8 + +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) + +#define MASK_2ND_EAPOL (WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _IEEE_802_1X_HDR { + UINT_8 ucVersion; + UINT_8 ucType; + UINT_16 u2Length; + /* followed by length octets of data */ +} IEEE_802_1X_HDR, *P_IEEE_802_1X_HDR; + +typedef struct _EAPOL_KEY { + UINT_8 ucType; + /* Note: key_info, key_length, and key_data_length are unaligned */ + UINT_8 aucKeyInfo[2]; /* big endian */ + UINT_8 aucKeyLength[2]; /* big endian */ + UINT_8 aucReplayCounter[8]; + UINT_8 aucKeyNonce[16]; + UINT_8 aucKeyIv[16]; + UINT_8 aucKeyRsc[8]; + UINT_8 aucKeyId[8]; /* Reserved in IEEE 802.11i/RSN */ + UINT_8 aucKeyMic[16]; + UINT_8 aucKeyDataLength[2]; /* big endian */ + /* followed by key_data_length bytes of key_data */ +} EAPOL_KEY, *P_EAPOL_KEY; + +/* WPA2 PMKID candicate structure */ +typedef struct _PMKID_CANDICATE_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_32 u4PreAuthFlags; +} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; + +#if 0 +/* WPA2 PMKID cache structure */ +typedef struct _PMKID_ENTRY_T { + PARAM_BSSID_INFO_T rBssidInfo; + BOOLEAN fgPmkidExist; +} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx); + +VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPort); + +BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec); + +BOOLEAN secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec); + +BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); + +VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags); + +BOOLEAN +secProcessEAPOL(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen); + +VOID +secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T pMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus); + +BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec); + +VOID secClearPmkid(IN P_ADAPTER_T prAdapter); + +BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter); + +BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PRIVACY_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h new file mode 100644 index 0000000000000..123dbebdacaf2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rate.h @@ -0,0 +1,93 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rate.h#1 +*/ + +/*! \file rate.h + \brief This file contains the rate utility function of + IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: rate.h + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * +*/ + +#ifndef _RATE_H +#define _RATE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in rate.c */ +/*----------------------------------------------------------------------------*/ +VOID +rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT PUINT_16 pu2OperationalRateSet, + OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate); + +VOID +rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen); + +BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex); + +BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RATE_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h new file mode 100644 index 0000000000000..1af3841ecec25 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm.h @@ -0,0 +1,396 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm.h#2 +*/ + +/*! \file "rlm.h" + \brief +*/ + +/* +** Log: rlm.h + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 09 30 2011 cm.chang + * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band + * . + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 13 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Use SCO of BSS_INFO to replace user-defined setting variables + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 18 2010 cm.chang + * [WCXRP00000114] [MT6620 Wi-Fi] [Driver] Fix compiling warning in Linux about RLM network index checking + * Enum member cannot be used as compiling option decision in Linux + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX HT GF compiling option + * + * 06 02 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Roll back to remove CFG_SUPPORT_BCM_TEST. + * + * 06 01 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Update BCM Test and RW configuration. + * + * 05 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some compiling options to control 11n functions + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 17 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * MT6620 does not support L-SIG TXOP + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Move default value of HT capability to rlm.h + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * + * Modify the prototype of rlmRecAssocRspHtInfo() + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add several function prototypes for HT operation + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +#ifndef _RLM_H +#define _RLM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define ELEM_EXT_CAP_DEFAULT_VAL \ + (ELEM_EXT_CAP_20_40_COEXIST_SUPPORT /*| ELEM_EXT_CAP_PSMP_CAP*/) + +#if CFG_SUPPORT_RX_STBC +#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_1_SS +#else +#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_NO_SUPPORTED +#endif + +#if CFG_SUPPORT_RX_SGI +#define FIELD_HT_CAP_INFO_SGI_20M HT_CAP_INFO_SHORT_GI_20M +#define FIELD_HT_CAP_INFO_SGI_40M HT_CAP_INFO_SHORT_GI_40M +#else +#define FIELD_HT_CAP_INFO_SGI_20M 0 +#define FIELD_HT_CAP_INFO_SGI_40M 0 +#endif + +#if CFG_SUPPORT_RX_HT_GF +#define FIELD_HT_CAP_INFO_HT_GF HT_CAP_INFO_HT_GF +#else +#define FIELD_HT_CAP_INFO_HT_GF 0 +#endif + +#define HT_CAP_INFO_DEFAULT_VAL \ + (HT_CAP_INFO_SUP_CHNL_WIDTH | FIELD_HT_CAP_INFO_HT_GF | \ + FIELD_HT_CAP_INFO_SGI_20M | FIELD_HT_CAP_INFO_SGI_40M | \ + FIELD_HT_CAP_INFO_RX_STBC | HT_CAP_INFO_DSSS_CCK_IN_40M) + +#define AMPDU_PARAM_DEFAULT_VAL \ + (AMPDU_PARAM_MAX_AMPDU_LEN_64K | AMPDU_PARAM_MSS_NO_RESTRICIT) + +#define SUP_MCS_TX_DEFAULT_VAL \ + SUP_MCS_TX_SET_DEFINED /* TX defined and TX/RX equal (TBD) */ + +#if CFG_SUPPORT_MFB +#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_BOTH +#else +#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_NO_FB +#endif + +#if CFG_SUPPORT_RX_RDG +#define FIELD_HT_EXT_CAP_RDR HT_EXT_CAP_RD_RESPONDER +#else +#define FIELD_HT_EXT_CAP_RDR 0 +#endif + +#if CFG_SUPPORT_MFB || CFG_SUPPORT_RX_RDG +#define FIELD_HT_EXT_CAP_HTC HT_EXT_CAP_HTC_SUPPORT +#else +#define FIELD_HT_EXT_CAP_HTC 0 +#endif + +#define HT_EXT_CAP_DEFAULT_VAL \ + (HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE | \ + FIELD_HT_EXT_CAP_MFB | FIELD_HT_EXT_CAP_HTC | \ + FIELD_HT_EXT_CAP_RDR) + +#define TX_BEAMFORMING_CAP_DEFAULT_VAL 0 +#define ASEL_CAP_DEFAULT_VAL 0 + +/* Define bandwidth from user setting */ +#define CONFIG_BW_20_40M 0 +#define CONFIG_BW_20M 1 /* 20MHz only */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* It is used for RLM module to judge if specific network is valid + * Note: Ad-hoc mode of AIS is not included now. (TBD) + */ +#define RLM_NET_PARAM_VALID(_prBssInfo) \ + (IS_BSS_ACTIVE(_prBssInfo) && \ + ((_prBssInfo)->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_IBSS || \ + RLM_NET_IS_BOW(_prBssInfo)) \ + ) + +#define RLM_NET_IS_11N(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11N) +#define RLM_NET_IS_11GN(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11GN) + +/* This macro is used to sweep all 3 networks */ +#define RLM_NET_FOR_EACH(_ucNetIdx) \ + for ((_ucNetIdx) = 0; \ + (_ucNetIdx) < NETWORK_TYPE_INDEX_NUM; \ + (_ucNetIdx)++) + +/* This macro is used to sweep all networks excluding BOW */ +#if CFG_ENABLE_BT_OVER_WIFI + /* Note: value of enum NETWORK_TYPE_BOW_INDEX is validated in + * rlmStuctureCheck(). + */ +#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) \ + for ((_ucNetIdx) = 0; \ + (_ucNetIdx) < NETWORK_TYPE_BOW_INDEX; \ + (_ucNetIdx)++) + +#define RLM_NET_IS_BOW(_prBssInfo) \ + ((_prBssInfo)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) + +#else +#define RLM_NET_FOR_EACH_NO_BOW(_ucNetIdx) RLM_NET_FOR_EACH(_ucNetIdx) +#define RLM_NET_IS_BOW(_prBssInfo) (FALSE) + +#endif /* end of CFG_ENABLE_BT_OVER_WIFI */ + +/* The bandwidth modes are not used anymore. They represent if AP + * can use 20/40 bandwidth, not all modes. (20110411) + */ +#define RLM_AP_IS_BW_40_ALLOWED(_prAdapter, _prBssInfo) \ + (((_prBssInfo)->eBand == BAND_2G4 && \ + (_prAdapter)->rWifiVar.rConnSettings.uc2G4BandwidthMode \ + == CONFIG_BW_20_40M) || \ + ((_prBssInfo)->eBand == BAND_5G && \ + (_prAdapter)->rWifiVar.rConnSettings.uc5GBandwidthMode \ + == CONFIG_BW_20_40M)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID rlmFsmEventInit(P_ADAPTER_T prAdapter); + +VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter); + +VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); + +VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); + +VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo); + +VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); + +VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +UINT32 +rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, + BOOLEAN fgShortGIDisabled, + UINT_8 u8SupportRxSgi20, + UINT_8 u8SupportRxSgi40, + UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf); + +UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme); + +#if CFG_SUPPORT_DFS /* Add by Enlai */ +VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE); +#endif + +VOID +rlmTxRateEnhanceConfig( + P_ADAPTER_T prAdapter + ); + +VOID +rlmCmd( + P_GLUE_INFO_T prGlueInfo, + UINT_8 *prInBuf, + UINT_32 u4InBufLen + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#ifndef _lint +static inline VOID rlmDataTypeCheck(VOID) +{ +#if CFG_ENABLE_BT_OVER_WIFI + DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_AIS_INDEX < NETWORK_TYPE_BOW_INDEX); + +#if CFG_ENABLE_WIFI_DIRECT + DATA_STRUCT_INSPECTING_ASSERT(NETWORK_TYPE_P2P_INDEX < NETWORK_TYPE_BOW_INDEX); +#endif +#endif + +} +#endif /* _lint */ + +#endif /* _RLM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h new file mode 100644 index 0000000000000..65e907041a28b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_domain.h @@ -0,0 +1,557 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_domain.h#1 +*/ + +/*! \file "rlm_domain.h" + \brief +*/ + +/* +** Log: rlm_domain.h + * + * 09 29 2011 cm.chang + * NULL + * Change the function prototype of rlmDomainGetChnlList() + * + * 09 08 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Provide legal channel function based on domain + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 01 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide query function about full channel list. + * + * Dec 1 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Declare public rDomainInfo + * +** +*/ + +#ifndef _RLM_DOMAIN_H +#define _RLM_DOMAIN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_SUBBAND_NUM 6 +#define MAX_SUBBAND_NUM_5G 8 + +#define COUNTRY_CODE_NULL ((UINT_16)0x0) + +/* ISO/IEC 3166-1 two-character country codes */ + +#define COUNTRY_CODE_AD (((UINT_16) 'A' << 8) | (UINT_16) 'D') /* Andorra */ +#define COUNTRY_CODE_AE (((UINT_16) 'A' << 8) | (UINT_16) 'E') /* UAE */ +#define COUNTRY_CODE_AF (((UINT_16) 'A' << 8) | (UINT_16) 'F') /* Afghanistan */ +#define COUNTRY_CODE_AG (((UINT_16) 'A' << 8) | (UINT_16) 'G') /* Antigua & Barbuda */ +#define COUNTRY_CODE_AI (((UINT_16) 'A' << 8) | (UINT_16) 'I') /* Anguilla */ +#define COUNTRY_CODE_AL (((UINT_16) 'A' << 8) | (UINT_16) 'L') /* Albania */ +#define COUNTRY_CODE_AM (((UINT_16) 'A' << 8) | (UINT_16) 'M') /* Armenia */ +#define COUNTRY_CODE_AN (((UINT_16) 'A' << 8) | (UINT_16) 'N') /* Netherlands Antilles */ +#define COUNTRY_CODE_AO (((UINT_16) 'A' << 8) | (UINT_16) 'O') /* Angola */ +#define COUNTRY_CODE_AR (((UINT_16) 'A' << 8) | (UINT_16) 'R') /* Argentina */ +#define COUNTRY_CODE_AS (((UINT_16) 'A' << 8) | (UINT_16) 'S') /* American Samoa (USA) */ +#define COUNTRY_CODE_AT (((UINT_16) 'A' << 8) | (UINT_16) 'T') /* Austria */ +#define COUNTRY_CODE_AU (((UINT_16) 'A' << 8) | (UINT_16) 'U') /* Australia */ +#define COUNTRY_CODE_AW (((UINT_16) 'A' << 8) | (UINT_16) 'W') /* Aruba */ +#define COUNTRY_CODE_AZ (((UINT_16) 'A' << 8) | (UINT_16) 'Z') /* Azerbaijan */ +#define COUNTRY_CODE_BA (((UINT_16) 'B' << 8) | (UINT_16) 'A') /* Bosnia and Herzegovina */ +#define COUNTRY_CODE_BB (((UINT_16) 'B' << 8) | (UINT_16) 'B') /* Barbados */ +#define COUNTRY_CODE_BD (((UINT_16) 'B' << 8) | (UINT_16) 'D') /* Bangladesh */ +#define COUNTRY_CODE_BE (((UINT_16) 'B' << 8) | (UINT_16) 'E') /* Belgium */ +#define COUNTRY_CODE_BF (((UINT_16) 'B' << 8) | (UINT_16) 'F') /* Burkina Faso */ +#define COUNTRY_CODE_BG (((UINT_16) 'B' << 8) | (UINT_16) 'G') /* Bulgaria */ +#define COUNTRY_CODE_BH (((UINT_16) 'B' << 8) | (UINT_16) 'H') /* Bahrain */ +#define COUNTRY_CODE_BI (((UINT_16) 'B' << 8) | (UINT_16) 'I') /* Burundi */ +#define COUNTRY_CODE_BJ (((UINT_16) 'B' << 8) | (UINT_16) 'J') /* Benin */ +#define COUNTRY_CODE_BM (((UINT_16) 'B' << 8) | (UINT_16) 'M') /* Bermuda */ +#define COUNTRY_CODE_BN (((UINT_16) 'B' << 8) | (UINT_16) 'N') /* Brunei */ +#define COUNTRY_CODE_BO (((UINT_16) 'B' << 8) | (UINT_16) 'O') /* Bolivia */ +#define COUNTRY_CODE_BR (((UINT_16) 'B' << 8) | (UINT_16) 'R') /* Brazil */ +#define COUNTRY_CODE_BS (((UINT_16) 'B' << 8) | (UINT_16) 'S') /* Bahamas */ +#define COUNTRY_CODE_BT (((UINT_16) 'B' << 8) | (UINT_16) 'T') /* Bhutan */ +#define COUNTRY_CODE_BW (((UINT_16) 'B' << 8) | (UINT_16) 'W') /* Botswana */ +#define COUNTRY_CODE_BY (((UINT_16) 'B' << 8) | (UINT_16) 'Y') /* Belarus */ +#define COUNTRY_CODE_BZ (((UINT_16) 'B' << 8) | (UINT_16) 'Z') /* Belize */ +#define COUNTRY_CODE_CA (((UINT_16) 'C' << 8) | (UINT_16) 'A') /* Canada */ +#define COUNTRY_CODE_CD (((UINT_16) 'C' << 8) | (UINT_16) 'D') /* Congo. Democratic Republic of the */ +#define COUNTRY_CODE_CF (((UINT_16) 'C' << 8) | (UINT_16) 'F') /* Central African Republic */ +#define COUNTRY_CODE_CG (((UINT_16) 'C' << 8) | (UINT_16) 'G') /* Congo. Republic of the */ +#define COUNTRY_CODE_CH (((UINT_16) 'C' << 8) | (UINT_16) 'H') /* Switzerland */ +#define COUNTRY_CODE_CI (((UINT_16) 'C' << 8) | (UINT_16) 'I') /* Cote d'lvoire */ +#define COUNTRY_CODE_CK (((UINT_16) 'C' << 8) | (UINT_16) 'K') /* Cook Island */ +#define COUNTRY_CODE_CL (((UINT_16) 'C' << 8) | (UINT_16) 'L') /* Chile */ +#define COUNTRY_CODE_CM (((UINT_16) 'C' << 8) | (UINT_16) 'M') /* Cameroon */ +#define COUNTRY_CODE_CN (((UINT_16) 'C' << 8) | (UINT_16) 'N') /* China */ +#define COUNTRY_CODE_CO (((UINT_16) 'C' << 8) | (UINT_16) 'O') /* Columbia */ +#define COUNTRY_CODE_CR (((UINT_16) 'C' << 8) | (UINT_16) 'R') /* Costa Rica */ +#define COUNTRY_CODE_CU (((UINT_16) 'C' << 8) | (UINT_16) 'U') /* Cuba */ +#define COUNTRY_CODE_CV (((UINT_16) 'C' << 8) | (UINT_16) 'V') /* Cape Verde */ +#define COUNTRY_CODE_CX (((UINT_16) 'C' << 8) | (UINT_16) 'X') /* "Christmas Island(Australia) */ +#define COUNTRY_CODE_CY (((UINT_16) 'C' << 8) | (UINT_16) 'Y') /* Cyprus */ +#define COUNTRY_CODE_CZ (((UINT_16) 'C' << 8) | (UINT_16) 'Z') /* Czech */ +#define COUNTRY_CODE_DE (((UINT_16) 'D' << 8) | (UINT_16) 'E') /* Germany */ +#define COUNTRY_CODE_DJ (((UINT_16) 'D' << 8) | (UINT_16) 'J') /* Djibouti */ +#define COUNTRY_CODE_DK (((UINT_16) 'D' << 8) | (UINT_16) 'K') /* Denmark */ +#define COUNTRY_CODE_DM (((UINT_16) 'D' << 8) | (UINT_16) 'M') /* Dominica */ +#define COUNTRY_CODE_DO (((UINT_16) 'D' << 8) | (UINT_16) 'O') /* Dominican Republic */ +#define COUNTRY_CODE_DZ (((UINT_16) 'D' << 8) | (UINT_16) 'Z') /* Algeria */ +#define COUNTRY_CODE_EC (((UINT_16) 'E' << 8) | (UINT_16) 'C') /* Ecuador */ +#define COUNTRY_CODE_EE (((UINT_16) 'E' << 8) | (UINT_16) 'E') /* Estonia */ +#define COUNTRY_CODE_EG (((UINT_16) 'E' << 8) | (UINT_16) 'G') /* Egypt */ +#define COUNTRY_CODE_EH (((UINT_16) 'E' << 8) | (UINT_16) 'H') /* Western Sahara (Morocco) */ +#define COUNTRY_CODE_ER (((UINT_16) 'E' << 8) | (UINT_16) 'R') /* Eritrea */ +#define COUNTRY_CODE_ES (((UINT_16) 'E' << 8) | (UINT_16) 'S') /* Spain */ +#define COUNTRY_CODE_ET (((UINT_16) 'E' << 8) | (UINT_16) 'T') /* Ethiopia */ +#define COUNTRY_CODE_EU (((UINT_16) 'E' << 8) | (UINT_16) 'U') /* Europe */ +#define COUNTRY_CODE_FI (((UINT_16) 'F' << 8) | (UINT_16) 'I') /* Finland */ +#define COUNTRY_CODE_FJ (((UINT_16) 'F' << 8) | (UINT_16) 'J') /* Fiji */ +#define COUNTRY_CODE_FK (((UINT_16) 'F' << 8) | (UINT_16) 'K') /* Falkland Island */ +#define COUNTRY_CODE_FM (((UINT_16) 'F' << 8) | (UINT_16) 'M') /* Micronesia */ +#define COUNTRY_CODE_FO (((UINT_16) 'F' << 8) | (UINT_16) 'O') /* Faroe Island */ +#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* France */ +#define COUNTRY_CODE_FR (((UINT_16) 'F' << 8) | (UINT_16) 'R') /* Wallis and Futuna (France) */ +#define COUNTRY_CODE_GA (((UINT_16) 'G' << 8) | (UINT_16) 'A') /* Gabon */ +#define COUNTRY_CODE_GB (((UINT_16) 'G' << 8) | (UINT_16) 'B') /* United Kingdom */ +#define COUNTRY_CODE_GD (((UINT_16) 'G' << 8) | (UINT_16) 'D') /* Grenada */ +#define COUNTRY_CODE_GE (((UINT_16) 'G' << 8) | (UINT_16) 'E') /* Georgia */ +#define COUNTRY_CODE_GF (((UINT_16) 'G' << 8) | (UINT_16) 'F') /* French Guiana */ +#define COUNTRY_CODE_GG (((UINT_16) 'G' << 8) | (UINT_16) 'G') /* Guernsey */ +#define COUNTRY_CODE_GH (((UINT_16) 'G' << 8) | (UINT_16) 'H') /* Ghana */ +#define COUNTRY_CODE_GI (((UINT_16) 'G' << 8) | (UINT_16) 'I') /* Gibraltar */ +#define COUNTRY_CODE_GM (((UINT_16) 'G' << 8) | (UINT_16) 'M') /* Gambia */ +#define COUNTRY_CODE_GN (((UINT_16) 'G' << 8) | (UINT_16) 'N') /* Guinea */ +#define COUNTRY_CODE_GP (((UINT_16) 'G' << 8) | (UINT_16) 'P') /* Guadeloupe */ +#define COUNTRY_CODE_GQ (((UINT_16) 'G' << 8) | (UINT_16) 'Q') /* Equatorial Guinea */ +#define COUNTRY_CODE_GR (((UINT_16) 'G' << 8) | (UINT_16) 'R') /* Greece */ +#define COUNTRY_CODE_GT (((UINT_16) 'G' << 8) | (UINT_16) 'T') /* Guatemala */ +#define COUNTRY_CODE_GU (((UINT_16) 'G' << 8) | (UINT_16) 'U') /* Guam */ +#define COUNTRY_CODE_GW (((UINT_16) 'G' << 8) | (UINT_16) 'W') /* Guinea-Bissau */ +#define COUNTRY_CODE_GY (((UINT_16) 'G' << 8) | (UINT_16) 'Y') /* Guyana */ +#define COUNTRY_CODE_HK (((UINT_16) 'H' << 8) | (UINT_16) 'K') /* Hong Kong */ +#define COUNTRY_CODE_HN (((UINT_16) 'H' << 8) | (UINT_16) 'N') /* Honduras */ +#define COUNTRY_CODE_HR (((UINT_16) 'H' << 8) | (UINT_16) 'R') /* Croatia */ +#define COUNTRY_CODE_HT (((UINT_16) 'H' << 8) | (UINT_16) 'T') /* Haiti */ +#define COUNTRY_CODE_HU (((UINT_16) 'H' << 8) | (UINT_16) 'U') /* Hungary */ +#define COUNTRY_CODE_ID (((UINT_16) 'I' << 8) | (UINT_16) 'D') /* Indonesia */ +#define COUNTRY_CODE_IE (((UINT_16) 'I' << 8) | (UINT_16) 'E') /* Ireland */ +#define COUNTRY_CODE_IL (((UINT_16) 'I' << 8) | (UINT_16) 'L') /* Israel */ +#define COUNTRY_CODE_IM (((UINT_16) 'I' << 8) | (UINT_16) 'M') /* Isle of Man */ +#define COUNTRY_CODE_IN (((UINT_16) 'I' << 8) | (UINT_16) 'N') /* India */ +#define COUNTRY_CODE_IQ (((UINT_16) 'I' << 8) | (UINT_16) 'Q') /* Iraq */ +#define COUNTRY_CODE_IR (((UINT_16) 'I' << 8) | (UINT_16) 'R') /* Iran */ +#define COUNTRY_CODE_IS (((UINT_16) 'I' << 8) | (UINT_16) 'S') /* Iceland */ +#define COUNTRY_CODE_IT (((UINT_16) 'I' << 8) | (UINT_16) 'T') /* Italy */ +#define COUNTRY_CODE_JE (((UINT_16) 'J' << 8) | (UINT_16) 'E') /* Jersey */ +#define COUNTRY_CODE_JM (((UINT_16) 'J' << 8) | (UINT_16) 'M') /* Jameica */ +#define COUNTRY_CODE_JO (((UINT_16) 'J' << 8) | (UINT_16) 'O') /* Jordan */ +#define COUNTRY_CODE_JP (((UINT_16) 'J' << 8) | (UINT_16) 'P') /* Japan */ +#define COUNTRY_CODE_KE (((UINT_16) 'K' << 8) | (UINT_16) 'E') /* Kenya */ +#define COUNTRY_CODE_KG (((UINT_16) 'K' << 8) | (UINT_16) 'G') /* Kyrgyzstan */ +#define COUNTRY_CODE_KH (((UINT_16) 'K' << 8) | (UINT_16) 'H') /* Cambodia */ +#define COUNTRY_CODE_KI (((UINT_16) 'K' << 8) | (UINT_16) 'I') /* Kiribati */ +#define COUNTRY_CODE_KM (((UINT_16) 'K' << 8) | (UINT_16) 'M') /* Comoros */ +#define COUNTRY_CODE_KN (((UINT_16) 'K' << 8) | (UINT_16) 'N') /* Saint Kitts and Nevis */ +#define COUNTRY_CODE_KP (((UINT_16) 'K' << 8) | (UINT_16) 'P') /* North Korea */ +#define COUNTRY_CODE_KR (((UINT_16) 'K' << 8) | (UINT_16) 'R') /* South Korea */ +#define COUNTRY_CODE_KW (((UINT_16) 'K' << 8) | (UINT_16) 'W') /* Kuwait */ +#define COUNTRY_CODE_KY (((UINT_16) 'K' << 8) | (UINT_16) 'Y') /* Cayman Islands */ +#define COUNTRY_CODE_KZ (((UINT_16) 'K' << 8) | (UINT_16) 'Z') /* Kazakhstan */ +#define COUNTRY_CODE_LA (((UINT_16) 'L' << 8) | (UINT_16) 'A') /* Laos */ +#define COUNTRY_CODE_LB (((UINT_16) 'L' << 8) | (UINT_16) 'B') /* Lebanon */ +#define COUNTRY_CODE_LC (((UINT_16) 'L' << 8) | (UINT_16) 'C') /* Saint Lucia */ +#define COUNTRY_CODE_LI (((UINT_16) 'L' << 8) | (UINT_16) 'I') /* Liechtenstein */ +#define COUNTRY_CODE_LK (((UINT_16) 'L' << 8) | (UINT_16) 'K') /* Sri Lanka */ +#define COUNTRY_CODE_LR (((UINT_16) 'L' << 8) | (UINT_16) 'R') /* Liberia */ +#define COUNTRY_CODE_LS (((UINT_16) 'L' << 8) | (UINT_16) 'S') /* Lesotho */ +#define COUNTRY_CODE_LT (((UINT_16) 'L' << 8) | (UINT_16) 'T') /* Lithuania */ +#define COUNTRY_CODE_LU (((UINT_16) 'L' << 8) | (UINT_16) 'U') /* Luxemburg */ +#define COUNTRY_CODE_LV (((UINT_16) 'L' << 8) | (UINT_16) 'V') /* Latvia */ +#define COUNTRY_CODE_LY (((UINT_16) 'L' << 8) | (UINT_16) 'Y') /* Libya */ +#define COUNTRY_CODE_MA (((UINT_16) 'M' << 8) | (UINT_16) 'A') /* Morocco */ +#define COUNTRY_CODE_MC (((UINT_16) 'M' << 8) | (UINT_16) 'C') /* Monaco */ +#define COUNTRY_CODE_MD (((UINT_16) 'M' << 8) | (UINT_16) 'D') /* Moldova */ +#define COUNTRY_CODE_ME (((UINT_16) 'M' << 8) | (UINT_16) 'E') /* Montenegro */ +#define COUNTRY_CODE_MF (((UINT_16) 'M' << 8) | (UINT_16) 'F') /* Saint Martin / Sint Marteen + (Added on window's list) */ +#define COUNTRY_CODE_MG (((UINT_16) 'M' << 8) | (UINT_16) 'G') /* Madagascar */ +#define COUNTRY_CODE_MH (((UINT_16) 'M' << 8) | (UINT_16) 'H') /* Marshall Islands */ +#define COUNTRY_CODE_MK (((UINT_16) 'M' << 8) | (UINT_16) 'K') /* Macedonia */ +#define COUNTRY_CODE_ML (((UINT_16) 'M' << 8) | (UINT_16) 'L') /* Mali */ +#define COUNTRY_CODE_MM (((UINT_16) 'M' << 8) | (UINT_16) 'M') /* Myanmar */ +#define COUNTRY_CODE_MN (((UINT_16) 'M' << 8) | (UINT_16) 'N') /* Mongolia */ +#define COUNTRY_CODE_MO (((UINT_16) 'M' << 8) | (UINT_16) 'O') /* Macao */ +#define COUNTRY_CODE_MP (((UINT_16) 'M' << 8) | (UINT_16) 'P') /* Northern Mariana Islands (Rota Island. + Saipan and Tinian Island) */ +#define COUNTRY_CODE_MQ (((UINT_16) 'M' << 8) | (UINT_16) 'Q') /* Martinique (France) */ +#define COUNTRY_CODE_MR (((UINT_16) 'M' << 8) | (UINT_16) 'R') /* Mauritania */ +#define COUNTRY_CODE_MS (((UINT_16) 'M' << 8) | (UINT_16) 'S') /* Montserrat (UK) */ +#define COUNTRY_CODE_MT (((UINT_16) 'M' << 8) | (UINT_16) 'T') /* Malta */ +#define COUNTRY_CODE_MU (((UINT_16) 'M' << 8) | (UINT_16) 'U') /* Mauritius */ +#define COUNTRY_CODE_MV (((UINT_16) 'M' << 8) | (UINT_16) 'V') /* Maldives */ +#define COUNTRY_CODE_MW (((UINT_16) 'M' << 8) | (UINT_16) 'W') /* Malawi */ +#define COUNTRY_CODE_MX (((UINT_16) 'M' << 8) | (UINT_16) 'X') /* Mexico */ +#define COUNTRY_CODE_MY (((UINT_16) 'M' << 8) | (UINT_16) 'Y') /* Malaysia */ +#define COUNTRY_CODE_MZ (((UINT_16) 'M' << 8) | (UINT_16) 'Z') /* Mozambique */ +#define COUNTRY_CODE_NA (((UINT_16) 'N' << 8) | (UINT_16) 'A') /* Namibia */ +#define COUNTRY_CODE_NC (((UINT_16) 'N' << 8) | (UINT_16) 'C') /* New Caledonia */ +#define COUNTRY_CODE_NE (((UINT_16) 'N' << 8) | (UINT_16) 'E') /* Niger */ +#define COUNTRY_CODE_NF (((UINT_16) 'N' << 8) | (UINT_16) 'F') /* Norfolk Island */ +#define COUNTRY_CODE_NG (((UINT_16) 'N' << 8) | (UINT_16) 'G') /* Nigeria */ +#define COUNTRY_CODE_NI (((UINT_16) 'N' << 8) | (UINT_16) 'I') /* Nicaragua */ +#define COUNTRY_CODE_NL (((UINT_16) 'N' << 8) | (UINT_16) 'L') /* Netherlands */ +#define COUNTRY_CODE_NO (((UINT_16) 'N' << 8) | (UINT_16) 'O') /* Norway */ +#define COUNTRY_CODE_NP (((UINT_16) 'N' << 8) | (UINT_16) 'P') /* Nepal */ +#define COUNTRY_CODE_NR (((UINT_16) 'N' << 8) | (UINT_16) 'R') /* Nauru */ +#define COUNTRY_CODE_NU (((UINT_16) 'N' << 8) | (UINT_16) 'U') /* Niue */ +#define COUNTRY_CODE_NZ (((UINT_16) 'N' << 8) | (UINT_16) 'Z') /* New Zealand */ +#define COUNTRY_CODE_OM (((UINT_16) 'O' << 8) | (UINT_16) 'M') /* Oman */ +#define COUNTRY_CODE_PA (((UINT_16) 'P' << 8) | (UINT_16) 'A') /* Panama */ +#define COUNTRY_CODE_PE (((UINT_16) 'P' << 8) | (UINT_16) 'E') /* Peru */ +#define COUNTRY_CODE_PF (((UINT_16) 'P' << 8) | (UINT_16) 'F') /* "French Polynesia */ +#define COUNTRY_CODE_PG (((UINT_16) 'P' << 8) | (UINT_16) 'G') /* Papua New Guinea */ +#define COUNTRY_CODE_PH (((UINT_16) 'P' << 8) | (UINT_16) 'H') /* Philippines */ +#define COUNTRY_CODE_PK (((UINT_16) 'P' << 8) | (UINT_16) 'K') /* Pakistan */ +#define COUNTRY_CODE_PL (((UINT_16) 'P' << 8) | (UINT_16) 'L') /* Poland */ +#define COUNTRY_CODE_PM (((UINT_16) 'P' << 8) | (UINT_16) 'M') /* Saint Pierre and Miquelon */ +#define COUNTRY_CODE_PN (((UINT_16) 'P' << 8) | (UINT_16) 'N') /* Pitcairn Islands */ +#define COUNTRY_CODE_PR (((UINT_16) 'P' << 8) | (UINT_16) 'R') /* Puerto Rico (USA) */ +#define COUNTRY_CODE_PS (((UINT_16) 'P' << 8) | (UINT_16) 'S') /* Palestinian Authority */ +#define COUNTRY_CODE_PT (((UINT_16) 'P' << 8) | (UINT_16) 'T') /* Portugal */ +#define COUNTRY_CODE_PW (((UINT_16) 'P' << 8) | (UINT_16) 'W') /* Palau */ +#define COUNTRY_CODE_PY (((UINT_16) 'P' << 8) | (UINT_16) 'Y') /* Paraguay */ +#define COUNTRY_CODE_QA (((UINT_16) 'Q' << 8) | (UINT_16) 'A') /* Qatar */ +#define COUNTRY_CODE_RE (((UINT_16) 'R' << 8) | (UINT_16) 'E') /* Reunion (France) */ +#define COUNTRY_CODE_RKS (((UINT_16) 'R' << 8) | (UINT_16) 'K') /* Kosvo (Added on window's list) */ +#define COUNTRY_CODE_RO (((UINT_16) 'R' << 8) | (UINT_16) 'O') /* Romania */ +#define COUNTRY_CODE_RS (((UINT_16) 'R' << 8) | (UINT_16) 'S') /* Serbia */ +#define COUNTRY_CODE_RU (((UINT_16) 'R' << 8) | (UINT_16) 'U') /* Russia */ +#define COUNTRY_CODE_RW (((UINT_16) 'R' << 8) | (UINT_16) 'W') /* Rwanda */ +#define COUNTRY_CODE_SA (((UINT_16) 'S' << 8) | (UINT_16) 'A') /* Saudi Arabia */ +#define COUNTRY_CODE_SB (((UINT_16) 'S' << 8) | (UINT_16) 'B') /* Solomon Islands */ +#define COUNTRY_CODE_SC (((UINT_16) 'S' << 8) | (UINT_16) 'C') /* Seychelles */ +#define COUNTRY_CODE_SD (((UINT_16) 'S' << 8) | (UINT_16) 'D') /* Sudan */ +#define COUNTRY_CODE_SE (((UINT_16) 'S' << 8) | (UINT_16) 'E') /* Sweden */ +#define COUNTRY_CODE_SG (((UINT_16) 'S' << 8) | (UINT_16) 'G') /* Singapole */ +#define COUNTRY_CODE_SI (((UINT_16) 'S' << 8) | (UINT_16) 'I') /* Slovenia */ +#define COUNTRY_CODE_SK (((UINT_16) 'S' << 8) | (UINT_16) 'K') /* Slovakia */ +#define COUNTRY_CODE_SL (((UINT_16) 'S' << 8) | (UINT_16) 'L') /* Sierra Leone */ +#define COUNTRY_CODE_SM (((UINT_16) 'S' << 8) | (UINT_16) 'M') /* San Marino */ +#define COUNTRY_CODE_SN (((UINT_16) 'S' << 8) | (UINT_16) 'N') /* Senegal */ +#define COUNTRY_CODE_SO (((UINT_16) 'S' << 8) | (UINT_16) 'O') /* Somalia */ +#define COUNTRY_CODE_SR (((UINT_16) 'S' << 8) | (UINT_16) 'R') /* Suriname */ +#define COUNTRY_CODE_SS (((UINT_16) 'S' << 8) | (UINT_16) 'S') /* South_Sudan */ +#define COUNTRY_CODE_ST (((UINT_16) 'S' << 8) | (UINT_16) 'T') /* Sao Tome and Principe */ +#define COUNTRY_CODE_SV (((UINT_16) 'S' << 8) | (UINT_16) 'V') /* El Salvador */ +#define COUNTRY_CODE_SY (((UINT_16) 'S' << 8) | (UINT_16) 'Y') /* Syria */ +#define COUNTRY_CODE_SZ (((UINT_16) 'S' << 8) | (UINT_16) 'Z') /* Swaziland */ +#define COUNTRY_CODE_TC (((UINT_16) 'T' << 8) | (UINT_16) 'C') /* Turks and Caicos Islands (UK) */ +#define COUNTRY_CODE_TD (((UINT_16) 'T' << 8) | (UINT_16) 'D') /* Chad */ +#define COUNTRY_CODE_TF (((UINT_16) 'T' << 8) | (UINT_16) 'F') /* French Southern and Antarctic Lands */ +#define COUNTRY_CODE_TG (((UINT_16) 'T' << 8) | (UINT_16) 'G') /* Togo */ +#define COUNTRY_CODE_TH (((UINT_16) 'T' << 8) | (UINT_16) 'H') /* Thailand */ +#define COUNTRY_CODE_TJ (((UINT_16) 'T' << 8) | (UINT_16) 'J') /* Tajikistan */ +#define COUNTRY_CODE_TL (((UINT_16) 'T' << 8) | (UINT_16) 'L') /* East Timor */ +#define COUNTRY_CODE_TM (((UINT_16) 'T' << 8) | (UINT_16) 'M') /* Turkmenistan */ +#define COUNTRY_CODE_TN (((UINT_16) 'T' << 8) | (UINT_16) 'N') /* Tunisia */ +#define COUNTRY_CODE_TO (((UINT_16) 'T' << 8) | (UINT_16) 'O') /* Tonga */ +#define COUNTRY_CODE_TR (((UINT_16) 'T' << 8) | (UINT_16) 'R') /* Turkey */ +#define COUNTRY_CODE_TT (((UINT_16) 'T' << 8) | (UINT_16) 'T') /* Trinidad and Tobago */ +#define COUNTRY_CODE_TV (((UINT_16) 'T' << 8) | (UINT_16) 'V') /* Tuvalu */ +#define COUNTRY_CODE_TW (((UINT_16) 'T' << 8) | (UINT_16) 'W') /* Taiwan */ +#define COUNTRY_CODE_TZ (((UINT_16) 'T' << 8) | (UINT_16) 'Z') /* Tanzania */ +#define COUNTRY_CODE_UA (((UINT_16) 'U' << 8) | (UINT_16) 'A') /* Ukraine */ +#define COUNTRY_CODE_UG (((UINT_16) 'U' << 8) | (UINT_16) 'G') /* Ugnada */ +#define COUNTRY_CODE_US (((UINT_16) 'U' << 8) | (UINT_16) 'S') /* US */ +#define COUNTRY_CODE_UY (((UINT_16) 'U' << 8) | (UINT_16) 'Y') /* Uruguay */ +#define COUNTRY_CODE_UZ (((UINT_16) 'U' << 8) | (UINT_16) 'Z') /* Uzbekistan */ +#define COUNTRY_CODE_VA (((UINT_16) 'V' << 8) | (UINT_16) 'A') /* Vatican (Holy See) */ +#define COUNTRY_CODE_VC (((UINT_16) 'V' << 8) | (UINT_16) 'C') /* Saint Vincent and the Grenadines */ +#define COUNTRY_CODE_VE (((UINT_16) 'V' << 8) | (UINT_16) 'E') /* Venezuela */ +#define COUNTRY_CODE_VG (((UINT_16) 'V' << 8) | (UINT_16) 'G') /* British Virgin Islands */ +#define COUNTRY_CODE_VI (((UINT_16) 'V' << 8) | (UINT_16) 'I') /* US Virgin Islands */ +#define COUNTRY_CODE_VN (((UINT_16) 'V' << 8) | (UINT_16) 'N') /* Vietnam */ +#define COUNTRY_CODE_VU (((UINT_16) 'V' << 8) | (UINT_16) 'U') /* Vanuatu */ +#define COUNTRY_CODE_WS (((UINT_16) 'W' << 8) | (UINT_16) 'S') /* Samoa */ +#define COUNTRY_CODE_YE (((UINT_16) 'Y' << 8) | (UINT_16) 'E') /* Yemen */ +#define COUNTRY_CODE_YT (((UINT_16) 'Y' << 8) | (UINT_16) 'T') /* Mayotte (France) */ +#define COUNTRY_CODE_ZA (((UINT_16) 'Z' << 8) | (UINT_16) 'A') /* South Africa */ +#define COUNTRY_CODE_ZM (((UINT_16) 'Z' << 8) | (UINT_16) 'M') /* Zambia */ +#define COUNTRY_CODE_ZW (((UINT_16) 'Z' << 8) | (UINT_16) 'W') /* Zimbabwe */ + +#define COUNTRY_CODE_DF (((UINT_16) 'D' << 8) | (UINT_16) 'F') /* Default country domain */ +#define COUNTRY_CODE_UDF (((UINT_16) 'U' << 8) | (UINT_16) 'D') /* User defined supported channel list + and passive scan channel list */ + +#define COUNTRY_CODE_FF (((UINT_16) 'F' << 8) | (UINT_16) 'F') /* enable open for all channel for Certification */ +#define COUNTRY_CODE_FE (((UINT_16) 'F' << 8) | (UINT_16) 'E') /* disable open for all channel for Certification */ + +/* dot11RegDomainsSupportValue */ +#define MIB_REG_DOMAIN_FCC 0x10 /* FCC (US) */ +#define MIB_REG_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define MIB_REG_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define MIB_REG_DOMAIN_SPAIN 0x31 /* Spain */ +#define MIB_REG_DOMAIN_FRANCE 0x32 /* France */ +#define MIB_REG_DOMAIN_JAPAN 0x40 /* MPHPT (Japan) */ +#define MIB_REG_DOMAIN_OTHER 0x00 /* other */ + +/*2.4G*/ +#define BAND_2G4_LOWER_BOUND 1 +#define BAND_2G4_UPPER_BOUND 14 +/*5G SubBand FCC spec*/ +#define UNII1_LOWER_BOUND 36 +#define UNII1_UPPER_BOUND 48 +#define UNII2A_LOWER_BOUND 52 +#define UNII2A_UPPER_BOUND 64 +#define UNII2C_LOWER_BOUND 100 +#define UNII2C_UPPER_BOUND 144 +#define UNII3_LOWER_BOUND 149 +#define UNII3_UPPER_BOUND 173 + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +#define POWER_LIMIT_TABLE_NULL 0xFFFF +#define MAX_TX_POWER 63 +#define MIN_TX_POWER -64 +#define MAX_CMD_SUPPORT_CHANNEL_NUM 64 + +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +typedef enum _ENUM_POWER_LIMIT_T { + PWR_LIMIT_CCK, + PWR_LIMIT_20M, + PWR_LIMIT_40M, + PWR_LIMIT_80M, + PWR_LIMIT_160M, + PWR_LIMIT_NUM +} ENUM_POWER_LIMIT_T, *P_ENUM_POWER_LIMIT_T; + +#endif + +typedef enum _ENUM_POWER_LIMIT_SUBBAND_T { + POWER_LIMIT_2G4, + POWER_LIMIT_UNII1, + POWER_LIMIT_UNII2A, + POWER_LIMIT_UNII2C, + POWER_LIMIT_UNII3, + POWER_LIMIT_SUBAND_NUM +} ENUM_POWER_LIMIT_SUBBAND_T, *P_ENUM_POWER_LIMIT_SUBBAND_T; + +/* Define channel offset in unit of 5MHz bandwidth */ +typedef enum _ENUM_CHNL_SPAN_T { + CHNL_SPAN_5 = 1, + CHNL_SPAN_10 = 2, + CHNL_SPAN_20 = 4, + CHNL_SPAN_40 = 8 +} ENUM_CHNL_SPAN_T, *P_ENUM_CHNL_SPAN_T; + +/* Define BSS operating bandwidth */ +typedef enum _ENUM_CHNL_BW_T { + CHNL_BW_20, + CHNL_BW_20_40, + CHNL_BW_10, + CHNL_BW_5 +} ENUM_CHNL_BW_T, *P_ENUM_CHNL_BW_T; + +/* In all bands, the first channel will be SCA and the second channel is SCB, + * then iteratively. + * Note the final channel will not be SCA. + */ +typedef struct _DOMAIN_SUBBAND_INFO { + /* Note1: regulation class depends on operation bandwidth and RF band. + * For example: 2.4GHz, 1~13, 20MHz ==> regulation class = 81 + * 2.4GHz, 1~13, SCA ==> regulation class = 83 + * 2.4GHz, 1~13, SCB ==> regulation class = 84 + * Note2: TX power limit is not specified here because path loss is unknown + */ + UINT_8 ucRegClass; /* Regulation class for 20MHz */ + UINT_8 ucBand; /* Type: ENUM_BAND_T */ + UINT_8 ucChannelSpan; /* Type: ENUM_CHNL_SPAN_T */ + UINT_8 ucFirstChannelNum; + UINT_8 ucNumChannels; + UINT_8 fgDfs; /* Type: BOOLEAN */ +} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; + +/* Use it as all available channel list for STA */ +typedef struct _DOMAIN_INFO_ENTRY { + PUINT_16 pu2CountryGroup; + UINT_32 u4CountryNum; + + /* If different attributes, put them into different rSubBands. + * For example, DFS shall be used or not. + */ + DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; +} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; + + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +typedef struct _CHANNEL_POWER_LIMIT { + UINT_8 ucCentralCh; + INT_8 cPwrLimitCCK; + INT_8 cPwrLimit20; + INT_8 cPwrLimit40; + INT_8 cPwrLimit80; + INT_8 cPwrLimit160; + UINT_8 ucFlag; + UINT_8 aucReserved[1]; +} CHANNEL_POWER_LIMIT, *P_CHANNEL_POWER_LIMIT; + +typedef struct _COUNTRY_CHANNEL_POWER_LIMIT { + UINT_8 aucCountryCode[2]; + UINT_8 ucCountryFlag; + UINT_8 ucChannelNum; + UINT_8 aucReserved[4]; + CHANNEL_POWER_LIMIT rChannelPowerLimit[80]; +} COUNTRY_CHANNEL_POWER_LIMIT, *P_COUNTRY_CHANNEL_POWER_LIMIT; + +#define CHANNEL_PWR_LIMIT(_channel, _pwrLimit_cck, _pwrLimit_bw20, \ + _pwrLimit_bw40, _pwrLimit_bw80, _pwrLimit_bw160, _ucFlag) \ + { \ + .ucCentralCh = (_channel), \ + .cPwrLimitCCK = (_pwrLimit_cck), \ + .cPwrLimit20 = (_pwrLimit_bw20), \ + .cPwrLimit40 = (_pwrLimit_bw40), \ + .cPwrLimit80 = (_pwrLimit_bw80), \ + .cPwrLimit160 = (_pwrLimit_bw160), \ + .ucFlag = (_ucFlag), \ + .aucReserved = {0} \ +} + +typedef struct _COUNTRY_POWER_LIMIT_TABLE_DEFAULT { + UINT_8 aucCountryCode[2]; + /* 0: ch 1 ~14 , 1: ch 36 ~48, 2: ch 52 ~64, 3: ch 100 ~144, 4: ch 149 ~165 */ + INT_8 aucPwrLimitSubBand[POWER_LIMIT_SUBAND_NUM]; + /* bit0: cPwrLimit2G4, bit1: cPwrLimitUnii1; bit2: cPwrLimitUnii2A; + * bit3: cPwrLimitUnii2C; bit4: cPwrLimitUnii3; mW: 0, mW\MHz : 1 */ + UINT_8 ucPwrUnit; +} COUNTRY_POWER_LIMIT_TABLE_DEFAULT, *P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT; + +typedef struct _COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION { + UINT_8 aucCountryCode[2]; + UINT_8 ucCentralCh; + INT_8 aucPwrLimit[PWR_LIMIT_NUM]; +} COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION, *P_COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION; + +typedef struct _SUBBAND_CHANNEL_T { + UINT_8 ucStartCh; + UINT_8 ucEndCh; + UINT_8 ucInterval; + UINT_8 ucReserved; +} SUBBAND_CHANNEL_T, *P_SUBBAND_CHANNEL_T; + +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CAL_CH_OFFSET_80M(_PRIMARY_CH, _CENTRAL_CH) \ + (((_PRIMARY_CH - _CENTRAL_CH) + 6) >> 2) + +#define CAL_CH_OFFSET_160M(_PRIMARY_CH, _CENTRAL_CH) \ + (((_PRIMARY_CH - _CENTRAL_CH) + 14) >> 2) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter); + +VOID +rlmDomainGetChnlList(P_ADAPTER_T prAdapter, + ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, + UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList); + +VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); + +VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); + +VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid); + +BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel); + +UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf); + +BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh); + +UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); + +BOOLEAN rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend, + ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2); + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +BOOLEAN +rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, + COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, + UINT_8 ucPwrLimitNum); + +VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter); + +UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode); + +VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_DOMAIN_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h new file mode 100644 index 0000000000000..7f29dba4ce069 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_obss.h @@ -0,0 +1,150 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_obss.h#1 +*/ + +/*! \file "rlm_obss.h" + \brief +*/ + +/* +** Log: rlm_obss.h + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop + * ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +#ifndef _RLM_OBSS_H +#define _RLM_OBSS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + +#define CHNL_LEVEL0 0 +#define CHNL_LEVEL1 1 +#define CHNL_LEVEL2 2 + +#define AFFECTED_CHNL_OFFSET 5 + +#define OBSS_SCAN_MIN_INTERVAL 10 /* In unit of sec */ + +#define PUBLIC_ACTION_MAX_LEN 200 /* In unit of byte */ + +/* P2P GO only */ +/* Define default OBSS Scan parameters (from MIB in spec.) */ +#define dot11OBSSScanPassiveDwell 20 +#define dot11OBSSScanActiveDwell 10 +#define dot11OBSSScanPassiveTotalPerChannel 200 +#define dot11OBSSScanActiveTotalPerChannel 20 +#define dot11BSSWidthTriggerScanInterval 300 /* Unit: sec */ +#define dot11BSSWidthChannelTransitionDelayFactor 5 +#define dot11OBSSScanActivityThreshold 25 + +#define OBSS_20_40M_TIMEOUT (dot11BSSWidthTriggerScanInterval + 10) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Control MAC PCO function */ +typedef enum _ENUM_SYS_PCO_PHASE_T { + SYS_PCO_PHASE_DISABLED = 0, + SYS_PCO_PHASE_20M, + SYS_PCO_PHASE_40M +} ENUM_SYS_PCO_PHASE_T, *P_ENUM_SYS_PCO_PHASE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID rlmObssInit(P_ADAPTER_T prAdapter); + +VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_OBSS_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h new file mode 100644 index 0000000000000..8665e48569bad --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_protection.h @@ -0,0 +1,122 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_protection.h#1 +*/ + +/*! \file "rlm_protection.h" + \brief +*/ + +/* +** Log: rlm_protection.h + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +#ifndef _RLM_PROTECTION_H +#define _RLM_PROTECTION_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SYS_PROTECT_MODE_T { + SYS_PROTECT_MODE_NONE = 0, /* Mode 0 */ + SYS_PROTECT_MODE_ERP, /* Mode 1 */ + SYS_PROTECT_MODE_NON_HT, /* Mode 2 */ + SYS_PROTECT_MODE_20M, /* Mode 3 */ + + SYS_PROTECT_MODE_NUM +} ENUM_SYS_PROTECT_MODE_T, *P_ENUM_SYS_PROTECT_MODE_T; + +/* This definition follows HT Protection field of HT Operation IE */ +typedef enum _ENUM_HT_PROTECT_MODE_T { + HT_PROTECT_MODE_NONE = 0, + HT_PROTECT_MODE_NON_MEMBER, + HT_PROTECT_MODE_20M, + HT_PROTECT_MODE_NON_HT, + + HT_PROTECT_MODE_NUM +} ENUM_HT_PROTECT_MODE_T, *P_ENUM_HT_PROTECT_MODE_T; + +typedef enum _ENUM_GF_MODE_T { + GF_MODE_NORMAL = 0, + GF_MODE_PROTECT, + GF_MODE_DISALLOWED, + + GF_MODE_NUM +} ENUM_GF_MODE_T, *P_ENUM_GF_MODE_T; + +typedef enum _ENUM_RIFS_MODE_T { + RIFS_MODE_NORMAL = 0, + RIFS_MODE_DISALLOWED, + + RIFS_MODE_NUM +} ENUM_RIFS_MODE_T, *P_ENUM_RIFS_MODE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_PROTECTION_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h new file mode 100644 index 0000000000000..d01c6e01e83f5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rlm_txpwr_init.h @@ -0,0 +1,1213 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rlm_txpwr_init.h#1 +*/ + +/*! \file "rlm_txpwr_init.h" + \brief +*/ + +/* +** Log: rlm_txpwr_init.h +*/ + + +#ifndef _RLM_TXPWR_INIT_H +#define _RLM_TXPWR_INIT_H + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/*Support Tx Power Range : 63~ -64 (unit : 0.5dBm)*/ + +#define PWR_LIMIT_2G4_IN_MW_MHZ BIT(0) +#define PWR_LIMIT_UNII1_IN_MW_MHZ BIT(1) +#define PWR_LIMIT_UNII2A_IN_MW_MHZ BIT(2) +#define PWR_LIMIT_UNII2C_IN_MW_MHZ BIT(3) +#define PWR_LIMIT_UNII3_IN_MW_MHZ BIT(4) + +#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT +#define CE_FCC_TXPWR_LIMIT_CCK 30 /* 15 dBm */ +#define CE_FCC_TXPWR_LIMIT_OFDM 20 /* 10 dBm */ +#define CE_FCC_TXPWR_LIMIT_HT40 18 /* 9 dBm */ +#endif + + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +COUNTRY_POWER_LIMIT_TABLE_DEFAULT g_rRlmPowerLimitDefault[] = { + + {{'A', 'O'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'B', 'Z'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'B', 'J'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'B', 'T'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'B', 'O'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'B', 'I'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'C', 'M'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'C', 'F'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'D'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'K', 'M'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'C', 'D'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'C', 'G'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'C', 'I'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'D', 'J'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'G', 'Q'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'E', 'R'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'F', 'J'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'G', 'A'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'G', 'M'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'G', 'N'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'G', 'W'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'R', 'K'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'K', 'G'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'L', 'Y'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'M', 'G'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'M', 'L'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'N', 'R'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'N', 'C'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'T'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'C'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'L'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'B'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'O'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'R'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'S', 'Z'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'J'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'G'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'O'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'M'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'T', 'V'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'V', 'U'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'Y', 'E'} + , {40, 63, 63, 63, 63} + , 0} + , + {{'A', 'S'} + , {60, 34, 46, 48, 60} + , 0} + , + {{'A', 'I'} + , {60, 34, 48, 60, 60} + , 0} + , + {{'B', 'M'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'C', 'A'} + , {60, 46, 48, 48, 60} + , 0} + , + {{'K', 'Y'} + , {60, 34, 48, 60, 60} + , 0} + , + {{'G', 'U'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'F', 'M'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'P', 'R'} + , {60, 34, 46, 48, 60} + , 0} + , + {{'U', 'S'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'V', 'I'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'A', 'R'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'A', 'U'} + , {63, 46, 46, 60, 63} + , 0} + , + {{'A', 'Z'} + , {40, 34, 48, 60, 60} + , 0} + , + {{'B', 'W'} + , {40, 46, 46, 60, 60} + , 0} + , + {{'K', 'H'} + , {40, 46, 46, 48, 60} + , 0} + , + {{'C', 'X'} + , {63, 46, 46, 60, 63} + , 0} + , + {{'C', 'O'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'C', 'R'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'E', 'C'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'G', 'D'} + , {40, 46, 46, 60, 60} + , 0} + , + {{'G', 'T'} + , {40, 34, 48, 48, 60} + , 0} + , + {{'H', 'K'} + , {63, 46, 46, 60, 63} + , 0} + , + {{'K', 'I'} + , {63, 46, 46, 60, 63} + , 0} + , + {{'L', 'B'} + , {40, 46, 46, 46, 46} + , 0} + , + {{'L', 'R'} + , {60, 46, 60, 63, 63} + , 0} + , + {{'M', 'N'} + , {46, 32, 46, 46, 58} + , 0} + , + {{'A', 'N'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'N', 'Z'} + , {63, 46, 60, 48, 63} + , 0} + , + {{'N', 'I'} + , {60, 34, 48, 48, 60} + , 0} + , + {{'P', 'W'} + , {60, 60, 60, 60, 60} + , 0} + , + {{'P', 'Y'} + , {60, 46, 46, 48, 60} + , 0} + , + {{'P', 'E'} + , {54, 46, 48, 42, 48} + , 0} + , + {{'P', 'H'} + , {40, 46, 46, 48, 48} + , 0} + , + {{'W', 'S'} + , {40, 40, 40, 40, 60} + , 0} + , + {{'S', 'G'} + , {46, 46, 46, 60, 60} + , 0} + , + {{'L', 'K'} + , {46, 46, 46, 46, 46} + , 0} + , + {{'T', 'H'} + , {40, 46, 46, 60, 60} + , 0} + , + {{'T', 'T'} + , {60, 46, 46, 60, 60} + , 0} + , + {{'U', 'Y'} + , {63, 46, 46, 46, 46} + , 0} + , + {{'V', 'N'} + , {46, 46, 46, 60, 60} + , 0} + , + {{'A', 'W'} + , {60, 46, 60, 60, 63} + , 0} + , + {{'L', 'A'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'A'} + , {40, 46, 46, 60, 60} + , 0} + , + {{'A', 'E'} + , {40, 46, 46, 60, 46} + , 0} + , + {{'U', 'G'} + , {40, 46, 46, 48, 60} + , 0} + , + {{'M', 'M'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'A', 'L'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'D', 'Z'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'A', 'D'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'A', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'B', 'Y'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'B', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'B', 'A'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'V', 'G'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'B', 'G'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'C', 'V'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'H', 'R'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'C', 'Y'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'C', 'Z'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'D', 'K'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'E', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'E', 'T'} + , {40, 40, 40, 40, 63} + , 0} + , + {{'F', 'I'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'F', 'R'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'G', 'F'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'P', 'F'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'T', 'F'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'G', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'D', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'G', 'H'} + , {40, 34, 48, 60, 63} + , 0} + , + {{'G', 'R'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'G', 'P'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'H', 'U'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'I', 'S'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'I', 'Q'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'I', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'I', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'K', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'L', 'V'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'L', 'S'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'L', 'I'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'L', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'L', 'U'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'K'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'Q'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'R'} + , {40, 46, 46, 46, 63} + , 0} + , + {{'M', 'U'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'Y', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'D'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'C'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'S'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'N', 'L'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'N', 'O'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'O', 'M'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'P', 'L'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'P', 'T'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'R', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'R', 'O'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'M', 'F'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'M'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'N'} + , {40, 40, 40, 60, 63} + , 0} + , + {{'R', 'S'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'K'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'I'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'Z', 'A'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'E', 'S'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'S', 'E'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'C', 'H'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'T', 'R'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'T', 'C'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'G', 'B'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'V', 'A'} + , {40, 46, 46, 60, 63} + , 0} + , + {{'A', 'M'} + , {40, 40, 40, 63, 63} + , 0} + , + {{'I', 'L'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'K', 'W'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'M', 'A'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'N', 'E'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'T', 'N'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'E', 'H'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'N', 'P'} + , {60, 46, 46, 63, 60} + , 0} + , + {{'A', 'F'} + , {40, 46, 63, 63, 63} + , 0} + , + {{'A', 'G'} + , {40, 46, 48, 63, 54} + , 0} + , + {{'B', 'S'} + , {63, 46, 60, 63, 63} + , 0} + , + {{'B', 'H'} + , {40, 46, 46, 63, 63} + , 0} + , + {{'B', 'B'} + , {40, 46, 48, 63, 54} + , 0} + , + {{'B', 'N'} + , {46, 46, 46, 63, 60} + , 0} + , + {{'C', 'L'} + , {40, 44, 44, 63, 44} + , 0} + , + {{'C', 'N'} + , {40, 46, 46, 63, 54} + , 0} + , + {{'E', 'G'} + , {40, 46, 46, 63, 46} + , 0} + , + {{'S', 'V'} + , {60, 34, 48, 63, 60} + , 0} + , + {{'I', 'N'} + , {60, 46, 46, 63, 60} + , 0} + , + {{'M', 'Y'} + , {54, 60, 60, 63, 60} + , 0} + , + {{'M', 'V'} + , {40, 46, 46, 63, 40} + , 0} + , + {{'P', 'A'} + , {60, 34, 48, 63, 60} + , 0} + , + {{'V', 'E'} + , {60, 46, 46, 63, 60} + , 0} + , + {{'Z', 'M'} + , {60, 46, 46, 63, 60} + , 0} + , + {{'J', 'O'} + , {40, 46, 63, 63, 46} + , 0} + , + {{'P', 'G'} + , {40, 46, 63, 63, 60} + , 0} + , + {{'B', 'F'} + , {40, 63, 63, 63, 60} + , 0} + , + {{'G', 'Y'} + , {60, 63, 63, 63, 60} + , 0} + , + {{'H', 'T'} + , {40, 63, 63, 63, 60} + , 0} + , + {{'H', 'N'} + , {60, 63, 63, 63, 60} + , 0} + , + {{'J', 'M'} + , {54, 63, 63, 63, 57} + , 0} + , + {{'M', 'O'} + , {40, 63, 63, 63, 40} + , 0} + , + {{'M', 'W'} + , {60, 63, 63, 63, 60} + , 0} + , + {{'P', 'K'} + , {40, 63, 63, 63, 40} + , 0} + , + {{'Q', 'A'} + , {40, 63, 63, 63, 40} + , 0} + , + {{'R', 'W'} + , {40, 63, 63, 63, 60} + , 0} + , + {{'K', 'N'} + , {40, 63, 63, 63, 60} + , 0} + , + {{'T', 'Z'} + , {40, 63, 63, 63, 40} + , 0} + , + {{'I', 'D'} + , {46, 63, 63, 63, 60} + , 0} + , + {{'N', 'G'} + , {40, 63, 46, 63, 60} + , 0} + , + {{'B', 'D'} + , {40, 46, 46, 60, 28} + , 0} + , + {{'B', 'R'} + , {52, 46, 46, 60, 60} + , 0} + , + {{'D', 'M'} + , {60, 34, 46, 48, 60} + , 0} + , + {{'D', 'O'} + , {63, 46, 46, 60, 63} + , 0} + , + {{'F', 'K'} + , {40, 46, 46, 60, 28} + , 0} + , + {{'K', 'Z'} + , {40, 34, 48, 60, 60} + , 0} + , + {{'M', 'X'} + , {60, 34, 48, 60, 63} + , 0} + , + {{'M', 'Z'} + , {40, 34, 46, 48, 60} + , 0} + , + {{'N', 'A'} + , {40, 34, 46, 48, 60} + , 0} + , + {{'R', 'U'} + , {40, 34, 48, 60, 60} + , 0} + , + {{'L', 'C'} + , {40, 34, 48, 48, 60} + , 0} + , + {{'V', 'C'} + , {40, 34, 46, 48, 60} + , 0} + , + {{'U', 'A'} + , {40, 46, 46, 46, 48} + , 0} + , + {{'U', 'Z'} + , {40, 48, 48, 48, 60} + , 0} + , + {{'Z', 'W'} + , {40, 34, 46, 48, 60} + , 0} + , + {{'M', 'P'} + , {60, 34, 46, 48, 60} + , 0} + , + {{'T', 'W'} + , {60, 63, 34, 48, 60} + , 0} + , + {{'C', 'K'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'C', 'U'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'T', 'L'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'F', 'O'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'G', 'I'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'G', 'G'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'I', 'R'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'I', 'M'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'J', 'E'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'K', 'P'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'M', 'H'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'N', 'U'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'N', 'F'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'P', 'S'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'P', 'N'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'P', 'M'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'S', 'S'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'S', 'D'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'S', 'Y'} + , {63, 63, 63, 63, 63} + , 0} + , + {{'J', 'P'} + , {46, 46, 46, 60, 63} + , 0} + , + {{'K', 'R'} + , {46, 34, 46, 46, 46} + , PWR_LIMIT_UNII1_IN_MW_MHZ} + , + +/*Default*/ + {{0, 0} + , {63, 63, 63, 63, 63} + , 0} +}; + +COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION g_rRlmPowerLimitConfiguration[] = { + + {{'A', 'I'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'A', 'Z'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'B', 'W'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'G', 'D'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'L', 'B'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'L', 'R'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'W', 'S'} + , 165, {40, 40, 40, 40, 40} + } + , + {{'V', 'N'} + , 144, {48, 48, 48, 48, 48} + } + , + {{'U', 'S'} + , 1, {38, 30, 60, 60, 60} + } + , + {{'U', 'S'} + , 3, {60, 60, 26, 60, 60} + } + , + {{'U', 'S'} + , 9, {60, 60, 26, 60, 60} + } + , + {{'U', 'S'} + , 11, {38, 30, 60, 60, 60} + } + , + {{'U', 'S'} + , 36, {34, 34, 34, 34, 34} + } + , + {{'U', 'S'} + , 38, {34, 34, 34, 34, 34} + } + , + {{'U', 'S'} + , 42, {34, 34, 34, 31, 34} + } + , + {{'U', 'S'} + , 58, {48, 48, 48, 31, 48} + } + , + {{'U', 'S'} + , 62, {48, 48, 34, 48, 48} + } + , + {{'U', 'S'} + , 64, {37, 37, 48, 48, 48} + } + , + {{'U', 'S'} + , 100, {37, 37, 48, 48, 48} + } + , + {{'U', 'S'} + , 102, {48, 48, 34, 48, 48} + } + , + {{'U', 'S'} + , 106, {48, 48, 48, 31, 48} + } + , + {{'U', 'S'} + , 155, {60, 60, 60, 31, 60} + } + , + {{'U', 'S'} + , 159, {60, 60, 34, 60, 60} + } + , + {{'U', 'S'} + , 165, {37, 37, 60, 60, 60} + } + , + +/*Default*/ + {{0, 0} + , 165, {63, 63, 63, 63, 63} + } +}; + +#if 0 +COUNTRY_CHANNEL_POWER_LIMIT g_rRlmCountryPowerLimitTable[] = { + { + {'A', 'O'} + , 0, 0, {0, 0, 0, 0} + , + { + CHANNEL_PWR_LIMIT(1, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(2, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(3, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(4, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(5, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(6, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(7, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(8, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(9, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(10, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(11, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(12, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(13, 40, 40, 40, 40, 40, 0), + CHANNEL_PWR_LIMIT(14, 40, 40, 40, 40, 40, 0), + + CHANNEL_PWR_LIMIT(36, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(38, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(40, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(42, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(44, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(46, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(48, 63, 63, 63, 63, 63, 0), + + CHANNEL_PWR_LIMIT(52, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(54, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(56, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(58, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(60, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(62, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(64, 63, 63, 63, 63, 63, 0), + + CHANNEL_PWR_LIMIT(100, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(102, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(104, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(106, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(108, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(110, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(112, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(114, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(116, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(118, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(120, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(122, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(124, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(126, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(128, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(130, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(132, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(134, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(136, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(138, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(140, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(142, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(144, 63, 63, 63, 63, 63, 0), + + CHANNEL_PWR_LIMIT(149, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(151, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(153, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(155, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(157, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(159, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(161, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(163, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(165, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(167, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(169, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(171, 63, 63, 63, 63, 63, 0), + CHANNEL_PWR_LIMIT(173, 63, 63, 63, 63, 63, 0) + } + } + , + { + /*Used to check the end of country entry */ + {0, 0} + , 0, 0, {0, 0, 0, 0} + , + { + /*Used to check the end of channel power limit */ + CHANNEL_PWR_LIMIT(ENDCH, 0, 0, 0, 0, 0, 0) + } + } /*end of CountryTable */ +}; +#endif +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#endif /* _RLM_TXPWR_INIT_H */ + + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h new file mode 100644 index 0000000000000..0df4ec3e08282 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/roaming_fsm.h @@ -0,0 +1,171 @@ +/* +** Id: +*/ + +/*! \file "roaming_fsm.h" + \brief This file defines the FSM for Roaming MODULE. + + This file defines the FSM for Roaming MODULE. +*/ + +/* +** Log: roaming_fsm.h + * + * 08 31 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * remove obsolete code. + * + * 08 15 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * add swcr in driver reg, 0x9fxx0000, to disable roaming . + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * +*/ + +#ifndef _ROAMING_FSM_H +#define _ROAMING_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Roaming Discovery interval, SCAN result need to be updated */ +#define ROAMING_DISCOVERY_TIMEOUT_SEC 5 /* Seconds. */ + +/* #define ROAMING_NO_SWING_RCPI_STEP 5 //rcpi */ +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_ROAMING_FAIL_REASON_T { + ROAMING_FAIL_REASON_CONNLIMIT = 0, + ROAMING_FAIL_REASON_NOCANDIDATE, + ROAMING_FAIL_REASON_NUM +} ENUM_ROAMING_FAIL_REASON_T; + +/* events of roaming between driver and firmware */ +typedef enum _ENUM_ROAMING_EVENT_T { + ROAMING_EVENT_START = 0, + ROAMING_EVENT_DISCOVERY, + ROAMING_EVENT_ROAM, + ROAMING_EVENT_FAIL, + ROAMING_EVENT_ABORT, + ROAMING_EVENT_NUM +} ENUM_ROAMING_EVENT_T; + +#define ROAMING_EVENT_REASON_TX_ERR BIT(0) +#define ROAMING_EVENT_REASON_RCPI BIT(1) + +typedef struct _ROAMING_PARAM_T { + UINT_16 u2Event; + UINT_16 u2Data; + UINT_16 u2Reason; +} ROAMING_PARAM_T, *P_ROAMING_PARAM_T; + + /**/ typedef enum _ENUM_ROAMING_STATE_T { + ROAMING_STATE_IDLE = 0, + ROAMING_STATE_DECISION, + ROAMING_STATE_DISCOVERY, + ROAMING_STATE_ROAM, + ROAMING_STATE_NUM +} ENUM_ROAMING_STATE_T; + +typedef struct _ROAMING_INFO_T { + BOOLEAN fgIsEnableRoaming; + + ENUM_ROAMING_STATE_T eCurrentState; + + OS_SYSTIME rRoamingDiscoveryUpdateTime; + +#define ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX 2 + UINT_32 RoamingEntryTimeoutSkipCount; + +} ROAMING_INFO_T, *P_ROAMING_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if CFG_SUPPORT_ROAMING +#define IS_ROAMING_ACTIVE(prAdapter) \ + (prAdapter->rWifiVar.rRoamingInfo.eCurrentState == ROAMING_STATE_ROAM) +#else +#define IS_ROAMING_ACTIVE(prAdapter) FALSE +#endif /* CFG_SUPPORT_ROAMING */ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID roamingFsmInit(IN P_ADAPTER_T prAdapter); + +VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter); + +VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); + +VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter); + +VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState); + +VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter); + +VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); + +VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter); + +VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Reason); + +VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ROAMING_FSM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h new file mode 100644 index 0000000000000..20ab14251f65d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/rsn.h @@ -0,0 +1,271 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/rsn.h#1 +*/ + +/*! \file rsn.h + \brief The wpa/rsn related define, macro and structure are described here. +*/ + +/* +** Log: rsn.h + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h + * and let the sw structure not align at byte + * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, + * Notice needed update P2P.ko. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 wh.su + * NULL + * remove non-used code. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify + * the security related callback function prototype. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function prototype for generate wap/rsn ie + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function input parameter + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some event function declaration + * + * Nov 26 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * move the internal data structure for pmkid to rsn.h + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the port control and class error function + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the pmkid candidate + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +#ifndef _RSN_H +#define _RSN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* ----- Definitions for Cipher Suite Selectors ----- */ +#define RSN_CIPHER_SUITE_USE_GROUP_KEY 0x00AC0F00 +#define RSN_CIPHER_SUITE_WEP40 0x01AC0F00 +#define RSN_CIPHER_SUITE_TKIP 0x02AC0F00 +#define RSN_CIPHER_SUITE_CCMP 0x04AC0F00 +#define RSN_CIPHER_SUITE_WEP104 0x05AC0F00 +#if CFG_SUPPORT_802_11W +#define RSN_CIPHER_SUITE_AES_128_CMAC 0x06AC0F00 +#endif + +#define WPA_CIPHER_SUITE_NONE 0x00F25000 +#define WPA_CIPHER_SUITE_WEP40 0x01F25000 +#define WPA_CIPHER_SUITE_TKIP 0x02F25000 +#define WPA_CIPHER_SUITE_CCMP 0x04F25000 +#define WPA_CIPHER_SUITE_WEP104 0x05F25000 + +/* ----- Definitions for Authentication and Key Management Suite Selectors ----- */ +#define RSN_AKM_SUITE_NONE 0x00AC0F00 +#define RSN_AKM_SUITE_802_1X 0x01AC0F00 +#define RSN_AKM_SUITE_PSK 0x02AC0F00 +#if CFG_SUPPORT_802_11W +#define RSN_AKM_SUITE_802_1X_SHA256 0x05AC0F00 +#define RSN_AKM_SUITE_PSK_SHA256 0x06AC0F00 +#endif + +#define WPA_AKM_SUITE_NONE 0x00F25000 +#define WPA_AKM_SUITE_802_1X 0x01F25000 +#define WPA_AKM_SUITE_PSK 0x02F25000 + +#define ELEM_ID_RSN_LEN_FIXED 20 /* The RSN IE len for associate request */ + +#define ELEM_ID_WPA_LEN_FIXED 22 /* The RSN IE len for associate request */ + +#define MASK_RSNIE_CAP_PREAUTH BIT(0) + +#define GET_SELECTOR_TYPE(x) ((UINT_8)(((x) >> 24) & 0x000000FF)) +#define SET_SELECTOR_TYPE(x, y) {x = (((x) & 0x00FFFFFF) | (((UINT_32)(y) << 24) & 0xFF000000))} + +#define AUTH_CIPHER_CCMP 0x00000008 + +/* Cihpher suite flags */ +#define CIPHER_FLAG_NONE 0x00000000 +#define CIPHER_FLAG_WEP40 0x00000001 /* BIT 1 */ +#define CIPHER_FLAG_TKIP 0x00000002 /* BIT 2 */ +#define CIPHER_FLAG_CCMP 0x00000008 /* BIT 4 */ +#define CIPHER_FLAG_WEP104 0x00000010 /* BIT 5 */ +#define CIPHER_FLAG_WEP128 0x00000020 /* BIT 6 */ + +#define WAIT_TIME_IND_PMKID_CANDICATE_SEC 6 /* seconds */ +#define TKIP_COUNTERMEASURE_SEC 60 /* seconds */ + +#if CFG_SUPPORT_802_11W +#define RSN_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define RSN_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define RSN_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Flags for PMKID Candidate list structure */ +#define EVENT_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 + +#define CONTROL_FLAG_UC_MGMT_NO_ENC BIT(5) + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define RSN_IE(fp) ((P_RSN_INFO_ELEM_T) fp) +#define WPA_IE(fp) ((P_WPA_INFO_ELEM_T) fp) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo); + +BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo); + +BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index); + +BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index); + +BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); + +VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +BOOLEAN +rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion); + +BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo); + +#if CFG_SUPPORT_AAA +void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode); +#endif + +VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType); + +VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex); + +BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter); + +VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); + +VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter); + +VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); +#if CFG_SUPPORT_WPS2 +VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +#endif + +#if CFG_SUPPORT_802_11W +UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter); + +void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter); + +void rsnStartSaQuery(IN P_ADAPTER_T prAdapter); + +void rsnStopSaQuery(IN P_ADAPTER_T prAdapter); + +void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype); +#endif +BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _RSN_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h new file mode 100644 index 0000000000000..c08b2244be6c4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/scan.h @@ -0,0 +1,988 @@ +/* +** Id: @(#) +*/ + +/*! \file "scan.h" + \brief + +*/ + +/* +** Log: scan.h + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration + * with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting + * preferred band configuration corresponding to network type. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than one SSID + * in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID + * support as well as uProbeDelay in NDIS 6.x driver model + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings + * to work around some tricky AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module + * with structure miss-align pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix compile error. + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 12 2010 yuche.tsai + * NULL + * Add a functio prototype to find p2p descriptor of a bss descriptor directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Add function prototype for return channel. + * modify data structure for scan specific device ID or TYPE. (Move from P2P Connection Settings to Scan Param) + * + * 08 05 2010 yuche.tsai + * NULL + * Check-in P2P Device Discovery Feature. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Add a option for channel time extension in scan abort command. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Scan status "FIND" is used for P2P FSM find state. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request + * will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related field in SCAN_PARAM_T. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * + * Add new HW CH macro support + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify scanBuildProbeReqFrameCommonIEs() to support P2P SCAN + * + * 02 23 2010 wh.su + * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver + * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Simplify the process of Beacon during SCAN and remove redundant variable in PRE_BSS_DESC_T + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding variable for wapi ap + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove non-used secuirty variavle + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Refine data structure of BSS_DESC_T and PRE_BSS_DESC_T + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add eNetType to rScanParam and revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add ucAvailablePhyTypeSet to BSS_DESC_T + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aucSrcAddress to SCAN_PARAM_T for P2P's Device Address + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security related variable + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security ie filed for scan parsing + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scanSearchBssDescByPolicy() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function declarations of scan_fsm.c + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scan.h to source control +** +*/ + +#ifndef _SCAN_H +#define _SCAN_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_vendor.h" + +/* TDLS test purpose */ +extern BOOLEAN flgTdlsTestExtCapElm; +extern UINT8 aucTdlsTestExtCapElm[]; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/*! Maximum buffer size of SCAN list */ +#define SCN_MAX_BUFFER_SIZE (CFG_MAX_NUM_BSS_LIST * ALIGN_4(sizeof(BSS_DESC_T))) + +#define SCN_RM_POLICY_EXCLUDE_CONNECTED BIT(0) /* Remove SCAN result except the connected one. */ +#define SCN_RM_POLICY_TIMEOUT BIT(1) /* Remove the timeout one */ +#define SCN_RM_POLICY_OLDEST_HIDDEN BIT(2) /* Remove the oldest one with hidden ssid */ +#define SCN_RM_POLICY_SMART_WEAKEST BIT(3) /* If there are more than half BSS which has the + * same ssid as connection setting, remove the + * weakest one from them + * Else remove the weakest one. + */ +#define SCN_RM_POLICY_ENTIRE BIT(4) /* Remove entire SCAN result */ + +#define SCN_BSS_DESC_SAME_SSID_THRESHOLD 3 /* This is used by POLICY SMART WEAKEST, + * If exceed this value, remove weakest BSS_DESC_T + * with same SSID first in large network. + */ + +/* the scan time in WFD mode + 2.4G/5G is about 9s so we need to enlarge the value */ +#define SCN_BSS_DESC_REMOVE_TIMEOUT_SEC 15 /* Second. */ + /* This is used by POLICY TIMEOUT, + * If exceed this value, remove timeout BSS_DESC_T. + */ + +#define SCN_PROBE_DELAY_MSEC 0 + +#define SCN_ADHOC_BSS_DESC_TIMEOUT_SEC 5 /* Second. */ + +#define SCN_NLO_NETWORK_CHANNEL_NUM (4) + +/*----------------------------------------------------------------------------*/ +/* MSG_SCN_SCAN_REQ */ +/*----------------------------------------------------------------------------*/ +#define SCAN_REQ_SSID_WILDCARD BIT(0) +#define SCAN_REQ_SSID_P2P_WILDCARD BIT(1) +#define SCAN_REQ_SSID_SPECIFIED BIT(2) + +/*----------------------------------------------------------------------------*/ +/* Support Multiple SSID SCAN */ +/*----------------------------------------------------------------------------*/ +#define SCN_SSID_MAX_NUM CFG_SCAN_SSID_MAX_NUM +#define SCN_SSID_MATCH_MAX_NUM CFG_SCAN_SSID_MATCH_MAX_NUM + +#define SWC_NUM_BSSID_THRESHOLD_DEFAULT 8 +#define SWC_RSSI_WINDSIZE_DEFAULT 8 +#define LOST_AP_WINDOW 16 +#define MAX_CHANNEL_NUM_PER_BUCKETS 8 + +#define SCN_BSS_JOIN_FAIL_THRESOLD 4 +#define SCN_BSS_JOIN_FAIL_CNT_RESET_SEC 15 +#define SCN_BSS_JOIN_FAIL_RESET_STEP 2 + +#if CFG_SUPPORT_BATCH_SCAN +/*----------------------------------------------------------------------------*/ +/* SCAN_BATCH_REQ */ +/*----------------------------------------------------------------------------*/ +#define SCAN_BATCH_REQ_START BIT(0) +#define SCAN_BATCH_REQ_STOP BIT(1) +#define SCAN_BATCH_REQ_RESULT BIT(2) +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SCAN_TYPE_T { + SCAN_TYPE_PASSIVE_SCAN = 0, + SCAN_TYPE_ACTIVE_SCAN, + SCAN_TYPE_NUM +} ENUM_SCAN_TYPE_T, *P_ENUM_SCAN_TYPE_T; + +typedef enum _ENUM_SCAN_STATE_T { + SCAN_STATE_IDLE = 0, + SCAN_STATE_SCANNING, + SCAN_STATE_NUM +} ENUM_SCAN_STATE_T; + +typedef enum _ENUM_SCAN_CHANNEL_T { + SCAN_CHANNEL_FULL = 0, + SCAN_CHANNEL_2G4, + SCAN_CHANNEL_5G, + SCAN_CHANNEL_P2P_SOCIAL, + SCAN_CHANNEL_SPECIFIED, + SCAN_CHANNEL_NUM +} ENUM_SCAN_CHANNEL, *P_ENUM_SCAN_CHANNEL; + +typedef struct _MSG_SCN_FSM_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_32 u4Dummy; +} MSG_SCN_FSM_T, *P_MSG_SCN_FSM_T; + +typedef enum _ENUM_PSCAN_STATE_T { + PSCN_IDLE = 1, + PSCN_SCANNING, + PSCN_RESET, + PSCAN_STATE_T_NUM +} ENUM_PSCAN_STATE_T; + +/*----------------------------------------------------------------------------*/ +/* BSS Descriptors */ +/*----------------------------------------------------------------------------*/ +struct _BSS_DESC_T { + LINK_ENTRY_T rLinkEntry; + + UINT_8 aucBSSID[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ + + BOOLEAN fgIsConnecting; /* If we are going to connect to this BSS + * (JOIN or ROAMING to another BSS), don't + * remove this record from BSS List. + */ + BOOLEAN fgIsConnected; /* If we have connected to this BSS (NORMAL_TR), + * don't removed this record from BSS list. + */ + + BOOLEAN fgIsHiddenSSID; /* When this flag is TRUE, means the SSID + * of this BSS is not known yet. + */ + UINT_8 ucSSIDLen; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + + OS_SYSTIME rUpdateTime; + + ENUM_BSS_TYPE_T eBSSType; + + UINT_16 u2CapInfo; + + UINT_16 u2BeaconInterval; + UINT_16 u2ATIMWindow; + + UINT_16 u2OperationalRateSet; + UINT_16 u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + + BOOLEAN fgIsERPPresent; + BOOLEAN fgIsHTPresent; + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this BSS */ + + UINT_8 ucChannelNum; + + ENUM_CHNL_EXT_T eSco; /* Record bandwidth for association process + Some AP will send association resp by 40MHz BW */ + ENUM_BAND_T eBand; + + UINT_8 ucDTIMPeriod; + + BOOLEAN fgIsLargerTSF; /* This BSS's TimeStamp is larger than us(TCL == 1 in RX_STATUS_T) */ + + UINT_8 ucRCPI; + + UINT_8 ucWmmFlag; /* A flag to indicate this BSS's WMM capability */ + + /*! \brief The srbiter Search State will matched the scan result, + and saved the selected cipher and akm, and report the score, + for arbiter join state, join module will carry this target BSS + to rsn generate ie function, for gen wpa/rsn ie */ + UINT_32 u4RsnSelectedGroupCipher; + UINT_32 u4RsnSelectedPairwiseCipher; + UINT_32 u4RsnSelectedAKMSuite; + + UINT_16 u2RsnCap; + + RSN_INFO_T rRSNInfo; + RSN_INFO_T rWPAInfo; +#if 1 /* CFG_SUPPORT_WAPI */ + WAPI_INFO_T rIEWAPI; + BOOLEAN fgIEWAPI; +#endif + BOOLEAN fgIERSN; + BOOLEAN fgIEWPA; + + /*! \brief RSN parameters selected for connection */ + /*! \brief The Select score for final AP selection, + 0, no sec, 1,2,3 group cipher is WEP, TKIP, CCMP */ + UINT_8 ucEncLevel; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsP2PPresent; + BOOLEAN fgIsP2PReport; /* TRUE: report to upper layer */ + P_P2P_DEVICE_DESC_T prP2pDesc; + + UINT_8 aucIntendIfAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from BSSID */ +/* UINT_8 ucDevCapabilityBitmap; */ /* Device Capability Attribute. (P2P_DEV_CAPABILITY_XXXX) */ +/* UINT_8 ucGroupCapabilityBitmap; */ /* Group Capability Attribute. (P2P_GROUP_CAPABILITY_XXXX) */ + + LINK_T rP2pDeviceList; + +/* P_LINK_T prP2pDeviceList; */ + + /* For + * 1. P2P Capability. + * 2. P2P Device ID. ( in aucSrcAddr[] ) + * 3. NOA (TODO:) + * 4. Extend Listen Timing. (Probe Rsp) (TODO:) + * 5. P2P Device Info. (Probe Rsp) + * 6. P2P Group Info. (Probe Rsp) + */ +#endif + + BOOLEAN fgIsIEOverflow; /* The received IE length exceed the maximum IE buffer size */ + UINT_16 u2RawLength; /* The byte count of aucRawBuf[] */ + UINT_16 u2IELength; /* The byte count of aucIEBuf[] */ + + ULARGE_INTEGER u8TimeStamp; /* Place u8TimeStamp before aucIEBuf[1] to force DW align */ + UINT_8 aucRawBuf[CFG_RAW_BUFFER_SIZE]; + UINT_8 aucIEBuf[CFG_IE_BUFFER_SIZE]; + UINT_8 ucJoinFailureCount; + OS_SYSTIME rJoinFailTime; +}; + +typedef struct _SCAN_PARAM_T { /* Used by SCAN FSM */ + /* Active or Passive */ + ENUM_SCAN_TYPE_T eScanType; + + /* Network Type */ + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + + /* Specified SSID Type */ + UINT_8 ucSSIDType; + UINT_8 ucSSIDNum; + + /* Length of Specified SSID */ + UINT_8 ucSpecifiedSSIDLen[SCN_SSID_MAX_NUM]; + + /* Specified SSID */ + UINT_8 aucSpecifiedSSID[SCN_SSID_MAX_NUM][ELEM_MAX_LEN_SSID]; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgFindSpecificDev; /* P2P: Discovery Protocol */ + UINT_8 aucDiscoverDevAddr[MAC_ADDR_LEN]; + BOOLEAN fgIsDevType; + P2P_DEVICE_TYPE_T rDiscoverDevType; + + UINT_16 u2PassiveListenInterval; + /* TODO: Find Specific Device Type. */ +#endif /* CFG_SUPPORT_P2P */ + + BOOLEAN fgIsObssScan; + BOOLEAN fgIsScanV2; + + /* Run time flags */ + UINT_16 u2ProbeDelayTime; + + /* channel information */ + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + + /* Feedback information */ + UINT_8 ucSeqNum; + + /* Information Element */ + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; + +} SCAN_PARAM_T, *P_SCAN_PARAM_T; + +typedef struct _NLO_PARAM_T { /* Used by SCAN FSM */ + SCAN_PARAM_T rScanParam; + + /* NLO */ + BOOLEAN fgStopAfterIndication; + UINT_8 ucFastScanIteration; + UINT_16 u2FastScanPeriod; + UINT_16 u2SlowScanPeriod; + + /* Match SSID */ + UINT_8 ucMatchSSIDNum; + UINT_8 ucMatchSSIDLen[SCN_SSID_MATCH_MAX_NUM]; + UINT_8 aucMatchSSID[SCN_SSID_MATCH_MAX_NUM][ELEM_MAX_LEN_SSID]; + + UINT_8 aucCipherAlgo[SCN_SSID_MATCH_MAX_NUM]; + UINT_16 au2AuthAlgo[SCN_SSID_MATCH_MAX_NUM]; + UINT_8 aucChannelHint[SCN_SSID_MATCH_MAX_NUM][SCN_NLO_NETWORK_CHANNEL_NUM]; + P_BSS_DESC_T aprPendingBssDescToInd[SCN_SSID_MATCH_MAX_NUM]; +} NLO_PARAM_T, *P_NLO_PARAM_T; + +#if 1 + +typedef struct _GSCN_CHANNEL_INFO_T { + UINT_8 ucBand; + UINT_8 ucChannel; /* frequency */ + UINT_8 ucPassive; /* 0 => active, 1 => passive scan; ignored for DFS */ + UINT_8 aucReserved[1]; + + UINT_32 u4DwellTimeMs; /* dwell time hint */ + /* Add channel class */ +} GSCN_CHANNEL_INFO_T, *P_GSCN_CHANNEL_INFO_T; + +typedef struct _GSCAN_CHANNEL_BUCKET_T { + + UINT_16 u2BucketIndex; /* bucket index, 0 based */ + UINT_8 ucBucketFreqMultiple; /* desired period, in millisecond; + * if this is too low, the firmware should choose to generate + * results as fast as it can instead of failing the command */ + /* report_events semantics - + * 0 => report only when scan history is % full + * 1 => same as 0 + report a scan completion event after scanning this bucket + * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL + * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to + supplicant as well (optional) . */ + UINT_8 ucReportFlag; + UINT_8 ucNumChannels; + UINT_8 aucReserved[3]; + WIFI_BAND eBand; /* when UNSPECIFIED, use channel list */ + GSCN_CHANNEL_INFO_T arChannelList[GSCAN_MAX_CHANNELS]; /* channels to scan; these may include DFS channels */ +} GSCAN_CHANNEL_BUCKET_T, *P_GSCAN_CHANNEL_BUCKET_T; + +typedef struct _CMD_GSCN_REQ_T { + UINT_8 ucFlags; + UINT_8 ucNumScnToCache; + UINT_8 aucReserved[2]; + UINT_32 u4BufferThreshold; + UINT_32 u4BasePeriod; /* base timer period in ms */ + UINT_32 u4NumBuckets; + UINT_32 u4MaxApPerScan; /* number of APs to store in each scan in the */ + /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ + + GSCAN_CHANNEL_BUCKET_T arChannelBucket[GSCAN_MAX_BUCKETS]; +} CMD_GSCN_REQ_T, *P_CMD_GSCN_REQ_T; + +#endif + +typedef struct _CMD_GSCN_SCN_COFIG_T { + UINT_8 ucNumApPerScn; /* GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN */ + UINT_32 u4NumScnToCache; /* GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE */ + UINT_32 u4BufferThreshold; /* GSCAN_ATTRIBUTE_REPORT_THRESHOLD */ +} CMD_GSCN_SCN_COFIG_T, *P_CMD_GSCN_SCN_COFIG_T; + +typedef struct _CMD_GET_GSCAN_RESULT { + UINT_8 ucVersion; + UINT_8 aucReserved[2]; + UINT_8 ucFlush; + UINT_32 u4Num; +} CMD_GET_GSCAN_RESULT_T, *P_CMD_GET_GSCAN_RESULT_T; + +typedef struct _CMD_BATCH_REQ_T { + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + UINT_8 ucCmd; /* Start/ Stop */ + UINT_8 ucMScan; /* an integer number of scans per batch */ + UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ + UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd like + approximate distance reported */ + UINT_8 ucChannel; /* channels */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + UINT_8 aucReserved[3]; + UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ + CHANNEL_INFO_T arChannelList[32]; /* channels */ +} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; + +typedef struct _PSCN_PARAM_T { + UINT_8 ucVersion; + CMD_NLO_REQ rCurrentCmdNloReq; + CMD_BATCH_REQ_T rCurrentCmdBatchReq; + CMD_GSCN_REQ_T rCurrentCmdGscnReq; + BOOLEAN fgNLOScnEnable; + BOOLEAN fgBatchScnEnable; + BOOLEAN fgGScnEnable; + UINT_32 u4BasePeriod; /* GSCAN_ATTRIBUTE_BASE_PERIOD */ +} PSCN_PARAM_T, *P_PSCN_PARAM_T; + +typedef struct _SCAN_INFO_T { + ENUM_SCAN_STATE_T eCurrentState; /* Store the STATE variable of SCAN FSM */ + + OS_SYSTIME rLastScanCompletedTime; + + SCAN_PARAM_T rScanParam; + NLO_PARAM_T rNloParam; + + UINT_32 u4NumOfBssDesc; + + UINT_8 aucScanBuffer[SCN_MAX_BUFFER_SIZE]; + + LINK_T rBSSDescList; + + LINK_T rFreeBSSDescList; + + LINK_T rPendingMsgList; + + /* Sparse Channel Detection */ + BOOLEAN fgIsSparseChannelValid; + RF_CHANNEL_INFO_T rSparseChannel; + + /* NLO scanning state tracking */ + BOOLEAN fgNloScanning; + BOOLEAN fgPscnOnnning; + BOOLEAN fgGScnConfigSet; + BOOLEAN fgGScnParamSet; + P_PSCN_PARAM_T prPscnParam; + ENUM_PSCAN_STATE_T eCurrentPSCNState; + +} SCAN_INFO_T, *P_SCAN_INFO_T; + +/* Incoming Mailbox Messages */ +typedef struct _MSG_SCN_SCAN_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_TYPE_T eScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDLength; + UINT_8 aucSSID[PARAM_MAX_LEN_SSID]; +#if CFG_ENABLE_WIFI_DIRECT + UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ +#endif + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ, *P_MSG_SCN_SCAN_REQ; + +typedef struct _MSG_SCN_SCAN_REQ_V2_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_TYPE_T eScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDNum; + P_PARAM_SSID_T prSsid; + UINT_16 u2ProbeDelay; + UINT_16 u2ChannelDwellTime; /* In TU. 1024us. */ + ENUM_SCAN_CHANNEL eScanChannel; + UINT_8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ_V2, *P_MSG_SCN_SCAN_REQ_V2; + +typedef struct _MSG_SCN_SCAN_CANCEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsChannelExt; +#endif +} MSG_SCN_SCAN_CANCEL, *P_MSG_SCN_SCAN_CANCEL; + +/* Outgoing Mailbox Messages */ +typedef enum _ENUM_SCAN_STATUS_T { + SCAN_STATUS_DONE = 0, + SCAN_STATUS_CANCELLED, + SCAN_STATUS_FAIL, + SCAN_STATUS_BUSY, + SCAN_STATUS_NUM +} ENUM_SCAN_STATUS, *P_ENUM_SCAN_STATUS; + +typedef struct _MSG_SCN_SCAN_DONE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + ENUM_SCAN_STATUS eScanStatus; +} MSG_SCN_SCAN_DONE, *P_MSG_SCN_SCAN_DONE; + +#if CFG_SUPPORT_AGPS_ASSIST +typedef enum { + AGPS_PHY_A, + AGPS_PHY_B, + AGPS_PHY_G, +} AP_PHY_TYPE; + +typedef struct _AGPS_AP_INFO_T { + UINT_8 aucBSSID[6]; + INT_16 i2ApRssi; /* -127..128 */ + UINT_16 u2Channel; /* 0..256 */ + AP_PHY_TYPE ePhyType; +} AGPS_AP_INFO_T, *P_AGPS_AP_INFO_T; + +typedef struct _AGPS_AP_LIST_T { + UINT_8 ucNum; + AGPS_AP_INFO_T arApInfo[32]; +} AGPS_AP_LIST_T, *P_AGPS_AP_LIST_T; +#endif + +typedef struct _CMD_SET_PSCAN_PARAM { + UINT_8 ucVersion; + CMD_NLO_REQ rCmdNloReq; + CMD_BATCH_REQ_T rCmdBatchReq; + CMD_GSCN_REQ_T rCmdGscnReq; + BOOLEAN fgNLOScnEnable; + BOOLEAN fgBatchScnEnable; + BOOLEAN fgGScnEnable; + UINT_32 u4BasePeriod; +} CMD_SET_PSCAN_PARAM, *P_CMD_SET_PSCAN_PARAM; + +typedef struct _CMD_SET_PSCAN_ADD_HOTLIST_BSSID { + UINT_8 aucMacAddr[6]; + UINT_8 ucFlags; + UINT_8 aucReserved[5]; +} CMD_SET_PSCAN_ADD_HOTLIST_BSSID, *P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID; + +typedef struct _CMD_SET_PSCAN_ADD_SWC_BSSID { + INT_32 i4RssiLowThreshold; + INT_32 i4RssiHighThreshold; + UINT_8 aucMacAddr[6]; + UINT_8 aucReserved[6]; +} CMD_SET_PSCAN_ADD_SWC_BSSID, *P_CMD_SET_PSCAN_ADD_SWC_BSSID; + +typedef struct _CMD_SET_PSCAN_MAC_ADDR { + UINT_8 ucVersion; + UINT_8 ucFlags; + UINT_8 aucMacAddr[6]; + UINT_8 aucReserved[8]; +} CMD_SET_PSCAN_MAC_ADDR, *P_CMD_SET_PSCAN_MAC_ADDR; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in scan.c */ +/*----------------------------------------------------------------------------*/ +VOID scnInit(IN P_ADAPTER_T prAdapter); + +VOID scnUninit(IN P_ADAPTER_T prAdapter); + +/* BSS-DESC Search */ +P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); + +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); + +P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]); + +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); + +#if CFG_SUPPORT_HOTSPOT_2_0 +P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); +#endif + +/* BSS-DESC Search - Alternative */ +P_BSS_DESC_T +scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]); + +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid); + +/* BSS-DESC Allocation */ +P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter); + +/* BSS-DESC Removal */ +VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy); + +VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); + +VOID +scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +/* BSS-DESC State Change */ +VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]); + +#if 0 +/* BSS-DESC Insertion */ +P_BSS_DESC_T scanAddToInternalScanResult(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb, IN P_BSS_DESC_T prBssDesc); +#endif + +/* BSS-DESC Insertion - ALTERNATIVE */ +P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); + +VOID +scanBuildProbeReqFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, + IN PUINT_8 pucDesiredSsid, IN UINT_32 u4DesiredSsidLen, IN UINT_16 u2SupportedRateSet); + +WLAN_STATUS scanSendProbeReqFrames(IN P_ADAPTER_T prAdapter, IN P_SCAN_PARAM_T prScanParam); + +VOID scanUpdateBssDescForSearch(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb); + +VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc); + +/*----------------------------------------------------------------------------*/ +/* Routines in scan_fsm.c */ +/*----------------------------------------------------------------------------*/ +VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState); + +/*----------------------------------------------------------------------------*/ +/* Command Routines */ +/*----------------------------------------------------------------------------*/ +VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter); + +VOID scnSendScanReq(IN P_ADAPTER_T prAdapter); + +VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter); + +VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* RX Event Handling */ +/*----------------------------------------------------------------------------*/ +VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone); + +VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg); + +VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg); + +VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Generation */ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus); + +/*----------------------------------------------------------------------------*/ +/* Query for sparse channel */ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +BOOLEAN +scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval); + +BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter); + +BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct); + +BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); + +BOOLEAN scnFsmGSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); + +#if 0 + +BOOLEAN scnFsmGSCNSetRssiSignificatn(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam); +#endif + +BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId); + +BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr); + +#if 1 /* CFG_SUPPORT_GSCN_NONSYNC_BROADCOM */ +BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam); + +#else +BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_REQ_T prCmdGscnParam); + +#endif + +BOOLEAN +scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, + IN P_CMD_NLO_REQ prCmdNloReq, + IN P_CMD_BATCH_REQ_T prCmdBatchReq, + IN P_CMD_GSCN_REQ_T prCmdGscnReq, + IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, + IN BOOLEAN fgRemoveNLOfromPSCN, + IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN); + +BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig); + +BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd); + +VOID +scnPSCNFsm(IN P_ADAPTER_T prAdapter, + ENUM_PSCAN_STATE_T eNextPSCNState, + IN P_CMD_NLO_REQ prCmdNloReq, + IN P_CMD_BATCH_REQ_T prCmdBatchReq, + IN P_CMD_GSCN_REQ_T prCmdGscnReq, + IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, + IN BOOLEAN fgRemoveNLOfromPSCN, + IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN); + +#endif /* _SCAN_H */ + +#if CFG_SUPPORT_AGPS_ASSIST +VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter); +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h new file mode 100644 index 0000000000000..c6c468e06c4a5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/sec_fsm.h @@ -0,0 +1,233 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/sec_fsm.h#1 +*/ + +/*! \file sec_fsm.h + \brief Declaration of functions and finite state machine for SECURITY Module. + + Function declaration for privacy.c and SEC_STATE for SECURITY FSM. +*/ + +/* +** Log: sec_fsm.h + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 03 04 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Code refine, and remove non-used code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, and modify the security + * related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * fixed the deauth Tx done callback parameter + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the reference function declaration + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * delete non-used code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function prototype + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function declaration + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the security variable + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** \main\maintrunk.MT5921\14 2009-04-06 15:35:47 GMT mtk01088 +** add the variable to set the disable AP selection for privacy check, for wps open networking. +** \main\maintrunk.MT5921\13 2008-11-19 11:46:01 GMT mtk01088 +** rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\12 2008-08-28 20:37:11 GMT mtk01088 +** remove non-used code +** +** \main\maintrunk.MT5921\11 2008-03-18 09:51:52 GMT mtk01088 +** Add function declaration for timer to indicate pmkid candidate +** \main\maintrunk.MT5921\10 2008-02-29 15:12:08 GMT mtk01088 +** add variable for sw port control +** \main\maintrunk.MT5921\9 2008-02-29 12:37:30 GMT mtk01088 +** rename the security related function declaration +** \main\maintrunk.MT5921\8 2007-12-27 13:59:08 GMT mtk01088 +** adjust the wlan table and sec fsm init timing +** \main\maintrunk.MT5921\7 2007-11-20 10:39:49 GMT mtk01088 +** add function timer for wait EAPoL Error timeout +** \main\maintrunk.MT5921\6 2007-11-06 20:39:08 GMT mtk01088 +** rename the counter measure timer +** \main\maintrunk.MT5921\5 2007-11-06 20:14:31 GMT mtk01088 +** add a abort function +** Revision 1.5 2007/07/16 02:33:42 MTK01088 +** change the ENUM declaration structure prefix from r to e +** +** Revision 1.4 2007/07/09 06:23:10 MTK01088 +** update +** +** Revision 1.3 2007/07/04 10:09:04 MTK01088 +** adjust the state for security fsm +** change function name +** +** Revision 1.2 2007/07/03 08:13:22 MTK01088 +** change the sec fsm state +** add the event for sec fsm +** +** Revision 1.1 2007/06/27 06:20:35 MTK01088 +** add the sec fsm header file +** +** +*/ +#ifndef _SEC_FSM_H +#define _SEC_FSM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* TKIP CounterMeasure interval for Rejoin to Network. */ +#define COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC 60 + +/* Timeout to wait the EAPoL Error Report frame Send out. */ +#define EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC 1 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef UINT_32 SEC_STATUS, *P_SEC_STATUS; + +#if 0 +/* WPA2 PMKID candicate structure */ +typedef struct _PMKID_CANDICATE_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; /* MAC address */ + UINT_32 u4PreAuthFlags; +} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; +#endif + +typedef SEC_STATUS(*PFN_SEC_FSM_STATE_HANDLER) (VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define SEC_STATE_TRANSITION_FLAG fgIsTransition +#define SEC_NEXT_STATE_VAR eNextState + +#define SEC_STATE_TRANSITION(prAdapter, prSta, eFromState, eToState) \ + { secFsmTrans_ ## eFromState ## _to_ ## eToState(prAdapter, prSta); \ + SEC_NEXT_STATE_VAR = SEC_STATE_ ## eToState; \ + SEC_STATE_TRANSITION_FLAG = (BOOLEAN)TRUE; \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Routines to handle the sec check */ +/*--------------------------------------------------------------*/ +/***** Routines in sec_fsm.c *****/ +VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEventInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID +secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); + +VOID +secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, IN ULONG ulParm); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _SEC_FSM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h new file mode 100644 index 0000000000000..1c0f9a76e1192 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/stats.h @@ -0,0 +1,368 @@ +/* +** Id: stats.h#1 +*/ + +/*! \file stats.h + \brief This file includes statistics support. +*/ + +/* +** Log: stats.h + * + * 07 17 2014 samp.lin + * NULL + * Initial version. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************** + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************** + */ +extern UINT_64 u8DrvOwnStart, u8DrvOwnEnd; +extern UINT32 u4DrvOwnMax; +extern BOOLEAN fgIsUnderSuspend; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* Command to TDLS core module */ +typedef enum _STATS_CMD_CORE_ID { + STATS_CORE_CMD_ENV_REQUEST = 0x00 +} STATS_CMD_CORE_ID; + +typedef enum _STATS_EVENT_HOST_ID { + STATS_HOST_EVENT_ENV_REPORT = 0x00, + STATS_HOST_EVENT_RX_DROP +} STATS_EVENT_HOST_ID; + +#define CFG_ARP BIT(0) +#define CFG_DNS BIT(1) +#define CFG_TCP BIT(2) +#define CFG_UDP BIT(3) +#define CFG_EAPOL BIT(4) +#define CFG_DHCP BIT(5) +#define CFG_ICMP BIT(6) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _STATS_CMD_CORE_T { + + UINT32 u4Command; /* STATS_CMD_CORE_ID */ + + UINT8 ucStaRecIdx; + UINT8 ucReserved[3]; + + UINT32 u4Reserved[4]; + +#define STATS_CMD_CORE_RESERVED_SIZE 50 + union { + UINT8 Reserved[STATS_CMD_CORE_RESERVED_SIZE]; + } Content; + +} STATS_CMD_CORE_T; + +typedef struct _STATS_INFO_ENV_T { + + BOOLEAN fgIsUsed; /* TRUE: used */ + + /* ------------------- TX ------------------- */ + BOOLEAN fgTxIsRtsUsed; /* TRUE: we use RTS/CTS currently */ + BOOLEAN fgTxIsRtsEverUsed; /* TRUE: we ever use RTS/CTS */ + BOOLEAN fgTxIsCtsSelfUsed; /* TRUE: we use CTS-self */ + +#define STATS_INFO_TX_PARAM_HW_BW40_OFFSET 0 +#define STATS_INFO_TX_PARAM_HW_SHORT_GI20_OFFSET 1 +#define STATS_INFO_TX_PARAM_HW_SHORT_GI40_OFFSET 2 +#define STATS_INFO_TX_PARAM_USE_BW40_OFFSET 3 +#define STATS_INFO_TX_PARAM_USE_SHORT_GI_OFFSET 4 +#define STATS_INFO_TX_PARAM_NO_ACK_OFFSET 5 + UINT_8 ucTxParam; + + UINT_8 ucStaRecIdx; + UINT_8 ucReserved1[2]; + + UINT32 u4TxDataCntAll; /* total tx count from host */ + UINT32 u4TxDataCntOK; /* total tx ok count to air */ + UINT32 u4TxDataCntErr; /* total tx err count to air */ + + /* WLAN_STATUS_BUFFER_RETAINED ~ WLAN_STATUS_PACKET_LIFETIME_ERROR */ + UINT32 u4TxDataCntErrType[6]; /* total tx err count for different type to air */ + + UINT_8 ucTxRate1NonHTMax; + UINT_8 ucTxRate1HTMax; + UINT32 u4TxRateCntNonHT[16]; /* tx done rate */ + UINT32 u4TxRateCntHT[16]; /* tx done rate */ + + UINT_8 ucTxAggBitmap; /* TX BA sessions TID0 ~ TID7 */ + UINT_8 ucTxPeerAggMaxSize; + + /* ------------------- RX ------------------- */ + BOOLEAN fgRxIsRtsUsed; /* TRUE: peer uses RTS/CTS currently */ + BOOLEAN fgRxIsRtsEverUsed; /* TRUE: peer ever uses RTS/CTS */ + + UINT_8 ucRcvRcpi; + UINT_8 ucHwChanNum; + BOOLEAN fgRxIsShortGI; + UINT_8 ucReserved2[1]; + + UINT32 u4RxDataCntAll; /* total rx count from peer */ + UINT32 u4RxDataCntErr; /* total rx err count */ + UINT32 u4RxRateCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ + + UINT_8 ucRxAggBitmap; /* RX BA sessions TID0 ~ TID7 */ + UINT_8 ucRxAggMaxSize; + +#define STATS_INFO_PHY_MODE_CCK 0 +#define STATS_INFO_PHY_MODE_OFDM 1 +#define STATS_INFO_PHY_MODE_HT 2 +#define STATS_INFO_PHY_MODE_VHT 3 + UINT_8 ucBssSupPhyMode; /* CCK, OFDM, HT, or VHT BSS */ + + UINT_8 ucVersion; /* the version of statistics info environment */ + + /* ------------------- Delay ------------------- */ +#define STATS_AIR_DELAY_INT 500 /* 500 byte */ + + /* delay in firmware from host to MAC */ + /* unit: us, for 500B, 1000B, max */ + UINT32 u4StayIntMaxH2M[3], u4StayIntMinH2M[3], u4StayIntAvgH2M[3]; + + /* delay in firmware from MAC to TX done */ + /* unit: 32us, for 500B, 1000B, max */ + UINT32 u4AirDelayMax[3], u4AirDelayMin[3], u4AirDelayAvg[3]; + + /* delay in firmware from host to TX done */ + /* unit: us, for 500B, 1000B, max */ + UINT32 u4StayIntMax[3], u4StayIntMin[3], u4StayIntAvg[3]; + UINT32 u4StayIntMaxSysTime[3]; + + /* delay in firmware from driver to TX done */ + /* unit: us, for 500B, 1000B, max */ + UINT32 u4StayIntMaxD2T[3], u4StayIntMinD2T[3], u4StayIntAvgD2T[3]; + + /* delay count in firmware from host to TX done */ + /* u4StayIntByConst: divide 4 fix partitions to count each delay in firmware */ +#define STATS_STAY_INT_CONST 1 /* 1ms */ +#define STATS_STAY_INT_CONST_2 5 +#define STATS_STAY_INT_CONST_3 10 +#define STATS_STAY_INT_CONST_4 15 +#define STATS_STAY_INT_CONST_NUM 4 + UINT32 u4StayIntByConst[STATS_STAY_INT_CONST_NUM]; + + /* + u4StayIntMaxPast: past maximum delay in firmware + u4StayIntCnt[]: divide 4 partitions to count each delay in firmware + */ +#define STATS_STAY_INT_NUM 4 + UINT32 u4StayIntMaxPast; + UINT32 u4StayIntCnt[STATS_STAY_INT_NUM + 1]; + + /* delay count in firmware from driver to HIF */ + /* u4StayIntD2HByConst: divide 4 fix partitions to count each delay in firmware */ +#define STATS_STAY_INT_D2H_CONST 10 /* 10ms */ +#define STATS_STAY_INT_D2H_CONST_2 20 +#define STATS_STAY_INT_D2H_CONST_3 30 +#define STATS_STAY_INT_D2H_CONST_4 40 +#define STATS_STAY_INT_D2H_CONST_NUM 4 + UINT32 u4StayIntD2HByConst[STATS_STAY_INT_D2H_CONST_NUM]; + + /* unit: us, for 500B, 1000B, max */ + UINT32 u4StayIntMaxRx[3], u4StayIntMinRx[3], u4StayIntAvgRx[3]; + + /* ------------------- Others ------------------- */ + UINT32 u4NumOfChanChange; /* total channel change count */ + UINT32 u4NumOfRetryCnt; /* total TX retry count */ + UINT32 u4RxFifoFullCnt; /* counter of the number of the packets which + pass RFCR but are dropped due to FIFO full. */ + UINT32 u4PsIntMax; /* maximum time from ps to active */ + UINT_8 ucNumOfPsChange; /* peer power save change count */ + UINT_8 ucReserved3[3]; + + UINT32 u4ReportSysTime; /* firmware system time */ + UINT32 u4RxDataCntOk; /* total rx count to hif */ + + /* V4 */ + UINT32 u4RxRateRetryCnt[3][16]; /* [0]:CCK, [1]:OFDM, [2]:MIXED (skip green mode) */ + UINT32 au4ChanIdleCnt[10]; /* past Channel idle count in unit of slot */ + + /* V5 */ + UINT32 u4BtContUseTime; /* the air time that BT continuous occypy */ + + /* V6 */ + UINT32 u4LastTxOkTime; /* last time we tx ok to the station */ + + /* V7 */ + UINT_8 ucBtWfCoexGrantCnt[8]; /* [0]:WF Rx Grant Cnt[1]: WF Tx Grant Cnt[2]: WF Grant with Priority1 */ + /* [4]:BT Rx Grant Cnt[5]: BT Tx Grant Cnt[6]: BT Grant with Priority1 */ + + /* V8 */ + UINT_32 u4RxMacFreeDescCnt[6]; + UINT_32 u4RxHifFreeDescCnt[6]; + + /* V9 */ +#define STATS_MAX_RX_DROP_TYPE 20 + UINT32 u4NumOfRxDrop[STATS_MAX_RX_DROP_TYPE]; + + /* V10 */ + UINT_32 u4NumOfTxDone; /* number of all packets (data/man/ctrl) tx done */ + UINT_32 u4NumOfTxDoneFixRate; /* number of done rate = 0 */ + UINT_32 u4NumOfTxDoneErrRate; /* number of error done rate */ + UINT_32 u4NumOfNullTxDone; /* number of null tx done */ + UINT_32 u4NumOfQoSNullTxDone; /* number of QoS-null tx done */ + + /* V11 */ + /* delay in firmware from HIF RX to HIF RX Done */ + /* unit: us, for 500B, 1000B, max */ + UINT32 u4StayIntMaxHR2HRD[3], u4StayIntMinHR2HRD[3], u4StayIntAvgHR2HRD[3]; + + /* V12 */ + UINT32 u4AirDelayTotal; /* agg all the air delay */ + + /* V13 */ + UINT32 u4CurrChnlInfo; /* add current channel information */ + + UINT_8 ucReserved_rate[4]; /* the field must be the last one */ +} STATS_INFO_ENV_T; + +/******************************************************************************* +* M A C R O D E C L A R A T I O N S +******************************************************************************** +*/ +#if (CFG_SUPPORT_STATISTICS == 1) + +#define STATS_ENV_REPORT_DETECT statsEnvReportDetect + +#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) \ +{ \ + (__StaRec__)->u4RxReorderFallAheadCnt++; \ +} + +#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) \ +{ \ + (__StaRec__)->u4RxReorderFallBehindCnt++; \ +} + +#define STATS_RX_REORDER_HOLE_INC(__StaRec__) \ +{ \ + (__StaRec__)->u4RxReorderHoleCnt++; \ +} + +#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) \ +{ \ + if ((__IsTimeout__) == TRUE) \ + (__StaRec__)->u4RxReorderHoleTimeoutCnt++; \ +} + +#define STATS_RX_ARRIVE_TIME_RECORD(__SwRfb__) \ +{ \ + (__SwRfb__)->rRxTime = StatsEnvTimeGet(); \ +} + +#define STATS_RX_PASS2OS_INC StatsEnvRxDone + +#define STATS_RX_PKT_INFO_DISPLAY StatsRxPktInfoDisplay + +#define STATS_TX_TIME_ARRIVE(__Skb__) \ +do { \ + UINT_64 __SysTime; \ + __SysTime = StatsEnvTimeGet(); /* us */ \ + GLUE_SET_PKT_XTIME(__Skb__, __SysTime); \ +} while (FALSE) + +#define STATS_TX_TIME_TO_HIF StatsEnvTxTime2Hif + +#define STATS_TX_PKT_CALLBACK StatsTxPktCallBack +#define STATS_TX_PKT_DONE_INFO_DISPLAY StatsTxPktDoneInfoDisplay + +#define STATS_DRIVER_OWN_RESET() \ +{ \ + u4DrvOwnMax = 0; \ +} +#define STATS_DRIVER_OWN_START_RECORD() \ +{ \ + u8DrvOwnStart = StatsEnvTimeGet(); \ +} +#define STATS_DRIVER_OWN_END_RECORD() \ +{ \ + u8DrvOwnEnd = StatsEnvTimeGet(); \ +} +#define STATS_DRIVER_OWN_STOP() \ +do { \ + UINT32 __Diff; \ + __Diff = (UINT32)(u8DrvOwnEnd - u8DrvOwnStart); \ + if (__Diff > u4DrvOwnMax) \ + u4DrvOwnMax = __Diff; \ +} while (FALSE) + +#else + +#define STATS_ENV_REPORT_DETECT(__Adapter__, __StaRecIndex__) + +#define STATS_RX_REORDER_FALL_AHEAD_INC(__StaRec__) +#define STATS_RX_REORDER_FALL_BEHIND_INC(__StaRec__) +#define STATS_RX_REORDER_HOLE_INC(__StaRec__) +#define STATS_RX_REORDER_HOLE_TIMEOUT_INC(__StaRec__, __IsTimeout__) +#define STATS_RX_PASS2OS_INC(__StaRec__, __SwRfb__) +#define STATS_RX_PKT_INFO_DISPLAY(__Pkt__) + +#define STATS_TX_TIME_ARRIVE(__Skb__) +#define STATS_TX_TIME_TO_HIF(__MsduInfo__, __HwTxHeader__) +#define STATS_TX_PKT_CALLBACK(__Pkt__, __fgIsNeedAck__) +#define STATS_TX_PKT_DONE_INFO_DISPLAY(__Adapter__, __Event__) + +#define STATS_DRIVER_OWN_RESET() +#define STATS_DRIVER_OWN_START_RECORD() +#define STATS_DRIVER_OWN_END_RECORD() +#define STATS_DRIVER_OWN_STOP() +#endif /* CFG_SUPPORT_STATISTICS */ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E F U N C T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C F U N C T I O N S +******************************************************************************** +*/ + +VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex); + +VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb); + +UINT_64 StatsEnvTimeGet(VOID); + +VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader); + +VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); + +VOID StatsRxPktInfoDisplay(UINT_8 *pPkt); + +VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo); + +VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf); + +VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet); + +UINT_16 StatsGetCfgTxDone(VOID); + +/* End of stats.h */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h new file mode 100644 index 0000000000000..50c4b558c2cd5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/swcr.h @@ -0,0 +1,187 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/swcr.h#1 +*/ + +/*! \file "swcr.h" + \brief +*/ + +/* + * + */ + +#ifndef _SWCR_H +#define _SWCR_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "nic_cmd_event.h" + +#if 0 +extern SWCR_MAP_ENTRY_T g_arRlmArSwCrMap[]; +#endif +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define SWCR_VAR(x) ((VOID *)&x) +#define SWCR_FUNC(x) ((VOID *)x) + +#define SWCR_T_FUNC BIT(7) + +#define SWCR_L_32 3 +#define SWCR_L_16 2 +#define SWCR_L_8 1 + +#define SWCR_READ 0 +#define SWCR_WRITE 1 + +#define SWCR_MAP_NUM(x) (sizeof(x)/sizeof(x[0])) + +#define SWCR_CR_NUM 7 + +#define SWCR_GET_RW_INDEX(action, rw, index) \ +do { \ + index = action & 0x7F; \ + rw = action >> 7; \ +} while (0) + +extern UINT_32 g_au4SwCr[]; /*: 0: command other: data */ + +typedef VOID(*PFN_SWCR_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); +typedef VOID(*PFN_CMD_RW_T) (P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); + +typedef struct _SWCR_MAP_ENTRY_T { + UINT_16 u2Type; + PVOID u4Addr; +} SWCR_MAP_ENTRY_T, *P_SWCR_MAP_ENTRY_T; + +typedef struct _SWCR_MOD_MAP_ENTRY_T { + UINT_8 ucMapNum; + P_SWCR_MAP_ENTRY_T prSwCrMap; +} SWCR_MOD_MAP_ENTRY_T, *P_SWCR_MOD_MAP_ENTRY_T; + +typedef enum _ENUM_SWCR_DBG_TYPE_T { + SWCR_DBG_TYPE_ALL = 0, + SWCR_DBG_TYPE_TXRX, + SWCR_DBG_TYPE_RX_RATES, + SWCR_DBG_TYPE_PS, + SWCR_DBG_TYPE_NUM +} ENUM_SWCR_DBG_TYPE_T; + +typedef enum _ENUM_SWCR_DBG_ALL_T { + SWCR_DBG_ALL_TX_CNT = 0, + SWCR_DBG_ALL_TX_BCN_CNT, + SWCR_DBG_ALL_TX_FAILED_CNT, + SWCR_DBG_ALL_TX_RETRY_CNT, + SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT, + SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT, + SWCR_DBG_ALL_TX_MGNT_DROP_CNT, + SWCR_DBG_ALL_TX_ERROR_CNT, + + SWCR_DBG_ALL_RX_CNT, + SWCR_DBG_ALL_RX_DROP_CNT, + SWCR_DBG_ALL_RX_DUP_DROP_CNT, + SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_FCSERR_CNT, + SWCR_DBG_ALL_RX_FIFOFULL_CNT, + SWCR_DBG_ALL_RX_PFDROP_CNT, + + SWCR_DBG_ALL_PWR_PS_POLL_CNT, + SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT, + SWCR_DBG_ALL_PWR_BCN_IND_CNT, + SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT, + SWCR_DBG_ALL_PWR_PM_STATE0, + SWCR_DBG_ALL_PWR_PM_STATE1, + SWCR_DBG_ALL_PWR_CUR_PS_PROF0, + SWCR_DBG_ALL_PWR_CUR_PS_PROF1, + + SWCR_DBG_ALL_AR_STA0_RATE, + SWCR_DBG_ALL_AR_STA0_BWGI, + SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI, + + SWCR_DBG_ALL_ROAMING_ENABLE, + SWCR_DBG_ALL_ROAMING_ROAM_CNT, + SWCR_DBG_ALL_ROAMING_INT_CNT, + + SWCR_DBG_ALL_BB_RX_MDRDY_CNT, + SWCR_DBG_ALL_BB_RX_FCSERR_CNT, + SWCR_DBG_ALL_BB_CCK_PD_CNT, + SWCR_DBG_ALL_BB_OFDM_PD_CNT, + SWCR_DBG_ALL_BB_CCK_SFDERR_CNT, + SWCR_DBG_ALL_BB_CCK_SIGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT, + + SWCR_DBG_ALL_NUM +} ENUM_SWCR_DBG_ALL_T; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); +VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); +VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); +VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); +void testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1); +VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); + +/* Support Debug */ +VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl); +VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam); +VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); +VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data); + +/* Debug Support */ +VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType); +VOID swCrDebugInit(P_ADAPTER_T prAdapter); +VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout); +VOID swCrDebugUninit(P_ADAPTER_T prAdapter); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h new file mode 100644 index 0000000000000..3b6991131d058 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/tdls.h @@ -0,0 +1,262 @@ +/* +** Id: include/tdls.h#1 +*/ + +/*! \file "tdls.h" + \brief This file contains the internal used in TDLS modules + for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: tdls.h + * + * 11 18 2013 vend_samp.lin + * NULL + * Initial version. + * + ** + */ + +#ifndef _TDLS_H +#define _TDLS_H + +#if (CFG_SUPPORT_TDLS == 1) + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define TDLS_CFG_CMD_TEST 1 +#define TDLS_CFG_HT_SUP 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); +extern BOOLEAN flgTdlsTestExtCapElm; +extern UINT8 aucTdlsTestExtCapElm[]; +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +typedef struct _TDLS_LINK_HIS_OTHERS_T { + BOOLEAN fgIsHt; /* TRUE: HT device */ + +} TDLS_LINK_HIS_OTHERS_T; + +/* command */ +typedef enum _TDLS_CMD_ID { + TDLS_CMD_TEST_TX_FRAME = 0x00, + TDLS_CMD_TEST_RCV_FRAME = 0x01, + TDLS_CMD_TEST_PEER_ADD = 0x02, + TDLS_CMD_TEST_PEER_UPDATE = 0x03, + TDLS_CMD_TEST_DATA_FRAME = 0x04, + TDLS_CMD_TEST_RCV_NULL = 0x05, + TDLS_CMD_MIB_UPDATE = 0x06, + TDLS_CMD_TEST_SKIP_TX_FAIL = 0x07, + TDLS_CMD_UAPSD_CONF = 0x08, + TDLS_CMD_CH_SW_CONF = 0x09, + TDLS_CMD_TEST_SKIP_KEEP_ALIVE = 0x0a, + TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT = 0x0b, + TDLS_CMD_TEST_TX_TDLS_FRAME = 0x0c, + TDLS_CMD_TEST_PROHIBIT_SET_IN_AP = 0x0d, + TDLS_CMD_TEST_SCAN_DISABLE = 0x0e, + TDLS_CMD_TEST_DATA_FRAME_CONT = 0x0f, + TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP = 0x10, + TDLS_CMD_SETUP_CONF = 0x11, + TDLS_CMD_INFO = 0x12, + TDLS_CMD_TEST_DELAY = 0x13, + TDLS_CMD_KEY_INFO = 0x14, + TDLS_CMD_TEST_PTI_TX_FAIL = 0x15 +} TDLS_CMD_ID; + +typedef enum _TDLS_EVENT_HOST_ID { + TDLS_HOST_EVENT_TEAR_DOWN = 0x00, /* TDLS_EVENT_HOST_SUBID_TEAR_DOWN */ + TDLS_HOST_EVENT_TX_DONE, + TDLS_HOST_EVENT_FME_STATUS, /* TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME */ + TDLS_HOST_EVENT_STATISTICS +} TDLS_EVENT_HOST_ID; + +typedef enum _TDLS_EVENT_HOST_SUBID_TEAR_DOWN { + TDLS_HOST_EVENT_TD_PTI_TIMEOUT = 0x00, + TDLS_HOST_EVENT_TD_AGE_TIMEOUT, + TDLS_HOST_EVENT_TD_PTI_SEND_FAIL, + TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL, + TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX, + TDLS_HOST_EVENT_TD_NON_STATE3, + TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN +} TDLS_EVENT_HOST_SUBID_TEAR_DOWN; + +typedef enum _TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME { + TDLS_HOST_EVENT_SF_BA, + TDLS_HOST_EVENT_SF_BA_OK, + TDLS_HOST_EVENT_SF_BA_DECLINE, + TDLS_HOST_EVENT_SF_BA_PEER, + TDLS_HOST_EVENT_SF_BA_RSP_OK, + TDLS_HOST_EVENT_SF_BA_RSP_DECLINE +} TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME; + +/* payload specific type in the LLC/SNAP header */ +#define TDLS_FRM_PAYLOAD_TYPE 2 + +#define TDLS_FRM_CATEGORY 12 + +typedef enum _TDLS_FRM_ACTION_ID { + TDLS_FRM_ACTION_SETUP_REQ = 0x00, + TDLS_FRM_ACTION_SETUP_RSP, + TDLS_FRM_ACTION_CONFIRM, + TDLS_FRM_ACTION_TEARDOWN, + TDLS_FRM_ACTION_PTI, + TDLS_FRM_ACTION_CHAN_SWITCH_REQ, + TDLS_FRM_ACTION_CHAN_SWITCH_RSP, + TDLS_FRM_ACTION_PEER_PSM_REQ, + TDLS_FRM_ACTION_PEER_PSM_RSP, + TDLS_FRM_ACTION_PTI_RSP, /* 0x09 */ + TDLS_FRM_ACTION_DISCOVERY_REQ, + + TDLS_FRM_ACTION_EVENT_TEAR_DOWN_TO_SUPPLICANT = 0x30, + + TDLS_FRM_DATA_TEST_DATA = 0x80 +} TDLS_FRM_ACTION_ID; + +#define TDLS_FRM_ACTION_DISCOVERY_RESPONSE 14 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* 7.3.2.62 Link Identifier element */ +#define ELEM_ID_LINK_IDENTIFIER 101 +#define ELEM_LEN_LINK_IDENTIFIER 18 + +typedef struct _IE_LINK_IDENTIFIER_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aBSSID[6]; + UINT_8 aInitiator[6]; + UINT_8 aResponder[6]; +} __KAL_ATTRIB_PACKED__ IE_LINK_IDENTIFIER_T; + +#define TDLS_LINK_IDENTIFIER_IE(__ie__) ((IE_LINK_IDENTIFIER_T *)(__ie__)) + +/* test command use */ +typedef struct _PARAM_CUSTOM_TDLS_CMD_STRUCT_T { + + UINT_8 ucFmeType; /* TDLS_FRM_ACTION_ID */ + + UINT_8 ucToken; + UINT_16 u2Cap; + + /* bit0: TDLS, bit1: Peer U-APSD Buffer, bit2: Channel Switching */ +#define TDLS_EX_CAP_PEER_UAPSD BIT(0) +#define TDLS_EX_CAP_CHAN_SWITCH BIT(1) +#define TDLS_EX_CAP_TDLS BIT(2) + UINT_8 ucExCap; + + UINT_8 arSupRate[4]; + UINT_8 arSupChan[4]; + + UINT_32 u4Timeout; + +#define TDLS_FME_MAC_ADDR_LEN 6 + UINT_8 arRspAddr[TDLS_FME_MAC_ADDR_LEN]; + UINT_8 arBssid[TDLS_FME_MAC_ADDR_LEN]; + +/* + Linux Kernel-3.10 + struct station_parameters { + const u8 *supported_rates; + struct net_device *vlan; + u32 sta_flags_mask, sta_flags_set; + u32 sta_modify_mask; + int listen_interval; + u16 aid; + u8 supported_rates_len; + u8 plink_action; + u8 plink_state; + const struct ieee80211_ht_cap *ht_capa; + const struct ieee80211_vht_cap *vht_capa; + u8 uapsd_queues; + u8 max_sp; + enum nl80211_mesh_power_mode local_pm; + u16 capability; + const u8 *ext_capab; + u8 ext_capab_len; + }; +*/ + struct ieee80211_ht_cap rHtCapa; + struct ieee80211_vht_cap rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ + struct station_parameters rPeerInfo; + +} PARAM_CUSTOM_TDLS_CMD_STRUCT_T; + +typedef struct _TDLS_MGMT_TX_INFO { + UINT8 aucPeer[6]; + UINT8 ucActionCode; + UINT8 ucDialogToken; + UINT16 u2StatusCode; + UINT32 u4SecBufLen; + UINT8 aucSecBuf[1000]; +} TDLS_MGMT_TX_INFO; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* check any TDLS link */ +#define TDLS_IS_NO_LINK_GOING(__GlueInfo__) \ + ((__GlueInfo__)->rTdlsLink.cLinkCnt == 0) + +/* increase TDLS link count */ +#define TDLS_LINK_INCREASE(__GlueInfo__) \ + ((__GlueInfo__)->rTdlsLink.cLinkCnt++) + +/* decrease TDLS link count */ +#define TDLS_LINK_DECREASE(__GlueInfo__) \ +do { \ + if ((__GlueInfo__)->rTdlsLink.cLinkCnt > 0) \ + (__GlueInfo__)->rTdlsLink.cLinkCnt--; \ +} while (0) + +/* get TDLS link count */ +#define TDLS_LINK_COUNT(__GlueInfo__) \ + ((__GlueInfo__)->rTdlsLink.cLinkCnt) + +/* reset TDLS link count */ +#define TDLS_LINK_COUNT_RESET(__GlueInfo__) \ + ((__GlueInfo__)->rTdlsLink.cLinkCnt = 0) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* Note: these functions are used only in tdls module, not other modules */ +UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt); + +TDLS_STATUS +TdlsDataFrameSend(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + UINT_8 *pPeerMac, + UINT_8 ucActionCode, + UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* CFG_SUPPORT_TDLS */ + +#endif /* _TDLS_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h new file mode 100644 index 0000000000000..12c9359f2e8f3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wapi.h @@ -0,0 +1,104 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wapi.h#1 +*/ + +/*! \file wapi.h + \brief The wapi related define, macro and structure are described here. +*/ + +/* +** Log: wapi.h + * + * 07 20 2010 wh.su + * + * . + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the wapi function name and adding the generate wapi ie function + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some wapi structure define + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** \main\maintrunk.MT5921\1 2009-10-09 17:06:29 GMT mtk01088 +** +*/ + +#ifndef _WAPI_H +#define _WAPI_H + +#if CFG_SUPPORT_WAPI + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define WAPI_CIPHER_SUITE_WPI 0x01721400 /* WPI_SMS4 */ +#define WAPI_AKM_SUITE_802_1X 0x01721400 /* WAI */ +#define WAPI_AKM_SUITE_PSK 0x02721400 /* WAI_PSK */ + +#define ELEM_ID_WAPI 68 /* WAPI IE */ + +#define WAPI_IE(fp) ((P_WAPI_INFO_ELEM_T) fp) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo); + +BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); + +/* BOOLEAN */ +/* wapiUpdateTxKeyIdx ( */ +/* IN P_STA_RECORD_T prStaRec, */ +/* IN UINT_8 ucWlanIdx */ +/* ); */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif +#endif /* _WAPI_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h new file mode 100644 index 0000000000000..5dc969f1cc05b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wlan_typedef.h @@ -0,0 +1,87 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/mgmt/wlan_typedef.h#1 +*/ + +/*! \file wlan_typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to all MGMT Protocol Stack. +*/ + +/* +** Log: wlan_typedef.h +*/ + +#ifndef _WLAN_TYPEDEF_H +#define _WLAN_TYPEDEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for BSS_INFO_T structure, to describe the attributes used in a + * common BSS. + */ +typedef struct _BSS_INFO_T BSS_INFO_T, *P_BSS_INFO_T; + +typedef BSS_INFO_T AIS_BSS_INFO_T, *P_AIS_BSS_INFO_T; +typedef BSS_INFO_T P2P_BSS_INFO_T, *P_P2P_BSS_INFO_T; +typedef BSS_INFO_T BOW_BSS_INFO_T, *P_BOW_BSS_INFO_T; + +typedef struct _AIS_SPECIFIC_BSS_INFO_T AIS_SPECIFIC_BSS_INFO_T, *P_AIS_SPECIFIC_BSS_INFO_T; +typedef struct _P2P_SPECIFIC_BSS_INFO_T P2P_SPECIFIC_BSS_INFO_T, *P_P2P_SPECIFIC_BSS_INFO_T; +typedef struct _BOW_SPECIFIC_BSS_INFO_T BOW_SPECIFIC_BSS_INFO_T, *P_BOW_SPECIFIC_BSS_INFO_T; +/* CFG_SUPPORT_WFD */ +typedef struct _WFD_CFG_SETTINGS_T WFD_CFG_SETTINGS_T, *P_WFD_CFG_SETTINGS_T; + +typedef struct _WFD_DBG_CFG_SETTINGS_T WFD_DBG_CFG_SETTINGS_T, *P_WFD_DBG_CFG_SETTINGS_T; + +/* BSS related structures */ +/* Type definition for BSS_DESC_T structure, to describe parameter sets of a particular BSS */ +typedef struct _BSS_DESC_T BSS_DESC_T, *P_BSS_DESC_T, **PP_BSS_DESC_T; + +#if CFG_SUPPORT_HOTSPOT_2_0 +typedef struct _HS20_INFO_T HS20_INFO_T, *P_HS20_INFO_T; +#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _WLAN_TYPEDEF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h new file mode 100644 index 0000000000000..09bc0b5d5151b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/mgmt/wnm.h @@ -0,0 +1,95 @@ +/* +** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/mgmt/wnm.h#1 +*/ + +/*! \file wnm.h + \brief This file contains the IEEE 802.11 family related 802.11v network management + for MediaTek 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wnm.h + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * +*/ + +#ifndef _WNM_H +#define _WNM_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _TIMINGMSMT_PARAM_T { + BOOLEAN fgInitiator; + UINT_8 ucTrigger; + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ + UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ + UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ +} TIMINGMSMT_PARAM_T, *P_TIMINGMSMT_PARAM_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +WLAN_STATUS +wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +VOID +wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA); + +#define WNM_UNIT_TEST 1 + +#if WNM_UNIT_TEST +VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WNM_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h new file mode 100644 index 0000000000000..d34f2c9c36a8b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/adapter.h @@ -0,0 +1,1506 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/adapter.h#3 +*/ + +/*! \file adapter.h + \brief Definition of internal data structure for driver manipulation. + + In this file we define the internal data structure - ADAPTER_T which stands + for MiniPort ADAPTER(From Windows point of view) or stands for Network ADAPTER. +*/ + +/* +** Log: adapter.h +** +** 08 31 2012 yuche.tsai +** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have +** connected to AP previously,one device reboots automatically with KE +** Fix possible KE when concurrent & disconnect. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration + * with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration + * corresponding to network type. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve inorder issue under AP mode. + * + * data frame may TX before assoc response frame. + * + * 11 19 2011 yuche.tsai + * NULL + * Update RSSI for P2P. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 10 21 2011 eddie.chen + * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout + * Add switch to ignore the STA aging timeout. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 20 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Remove ERP member in adapter structure + * + * 09 14 2011 yuche.tsai + * NULL + * Add P2P IE in assoc response. + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. + * Action frame callback for GO Device Discoverability Req. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Network. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Make assoc req to append P2P IE if wifi direct is enabled. + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically + * continuous memory shortage after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce + * physically continuous memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 yuche.tsai + * [WCXRP00000533] [Volunteer Patch][MT6620][Driver] Provide a P2P function API for Legacy WiFi to query AP mode. + * Provide an API for Legacy WiFi to query the operation mode.. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as + * initial RSSI right after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid + * using a uninitialized MAC-RX RCPI. + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Change GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module + * with structure miss-align pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to + * target station for AAA module. + * Provide disconnect function for AAA module. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 george.huang + * [WCXRP00000400] [MT6620 Wi-Fi] support CTIA power mode setting + * Support CTIA power mode setting. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Add CWMin CWMax for AP to generate IE. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] + * Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Add a common IE buffer in P2P INFO structure. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 cp.wu + * NULL + * restore configuration as before. + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 yuche.tsai + * NULL + * Add an intend mode for BSS info. + * It is used to let P2P BSS Info to know which OP Mode it is going to become. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 02 2010 cp.wu + * NULL + * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 yuche.tsai + * + * Remove BSS info which is redonedent in Wifi Var.. + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P FSM Info in adapter. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P related field, additional include p2p_fsm.h if p2p is enabled. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 04 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * reserve field of privacy filter and RTS threshold setting. + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * 2) command sequence number is now increased atomically + * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move ucCmdSeqNum as instance variable + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * 4. correct some HAL implementation + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * and result is retrieved by get ATInfo instead + * * * 2) add 4 counter for recording aggregation statistics + * + * 12 28 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate redundant variables for connection_state +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-16 18:02:03 GMT mtk02752 +** add external reference to avoid compilation error +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:40:26 GMT mtk02752 +** eliminate unused member +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-08 17:36:08 GMT mtk02752 +** add RF test data members into P_ADAPTER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:45 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-28 10:29:57 GMT mtk01461 +** Add read WTSR for SDIO_STATUS_ENHANCE mode +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:37:35 GMT mtk01461 +** Add prPendingCmdInfoOfOID for temporarily saving the CMD_INFO_T before en-queue to rCmdQueue +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:57:51 GMT mtk01461 +** Add MGMT Buffer Info +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:34:12 GMT mtk01461 +** Add SW pre test CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:41:48 GMT mtk01461 +** Add fgIsWmmAssoc flag for TC assignment +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:51 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:51:52 GMT mtk01426 +** Add #if CFG_SDIO_RX_ENHANCE related data structure +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:17 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _ADAPTER_H +#define _ADAPTER_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if CFG_SUPPORT_HOTSPOT_2_0 +#include "hs20.h" +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _ENHANCE_MODE_DATA_STRUCT_T SDIO_CTRL_T, *P_SDIO_CTRL_T; + +typedef struct _WLAN_INFO_T { + PARAM_BSSID_EX_T rCurrBssId; + + /* Scan Result */ + PARAM_BSSID_EX_T arScanResult[CFG_MAX_NUM_BSS_LIST]; + PUINT_8 apucScanResultIEs[CFG_MAX_NUM_BSS_LIST]; + UINT_32 u4ScanResultNum; + + /* IE pool for Scanning Result */ + UINT_8 aucScanIEBuf[CFG_MAX_COMMON_IE_BUF_LEN]; + UINT_32 u4ScanIEBufferUsage; + + OS_SYSTIME u4SysTime; + + /* connection parameter (for Ad-Hoc) */ + UINT_16 u2BeaconPeriod; + UINT_16 u2AtimWindow; + + PARAM_RATES eDesiredRates; + CMD_LINK_ATTRIB eLinkAttr; +/* CMD_PS_PROFILE_T ePowerSaveMode; */ + CMD_PS_PROFILE_T arPowerSaveMode[NETWORK_TYPE_INDEX_NUM]; + + /* trigger parameter */ + ENUM_RSSI_TRIGGER_TYPE eRssiTriggerType; + PARAM_RSSI rRssiTriggerValue; + + /* Privacy Filter */ + ENUM_PARAM_PRIVACY_FILTER_T ePrivacyFilter; + + /* RTS Threshold */ + PARAM_RTS_THRESHOLD eRtsThreshold; + + /* Network Type */ + UINT_8 ucNetworkType; + + /* Network Type In Use */ + UINT_8 ucNetworkTypeInUse; + +} WLAN_INFO_T, *P_WLAN_INFO_T; + +/* Session for CONNECTION SETTINGS */ +typedef struct _CONNECTION_SETTINGS_T { + + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + + UINT_8 ucDelayTimeOfDisconnectEvent; + + BOOLEAN fgIsConnByBssidIssued; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + + BOOLEAN fgIsConnReqIssued; + BOOLEAN fgIsDisconnectedByNonRequest; + + UINT_8 ucSSIDLen; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + + ENUM_PARAM_OP_MODE_T eOPMode; + + ENUM_PARAM_CONNECTION_POLICY_T eConnectionPolicy; + + ENUM_PARAM_AD_HOC_MODE_T eAdHocMode; + + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + + BOOLEAN fgIsScanReqIssued; + + /* MIB attributes */ + UINT_16 u2BeaconPeriod; + + UINT_16 u2RTSThreshold; /* User desired setting */ + + UINT_16 u2DesiredNonHTRateSet; /* User desired setting */ + + UINT_8 ucAdHocChannelNum; /* For AdHoc */ + + ENUM_BAND_T eAdHocBand; /* For AdHoc */ + + UINT_32 u4FreqInKHz; /* Center frequency */ + + /* ATIM windows using for IBSS power saving function */ + UINT_16 u2AtimWindow; + + /* Features */ + BOOLEAN fgIsEnableRoaming; + + BOOLEAN fgIsAdHocQoSEnable; + + ENUM_PARAM_PHY_CONFIG_T eDesiredPhyConfig; + + /* Used for AP mode for desired channel and bandwidth */ + UINT_16 u2CountryCode; + UINT_16 u2CountryCodeBakup; + UINT_8 uc2G4BandwidthMode; /* 20/40M or 20M only */ + UINT_8 uc5GBandwidthMode; /* 20/40M or 20M only */ + + BOOLEAN fgTxShortGIDisabled; + BOOLEAN fgRxShortGIDisabled; + +#if CFG_SUPPORT_802_11D + BOOLEAN fgMultiDomainCapabilityEnabled; +#endif /* CFG_SUPPORT_802_11D */ + +#if 1 /* CFG_SUPPORT_WAPI */ + BOOLEAN fgWapiMode; + UINT_32 u4WapiSelectedGroupCipher; + UINT_32 u4WapiSelectedPairwiseCipher; + UINT_32 u4WapiSelectedAKMSuite; +#endif + + /* CR1486, CR1640 */ + /* for WPS, disable the privacy check for AP selection policy */ + BOOLEAN fgPrivacyCheckDisable; + + /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 bmfgApsdEnAc; + + /* for RSN info store, when upper layer set rsn info */ + RSN_INFO_T rRsnInfo; + +} CONNECTION_SETTINGS_T, *P_CONNECTION_SETTINGS_T; + +struct _BSS_INFO_T { + + ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ + ENUM_PARAM_MEDIA_STATE_T eConnectionStateIndicated; /* The Media State that report to HOST */ + + ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ +#if CFG_ENABLE_WIFI_DIRECT + ENUM_OP_MODE_T eIntendOPMode; +#endif + + BOOLEAN fgIsNetActive; /* TRUE if this network has been activated */ + + UINT_8 ucNetTypeIndex; /* ENUM_NETWORK_TYPE_INDEX_T */ + + UINT_8 ucReasonOfDisconnect; /* Used by media state indication */ + + UINT_8 ucSSIDLen; /* Length of SSID */ + +#if CFG_ENABLE_WIFI_DIRECT + ENUM_HIDDEN_SSID_TYPE_T eHiddenSsidType; /* For Hidden SSID usage. */ +#endif + + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID used in this BSS */ + + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* The BSSID of the associated BSS */ + + UINT_8 aucOwnMacAddr[MAC_ADDR_LEN]; /* Owned MAC Address used in this BSS */ + + P_STA_RECORD_T prStaRecOfAP; /* For Infra Mode, and valid only if + * eConnectionState == MEDIA_STATE_CONNECTED + */ + LINK_T rStaRecOfClientList; /* For IBSS/AP Mode, all known STAs in current BSS */ + + UINT_16 u2CapInfo; /* Change Detection */ + + UINT_16 u2BeaconInterval; /* The Beacon Interval of this BSS */ + + UINT_16 u2ATIMWindow; /* For IBSS Mode */ + + UINT_16 u2AssocId; /* For Infra Mode, it is the Assoc ID assigned by AP. + */ + + UINT_8 ucDTIMPeriod; /* For Infra/AP Mode */ + + UINT_8 ucDTIMCount; /* For AP Mode, it is the DTIM value we should carried in + * the Beacon of next TBTT. + */ + + UINT_8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (This is deduced from received BSS_DESC_T) + */ + + UINT_8 ucNonHTBasicPhyType; /* The Basic PHY Type Index, used to setup Phy Capability */ + + UINT_8 ucConfigAdHocAPMode; /* The configuration of AdHoc/AP Mode. e.g. 11g or 11b */ + + UINT_8 ucBeaconTimeoutCount; /* For Infra/AP Mode, it is a threshold of Beacon Lost Count to + confirm connection was lost */ + + BOOLEAN fgHoldSameBssidForIBSS; /* For IBSS Mode, to keep use same BSSID to extend the life cycle of an IBSS */ + + BOOLEAN fgIsBeaconActivated; /* For AP/IBSS Mode, it is used to indicate that Beacon is sending */ + + P_MSDU_INFO_T prBeacon; /* For AP/IBSS Mode - Beacon Frame */ + + BOOLEAN fgIsIBSSMaster; /* For IBSS Mode - To indicate that we can reply ProbeResp Frame. + In current TBTT interval */ + + BOOLEAN fgIsShortPreambleAllowed; /* From Capability Info. of AssocResp Frame + AND of Beacon/ProbeResp Frame */ + BOOLEAN fgUseShortPreamble; /* Short Preamble is enabled in current BSS. */ + BOOLEAN fgUseShortSlotTime; /* Short Slot Time is enabled in current BSS. */ + + UINT_16 u2OperationalRateSet; /* Operational Rate Set of current BSS */ + UINT_16 u2BSSBasicRateSet; /* Basic Rate Set of current BSS */ + + UINT_8 ucAllSupportedRatesLen; /* Used for composing Beacon Frame in AdHoc or AP Mode */ + UINT_8 aucAllSupportedRates[RATE_NUM]; + + UINT_8 ucAssocClientCnt; /* TODO(Kevin): Number of associated clients */ + + BOOLEAN fgIsProtection; + BOOLEAN fgIsQBSS; /* fgIsWmmBSS; *//* For Infra/AP/IBSS Mode, it is used to indicate if we support WMM in + * current BSS. */ + BOOLEAN fgIsNetAbsent; /* TRUE: BSS is absent, FALSE: BSS is present */ + + UINT_32 u4RsnSelectedGroupCipher; + UINT_32 u4RsnSelectedPairwiseCipher; + UINT_32 u4RsnSelectedAKMSuite; + UINT_16 u2RsnSelectedCapInfo; + + /*------------------------------------------------------------------------*/ + /* Power Management related information */ + /*------------------------------------------------------------------------*/ + PM_PROFILE_SETUP_INFO_T rPmProfSetupInfo; + + /*------------------------------------------------------------------------*/ + /* WMM/QoS related information */ + /*------------------------------------------------------------------------*/ + UINT_8 ucWmmParamSetCount; /* Used to detect the change of EDCA parameters. For AP mode, + the value is used in WMM IE */ + + AC_QUE_PARMS_T arACQueParms[WMM_AC_INDEX_NUM]; + + UINT_8 aucCWminLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWminLog2 */ + UINT_8 aucCWmaxLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the CWmaxLog2 */ + AC_QUE_PARMS_T arACQueParmsForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the value */ + + /*------------------------------------------------------------------------*/ + /* 802.11n HT operation IE when (prStaRec->ucPhyTypeSet & PHY_TYPE_BIT_HT) */ + /* is true. They have the same definition with fields of */ + /* information element (CM) */ + /*------------------------------------------------------------------------*/ + ENUM_BAND_T eBand; + UINT_8 ucPrimaryChannel; + UINT_8 ucHtOpInfo1; + UINT_16 u2HtOpInfo2; + UINT_16 u2HtOpInfo3; + + /*------------------------------------------------------------------------*/ + /* Required protection modes (CM) */ + /*------------------------------------------------------------------------*/ + BOOLEAN fgErpProtectMode; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + ENUM_RIFS_MODE_T eRifsOperationMode; + + BOOLEAN fgObssErpProtectMode; /* GO only */ + ENUM_HT_PROTECT_MODE_T eObssHtProtectMode; /* GO only */ + ENUM_GF_MODE_T eObssGfOperationMode; /* GO only */ + BOOLEAN fgObssRifsOperationMode; /* GO only */ + + /*------------------------------------------------------------------------*/ + /* OBSS to decide if 20/40M bandwidth is permitted. */ + /* The first member indicates the following channel list length. */ + /*------------------------------------------------------------------------*/ + BOOLEAN fgAssoc40mBwAllowed; + BOOLEAN fg40mBwAllowed; + ENUM_CHNL_EXT_T eBssSCO; /* Real setting for HW + * 20/40M AP mode will always set 40M, + * but its OP IE can be changed. + */ + UINT_8 auc2G_20mReqChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_NonHtChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_PriChnlList[CHNL_LIST_SZ_2G + 1]; + UINT_8 auc2G_SecChnlList[CHNL_LIST_SZ_2G + 1]; + + UINT_8 auc5G_20mReqChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_NonHtChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_PriChnlList[CHNL_LIST_SZ_5G + 1]; + UINT_8 auc5G_SecChnlList[CHNL_LIST_SZ_5G + 1]; + + TIMER_T rObssScanTimer; + UINT_16 u2ObssScanInterval; /* in unit of sec */ + + BOOLEAN fgObssActionForcedTo20M; /* GO only */ + BOOLEAN fgObssBeaconForcedTo20M; /* GO only */ + + /*------------------------------------------------------------------------*/ + /* HW Related Fields (Kevin) */ + /*------------------------------------------------------------------------*/ + UINT_8 ucHwDefaultFixedRateCode; /* The default rate code copied to MAC TX Desc */ + UINT_16 u2HwLPWakeupGuardTimeUsec; + + UINT_8 ucBssFreeQuota; /* The value is updated from FW */ +#if CFG_ENABLE_GTK_FRAME_FILTER + P_IPV4_NETWORK_ADDRESS_LIST prIpV4NetAddrList; +#endif + UINT_16 u2DeauthReason; + +#if (CFG_SUPPORT_TDLS == 1) + BOOLEAN fgTdlsIsProhibited; /* TRUE: AP prohibits TDLS links */ + BOOLEAN fgTdlsIsChSwProhibited; /* TRUE: AP prohibits TDLS chan switch */ +#endif /* CFG_SUPPORT_TDLS */ +}; + +struct _AIS_SPECIFIC_BSS_INFO_T { + UINT_8 ucRoamingAuthTypes; /* This value indicate the roaming type used in AIS_JOIN */ + + BOOLEAN fgIsIBSSActive; + + /*! \brief Global flag to let arbiter stay at standby and not connect to any network */ + BOOLEAN fgCounterMeasure; + UINT_8 ucWEPDefaultKeyID; + BOOLEAN fgTransmitKeyExist; /* Legacy wep Transmit key exist or not */ + + /* While Do CounterMeasure procedure, check the EAPoL Error report have send out */ + BOOLEAN fgCheckEAPoLTxDone; + + UINT_32 u4RsnaLastMICFailTime; + + /* Stored the current bss wpa rsn cap filed, used for roaming policy */ + /* UINT_16 u2RsnCap; */ + TIMER_T rPreauthenticationTimer; + + /* By the flow chart of 802.11i, + wait 60 sec before associating to same AP + or roaming to a new AP + or sending data in IBSS, + keep a timer for handle the 60 sec counterMeasure */ + TIMER_T rRsnaBlockTrafficTimer; + TIMER_T rRsnaEAPoLReportTimeoutTimer; + + /* For Keep the Tx/Rx Mic key for TKIP SW Calculate Mic */ + /* This is only one for AIS/AP */ + UINT_8 aucTxMicKey[8]; + UINT_8 aucRxMicKey[8]; + + /* Buffer for WPA2 PMKID */ + /* The PMKID cache lifetime is expire by media_disconnect_indication */ + UINT_32 u4PmkidCandicateCount; + PMKID_CANDICATE_T arPmkidCandicate[CFG_MAX_PMKID_CACHE]; + UINT_32 u4PmkidCacheCount; + PMKID_ENTRY_T arPmkidCache[CFG_MAX_PMKID_CACHE]; + BOOLEAN fgIndicatePMKID; +#if CFG_SUPPORT_802_11W + BOOLEAN fgMgmtProtection; + UINT_32 u4SaQueryStart; + UINT_32 u4SaQueryCount; + UINT_8 ucSaQueryTimedOut; + PUINT_8 pucSaQueryTransId; + TIMER_T rSaQueryTimer; + BOOLEAN fgBipKeyInstalled; +#endif +}; + +struct _BOW_SPECIFIC_BSS_INFO_T { + UINT_16 u2Reserved; /* Reserved for Data Type Check */ +}; + +#if CFG_SLT_SUPPORT +typedef struct _SLT_INFO_T { + + P_BSS_DESC_T prPseudoBssDesc; + UINT_16 u2SiteID; + UINT_8 ucChannel2G4; + UINT_8 ucChannel5G; + BOOLEAN fgIsDUT; + UINT_32 u4BeaconReceiveCnt; + /* ///////Deprecated///////// */ + P_STA_RECORD_T prPseudoStaRec; +} SLT_INFO_T, *P_SLT_INFO_T; +#endif + +/* Major member variables for WiFi FW operation. + Variables within this region will be ready for access after WIFI function is enabled. +*/ +typedef struct _WIFI_VAR_T { + BOOLEAN fgIsRadioOff; + + BOOLEAN fgIsEnterD3ReqIssued; + + BOOLEAN fgDebugCmdResp; + + CONNECTION_SETTINGS_T rConnSettings; + + SCAN_INFO_T rScanInfo; + +#if CFG_SUPPORT_ROAMING + ROAMING_INFO_T rRoamingInfo; +#endif /* CFG_SUPPORT_ROAMING */ + + AIS_FSM_INFO_T rAisFsmInfo; + + ENUM_PWR_STATE_T aePwrState[NETWORK_TYPE_INDEX_NUM]; + + BSS_INFO_T arBssInfo[NETWORK_TYPE_INDEX_NUM]; + + AIS_SPECIFIC_BSS_INFO_T rAisSpecificBssInfo; + +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings; + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + P_P2P_FSM_INFO_T prP2pFsmInfo; +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + BOW_SPECIFIC_BSS_INFO_T rBowSpecificBssInfo; + BOW_FSM_INFO_T rBowFsmInfo; +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + DEAUTH_INFO_T arDeauthInfo[MAX_DEAUTH_INFO_COUNT]; + + /* Current Wi-Fi Settings and Flags */ + UINT_8 aucPermanentAddress[MAC_ADDR_LEN]; + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + UINT_8 aucDeviceAddress[MAC_ADDR_LEN]; + UINT_8 aucInterfaceAddress[MAC_ADDR_LEN]; + + UINT_8 ucAvailablePhyTypeSet; + + ENUM_PHY_TYPE_INDEX_T eNonHTBasicPhyType2G4; /* Basic Phy Type used by SCN according + * to the set of Available PHY Types + */ + + ENUM_PARAM_PREAMBLE_TYPE_T ePreambleType; + ENUM_REGISTRY_FIXED_RATE_T eRateSetting; + + BOOLEAN fgIsShortSlotTimeOptionEnable; + /* User desired setting, but will honor the capability of AP */ + + BOOLEAN fgEnableJoinToHiddenSSID; + BOOLEAN fgSupportWZCDisassociation; + + BOOLEAN fgSupportQoS; + BOOLEAN fgSupportAmpduTx; + BOOLEAN fgSupportAmpduRx; + BOOLEAN fgSupportTspec; + BOOLEAN fgSupportUAPSD; + BOOLEAN fgSupportULPSMP; + UINT_8 u8SupportRxSgi20; /* 0: default 1: enable 2:disble */ + UINT_8 u8SupportRxSgi40; + UINT_8 u8SupportRxGf; + UINT_8 u8SupportRxSTBC; +#if CFG_SUPPORT_CFG_FILE + UINT_8 ucApWpsMode; + UINT_8 ucCert11nMode; +#endif +#if CFG_SUPPORT_CE_FCC_TXPWR_LIMIT + UINT_8 ucCeFccTxPwrLimit; + UINT_8 ucCeFccTxPwrLimitCck; + UINT_8 ucCeFccTxPwrLimitOfdmHt20; + UINT_8 ucCeFccTxPwrLimitHt40; +#endif + +#if CFG_SLT_SUPPORT + SLT_INFO_T rSltInfo; +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 + HS20_INFO_T rHS20Info; +#endif +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + PARAM_GET_CHN_LOAD rChnLoadInfo; +#endif + +} WIFI_VAR_T, *P_WIFI_VAR_T; /* end of _WIFI_VAR_T */ + +/* cnm_timer module */ +typedef struct { + LINK_T rLinkHead; + OS_SYSTIME rNextExpiredSysTime; + KAL_WAKE_LOCK_T rWakeLock; + BOOLEAN fgWakeLocked; +} ROOT_TIMER, *P_ROOT_TIMER; + +/* FW/DRV/NVRAM version information */ +typedef struct { + + /* NVRAM or Registry */ + UINT_16 u2Part1CfgOwnVersion; + UINT_16 u2Part1CfgPeerVersion; + UINT_16 u2Part2CfgOwnVersion; + UINT_16 u2Part2CfgPeerVersion; + + /* Firmware */ + UINT_16 u2FwProductID; + UINT_16 u2FwOwnVersion; + UINT_16 u2FwPeerVersion; + +} WIFI_VER_INFO_T, *P_WIFI_VER_INFO_T; + +#if CFG_ENABLE_WIFI_DIRECT +/* +* p2p function pointer structure +*/ + +typedef struct _P2P_FUNCTION_LINKER { + P2P_REMOVE prP2pRemove; +/* NIC_P2P_MEDIA_STATE_CHANGE prNicP2pMediaStateChange; */ +/* SCAN_UPDATE_P2P_DEVICE_DESC prScanUpdateP2pDeviceDesc; */ +/* P2P_FSM_RUN_EVENT_RX_PROBE_RESPONSE_FRAME prP2pFsmRunEventRxProbeResponseFrame; */ + P2P_GENERATE_P2P_IE prP2pGenerateWSC_IEForBeacon; +/* P2P_CALCULATE_WSC_IE_LEN_FOR_PROBE_RSP prP2pCalculateWSC_IELenForProbeRsp; */ +/* P2P_GENERATE_WSC_IE_FOR_PROBE_RSP prP2pGenerateWSC_IEForProbeRsp; */ +/* SCAN_REMOVE_P2P_BSS_DESC prScanRemoveP2pBssDesc; */ +/* P2P_HANDLE_SEC_CHECK_RSP prP2pHandleSecCheckRsp; */ + P2P_NET_REGISTER prP2pNetRegister; + P2P_NET_UNREGISTER prP2pNetUnregister; + P2P_CALCULATE_P2P_IE_LEN prP2pCalculateP2p_IELenForAssocReq; /* All IEs generated from supplicant. */ + P2P_GENERATE_P2P_IE prP2pGenerateP2p_IEForAssocReq; /* All IEs generated from supplicant. */ +} P2P_FUNCTION_LINKER, *P_P2P_FUNCTION_LINKER; + +#endif + +/* + *State Machine: + *-->STOP: Turn on/off WiFi + *-->DISABLE: Screen was off (wlanHandleSystemSuspend) + *-->ENABLE: Screen was on (wlanHandleSystemResume) + *----->clear DISABLE + *-->RUNNING: Screen was on && Tx/Rx was ongoing (wlanHardStartXmit/kalRxIndicatePkts) +*/ +struct GL_PER_MON_T { + TIMER_T rPerfMonTimer; + ULONG ulPerfMonFlag; + ULONG ulLastTxBytes; + ULONG ulLastRxBytes; + ULONG ulP2PLastTxBytes; + ULONG ulP2PLastRxBytes; + /*in bps*/ + ULONG ulThroughput; + /*in ms*/ + UINT32 u4UpdatePeriod; + UINT32 u4TarPerfLevel; + UINT32 u4CurrPerfLevel; +}; + +/* + * Major ADAPTER structure + * Major data structure for driver operation + */ +struct _ADAPTER_T { + UINT_8 ucRevID; + + UINT_16 u2NicOpChnlNum; + + BOOLEAN fgIsEnableWMM; + BOOLEAN fgIsWmmAssoc; /* This flag is used to indicate that WMM is enable in current BSS */ + + UINT_32 u4OsPacketFilter; /* packet filter used by OS */ + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + UINT_32 u4CSUMFlags; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + ENUM_BAND_T aePreferBand[NETWORK_TYPE_INDEX_NUM]; + + /* ADAPTER flags */ + UINT_32 u4Flags; + UINT_32 u4HwFlags; + + BOOLEAN fgIsRadioOff; + + BOOLEAN fgIsEnterD3ReqIssued; + + UINT_8 aucMacAddress[MAC_ADDR_LEN]; + + ENUM_PHY_TYPE_INDEX_T eCurrentPhyType; /* Current selection basing on the set of Available PHY Types */ + +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + UINT_32 u4CoalescingBufCachedSize; + PUINT_8 pucCoalescingBufCached; +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + /* Buffer for CMD_INFO_T, Mgt packet and mailbox message */ + BUF_INFO_T rMgtBufInfo; + BUF_INFO_T rMsgBufInfo; + PUINT_8 pucMgtBufCached; + UINT_32 u4MgtBufCachedSize; + UINT_8 aucMsgBuf[MSG_BUFFER_SIZE]; +#if CFG_DBG_MGT_BUF + UINT_32 u4MemAllocDynamicCount; /* Debug only */ + UINT_32 u4MemFreeDynamicCount; /* Debug only */ +#endif + + STA_RECORD_T arStaRec[CFG_STA_REC_NUM]; + + /* Element for TX PATH */ + TX_CTRL_T rTxCtrl; + QUE_T rFreeCmdList; + CMD_INFO_T arHifCmdDesc[CFG_TX_MAX_CMD_PKT_NUM]; + + /* Element for RX PATH */ + RX_CTRL_T rRxCtrl; + + P_SDIO_CTRL_T prSDIOCtrl; + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + /* Element for MT6620 E1 HIFSYS workaround */ + BOOLEAN fgIsClockGatingEnabled; +#endif + + /* Buffer for Authentication Event */ + /* Move to glue layer and refine the kal function */ + /* Reference to rsnGeneratePmkidIndication function at rsn.c */ + UINT_8 aucIndicationEventBuffer[(CFG_MAX_PMKID_CACHE * 20) + 8]; + + UINT_32 u4IntStatus; + + ENUM_ACPI_STATE_T rAcpiState; + + BOOLEAN fgIsIntEnable; + BOOLEAN fgIsIntEnableWithLPOwnSet; + + BOOLEAN fgIsFwOwn; + BOOLEAN fgWiFiInSleepyState; + + UINT_32 u4PwrCtrlBlockCnt; + + QUE_T rPendingCmdQueue; + + P_GLUE_INFO_T prGlueInfo; + + UINT_8 ucCmdSeqNum; + UINT_8 ucTxSeqNum; + +#if 1 /* CFG_SUPPORT_WAPI */ + BOOLEAN fgUseWapi; +#endif + + /* RF Test flags */ + BOOLEAN fgTestMode; + + /* WLAN Info for DRIVER_CORE OID query */ + WLAN_INFO_T rWlanInfo; + +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsP2PRegistered; + ENUM_NET_REG_STATE_T rP2PNetRegState; + BOOLEAN fgIsWlanLaunched; + P_P2P_INFO_T prP2pInfo; +#if CFG_SUPPORT_P2P_RSSI_QUERY + OS_SYSTIME rP2pLinkQualityUpdateTime; + BOOLEAN fgIsP2pLinkQualityValid; + EVENT_LINK_QUALITY rP2pLinkQuality; +#endif + + /* FSM Timer */ + TIMER_T rP2pFsmTimeoutTimer; +#endif + + /* Online Scan Option */ + BOOLEAN fgEnOnlineScan; + + /* Online Scan Option */ + BOOLEAN fgDisBcnLostDetection; + + /* MAC address */ + PARAM_MAC_ADDRESS rMyMacAddr; + + /* Wake-up Event for WOL */ + UINT_32 u4WakeupEventEnable; + + /* Event Buffering */ + EVENT_STATISTICS rStatStruct; + OS_SYSTIME rStatUpdateTime; + BOOLEAN fgIsStatValid; + + EVENT_LINK_QUALITY rLinkQuality; + OS_SYSTIME rLinkQualityUpdateTime; + BOOLEAN fgIsLinkQualityValid; + OS_SYSTIME rLinkRateUpdateTime; + BOOLEAN fgIsLinkRateValid; + + /* WIFI_VAR_T */ + WIFI_VAR_T rWifiVar; + + /* MTK WLAN NIC driver IEEE 802.11 MIB */ + IEEE_802_11_MIB_T rMib; + + /* Mailboxs for inter-module communication */ + MBOX_T arMbox[MBOX_ID_TOTAL_NUM]; + + /* Timers for OID Pending Handling */ + TIMER_T rOidTimeoutTimer; + + TIMER_T rReturnIndicatedRfbListTimer; + + /* Root Timer for cnm_timer module */ + ROOT_TIMER rRootTimer; + + /* RLM maintenance */ + ENUM_CHNL_EXT_T eRfSco; + ENUM_SYS_PROTECT_MODE_T eSysProtectMode; + ENUM_GF_MODE_T eSysHtGfMode; + ENUM_RIFS_MODE_T eSysTxRifsMode; + ENUM_SYS_PCO_PHASE_T eSysPcoPhase; + + P_DOMAIN_INFO_ENTRY prDomainInfo; + + /* QM */ + QUE_MGT_T rQM; + + CNM_INFO_T rCnmInfo; + + UINT_32 u4PowerMode; + + UINT_32 u4CtiaPowerMode; + BOOLEAN fgEnCtiaPowerMode; + + UINT_32 fgEnArpFilter; + + UINT_32 u4UapsdAcBmp; + + UINT_32 u4MaxSpLen; + + UINT_32 u4PsCurrentMeasureEn; + + /* Version Information */ + WIFI_VER_INFO_T rVerInfo; + + /* 5GHz support (from F/W) */ + BOOLEAN fgIsHw5GBandDisabled; + BOOLEAN fgEnable5GBand; + BOOLEAN fgIsEepromUsed; + BOOLEAN fgIsEfuseValid; + BOOLEAN fgIsEmbbededMacAddrValid; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + BOOLEAN fgIsPowerLimitTableValid; +#endif + + /* Packet Forwarding Tracking */ + INT_32 i4PendingFwdFrameCount; + +#if CFG_SUPPORT_RDD_TEST_MODE + UINT_8 ucRddStatus; +#endif + + BOOLEAN fgDisStaAgingTimeoutDetection; +#if CFG_SUPPORT_CFG_FILE + P_WLAN_CFG_T prWlanCfg; + WLAN_CFG_T rWlanCfg; +#endif +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT + KAL_WAKE_LOCK_T rApWakeLock; +#endif + UINT_32 u4FwCompileFlag0; + UINT_32 u4FwCompileFlag1; + KAL_WAKE_LOCK_T rTxThreadWakeLock; + KAL_WAKE_LOCK_T rAhbIsrWakeLock; + +#if CFG_SUPPORT_ROAMING_ENC + BOOLEAN fgIsRoamingEncEnabled; +#endif /* CFG_SUPPORT_ROAMING_ENC */ + +#if (CFG_SUPPORT_TDLS == 1) + BOOLEAN fgTdlsIsSup; +#endif /* CFG_SUPPORT_TDLS */ + + UINT_8 ucScanTime; + +#if CFG_SUPPORT_DBG_POWERMODE + BOOLEAN fgEnDbgPowerMode; /* dbg privilege power mode, always keep in active */ +#endif + + UINT_32 u4AirDelayTotal; /* dbg privilege power mode, always keep in active */ + ULONG ulSuspendFlag; + struct GL_PER_MON_T rPerMonitor; +}; /* end of _ADAPTER_T */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define SUSPEND_FLAG_FOR_WAKEUP_REASON (0) +#define SUSPEND_FLAG_CLEAR_WHEN_RESUME (1) + +/*----------------------------------------------------------------------------*/ +/* Macros for BSS_INFO_T - Flag of Net Active */ +/*----------------------------------------------------------------------------*/ +#define IS_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive) +#define IS_BSS_ACTIVE(_prBssInfo) ((_prBssInfo)->fgIsNetActive) + +#define IS_AIS_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_AIS_INDEX) +#define IS_P2P_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_P2P_INDEX) +#define IS_BOW_ACTIVE(_prAdapter) IS_NET_ACTIVE(_prAdapter, NETWORK_TYPE_BOW_INDEX) + +#define SET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = TRUE; } + +#define UNSET_NET_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)].fgIsNetActive = FALSE; } + +#define BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ + { UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; \ + P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ + \ + _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; \ + _prBssInfo->fgIsNetActive = FALSE; \ + _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ + _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ + COPY_MAC_ADDR(_prBssInfo->aucBSSID, _aucZeroMacAddr); \ + LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ + _prBssInfo->fgIsBeaconActivated = FALSE; \ + _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ + _prBssInfo->fgIsNetAbsent = FALSE; \ + } + +#if CFG_ENABLE_BT_OVER_WIFI +#define BOW_BSS_INFO_INIT(_prAdapter, _NetTypeIndex) \ + { \ + P_BSS_INFO_T _prBssInfo = &(_prAdapter->rWifiVar.arBssInfo[(_NetTypeIndex)]); \ + \ + _prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; \ + _prBssInfo->eCurrentOPMode = OP_MODE_BOW; \ + _prBssInfo->ucNetTypeIndex = (_NetTypeIndex); \ + _prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; \ + LINK_INITIALIZE(&_prBssInfo->rStaRecOfClientList); \ + _prBssInfo->fgIsBeaconActivated = TRUE; \ + _prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ + _prBssInfo->fgIsNetAbsent = FALSE; \ + } +#endif + +#define PERF_MON_DISABLE_BIT_OFF (0) +#define PERF_MON_STOP_BIT_OFF (1) +#define PERF_MON_RUNNING_BIT_OFF (2) + +#define THROUGHPUT_L1_THRESHOLD (20*1024*1024) +#define THROUGHPUT_L2_THRESHOLD (60*1024*1024) +#define THROUGHPUT_L3_THRESHOLD (135*1024*1024) + +/*----------------------------------------------------------------------------*/ +/* Macros for Power State */ +/*----------------------------------------------------------------------------*/ +#define SET_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_IDLE; } + +#define SET_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_ACTIVE; } + +#define SET_NET_PWR_STATE_PS(_prAdapter, _NetTypeIndex) \ + {_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] = PWR_STATE_PS; } + +#define IS_NET_PWR_STATE_ACTIVE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_ACTIVE) + +#define IS_NET_PWR_STATE_IDLE(_prAdapter, _NetTypeIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_NetTypeIndex)] == PWR_STATE_IDLE) + +#define IS_SCN_PWR_STATE_ACTIVE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_ACTIVE) + +#define IS_SCN_PWR_STATE_IDLE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_IDLE) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _ADAPTER_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h new file mode 100644 index 0000000000000..6c4c1b76622b2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/bow.h @@ -0,0 +1,322 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/bow.h#1 +*/ + +/* +** Log: bow.h + * + * 01 16 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support BOW for 5GHz band. + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 22 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Submit missing BoW header files. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW structure. + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add Activity Report definition. + * + * 10 18 2010 chinghwa.yu + * [WCXRP00000110] [MT6620 Wi-Fi] [Driver] Fix BoW Connected event size + * Fix wrong BoW event size. + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * basic implementation for EVENT_BT_OVER_WIFI + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * sync. with design document for interface change. + * + * 04 02 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * Wi-Fi driver no longer needs to implement 802.11 PAL, thus replaced by wrapping command/event definitions + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * correct typo. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * update for all command/event needed to be supported by 802.11 PAL. + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * +*/ + +#ifndef _BOW_H_ +#define _BOW_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define BOWDEVNAME "bow0" + +#define MAX_BOW_NUMBER_OF_CHANNEL_2G4 14 +#define MAX_BOW_NUMBER_OF_CHANNEL_5G 4 +/* (MAX_BOW_NUMBER_OF_CHANNEL_2G4 + MAX_BOW_NUMBER_OF_CHANNEL_5G) */ +#define MAX_BOW_NUMBER_OF_CHANNEL 18 + +#define MAX_ACTIVITY_REPORT 2 +#define MAX_ACTIVITY_REPROT_TIME 660 + +#define ACTIVITY_REPORT_STATUS_SUCCESS 0 +#define ACTIVITY_REPORT_STATUS_FAILURE 1 +#define ACTIVITY_REPORT_STATUS_TIME_INVALID 2 +#define ACTIVITY_REPORT_STATUS_OTHERS 3 + +#define ACTIVITY_REPORT_SCHEDULE_UNKNOWN 0 /* Does not know the schedule of the interference */ +#define ACTIVITY_REPORT_SCHEDULE_KNOWN 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _BT_OVER_WIFI_COMMAND_HEADER_T { + UINT_8 ucCommandId; + UINT_8 ucSeqNumber; + UINT_16 u2PayloadLength; +} AMPC_COMMAND_HEADER_T, *P_AMPC_COMMAND_HEADER_T; + +typedef struct _BT_OVER_WIFI_COMMAND { + AMPC_COMMAND_HEADER_T rHeader; + UINT_8 aucPayload[0]; +} AMPC_COMMAND, *P_AMPC_COMMAND; + +typedef struct _BT_OVER_WIFI_EVENT_HEADER_T { + UINT_8 ucEventId; + UINT_8 ucSeqNumber; + UINT_16 u2PayloadLength; +} AMPC_EVENT_HEADER_T, *P_AMPC_EVENT_HEADER_T; + +typedef struct _BT_OVER_WIFI_EVENT { + AMPC_EVENT_HEADER_T rHeader; + UINT_8 aucPayload[0]; +} AMPC_EVENT, *P_AMPC_EVENT; + +typedef struct _CHANNEL_DESC_T { + UINT_8 ucChannelBand; + UINT_8 ucChannelNum; +} CHANNEL_DESC, P_CHANNEL_DESC; + +/* Command Structures */ +typedef struct _BOW_SETUP_CONNECTION { +/* Fixed to 2.4G */ + UINT_8 ucChannelNum; + UINT_8 ucReserved1; + UINT_8 aucPeerAddress[6]; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 ucPAL_Capabilities; + INT_8 cMaxTxPower; + UINT_8 ucReserved2; + +/* Pending, for future BOW 5G supporting. */ +/* UINT_8 aucPeerAddress[6]; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 ucPAL_Capabilities; + INT_8 cMaxTxPower; + UINT_8 ucChannelListNum; + CHANNEL_DESC arChannelList[1]; +*/ +} BOW_SETUP_CONNECTION, *P_BOW_SETUP_CONNECTION; + +typedef struct _BOW_DESTROY_CONNECTION { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_DESTROY_CONNECTION, *P_BOW_DESTROY_CONNECTION; + +typedef struct _BOW_SET_PTK { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; + UINT_8 aucTemporalKey[16]; +} BOW_SET_PTK, *P_BOW_SET_PTK; + +typedef struct _BOW_READ_RSSI { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_READ_RSSI, *P_BOW_READ_RSSI; + +typedef struct _BOW_READ_LINK_QUALITY { + UINT_8 aucPeerAddress[6]; + UINT_8 aucReserved[2]; +} BOW_READ_LINK_QUALITY, *P_BOW_READ_LINK_QUALITY; + +typedef struct _BOW_SHORT_RANGE_MODE { + UINT_8 aucPeerAddress[6]; + INT_8 cTxPower; + UINT_8 ucReserved; +} BOW_SHORT_RANGE_MODE, *P_BOW_SHORT_RANGE_MODE; + +/* Event Structures */ +typedef struct _BOW_COMMAND_STATUS { + UINT_8 ucStatus; + UINT_8 ucReserved[3]; +} BOW_COMMAND_STATUS, *P_BOW_COMMAND_STATUS; + +typedef struct _BOW_MAC_STATUS { + UINT_8 aucMacAddr[6]; + UINT_8 ucAvailability; + UINT_8 ucNumOfChannel; + CHANNEL_DESC arChannelList[MAX_BOW_NUMBER_OF_CHANNEL]; +} BOW_MAC_STATUS, *P_BOW_MAC_STATUS; + +typedef struct _BOW_LINK_CONNECTED { + CHANNEL_DESC rChannel; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_LINK_CONNECTED, *P_BOW_LINK_CONNECTED; + +typedef struct _BOW_LINK_DISCONNECTED { + UINT_8 ucReason; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_LINK_DISCONNECTED, *P_BOW_LINK_DISCONNECTED; + +typedef struct _BOW_RSSI { + INT_8 cRssi; + UINT_8 aucReserved[3]; +} BOW_RSSI, *P_BOW_RSSI; + +typedef struct _BOW_LINK_QUALITY { + UINT_8 ucLinkQuality; + UINT_8 aucReserved[3]; +} BOW_LINK_QUALITY, *P_BOW_LINK_QUALITY; + +typedef enum _ENUM_BOW_CMD_ID_T { + BOW_CMD_ID_GET_MAC_STATUS = 1, + BOW_CMD_ID_SETUP_CONNECTION, + BOW_CMD_ID_DESTROY_CONNECTION, + BOW_CMD_ID_SET_PTK, + BOW_CMD_ID_READ_RSSI, + BOW_CMD_ID_READ_LINK_QUALITY, + BOW_CMD_ID_SHORT_RANGE_MODE, + BOW_CMD_ID_GET_CHANNEL_LIST, +} ENUM_BOW_CMD_ID_T, *P_ENUM_BOW_CMD_ID_T; + +typedef enum _ENUM_BOW_EVENT_ID_T { + BOW_EVENT_ID_COMMAND_STATUS = 1, + BOW_EVENT_ID_MAC_STATUS, + BOW_EVENT_ID_LINK_CONNECTED, + BOW_EVENT_ID_LINK_DISCONNECTED, + BOW_EVENT_ID_RSSI, + BOW_EVENT_ID_LINK_QUALITY, + BOW_EVENT_ID_CHANNEL_LIST, + BOW_EVENT_ID_CHANNEL_SELECTED, +} ENUM_BOW_EVENT_ID_T, *P_ENUM_BOW_EVENT_ID_T; + +typedef enum _ENUM_BOW_DEVICE_STATE { + BOW_DEVICE_STATE_DISCONNECTED = 0, + BOW_DEVICE_STATE_DISCONNECTING, + BOW_DEVICE_STATE_ACQUIRING_CHANNEL, + BOW_DEVICE_STATE_STARTING, + BOW_DEVICE_STATE_SCANNING, + BOW_DEVICE_STATE_CONNECTING, + BOW_DEVICE_STATE_CONNECTED, + BOW_DEVICE_STATE_NUM +} ENUM_BOW_DEVICE_STATE, *P_ENUM_BOW_DEVICE_STATE; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#endif /*_BOW_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h new file mode 100644 index 0000000000000..c1ecb303b877f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/cmd_buf.h @@ -0,0 +1,150 @@ +/* +** Id: +*/ + +/*! \file "cmd_buf.h" + \brief In this file we define the structure for Command Packet. + + In this file we define the structure for Command Packet and the control unit + of MGMT Memory Pool. +*/ + +/* +** Log: cmd_buf.h + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by + * ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow + * under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Enable change log +*/ + +#ifndef _CMD_BUF_H +#define _CMD_BUF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _COMMAND_TYPE { + COMMAND_TYPE_GENERAL_IOCTL, + COMMAND_TYPE_NETWORK_IOCTL, + COMMAND_TYPE_SECURITY_FRAME, + COMMAND_TYPE_MANAGEMENT_FRAME, + COMMAND_TYPE_NUM +} COMMAND_TYPE, *P_COMMAND_TYPE; + +typedef VOID(*PFN_CMD_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +typedef VOID(*PFN_CMD_TIMEOUT_HANDLER) (IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +struct _CMD_INFO_T { + QUE_ENTRY_T rQueEntry; + + COMMAND_TYPE eCmdType; + + UINT_16 u2InfoBufLen; /* This is actual CMD buffer length */ + PUINT_8 pucInfoBuffer; /* May pointer to structure in prAdapter */ + P_NATIVE_PACKET prPacket; /* only valid when it's a security frame */ + + ENUM_NETWORK_TYPE_INDEX_T eNetworkType; + UINT_8 ucStaRecIndex; /* only valid when it's a security frame */ + + PFN_CMD_DONE_HANDLER pfCmdDoneHandler; + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler; + + BOOLEAN fgIsOid; /* Used to check if we need indicate */ + + UINT_8 ucCID; + BOOLEAN fgSetQuery; + BOOLEAN fgNeedResp; + BOOLEAN fgDriverDomainMCR; /* Access Driver Domain MCR, for CMD_ID_ACCESS_REG only */ + UINT_8 ucCmdSeqNum; + UINT_32 u4SetInfoLen; /* Indicate how many byte we read for Set OID */ + + /* information indicating by OID/ioctl */ + PVOID pvInformationBuffer; + UINT_32 u4InformationBufferLength; + + /* private data */ + UINT_32 u4PrivateData; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter); + +P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length); + +VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +/*----------------------------------------------------------------------------*/ +/* Routines for CMDs */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); +VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _CMD_BUF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h new file mode 100644 index 0000000000000..0fdb9dcadeeff --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hal.h @@ -0,0 +1,618 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hal.h#1 +*/ + +/*! \file "hal.h" + \brief The declaration of hal functions + + N/A +*/ + +/* +** Log: hal.h + * + * 04 01 2011 tsaiyuan.hsu + * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues + * fix the klocwork issues, 57500, 57501, 57502 and 57503. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 09 01 2010 cp.wu + * NULL + * move HIF CR initialization from where after sdioSetupCardFeature() to wlanAdapterStart() + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change zero-padding for TX port access to HAL. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * 4. correct some HAL implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-16 18:02:26 GMT mtk02752 +** include precomp.h +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:16 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 13:54:15 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-11 10:36:01 GMT mtk01084 +** modify HAL functions +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-09 22:56:28 GMT mtk01084 +** modify HW access routines +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-10-29 19:50:09 GMT mtk01084 +** add new macro HAL_TX_PORT_WR +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-23 16:08:10 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-13 21:58:50 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-05-18 14:28:10 GMT mtk01084 +** fix issue in HAL_DRIVER_OWN_BY_SDIO_CMD52() +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-11 17:26:33 GMT mtk01084 +** modify the bit definition to check driver own status +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:30:22 GMT mtk01461 +** Fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:50:34 GMT mtk01461 +** Redefine HAL_PORT_RD/WR macro for SW pre test +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-24 09:46:49 GMT mtk01084 +** fix LINT error +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 16:53:38 GMT mtk01084 +** add HAL_DRIVER_OWN_BY_SDIO_CMD52() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-18 20:53:13 GMT mtk01426 +** Fixed lint warn +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:20 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _HAL_H +#define _HAL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* Macros for flag operations for the Adapter structure */ +#define HAL_SET_FLAG(_M, _F) ((_M)->u4HwFlags |= (_F)) +#define HAL_CLEAR_FLAG(_M, _F) ((_M)->u4HwFlags &= ~(_F)) +#define HAL_TEST_FLAG(_M, _F) ((_M)->u4HwFlags & (_F)) +#define HAL_TEST_FLAGS(_M, _F) (((_M)->u4HwFlags & (_F)) == (_F)) + +#if defined(_HIF_SDIO) +#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ +do { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + /* DBGLOG(HAL, ERROR, ("HAL_MCR_RD access fail! 0x%x: 0x%x\n", */ \ + /* (UINT32)_u4Offset, (UINT32)*_pu4Value)); */ \ + } \ + } else { \ + /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_RD access! 0x%x\n", (UINT32)_u4Offset)); */ \ + } \ +} while (0) + +#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ +do { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + /* DBGLOG(HAL, ERROR, ("HAL_MCR_WR access fail! 0x%x: 0x%x\n", */ \ + /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ + } \ + } else { \ + /* DBGLOG(HAL, WARN, ("ignore HAL_MCR_WR access! 0x%x: 0x%x\n", */ \ + /* (UINT32)_u4Offset, (UINT32)_u4Value)); */ \ + } \ +} while (0) + +#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ +{ \ + /*fgResult = FALSE; */\ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, "HAL_PORT_RD access fail! 0x%x\n", _u4Port); \ + } \ + else { \ + /*fgResult = TRUE;*/ } \ + } else { \ + DBGLOG(HAL, WARN, "ignore HAL_PORT_RD access! 0x%x\n", _u4Port); \ + } \ +} + +#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ +{ \ + /*fgResult = FALSE; */\ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, "HAL_PORT_WR access fail! 0x%x\n", _u4Port); \ + } \ + else { \ + /*fgResult = TRUE;*/ } \ + } else { \ + DBGLOG(HAL, WARN, "ignore HAL_PORT_WR access! 0x%x\n", _u4Port); \ + } \ +} + +#if 0 /* only for SDIO */ +#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf) == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, "HAL_BYTE_WR access fail! 0x%x\n", _u4Port); \ + } \ + else { \ + /* Todo:: Nothing*/ \ + } \ + } \ + else { \ + DBGLOG(HAL, WARN, "ignore HAL_BYTE_WR access! 0x%x\n", _u4Port); \ + } \ +} +#endif + +#define HAL_DRIVER_OWN_BY_SDIO_CMD52(_prAdapter, _pfgDriverIsOwnReady) \ +{ \ + UINT_8 ucBuf = BIT(1); \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == FALSE) { \ + if (kalDevReadAfterWriteWithSdioCmd52(_prAdapter->prGlueInfo, MCR_WHLPCR_BYTE1, &ucBuf, 1) \ + == FALSE) {\ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = TRUE; \ + DBGLOG(HAL, ERROR, "kalDevReadAfterWriteWithSdioCmd52 access fail!\n"); \ + } \ + else { \ + *_pfgDriverIsOwnReady = (ucBuf & BIT(0)) ? TRUE : FALSE; \ + } \ + } else { \ + DBGLOG(HAL, WARN, "ignore HAL_DRIVER_OWN_BY_SDIO_CMD52 access!\n"); \ + } \ +} + +#else /* #if defined(_HIF_SDIO) */ +#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegRead(_prAdapter->prGlueInfo, _u4Offset, _pu4Value) \ + == FALSE) \ + fgIsBusAccessFailed = TRUE; \ +} + +#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevRegWrite(_prAdapter->prGlueInfo, _u4Offset, _u4Value) \ + == FALSE) \ + fgIsBusAccessFailed = TRUE; \ +} + +#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + == FALSE) \ + fgIsBusAccessFailed = TRUE; \ +} + +#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + == FALSE) \ + fgIsBusAccessFailed = TRUE; \ +} + +#if 0 /* only for SDIO */ +#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ +{ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ +kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, _u4Port, _ucBuf); \ +} +#endif + +#endif /* #if defined(_HIF_SDIO) */ + +#define HAL_READ_RX_PORT(prAdapter, u4PortId, u4Len, pvBuf, _u4ValidBufSize) \ +{ \ + ASSERT(u4PortId < 2); \ + HAL_PORT_RD(prAdapter, \ + ((u4PortId == 0) ? MCR_WRDR0 : MCR_WRDR1), \ + u4Len, \ + pvBuf, \ + _u4ValidBufSize/*temp!!*//*4Kbyte*/); \ +} + +#define HAL_WRITE_TX_PORT(_prAdapter, _ucTxPortIdx, _u4Len, _pucBuf, _u4ValidBufSize) \ +{ \ + ASSERT(_ucTxPortIdx < 2); \ + if ((_u4ValidBufSize - _u4Len) >= sizeof(UINT_32)) { \ + /* fill with single dword of zero as TX-aggregation termination */ \ + *(PUINT_32) (&((_pucBuf)[ALIGN_4(_u4Len)])) = 0; \ + } \ + HAL_PORT_WR(_prAdapter, \ + (_ucTxPortIdx == 0) ? MCR_WTDR0 : MCR_WTDR1, \ + _u4Len, \ + _pucBuf, \ + _u4ValidBufSize/*temp!!*//*4KByte*/); \ +} + +/* The macro to read the given MCR several times to check if the wait + condition come true. */ +#define HAL_MCR_RD_AND_WAIT(_pAdapter, _offset, _pReadValue, _waitCondition, _waitDelay, _waitCount, _status) \ +{ \ + UINT_32 count; \ + (_status) = FALSE; \ + for (count = 0; count < (_waitCount); count++) { \ + HAL_MCR_RD((_pAdapter), (_offset), (_pReadValue)); \ + if ((_waitCondition)) { \ + (_status) = TRUE; \ + break; \ + } \ + kalUdelay((_waitDelay)); \ + } \ +} + +/* The macro to write 1 to a R/S bit and read it several times to check if the + command is done */ +#define HAL_MCR_WR_AND_WAIT(_pAdapter, _offset, _writeValue, _busyMask, _waitDelay, _waitCount, _status) \ +{ \ + UINT_32 u4Temp; \ + UINT_32 u4Count = _waitCount; \ + (_status) = FALSE; \ + HAL_MCR_WR((_pAdapter), (_offset), (_writeValue)); \ + do { \ + kalUdelay((_waitDelay)); \ + HAL_MCR_RD((_pAdapter), (_offset), &u4Temp); \ + if (!(u4Temp & (_busyMask))) { \ + (_status) = TRUE; \ + break; \ + } \ + u4Count--; \ + } while (u4Count); \ +} + +#define HAL_GET_CHIP_ID_VER(_prAdapter, pu2ChipId, pu2Version) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WCIR, \ + &u4Value); \ + *pu2ChipId = (UINT_16)(u4Value & WCIR_CHIP_ID); \ + *pu2Version = (UINT_16)(u4Value & WCIR_REVISION_ID) >> 16; \ +} + +#define HAL_WAIT_WIFI_FUNC_READY(_prAdapter) \ +{ \ + UINT_32 u4Value; \ + UINT_32 i; \ + for (i = 0; i < 100; i++) { \ + HAL_MCR_RD(_prAdapter, \ + MCR_WCIR, \ + &u4Value); \ + if (u4Value & WCIR_WLAN_READY) { \ + break; \ + } \ + NdisMSleep(10); \ + } \ +} + +#define HAL_INTR_DISABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_INT_EN_CLR) + +#define HAL_INTR_ENABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_INT_EN_SET) + +#define HAL_INTR_ENABLE_AND_LP_OWN_SET(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + (WHLPCR_INT_EN_SET | WHLPCR_FW_OWN_REQ_SET)) + +#define HAL_LP_OWN_SET(_prAdapter) \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_FW_OWN_REQ_SET) + +#define HAL_LP_OWN_CLR_OK(_prAdapter, _pfgResult) \ +{ \ + UINT_32 i; \ + UINT_32 u4RegValue; \ + UINT_32 u4LoopCnt = 2048 / 8; \ + *_pfgResult = TRUE; \ + /* Software get LP ownership */ \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHLPCR, \ + WHLPCR_FW_OWN_REQ_CLR) \ + for (i = 0; i < u4LoopCnt; i++) { \ + HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ + if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ + break; \ + } \ + else { \ + kalUdelay(8); \ + } \ + } \ + if (i == u4LoopCnt) { \ + *_pfgResult = FALSE; \ + /*ERRORLOG(("LP cannot be own back (%ld)", u4LoopCnt));*/ \ + /* check the time of LP instructions need to perform from Sleep to On */ \ + /*ASSERT(0); */ \ + } \ +} + +#define HAL_GET_ABNORMAL_INTERRUPT_REASON_CODE(_prAdapter, pu4AbnormalReason) \ +{ \ + HAL_MCR_RD(_prAdapter, \ + MCR_WASR, \ + pu4AbnormalReason); \ +} + +#define HAL_DISABLE_RX_ENHANCE_MODE(_prAdapter) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value & ~WHCR_RX_ENHANCE_MODE_EN); \ +} + +#define HAL_ENABLE_RX_ENHANCE_MODE(_prAdapter) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value | WHCR_RX_ENHANCE_MODE_EN); \ +} + +#define HAL_CFG_MAX_HIF_RX_LEN_NUM(_prAdapter, _ucNumOfRxLen) \ +{ \ + UINT_32 u4Value, ucNum; \ + ucNum = ((_ucNumOfRxLen >= 16) ? 0 : _ucNumOfRxLen); \ + u4Value = 0; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + u4Value &= ~WHCR_MAX_HIF_RX_LEN_NUM; \ + u4Value |= ((((UINT_32)ucNum) << 4) & WHCR_MAX_HIF_RX_LEN_NUM); \ + HAL_MCR_WR(_prAdapter, \ + MCR_WHCR, \ + u4Value); \ +} + +#define HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(prAdapter, \ + MCR_WHCR, \ + u4Value & ~WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = TRUE;\ +} + +#define HAL_SET_INTR_STATUS_WRITE_1_CLEAR(prAdapter) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, \ + MCR_WHCR, \ + &u4Value); \ + HAL_MCR_WR(prAdapter, \ + MCR_WHCR, \ + u4Value | WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = FALSE;\ +} + +/* Note: enhance mode structure may also carried inside the buffer, + if the length of the buffer is long enough */ +#define HAL_READ_INTR_STATUS(prAdapter, length, pvBuf) \ + HAL_PORT_RD(prAdapter, \ + MCR_WHISR, \ + length, \ + pvBuf, \ + length) + +#define HAL_READ_TX_RELEASED_COUNT(_prAdapter, aucTxReleaseCount) \ +{ \ + PUINT_32 pu4Value = (PUINT_32)aucTxReleaseCount; \ + HAL_MCR_RD(_prAdapter, \ + MCR_WTSR0, \ + &pu4Value[0]); \ + HAL_MCR_RD(_prAdapter, \ + MCR_WTSR1, \ + &pu4Value[1]); \ +} + +#define HAL_READ_RX_LENGTH(prAdapter, pu2Rx0Len, pu2Rx1Len) \ +{ \ + UINT_32 u4Value; \ + u4Value = 0; \ + HAL_MCR_RD(prAdapter, \ + MCR_WRPLR, \ + &u4Value); \ + *pu2Rx0Len = (UINT_16)u4Value; \ + *pu2Rx1Len = (UINT_16)(u4Value >> 16); \ +} + +#define HAL_GET_INTR_STATUS_FROM_ENHANCE_MODE_STRUCT(pvBuf, u2Len, pu4Status) \ +{ \ + PUINT_32 pu4Buf = (PUINT_32)pvBuf; \ + *pu4Status = pu4Buf[0]; \ +} + +#define HAL_GET_TX_STATUS_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4BufOut, u4LenBufOut) \ +{ \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + ASSERT(u4LenBufOut >= 8); \ + pu4BufOut[0] = pu4Buf[1]; \ + pu4BufOut[1] = pu4Buf[2]; \ +} + +#define HAL_GET_RX_LENGTH_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu2Rx0Num, au2Rx0Len, pu2Rx1Num, au2Rx1Len) \ +{ \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + ASSERT((sizeof(au2Rx0Len) / sizeof(UINT_16)) >= 16); \ + ASSERT((sizeof(au2Rx1Len) / sizeof(UINT_16)) >= 16); \ + *pu2Rx0Num = (UINT_16)pu4Buf[3]; \ + *pu2Rx1Num = (UINT_16)(pu4Buf[3] >> 16); \ + kalMemCopy(au2Rx0Len, &pu4Buf[4], 8); \ + kalMemCopy(au2Rx1Len, &pu4Buf[12], 8); \ +} + +#define HAL_GET_MAILBOX_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4Mailbox0, pu4Mailbox1) \ +{ \ + PUINT_32 pu4Buf = (PUINT_32)pvInBuf; \ + *pu4Mailbox0 = (UINT_16)pu4Buf[21]; \ + *pu4Mailbox1 = (UINT_16)pu4Buf[22]; \ +} + +#define HAL_IS_TX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_TX_DONE_INT) ? TRUE : FALSE) + +#define HAL_IS_RX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)) ? TRUE : FALSE) + +#define HAL_IS_ABNORMAL_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_ABNORMAL_INT) ? TRUE : FALSE) + +#define HAL_IS_FW_OWNBACK_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_FW_OWN_BACK_INT) ? TRUE : FALSE) + +#define HAL_PUT_MAILBOX(prAdapter, u4MboxId, u4Data) \ +{ \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_WR(prAdapter, \ + ((u4MboxId == 0) ? MCR_H2DSM0R : MCR_H2DSM1R), \ + u4Data); \ +} + +#define HAL_GET_MAILBOX(prAdapter, u4MboxId, pu4Data) \ +{ \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_RD(prAdapter, \ + ((u4MboxId == 0) ? MCR_D2HRM0R : MCR_D2HRM1R), \ + pu4Data); \ +} + +#define HAL_SET_MAILBOX_READ_CLEAR(prAdapter, fgEnableReadClear) \ +{ \ + UINT_32 u4Value; \ + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value);\ + HAL_MCR_WR(prAdapter, MCR_WHCR, \ + (fgEnableReadClear) ? \ + (u4Value | WHCR_W_MAILBOX_RD_CLR_EN) : \ + (u4Value & ~WHCR_W_MAILBOX_RD_CLR_EN)); \ + prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear = fgEnableReadClear;\ +} + +#define HAL_GET_MAILBOX_READ_CLEAR(prAdapter) (prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _HAL_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h new file mode 100644 index 0000000000000..b9aa154b097ef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_rx.h @@ -0,0 +1,220 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_rx.h#1 +*/ + +/*! \file "hif_rx.h" + \brief Provide HIF RX Header Information between F/W and Driver + + N/A +*/ + +/* +** Log: hif_rx.h + * + * 09 01 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * follow-ups for HIF_RX_HEADER_T update: + * 1) add TCL + * 2) add RCPI + * 3) add ChannelNumber + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:44:00 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-09 13:59:20 GMT MTK02468 +** Added HIF_RX_HDR parsing macros +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 19:54:54 GMT mtk02752 +** adopt HIF_RX_HEADER_T in new data path +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-29 19:51:19 GMT mtk01084 +** modify FW/ driver interface +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:33:58 GMT mtk01461 +** Add define of HW_APPENED_LEN +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:51:02 GMT mtk01461 +** Rename ENUM_HIF_RX_PKT_TYPE_T +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 12:05:03 GMT mtk01426 +** Remove __KAL_ATTRIB_PACKED__ and add hifDataTypeCheck() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:18:52 GMT mtk01426 +** Add comment to HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:23 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _HIF_RX_H +#define _HIF_RX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/*! HIF_RX_HEADER_T */ +/* DW 0, Byte 1 */ +#define HIF_RX_HDR_PACKET_TYPE_MASK BITS(0, 1) +#define HIF_RX_HDR_SEC_MODE_MASK BITS(2, 5) +#define HIF_RX_HDR_SEC_MODE_OFFSET 2 + +/* DW 1, Byte 0 */ +#define HIF_RX_HDR_HEADER_LEN BITS(2, 7) +#define HIF_RX_HDR_HEADER_LEN_OFFSET 2 +#define HIF_RX_HDR_HEADER_OFFSET_MASK BITS(0, 1) + +/* DW 1, Byte 1 */ +#define HIF_RX_HDR_80211_HEADER_FORMAT BIT(0) +#define HIF_RX_HDR_DO_REORDER BIT(1) +#define HIF_RX_HDR_PAL BIT(2) +#define HIF_RX_HDR_TCL BIT(3) +#define HIF_RX_HDR_NETWORK_IDX_MASK BITS(4, 7) +#define HIF_RX_HDR_NETWORK_IDX_OFFSET 4 + +/* DW 1, Byte 2, 3 */ +#define HIF_RX_HDR_SEQ_NO_MASK BITS(0, 11) +#define HIF_RX_HDR_TID_MASK BITS(12, 14) +#define HIF_RX_HDR_TID_OFFSET 12 +#define HIF_RX_HDR_BAR_FRAME BIT(15) + +#define HIF_RX_HDR_FLAG_AMP_WDS BIT(0) +#define HIF_RX_HDR_FLAG_802_11_FORMAT BIT(1) +#define HIF_RX_HDR_FLAG_BAR_FRAME BIT(2) +#define HIF_RX_HDR_FLAG_DO_REORDERING BIT(3) +#define HIF_RX_HDR_FLAG_CTRL_WARPPER_FRAME BIT(4) + +#define HIF_RX_HW_APPENDED_LEN 4 + +/* For DW 2, Byte 3 - ucHwChannelNum */ +#define HW_CHNL_NUM_MAX_2G4 14 +#define HW_CHNL_NUM_MAX_4G_5G (255 - HW_CHNL_NUM_MAX_2G4) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _HIF_RX_HEADER_T { + UINT_16 u2PacketLen; + UINT_16 u2PacketType; + UINT_8 ucHerderLenOffset; + UINT_8 uc80211_Reorder_PAL_TCL; + UINT_16 u2SeqNoTid; + UINT_8 ucStaRecIdx; + UINT_8 ucRcpi; + UINT_8 ucHwChannelNum; + UINT_8 ucReserved; +} HIF_RX_HEADER_T, *P_HIF_RX_HEADER_T; + +typedef enum _ENUM_HIF_RX_PKT_TYPE_T { + HIF_RX_PKT_TYPE_DATA = 0, + HIF_RX_PKT_TYPE_EVENT, + HIF_RX_PKT_TYPE_TX_LOOPBACK, + HIF_RX_PKT_TYPE_MANAGEMENT, + HIF_RX_PKT_TYPE_NUM +} ENUM_HIF_RX_PKT_TYPE_T, *P_ENUM_HIF_RX_PKT_TYPE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define HIF_RX_HDR_SIZE sizeof(HIF_RX_HEADER_T) + +#define HIF_RX_HDR_GET_80211_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_80211_HEADER_FORMAT) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_REORDER_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_DO_REORDER) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_PAL_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_PAL) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_TCL_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_TCL) ? TRUE : FALSE)) +#define HIF_RX_HDR_GET_NETWORK_IDX(_prHifRxHdr) \ + ((((_prHifRxHdr)->uc80211_Reorder_PAL_TCL) & HIF_RX_HDR_NETWORK_IDX_MASK)\ + >> HIF_RX_HDR_NETWORK_IDX_OFFSET) + +#define HIF_RX_HDR_GET_SEC_MODE(_prHifRxHdr) \ + ((((_prHifRxHdr)->u2PacketType) & HIF_RX_HDR_SEC_MODE_MASK) >> HIF_RX_HDR_SEC_MODE_OFFSET) + +#define HIF_RX_HDR_GET_TID(_prHifRxHdr) \ + ((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_TID_MASK)\ + >> HIF_RX_HDR_TID_OFFSET) +#define HIF_RX_HDR_GET_SN(_prHifRxHdr) \ + (((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_SEQ_NO_MASK) +#define HIF_RX_HDR_GET_BAR_FLAG(_prHifRxHdr) \ + (((((_prHifRxHdr)->u2SeqNoTid) & HIF_RX_HDR_BAR_FRAME) ? TRUE : FALSE)) + +#define HIF_RX_HDR_GET_CHNL_NUM(_prHifRxHdr) \ + ((((_prHifRxHdr)->ucHwChannelNum) > HW_CHNL_NUM_MAX_4G_5G) ? \ + (((_prHifRxHdr)->ucHwChannelNum) - HW_CHNL_NUM_MAX_4G_5G) : \ + ((_prHifRxHdr)->ucHwChannelNum)) + +/* To do: support more bands other than 2.4G and 5G */ +#define HIF_RX_HDR_GET_RF_BAND(_prHifRxHdr) \ + ((((_prHifRxHdr)->ucHwChannelNum) <= HW_CHNL_NUM_MAX_2G4) ? \ + BAND_2G4 : BAND_5G) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static inline VOID hifDataTypeCheck(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this for porting driver to different RTOS. + */ +static inline VOID hifDataTypeCheck(VOID) +{ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_RX_HEADER_T) == 12); + +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h new file mode 100644 index 0000000000000..17252f2c7760c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/hif_tx.h @@ -0,0 +1,214 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/hif_tx.h#1 +*/ + +/* +** Log: hif_tx.h + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill extra information for revised HIF_TX_HEADER. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate + * 2) add packet type for indicating management frames + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * 2. follow MSDN defined behavior when associates to another AP + * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 01 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-10 16:43:40 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-24 19:55:11 GMT mtk02752 +** adopt HIF_TX_HEADER_T in new data path +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-23 17:54:13 GMT mtk02752 +** CMD_HDR_SIZE = (sizeof(WIFI_CMD_T)) to follow up CM's CMD/EVENT documentation +** +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-17 22:41:10 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-17 17:34:07 GMT mtk02752 +** remove HIF_TX_BUFF_COUNT_TC0 (move to nic_tx.h) +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-17 12:14:12 GMT mtk02752 +** add initial value for HIF_TX_BUFF_COUNT_TC5 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-13 13:54:18 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-04 14:11:14 GMT mtk01084 +** modify SW TX data format +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-29 19:51:53 GMT mtk01084 +** modify FW/ driver interface +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-20 12:22:46 GMT mtk01461 +** Add SeqNum field to CMD Header +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:40:52 GMT mtk01461 +** Update the Log Sign +*/ + +#ifndef _HIF_TX_H +#define _HIF_TX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Maximum buffer size for individual HIF TCQ Buffer */ +#define HIF_TX_BUFF_MAX_SIZE 1552 /* Reserved field was not included */ + +/* Maximum buffer count for individual HIF TCQ */ +#define HIF_TX_BUFF_COUNT_TC0 3 +#define HIF_TX_BUFF_COUNT_TC1 3 +#define HIF_TX_BUFF_COUNT_TC2 3 +#define HIF_TX_BUFF_COUNT_TC3 3 +#define HIF_TX_BUFF_COUNT_TC4 2 + +#define TX_HDR_SIZE sizeof(HIF_TX_HEADER_T) + +#define CMD_HDR_SIZE sizeof(WIFI_CMD_T) + +#define CMD_PKT_SIZE_FOR_IMAGE 2048 /* !< 2048 Bytes CMD payload buffer */ + +/*! NIC_HIF_TX_HEADER_T */ +/* DW 0, Byte 0,1 */ +#define HIF_TX_HDR_TX_BYTE_COUNT_MASK BITS(0, 11) +#define HIF_TX_HDR_USER_PRIORITY_OFFSET 12 + +/* DW 0, Byte 2 */ +#define HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK BITS(0, 7) + +/* DW 0, Byte 3 */ +#define HIF_TX_HDR_IP_CSUM BIT(0) +#define HIF_TX_HDR_TCP_CSUM BIT(1) +#define HIF_TX_HDR_RESOURCE_MASK BITS(2, 5) +#define HIF_TX_HDR_RESOURCE_OFFSET 2 +#define HIF_TX_HDR_PACKET_TYPE_MASK BITS(6, 7) +#define HIF_TX_HDR_PACKET_TYPE_OFFSET 6 + +/* DW 1, Byte 0 */ +#define HIF_TX_HDR_WLAN_HEADER_LEN_MASK BITS(0, 5) + +/* DW 1, Byte 1 */ +#define HIF_TX_HDR_FORMAT_ID_MASK BITS(0, 2) +#define HIF_TX_HDR_NETWORK_TYPE_MASK BITS(4, 5) +#define HIF_TX_HDR_NETWORK_TYPE_OFFSET 4 +#define HIF_TX_HDR_FLAG_1X_FRAME_MASK BIT(6) +#define HIF_TX_HDR_FLAG_1X_FRAME_OFFSET 6 +#define HIF_TX_HDR_FLAG_802_11_FORMAT_MASK BIT(7) +#define HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET 7 + +/* DW2, Byte 3 */ +#define HIF_TX_HDR_PS_FORWARDING_TYPE_MASK BITS(0, 1) +#define HIF_TX_HDR_PS_SESSION_ID_MASK BITS(2, 4) +#define HIF_TX_HDR_PS_SESSION_ID_OFFSET 2 +#define HIF_TX_HDR_BURST_END_MASK BIT(5) +#define HIF_TX_HDR_BURST_END_OFFSET 5 + +/* DW3, Byte 1 */ +#define HIF_TX_HDR_NEED_ACK BIT(0) +#define HIF_TX_HDR_BIP BIT(1) +#define HIF_TX_HDR_BASIC_RATE BIT(2) +#define HIF_TX_HDR_NEED_TX_DONE_STATUS BIT(3) +#define HIF_TX_HDR_RTS BIT(4) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _HIF_HW_TX_HEADER_T { + UINT_16 u2TxByteCount; + UINT_8 ucEtherTypeOffset; + UINT_8 ucCSflags; + UINT_8 aucBuffer[0]; +} HIF_HW_TX_HEADER_T, *P_HIF_HW_TX_HEADER_T; + +typedef struct _HIF_TX_HEADER_T { + UINT_16 u2TxByteCount_UserPriority; + UINT_8 ucEtherTypeOffset; + UINT_8 ucResource_PktType_CSflags; + UINT_8 ucWlanHeaderLength; + UINT_8 ucPktFormtId_Flags; + UINT_16 u2LLH; /* for BOW */ + UINT_16 u2SeqNo; /* for BOW */ + UINT_8 ucStaRecIdx; + UINT_8 ucForwardingType_SessionID_Reserved; + UINT_8 ucPacketSeqNo; + UINT_8 ucAck_BIP_BasicRate; + UINT_8 aucReserved[2]; +} HIF_TX_HEADER_T, *P_HIF_TX_HEADER_T; + +typedef enum _ENUM_HIF_TX_PKT_TYPE_T { + HIF_TX_PKT_TYPE_DATA = 0, + HIF_TX_PKT_TYPE_CMD, + HIF_TX_PKT_TYPE_HIF_LOOPBACK, + HIF_TX_PKT_TYPE_MANAGEMENT, + HIF_TX_PKT_TYPE_NUM +} ENUM_HIF_TX_PKT_TYPE_T, *P_ENUM_HIF_TX_PKT_TYPE_T; + +typedef enum _ENUM_HIF_OOB_CTRL_PKT_TYPE_T { + HIF_OOB_CTRL_PKT_TYPE_LOOPBACK = 1, + HIF_OOB_CTRL_PKT_TYP_NUM +} ENUM_HIF_OOB_CTRL_PKT_TYPE_T, *P_ENUM_HIF_OOB_CTRL_PKT_TYPE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define TFCB_FRAME_PAD_TO_DW(u2Length) ALIGN_4(u2Length) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* Kevin: we don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + */ +static inline VOID hif_txDataTypeCheck(VOID); + +static inline VOID hif_txDataTypeCheck(VOID) +{ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_TX_HEADER_T) == 16); + +} + +#endif /*_HIF_TX_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h new file mode 100644 index 0000000000000..ff38d30c3cf2f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mac.h @@ -0,0 +1,2323 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/mac.h#1 +*/ + +/*! \file "mac.h" + \brief Brief description. + + Detail description. +*/ + +/* +** Log: mac.h + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h + * and let the sw structure not align at byte + * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, + * Notice needed update P2P.ko. + * + * 05 06 2011 wh.su + * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send + * the wrong beacon make driver got incorrect support rate set + * Add the length check before access the ie length filed. + * + * 05 06 2011 wh.su + * [WCXRP00000699] [MT6620 Wi-Fi][Driver] Add the ie pointer check for avoid TP-LINK AP send + * the wrong beacon make driver got incorrect support rate set + * adding the length check before processing next ie.. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discover ability support. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Some action frame define is not belong to P2P. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Add some service discovery MAC define, phase I. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 13 2010 cp.wu + * [WCXRP00000256] [MT6620 Wi-Fi][Driver] Eliminate potential issues which is identified by Klockwork + * suppress warning reported by Klockwork. + * + * 11 01 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * revert to previous revision. (this file is not necessary to be changed) + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 02 2010 yuche.tsai + * NULL + * 1. Add P2P MAC define. + * 2. Add scan device found event + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add WFA specific OUI. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P IE ID & Vendor OUI TYPE for P2P. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge MAC.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added OFFSET_BAR_SSC_SN +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:00:24 GMT MTK02468 +** Added offsets and masks for the BA Parameter Set filed +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:26 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _MAC_H +#define _MAC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* 3 --------------- Constants for Ethernet/802.11 MAC --------------- */ +/* MAC Address */ +#define MAC_ADDR_LEN 6 + +#define MAC_ADDR_LOCAL_ADMIN BIT(1) + +#define ETH_P_IPV4 0x0800 +#define ETH_P_IPX 0x8137 /* Novell IPX */ +#define ETH_P_AARP 0x80F3 /* AppleTalk Address Resolution Protocol (AARP) */ +#define ETH_P_IPV6 0x86DD + +#define IP_VERSION_4 4 +#define IP_VERSION_6 6 + +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 17 + +#define IPV4_HDR_IP_IDENTIFICATION_OFFSET 4 +#define IPV4_HDR_IP_PROTOCOL_OFFSET 9 +#define IPV4_HDR_IP_CSUM_OFFSET 10 +#define IPV4_HDR_IP_SRC_ADDR_OFFSET 12 +#define IPV4_HDR_IP_DST_ADDR_OFFSET 16 + +#define IPV6_HDR_IP_PROTOCOL_OFFSET 6 +#define IPV6_HDR_IP_SRC_ADDR_OFFSET 8 +#define IPV6_HDR_IP_DST_ADDR_OFFSET 24 +#define IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET 32 +#define IPV6_HDR_IP_DST_ADDR_MAC_LOW_OFFSET 37 +#define IPV6_PROTOCOL_ICMPV6 0x3A +#define IPV6_ADDR_LEN 16 +#define IPV6_HDR_LEN 40 + +#define ARP_OPERATION_OFFSET 6 +#define ARP_SNEDER_MAC_OFFSET 8 +#define ARP_SENDER_IP_OFFSET 14 +#define ARP_TARGET_MAC_OFFSET 18 +#define ARP_TARGET_IP_OFFSET 24 +#define ARP_OPERATION_REQUEST 0x0001 +#define ARP_OPERATION_RESPONSE 0x0002 + +#define ICMPV6_TYPE_OFFSET 0 +#define ICMPV6_FLAG_OFFSET 4 +#define ICMPV6_TARGET_ADDR_OFFSET 8 +#define ICMPV6_TARGET_LL_ADDR_TYPE_OFFSET 24 +#define ICMPV6_TARGET_LL_ADDR_LEN_OFFSET 25 +#define ICMPV6_TARGET_LL_ADDR_TA_OFFSET 26 + +#define ICMPV6_FLAG_ROUTER_BIT BIT(7) +#define ICMPV6_FLAG_SOLICITED_BIT BIT(6) +#define ICMPV6_FLAG_OVERWRITE_BIT BIT(5) +#define ICMPV6_TYPE_NEIGHBOR_SOLICITATION 0x87 +#define ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT 0x88 + +#define TCP_HDR_TCP_CSUM_OFFSET 16 +#define UDP_HDR_UDP_CSUM_OFFSET 6 + +#define LLC_LEN 8 /* LLC(3) + SNAP(3) + EtherType(2) */ + +#define NULL_MAC_ADDR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#define BC_MAC_ADDR {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} + +/* Ethernet Frame Field Size, in byte */ +#define ETHER_HEADER_LEN 14 +#define ETHER_TYPE_LEN 2 +#define ETHER_MIN_PKT_SZ 60 +#define ETHER_MAX_PKT_SZ 1514 + +/* IEEE 802.11 WLAN Frame Field Size, in byte */ +#define WLAN_MAC_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_HEADER_A4_LEN 30 /* Address 4 included */ +#define WLAN_MAC_HEADER_QOS_LEN 26 /* QoS Control included */ +#define WLAN_MAC_HEADER_QOS_HTC_LEN 30 /* QoS Control and HTC included */ +#define WLAN_MAC_HEADER_A4_QOS_LEN 32 /* Address 4 and QoS Control included */ +#define WLAN_MAC_HEADER_A4_QOS_HTC_LEN 36 /* Address 4, QoS Control and HTC included */ +#define WLAN_MAC_MGMT_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_MGMT_HEADER_HTC_LEN 28 /* HTC included */ + +#define QOS_CTRL_LEN 2 +#define HT_CTRL_LEN 4 + +#define WLAN_MAC_CTS_ACK_LEN (WLAN_MAC_CTS_ACK_FRAME_HEADER_LEN + FCS_LEN) + +/* 6.2.1.1.2 Semantics of the service primitive */ +#define MSDU_MAX_LENGTH 2304 + +/* 7.1.3.3.3 Broadcast BSSID */ +#define BC_BSSID BC_MAC_ADDR + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.3.1.6 Listen Interval field */ +#define DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD 2 /* In unit of AP's DTIM interval, */ +#define DEFAULT_LISTEN_INTERVAL 10 + +/* 7.3.2.1 Broadcast(Wildcard) SSID */ +#define BC_SSID "" +#define BC_SSID_LEN 0 + +/* 7.3.2.2 Data Rate Value */ +#define RATE_1M 2 /* 1M in unit of 500kb/s */ +#define RATE_2M 4 /* 2M */ +#define RATE_5_5M 11 /* 5.5M */ +#define RATE_11M 22 /* 11M */ +#define RATE_22M 44 /* 22M */ +#define RATE_33M 66 /* 33M */ +#define RATE_6M 12 /* 6M */ +#define RATE_9M 18 /* 9M */ +#define RATE_12M 24 /* 12M */ +#define RATE_18M 36 /* 18M */ +#define RATE_24M 48 /* 24M */ +#define RATE_36M 72 /* 36M */ +#define RATE_48M 96 /* 48M */ +#define RATE_54M 108 /* 54M */ +/* 7.3.2.14 BSS membership selector */ +#define RATE_HT_PHY 127 /* BSS Selector - Clause 20. HT PHY */ +#define RATE_MASK BITS(0, 6) /* mask bits for the rate */ +#define RATE_BASIC_BIT BIT(7) /* mask bit for the rate belonging to the BSSBasicRateSet */ + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +/* 9.2.10 DIFS */ +#define DIFS 2 /* 2 x aSlotTime */ + +/* 11.3 STA Authentication and Association */ +#define STA_STATE_1 0 /* Accept Class 1 frames */ +#define STA_STATE_2 1 /* Accept Class 1 & 2 frames */ +#define STA_STATE_3 2 /* Accept Class 1,2 & 3 frames */ + +/* 15.4.8.5 802.11k RCPI-dBm mapping*/ +#define NDBM_LOW_BOUND_FOR_RCPI 110 +#define RCPI_LOW_BOUND 0 +#define RCPI_HIGH_BOUND 220 +#define RCPI_MEASUREMENT_NOT_AVAILABLE 255 + +/* PHY characteristics */ +/* 17.4.4/18.3.3/19.8.4 Slot Time (aSlotTime) */ +#define SLOT_TIME_LONG 20 /* Long Slot Time */ +#define SLOT_TIME_SHORT 9 /* Short Slot Time */ + +#define SLOT_TIME_HR_DSSS SLOT_TIME_LONG /* 802.11b aSlotTime */ +#define SLOT_TIME_OFDM SLOT_TIME_SHORT /* 802.11a aSlotTime(20M Spacing) */ +#define SLOT_TIME_OFDM_10M_SPACING 13 /* 802.11a aSlotTime(10M Spacing) */ +#define SLOT_TIME_ERP_LONG SLOT_TIME_LONG /* 802.11g aSlotTime(Long) */ +#define SLOT_TIME_ERP_SHORT SLOT_TIME_SHORT /* 802.11g aSlotTime(Short) */ + +/* 17.4.4/18.3.3/19.8.4 Contention Window (aCWmin & aCWmax) */ +#define CWMIN_OFDM 15 /* 802.11a aCWmin */ +#define CWMAX_OFDM 1023 /* 802.11a aCWmax */ + +#define CWMIN_HR_DSSS 31 /* 802.11b aCWmin */ +#define CWMAX_HR_DSSS 1023 /* 802.11b aCWmax */ + +#define CWMIN_ERP_0 31 /* 802.11g aCWmin(0) - for only have 1/2/5/11Mbps Rates */ +#define CWMIN_ERP_1 15 /* 802.11g aCWmin(1) */ +#define CWMAX_ERP 1023 /* 802.11g aCWmax */ + +/* Short Inter-Frame Space (aSIFSTime) */ +/* 15.3.3 802.11b aSIFSTime */ +#define SIFS_TIME_HR_DSSS 10 +/* 17.4.4 802.11a aSIFSTime */ +#define SIFS_TIME_OFDM 16 +/* 19.8.4 802.11g aSIFSTime */ +#define SIFS_TIME_ERP 10 + +/* 15.4.6.2 Number of operating channels */ +#define CH_1 0x1 +#define CH_2 0x2 +#define CH_3 0x3 +#define CH_4 0x4 +#define CH_5 0x5 +#define CH_6 0x6 +#define CH_7 0x7 +#define CH_8 0x8 +#define CH_9 0x9 +#define CH_10 0xa +#define CH_11 0xb +#define CH_12 0xc +#define CH_13 0xd +#define CH_14 0xe + +#define MAXIMUM_OPERATION_CHANNEL_LIST 46 + +/* 3 --------------- IEEE 802.11 PICS --------------- */ +/* Annex D - dot11OperationEntry 2 */ +#define DOT11_RTS_THRESHOLD_MIN 0 +#define DOT11_RTS_THRESHOLD_MAX 2347 /* from Windows DDK */ +/* #define DOT11_RTS_THRESHOLD_MAX 3000 // from Annex D */ + +#define DOT11_RTS_THRESHOLD_DEFAULT \ + DOT11_RTS_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 5 */ +#define DOT11_FRAGMENTATION_THRESHOLD_MIN 256 +#define DOT11_FRAGMENTATION_THRESHOLD_MAX 2346 /* from Windows DDK */ +/* #define DOT11_FRAGMENTATION_THRESHOLD_MAX 3000 // from Annex D */ + +#define DOT11_FRAGMENTATION_THRESHOLD_DEFAULT \ + DOT11_FRAGMENTATION_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 6 */ +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MIN 1 +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_DEFAULT 4095 /* 802.11 define 512 */ + /* MT5921 only aceept N <= 4095 */ + +/* Annex D - dot11OperationEntry 7 */ +#define DOT11_RECEIVE_LIFETIME_TU_MIN 1 +#define DOT11_RECEIVE_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_RECEIVE_LIFETIME_TU_DEFAULT 4096 /* 802.11 define 512 */ + +/* Annex D - dot11StationConfigEntry 12 */ +#define DOT11_BEACON_PERIOD_MIN 1 /* TU. */ +#define DOT11_BEACON_PERIOD_MAX 0xffff /* TU. */ +#define DOT11_BEACON_PERIOD_DEFAULT 100 /* TU. */ + +/* Annex D - dot11StationConfigEntry 13 */ +#define DOT11_DTIM_PERIOD_MIN 1 /* TU. */ +#define DOT11_DTIM_PERIOD_MAX 255 /* TU. */ +#define DOT11_DTIM_PERIOD_DEFAULT 1 /* TU. */ + +/* Annex D - dot11RegDomainsSupportValue */ +#define REGULATION_DOMAIN_FCC 0x10 /* FCC (US) */ +#define REGULATION_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define REGULATION_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define REGULATION_DOMAIN_SPAIN 0x31 /* Spain */ +#define REGULATION_DOMAIN_FRANCE 0x32 /* France */ +#define REGULATION_DOMAIN_JAPAN 0x40 /* MKK (Japan) */ +#define REGULATION_DOMAIN_CHINA 0x50 /* China */ +#define REGULATION_DOMAIN_OTHER 0x00 /* Other */ + +/* 3 --------------- IEEE 802.11 MAC header fields --------------- */ +/* 7.1.3.1 Masks for the subfields in the Frame Control field */ +#define MASK_FC_PROTOCOL_VER BITS(0, 1) +#define MASK_FC_TYPE BITS(2, 3) +#define MASK_FC_SUBTYPE BITS(4, 7) +#define MASK_FC_SUBTYPE_QOS_DATA BIT(7) +#define MASK_FC_TO_DS BIT(8) +#define MASK_FC_FROM_DS BIT(9) +#define MASK_FC_MORE_FRAG BIT(10) +#define MASK_FC_RETRY BIT(11) +#define MASK_FC_PWR_MGT BIT(12) +#define MASK_FC_MORE_DATA BIT(13) +#define MASK_FC_PROTECTED_FRAME BIT(14) +#define MASK_FC_ORDER BIT(15) + +#define MASK_FRAME_TYPE (MASK_FC_TYPE | MASK_FC_SUBTYPE) +#define MASK_TO_DS_FROM_DS (MASK_FC_TO_DS | MASK_FC_FROM_DS) + +#define MAX_NUM_OF_FC_SUBTYPES 16 +#define OFFSET_OF_FC_SUBTYPE 4 + +/* 7.1.3.1.2 MAC frame types and subtypes */ +#define MAC_FRAME_TYPE_MGT 0 +#define MAC_FRAME_TYPE_CTRL BIT(2) +#define MAC_FRAME_TYPE_DATA BIT(3) +#define MAC_FRAME_TYPE_QOS_DATA (MAC_FRAME_TYPE_DATA | MASK_FC_SUBTYPE_QOS_DATA) + +#define MAC_FRAME_ASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0000) +#define MAC_FRAME_ASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0010) +#define MAC_FRAME_REASSOC_REQ (MAC_FRAME_TYPE_MGT | 0x0020) +#define MAC_FRAME_REASSOC_RSP (MAC_FRAME_TYPE_MGT | 0x0030) +#define MAC_FRAME_PROBE_REQ (MAC_FRAME_TYPE_MGT | 0x0040) +#define MAC_FRAME_PROBE_RSP (MAC_FRAME_TYPE_MGT | 0x0050) +#define MAC_FRAME_BEACON (MAC_FRAME_TYPE_MGT | 0x0080) +#define MAC_FRAME_ATIM (MAC_FRAME_TYPE_MGT | 0x0090) +#define MAC_FRAME_DISASSOC (MAC_FRAME_TYPE_MGT | 0x00A0) +#define MAC_FRAME_AUTH (MAC_FRAME_TYPE_MGT | 0x00B0) +#define MAC_FRAME_DEAUTH (MAC_FRAME_TYPE_MGT | 0x00C0) +#define MAC_FRAME_ACTION (MAC_FRAME_TYPE_MGT | 0x00D0) +#define MAC_FRAME_ACTION_NO_ACK (MAC_FRAME_TYPE_MGT | 0x00E0) + +#define MAC_FRAME_CONTRL_WRAPPER (MAC_FRAME_TYPE_CTRL | 0x0070) +#define MAC_FRAME_BLOCK_ACK_REQ (MAC_FRAME_TYPE_CTRL | 0x0080) +#define MAC_FRAME_BLOCK_ACK (MAC_FRAME_TYPE_CTRL | 0x0090) +#define MAC_FRAME_PS_POLL (MAC_FRAME_TYPE_CTRL | 0x00A0) +#define MAC_FRAME_RTS (MAC_FRAME_TYPE_CTRL | 0x00B0) +#define MAC_FRAME_CTS (MAC_FRAME_TYPE_CTRL | 0x00C0) +#define MAC_FRAME_ACK (MAC_FRAME_TYPE_CTRL | 0x00D0) +#define MAC_FRAME_CF_END (MAC_FRAME_TYPE_CTRL | 0x00E0) +#define MAC_FRAME_CF_END_CF_ACK (MAC_FRAME_TYPE_CTRL | 0x00F0) + +#define MAC_FRAME_DATA (MAC_FRAME_TYPE_DATA | 0x0000) +#define MAC_FRAME_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0010) +#define MAC_FRAME_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0020) +#define MAC_FRAME_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0030) +#define MAC_FRAME_NULL (MAC_FRAME_TYPE_DATA | 0x0040) +#define MAC_FRAME_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0050) +#define MAC_FRAME_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0060) +#define MAC_FRAME_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x0070) +#define MAC_FRAME_QOS_DATA (MAC_FRAME_TYPE_DATA | 0x0080) +#define MAC_FRAME_QOS_DATA_CF_ACK (MAC_FRAME_TYPE_DATA | 0x0090) +#define MAC_FRAME_QOS_DATA_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00A0) +#define MAC_FRAME_QOS_DATA_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00B0) +#define MAC_FRAME_QOS_NULL (MAC_FRAME_TYPE_DATA | 0x00C0) +#define MAC_FRAME_QOS_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00E0) +#define MAC_FRAME_QOS_CF_ACK_CF_POLL (MAC_FRAME_TYPE_DATA | 0x00F0) + +/* 7.1.3.2 Mask for the AID value in the Duration/ID field */ +#define MASK_DI_DURATION BITS(0, 14) +#define MASK_DI_AID BITS(0, 13) +#define MASK_DI_AID_MSB BITS(14, 15) +#define MASK_DI_CFP_FIXED_VALUE BIT(15) + +/* 7.1.3.4 Masks for the subfields in the Sequence Control field */ +#define MASK_SC_SEQ_NUM BITS(4, 15) +#define MASK_SC_SEQ_NUM_OFFSET 4 +#define MASK_SC_FRAG_NUM BITS(0, 3) +#define INVALID_SEQ_CTRL_NUM 0x000F /* According to 6.2.1.1.2 + * FRAG_NUM won't equal to 15 + */ + +/* 7.1.3.5 QoS Control field */ +#define TID_NUM 16 +#define TID_MASK BITS(0, 3) +#define EOSP BIT(4) +#define ACK_POLICY BITS(5, 6) +#define A_MSDU_PRESENT BIT(7) + +#define MASK_QC_TID BITS(0, 3) +#define MASK_QC_EOSP BIT(4) +#define MASK_QC_EOSP_OFFSET 4 +#define MASK_QC_ACK_POLICY BITS(5, 6) +#define MASK_QC_ACK_POLICY_OFFSET 5 +#define MASK_QC_A_MSDU_PRESENT BIT(7) + +/* 7.1.3.5a HT Control field */ +#define HT_CTRL_LINK_ADAPTATION_CTRL BITS(0, 15) +#define HT_CTRL_CALIBRATION_POSITION BITS(16, 17) +#define HT_CTRL_CALIBRATION_SEQUENCE BITS(18, 19) +#define HT_CTRL_CSI_STEERING BITS(22, 23) +#define HT_CTRL_NDP_ANNOUNCEMENT BIT(24) +#define HT_CTRL_AC_CONSTRAINT BIT(30) +#define HT_CTRL_RDG_MORE_PPDU BIT(31) + +#define LINK_ADAPTATION_CTRL_TRQ BIT(1) +#define LINK_ADAPTATION_CTRL_MAI_MRQ BIT(2) +#define LINK_ADAPTATION_CTRL_MAI_MSI BITS(3, 5) +#define LINK_ADAPTATION_CTRL_MFSI BITS(6, 8) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_CMD BITS(9, 11) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_DATA BITS(12, 15) + +/* 7.1.3.5.3 Ack Policy subfield*/ +#define ACK_POLICY_NORMAL_ACK_IMPLICIT_BA_REQ 0 +#define ACK_POLICY_NO_ACK 1 +#define ACK_POLICY_NO_EXPLICIT_ACK_PSMP_ACK 2 +#define ACK_POLICY_BA 3 + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +#define PSPOLL_FRAME_LEN 16 /* w/o FCS */ + +/* 7.2.7.1 BAR */ +#define OFFSET_BAR_SSC_SN 4 + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +/* 2009.11.30 mtk02468: Moved these definitions to the right place */ +#if 0 +/* Block Ack Parameter Set field */ +#define BA_PARM_BA_POLICY BIT(1) +#define BA_PARM_TID BITS(2, 5) +#define BA_PARM_BUFFER_SIZE BITS(6, 15) +#endif + +#define BA_POLICY_IMMEDIATE BIT(1) + +/* Block Ack Starting Sequence Control field */ +#define BA_START_SEQ_CTL_FRAG_NUM BITS(0, 3) +#define BA_START_SEQ_CTL_SSN BITS(4, 15) + +/* BAR Control field */ +#define BAR_CONTROL_NO_ACK_POLICY BIT(0) +#define BAR_CONTROL_MULTI_TID BIT(1) +#define BAR_CONTROL_COMPRESSED_BA BIT(2) +#define BAR_CONTROL_TID_INFO BITS(12, 15) +#define BAR_CONTROL_TID_INFO_OFFSET 12 + +/* TID Value */ +#define BAR_INFO_TID_VALUE BITS(12, 15) + +#define BAR_COMPRESSED_VARIANT_FRAME_LEN (16 + 4) + +/* 3 --------------- IEEE 802.11 frame body fields --------------- */ +/* 3 Management frame body components (I): Fixed Fields. */ +/* 7.3.1.1 Authentication Algorithm Number field */ +#define AUTH_ALGORITHM_NUM_FIELD_LEN 2 + +#define AUTH_ALGORITHM_NUM_OPEN_SYSTEM 0 /* Open System */ +#define AUTH_ALGORITHM_NUM_SHARED_KEY 1 /* Shared Key */ +#define AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION 2 /* Fast BSS Transition */ + +/* 7.3.1.2 Authentication Transaction Sequence Number field */ +#define AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN 2 +#define AUTH_TRANSACTION_SEQ_1 1 +#define AUTH_TRANSACTION_SEQ_2 2 +#define AUTH_TRANSACTION_SEQ_3 3 +#define AUTH_TRANSACTION_SEQ_4 4 + +/* 7.3.1.3 Beacon Interval field */ +#define BEACON_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.4 Capability Information field */ +#define CAP_INFO_FIELD_LEN 2 +#define CAP_INFO_ESS BIT(0) +#define CAP_INFO_IBSS BIT(1) +#define CAP_INFO_BSS_TYPE (CAP_INFO_ESS | CAP_INFO_IBSS) +#define CAP_INFO_CF_POLLABLE BIT(2) +#define CAP_INFO_CF_POLL_REQ BIT(3) +#define CAP_INFO_CF (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) +#define CAP_INFO_PRIVACY BIT(4) +#define CAP_INFO_SHORT_PREAMBLE BIT(5) +#define CAP_INFO_PBCC BIT(6) +#define CAP_INFO_CH_AGILITY BIT(7) +#define CAP_INFO_SPEC_MGT BIT(8) +#define CAP_INFO_QOS BIT(9) +#define CAP_INFO_SHORT_SLOT_TIME BIT(10) +#define CAP_INFO_APSD BIT(11) +#define CAP_INFO_RESERVED BIT(12) +#define CAP_INFO_DSSS_OFDM BIT(13) +#define CAP_INFO_DELAYED_BLOCK_ACK BIT(14) +#define CAP_INFO_IMM_BLOCK_ACK BIT(15) +/* STA usage of CF-Pollable and CF-Poll Request subfields */ +/* STA: not CF-Pollable */ +#define CAP_CF_STA_NOT_POLLABLE 0x0000 +/* STA: CF-Pollable, not requesting on the CF-Polling list */ +#define CAP_CF_STA_NOT_ON_LIST CAP_INFO_CF_POLL_REQ +/* STA: CF-Pollable, requesting on the CF-Polling list */ +#define CAP_CF_STA_ON_LIST CAP_INFO_CF_POLLABLE +/* STA: CF-Pollable, requesting never to be polled */ +#define CAP_CF_STA_NEVER_POLLED (CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) + +/* AP usage of CF-Pollable and CF-Poll Request subfields */ +/* AP: No point coordinator (PC) */ +#define CAP_CF_AP_NO_PC 0x0000 +/* AP: PC at AP for delivery only (no polling) */ +#define CAP_CF_AP_DELIVERY_ONLY CAP_INFO_CF_POLL_REQ +/* AP: PC at AP for delivery and polling */ +#define CAP_CF_AP_DELIVERY_POLLING CAP_INFO_CF_POLLABLE + +/* 7.3.1.5 Current AP Address field */ +#define CURR_AP_ADDR_FIELD_LEN MAC_ADDR_LEN + +/* 7.3.1.6 Listen Interval field */ +#define LISTEN_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.7 Reason Code field */ +#define REASON_CODE_FIELD_LEN 2 + +#define REASON_CODE_RESERVED 0 /* Reseved */ +#define REASON_CODE_UNSPECIFIED 1 /* Unspecified reason */ +#define REASON_CODE_PREV_AUTH_INVALID 2 /* Previous auth no longer valid */ +#define REASON_CODE_DEAUTH_LEAVING_BSS 3 /* Deauth because sending STA is leaving BSS */ +#define REASON_CODE_DISASSOC_INACTIVITY 4 /* Disassoc due to inactivity */ +#define REASON_CODE_DISASSOC_AP_OVERLOAD 5 /* Disassoc because AP is unable to handle all assoc STAs */ +#define REASON_CODE_CLASS_2_ERR 6 /* Class 2 frame rx from nonauth STA */ +#define REASON_CODE_CLASS_3_ERR 7 /* Class 3 frame rx from nonassoc STA */ +#define REASON_CODE_DISASSOC_LEAVING_BSS 8 /* Disassoc because sending STA is leaving BSS */ +#define REASON_CODE_ASSOC_BEFORE_AUTH 9 /* STA requesting (re)assoc is not auth with responding STA */ +#define REASON_CODE_DISASSOC_PWR_CAP_UNACCEPTABLE 10 /* Disassoc because the info in Power Capability is + unacceptable */ +#define REASON_CODE_DISASSOC_SUP_CHS_UNACCEPTABLE 11 /* Disassoc because the info in Supported Channels is + unacceptable */ +#define REASON_CODE_INVALID_INFO_ELEM 13 /* Invalid information element */ +#define REASON_CODE_MIC_FAILURE 14 /* MIC failure */ +#define REASON_CODE_4_WAY_HANDSHAKE_TIMEOUT 15 /* 4-way handshake timeout */ +#define REASON_CODE_GROUP_KEY_UPDATE_TIMEOUT 16 /* Group key update timeout */ +#define REASON_CODE_DIFFERENT_INFO_ELEM 17 /* Info element in 4-way handshake different from + (Re-)associate request/Probe response/Beacon */ +#define REASON_CODE_MULTICAST_CIPHER_NOT_VALID 18 /* Multicast Cipher is not valid */ +#define REASON_CODE_UNICAST_CIPHER_NOT_VALID 19 /* Unicast Cipher is not valid */ +#define REASON_CODE_AKMP_NOT_VALID 20 /* AKMP is not valid */ +#define REASON_CODE_UNSUPPORTED_RSNE_VERSION 21 /* Unsupported RSNE version */ +#define REASON_CODE_INVALID_RSNE_CAPABILITIES 22 /* Invalid RSNE Capabilities */ +#define REASON_CODE_IEEE_802_1X_AUTH_FAILED 23 /* IEEE 802.1X Authentication failed */ +#define REASON_CODE_CIPHER_REJECT_SEC_POLICY 24 /* Cipher suite rejected because of the security policy */ +#define REASON_CODE_DISASSOC_UNSPECIFIED_QOS 32 /* Disassoc for unspecified, QoS-related reason */ +#define REASON_CODE_DISASSOC_LACK_OF_BANDWIDTH 33 /* Disassoc because QAP lacks sufficient bandwidth + for this QSTA */ +#define REASON_CODE_DISASSOC_ACK_LOST_POOR_CHANNEL 34 /* Disassoc because of too many ACKs lost for AP transmissions + and/or poor channel conditions */ +#define REASON_CODE_DISASSOC_TX_OUTSIDE_TXOP_LIMIT 35 /* Disassoc because QSTA is transmitting outside the limits of + its TXOPs */ +#define REASON_CODE_PEER_WHILE_LEAVING 36 /* QSTA is leaving the QBSS or resetting */ +#define REASON_CODE_PEER_REFUSE_DLP 37 /* Peer does not want to use this mechanism */ +#define REASON_CODE_PEER_SETUP_REQUIRED 38 /* Frames received but a setup is reqired */ +#define REASON_CODE_PEER_TIME_OUT 39 /* Time out */ +#define REASON_CODE_PEER_CIPHER_UNSUPPORTED 45 /* Peer does not support the requested cipher suite */ +#define REASON_CODE_BEACON_TIMEOUT 100 /* for beacon timeout, defined by mediatek */ +#define REASON_CODE_BSS_SECURITY_CHANGE 101 /* for BSS security change, defined by mediatek */ +/* 7.3.1.8 AID field */ +#define AID_FIELD_LEN 2 +#define AID_MASK BITS(0, 13) +#define AID_MSB BITS(14, 15) +#define AID_MIN_VALUE 1 +#define AID_MAX_VALUE 2007 + +/* 7.3.1.9 Status Code field */ +#define STATUS_CODE_FIELD_LEN 2 + +#define STATUS_CODE_RESERVED 0 /* Reserved - Used by TX Auth */ +#define STATUS_CODE_SUCCESSFUL 0 /* Successful */ +#define STATUS_CODE_UNSPECIFIED_FAILURE 1 /* Unspecified failure */ +#define STATUS_CODE_CAP_NOT_SUPPORTED 10 /* Cannot support all requested cap in the Cap Info field */ +#define STATUS_CODE_REASSOC_DENIED_WITHOUT_ASSOC 11 /* Reassoc denied due to inability to confirm that + assoc exists */ +#define STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD 12 /* Assoc denied due to reason outside the scope of this std. */ +#define STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED 13 /* Responding STA does not support the specified + auth algorithm */ +#define STATUS_CODE_AUTH_OUT_OF_SEQ 14 /* Rx an auth frame with auth transaction seq num + out of expected seq */ +#define STATUS_CODE_AUTH_REJECTED_CHAL_FAIL 15 /* Auth rejected because of challenge failure */ +#define STATUS_CODE_AUTH_REJECTED_TIMEOUT 16 /* Auth rejected due to timeout waiting for next frame + in sequence */ +#define STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD 17 /* Assoc denied because AP is unable to handle additional + assoc STAs */ +#define STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED 18 /* Assoc denied due to requesting STA not supporting + all of basic rates */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_PREAMBLE 19 /* Assoc denied due to requesting STA not supporting short + preamble */ +#define STATUS_CODE_ASSOC_DENIED_NO_PBCC 20 /* Assoc denied due to requesting STA not supporting PBCC */ +#define STATUS_CODE_ASSOC_DENIED_NO_CH_AGILITY 21 /* Assoc denied due to requesting STA not supporting channel + agility */ +#define STATUS_CODE_ASSOC_REJECTED_NO_SPEC_MGT 22 /* Assoc rejected because Spectrum Mgt capability is required */ +#define STATUS_CODE_ASSOC_REJECTED_PWR_CAP 23 /* Assoc rejected because the info in Power Capability + is unacceptable */ +#define STATUS_CODE_ASSOC_REJECTED_SUP_CHS 24 /* Assoc rejected because the info in Supported Channels + is unacceptable */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 /* Assoc denied due to requesting STA not supporting + short slot time */ +#define STATUS_CODE_ASSOC_DENIED_NO_DSSS_OFDM 26 /* Assoc denied due to requesting STA not supporting + DSSS-OFDM */ +#if CFG_SUPPORT_802_11W +#define STATUS_CODE_ASSOC_REJECTED_TEMPORARILY 30 /* IEEE 802.11w, Assoc denied due to the SA query */ +#define STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 /* IEEE 802.11w, Assoc denied due to the MFP select + policy */ +#endif +#define STATUS_CODE_UNSPECIFIED_QOS_FAILURE 32 /* Unspecified, QoS-related failure */ +#define STATUS_CODE_ASSOC_DENIED_BANDWIDTH 33 /* Assoc denied due to insufficient bandwidth to handle another + QSTA */ +#define STATUS_CODE_ASSOC_DENIED_POOR_CHANNEL 34 /* Assoc denied due to excessive frame loss rates and/or poor + channel conditions */ +#define STATUS_CODE_ASSOC_DENIED_NO_QOS_FACILITY 35 /* Assoc denied due to requesting STA not supporting QoS + facility */ +#define STATUS_CODE_REQ_DECLINED 37 /* Request has been declined */ +#define STATUS_CODE_REQ_INVALID_PARAMETER_VALUE 38 /* Request has not been successful as one or more parameters + have invalid values */ +#define STATUS_CODE_REQ_NOT_HONORED_TSPEC 39 /* TS not created because request cannot be honored. + Suggested TSPEC provided. */ +#define STATUS_CODE_INVALID_INFO_ELEMENT 40 /* Invalid information element */ +#define STATUS_CODE_INVALID_GROUP_CIPHER 41 /* Invalid group cipher */ +#define STATUS_CODE_INVALID_PAIRWISE_CIPHER 42 /* Invalid pairwise cipher */ +#define STATUS_CODE_INVALID_AKMP 43 /* Invalid AKMP */ +#define STATUS_CODE_UNSUPPORTED_RSN_IE_VERSION 44 /* Unsupported RSN information element version */ +#define STATUS_CODE_INVALID_RSN_IE_CAP 45 /* Invalid RSN information element capabilities */ +#define STATUS_CODE_CIPHER_SUITE_REJECTED 46 /* Cipher suite rejected because of security policy */ +#define STATUS_CODE_REQ_NOT_HONORED_TS_DELAY 47 /* TS not created because request cannot be honored. + Attempt to create a TS later. */ +#define STATUS_CODE_DIRECT_LINK_NOT_ALLOWED 48 /* Direct Link is not allowed in the BSS by policy */ +#define STATUS_CODE_DESTINATION_STA_NOT_PRESENT 49 /* Destination STA is not present within this QBSS */ +#define STATUS_CODE_DESTINATION_STA_NOT_QSTA 50 /* Destination STA is not a QSTA */ +#define STATUS_CODE_ASSOC_DENIED_LARGE_LIS_INTERVAL 51 /* Association denied because the ListenInterval is too large */ + +/* proprietary definition of reserved field of Status Code */ +#define STATUS_CODE_JOIN_FAILURE 0xFFF0 /* Join failure */ +#define STATUS_CODE_JOIN_TIMEOUT 0xFFF1 /* Join timeout */ +#define STATUS_CODE_AUTH_TIMEOUT 0xFFF2 /* Authentication timeout */ +#define STATUS_CODE_ASSOC_TIMEOUT 0xFFF3 /* (Re)Association timeout */ +#define STATUS_CODE_CCX_CCKM_REASSOC_FAILURE 0xFFF4 /* CCX CCKM reassociation failure */ + +/* 7.3.1.10 Timestamp field */ +#define TIMESTAMP_FIELD_LEN 8 + +/* 7.3.1.11 Category of Action field */ +#define CATEGORY_SPEC_MGT 0 +#define CATEGORY_QOS_ACTION 1 /* QoS action */ +#define CATEGORY_DLS_ACTION 2 /* Direct Link Protocol (DLP) action */ +#define CATEGORY_BLOCK_ACK_ACTION 3 /* Block ack action */ +#define CATEGORY_PUBLIC_ACTION 4 /* Public action */ +#define CATEGORY_RM_ACTION 5 /* Radio measurement action */ +#define CATEGORY_HT_ACTION 7 +#if CFG_SUPPORT_802_11W +#define CATEGORY_SA_QUERT_ACTION 8 +#endif +#define CATEGORY_WNM_ACTION 10 /* 802.11v Wireless Network Management */ +#define CATEGORY_UNPROTECTED_WNM_ACTION 11 /* 802.11v Wireless Network Management */ +#define CATEGORY_WME_MGT_NOTIFICATION 17 /* WME management notification */ +#define CATEGORY_VENDOR_SPECIFIC_ACTION 127 + +/* 7.3.1.14 Block Ack Parameter Set field */ +#define BA_PARAM_SET_ACK_POLICY_MASK BIT(1) +#define BA_PARAM_SET_ACK_POLICY_MASK_OFFSET 1 +#define BA_PARAM_SET_TID_MASK BITS(2, 5) +#define BA_PARAM_SET_TID_MASK_OFFSET 2 +#define BA_PARAM_SET_BUFFER_SIZE_MASK BITS(6, 15) +#define BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET 6 + +#define BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA 1 +#define BA_PARAM_SET_ACK_POLICY_DELAYED_BA 0 + +/* 3 Management frame body components (II): Information Elements. */ +/* 7.3.2 Element IDs of information elements */ +#define ELEM_HDR_LEN 2 + +#define ELEM_ID_SSID 0 /* SSID */ +#define ELEM_ID_SUP_RATES 1 /* Supported rates */ +#define ELEM_ID_FH_PARAM_SET 2 /* FH parameter set */ +#define ELEM_ID_DS_PARAM_SET 3 /* DS parameter set */ +#define ELEM_ID_CF_PARAM_SET 4 /* CF parameter set */ +#define ELEM_ID_TIM 5 /* TIM */ +#define ELEM_ID_IBSS_PARAM_SET 6 /* IBSS parameter set */ +#define ELEM_ID_COUNTRY_INFO 7 /* Country information */ +#define ELEM_ID_HOPPING_PATTERN_PARAM 8 /* Hopping pattern parameters */ +#define ELEM_ID_HOPPING_PATTERN_TABLE 9 /* Hopping pattern table */ +#define ELEM_ID_REQUEST 10 /* Request */ +#define ELEM_ID_BSS_LOAD 11 /* BSS load */ +#define ELEM_ID_EDCA_PARAM_SET 12 /* EDCA parameter set */ +#define ELEM_ID_TSPEC 13 /* Traffic specification (TSPEC) */ +#define ELEM_ID_TCLAS 14 /* Traffic classification (TCLAS) */ +#define ELEM_ID_SCHEDULE 15 /* Schedule */ +#define ELEM_ID_CHALLENGE_TEXT 16 /* Challenge text */ + +#define ELEM_ID_PWR_CONSTRAINT 32 /* Power constraint */ +#define ELEM_ID_PWR_CAP 33 /* Power capability */ +#define ELEM_ID_TPC_REQ 34 /* TPC request */ +#define ELEM_ID_TPC_REPORT 35 /* TPC report */ +#define ELEM_ID_SUP_CHS 36 /* Supported channels */ +#define ELEM_ID_CH_SW_ANNOUNCEMENT 37 /* Channel switch announcement */ +#define ELEM_ID_MEASUREMENT_REQ 38 /* Measurement request */ +#define ELEM_ID_MEASUREMENT_REPORT 39 /* Measurement report */ +#define ELEM_ID_QUIET 40 /* Quiet */ +#define ELEM_ID_IBSS_DFS 41 /* IBSS DFS */ +#define ELEM_ID_ERP_INFO 42 /* ERP information */ +#define ELEM_ID_TS_DELAY 43 /* TS delay */ +#define ELEM_ID_TCLAS_PROCESSING 44 /* TCLAS processing */ +#define ELEM_ID_HT_CAP 45 /* HT Capabilities subelement */ +#define ELEM_ID_QOS_CAP 46 /* QoS capability */ +#define ELEM_ID_RSN 48 /* RSN IE */ +#define ELEM_ID_EXTENDED_SUP_RATES 50 /* Extended supported rates */ +#define ELEM_ID_TIMEOUT_INTERVAL 56 /* 802.11w SA Timeout interval */ +#define ELEM_ID_SUP_OPERATING_CLASS 59 /* Supported Operating Classes */ +#define ELEM_ID_HT_OP 61 /* HT Operation */ +#define ELEM_ID_SCO 62 /* Secondary Channel Offset */ +#define ELEM_ID_RRM_ENABLED_CAP 70 /* Radio Resource Management Enabled Capabilities */ +#define ELEM_ID_20_40_BSS_COEXISTENCE 72 /* 20/40 BSS Coexistence */ +#define ELEM_ID_20_40_INTOLERANT_CHNL_REPORT 73 /* 20/40 BSS Intolerant Channel Report */ +#define ELEM_ID_OBSS_SCAN_PARAMS 74 /* Overlapping BSS Scan Parameters */ +#define ELEM_ID_INTERWORKING 107 /* Interworking with External Network */ +#define ELEM_ID_ADVERTISEMENT_PROTOCOL 108 /* Advertisement Protocol */ +#define ELEM_ID_ROAMING_CONSORTIUM 111 /* Roaming Consortium */ +#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ + +#define ELEM_ID_VENDOR 221 /* Vendor specific IE */ +#define ELEM_ID_WPA ELEM_ID_VENDOR /* WPA IE */ +#define ELEM_ID_WMM ELEM_ID_VENDOR /* WMM IE */ +#define ELEM_ID_P2P ELEM_ID_VENDOR /* WiFi Direct */ +#define ELEM_ID_WFD ELEM_ID_VENDOR /* WiFi Direct */ +#define ELEM_ID_WSC ELEM_ID_VENDOR /* WSC IE */ + +#define ELEM_ID_RESERVED 255 /* Reserved */ + +/* 7.3.2.1 SSID element */ +#define ELEM_MAX_LEN_SSID 32 + +/* 7.3.2.2 Supported Rates */ +#define ELEM_MAX_LEN_SUP_RATES 8 + +/* 7.3.2.4 DS Parameter Set */ +#define ELEM_MAX_LEN_DS_PARAMETER_SET 1 + +/* 7.3.2.5 CF Parameter Set */ +#define ELEM_CF_PARM_LEN 8 + +/* 7.3.2.6 TIM */ +#define ELEM_MIX_LEN_TIM 4 +#define ELEM_MAX_LEN_TIM 254 + +/* 7.3.2.7 IBSS Parameter Set element */ +#define ELEM_MAX_LEN_IBSS_PARAMETER_SET 2 + +/* 7.3.2.8 Challenge Text element */ +#define ELEM_MIN_LEN_CHALLENGE_TEXT 1 +#define ELEM_MAX_LEN_CHALLENGE_TEXT 253 + +/* 7.3.2.9 Country Information element */ +/* Country IE should contain at least 3-bytes country code string and one subband triplet. */ +#define ELEM_MIN_LEN_COUNTRY_INFO 6 + +#define ELEM_ID_COUNTRY_INFO_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_SUBBAND_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_REGULATORY_TRIPLET_LEN_FIXED 3 + +/* 7.3.2.13 ERP Information element */ +#define ELEM_MAX_LEN_ERP 1 +/* -- bits in the ERP Information element */ +#define ERP_INFO_NON_ERP_PRESENT BIT(0) /* NonERP_Present bit */ +#define ERP_INFO_USE_PROTECTION BIT(1) /* Use_Protection bit */ +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) /* Barker_Preamble_Mode bit */ + +/* 7.3.2.14 Extended Supported Rates */ +#define ELEM_MAX_LEN_EXTENDED_SUP_RATES 255 + +#if CFG_SUPPORT_DFS +/* 7.3.2.19 Supported Channels element */ +#define ELEM_MAX_LEN_SUPPORTED_CHANNELS 7 +#endif + +/* 7.3.2.21 Measurement Request element */ +#define ELEM_RM_TYPE_BASIC_REQ 0 +#define ELEM_RM_TYPE_CCA_REQ 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REQ 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REQ 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REQ 4 +#define ELEM_RM_TYPE_BEACON_REQ 5 +#define ELEM_RM_TYPE_FRAME_REQ 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REQ 7 +#define ELEM_RM_TYPE_LCI_REQ 8 +#define ELEM_RM_TYPE_TS_REQ 9 +#define ELEM_RM_TYPE_MEASURE_PAUSE_REQ 255 + +/* 7.3.2.22 Measurement Report element */ +#define ELEM_RM_TYPE_BASIC_REPORT 0 +#define ELEM_RM_TYPE_CCA_REPORT 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REPORT 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REPORT 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REPORT 4 +#define ELEM_RM_TYPE_BEACON_REPORT 5 +#define ELEM_RM_TYPE_FRAME_REPORT 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REPORT 7 +#define ELEM_RM_TYPE_LCI_REPORT 8 +#define ELEM_RM_TYPE_TS_REPORT 9 +/*Auto Channel Selection*/ +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +#define ELEM_RM_TYPE_ACS_CHN 1 +#define ELEM_RM_TYPE_LTE_CHN 2 +#endif + +/* 7.3.2.25 RSN information element */ +#define ELEM_MAX_LEN_WPA 34 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_RSN 38 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_WAPI 38 /* one pairwise, one AKM suite, one BKID */ +#define ELEM_MAX_LEN_WSC 200 /* one pairwise, one AKM suite, one BKID */ + +#if CFG_SUPPORT_802_11W +#define ELEM_WPA_CAP_MFPR BIT(6) +#define ELEM_WPA_CAP_MFPC BIT(7) +#endif + +/* 7.3.2.27 Extended Capabilities information element */ +#define ELEM_EXT_CAP_20_40_COEXIST_SUPPORT BIT(0) +#define ELEM_EXT_CAP_PSMP_CAP BIT(4) +#define ELEM_EXT_CAP_SERVICE_INTERVAL_GRANULARITY BIT(5) +#define ELEM_EXT_CAP_SCHEDULE_PSMP BIT(6) + +#define ELEM_EXT_CAP_BSS_TRANSITION_BIT 19 +#define ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT 27 +#define ELEM_EXT_CAP_INTERWORKING_BIT 31 +#define ELEM_EXT_CAP_WNM_NOTIFICATION_BIT 46 + +#if CFG_SUPPORT_HOTSPOT_2_0 +#define ELEM_MAX_LEN_EXT_CAP (6) +#else +#define ELEM_MAX_LEN_EXT_CAP (3 - ELEM_HDR_LEN) +#endif + +/* 7.3.2.30 TSPEC element */ +#define TS_INFO_TRAFFIC_TYPE_MASK BIT(0) /* WMM: 0 (Asynchronous TS of low-duty cycles) */ +#define TS_INFO_TID_OFFSET 1 +#define TS_INFO_TID_MASK BITS(1, 4) +#define TS_INFO_DIRECTION_OFFSET 5 +#define TS_INFO_DIRECTION_MASK BITS(5, 6) +#define TS_INFO_ACCESS_POLICY_OFFSET 7 +#define TS_INFO_ACCESS_POLICY_MASK BITS(7, 8) +#define TS_INFO_AGGREGATION_MASK BIT(9) /* WMM: 0 */ +#define TS_INFO_APSD_MASK BIT(10) +#define TS_INFO_UP_OFFSET 11 +#define TS_INFO_UP_MASK BITS(11, 13) +#define TS_INFO_ACK_POLICY_OFFSET 14 +#define TS_INFO_ACK_POLICY_MASK BITS(14, 15) +#define TS_INFO_SCHEDULE_MASK 16 + +/* 7.3.2.56 HT capabilities element */ +#define ELEM_MAX_LEN_HT_CAP (28 - ELEM_HDR_LEN) /* sizeof(IE_HT_CAP_T)-2 */ + +/* 7.3.2.56.2 HT capabilities Info field */ +#define HT_CAP_INFO_LDPC_CAP BIT(0) +#define HT_CAP_INFO_SUP_CHNL_WIDTH BIT(1) +#define HT_CAP_INFO_SM_POWER_SAVE BITS(2, 3) +#define HT_CAP_INFO_HT_GF BIT(4) +#define HT_CAP_INFO_SHORT_GI_20M BIT(5) +#define HT_CAP_INFO_SHORT_GI_40M BIT(6) +#define HT_CAP_INFO_TX_STBC BIT(7) +#define HT_CAP_INFO_RX_STBC BITS(8, 9) +#define HT_CAP_INFO_HT_DELAYED_BA BIT(10) +#define HT_CAP_INFO_MAX_AMSDU_LEN BIT(11) +#define HT_CAP_INFO_DSSS_CCK_IN_40M BIT(12) +#define HT_CAP_INFO_40M_INTOLERANT BIT(14) +#define HT_CAP_INFO_LSIG_TXOP_SUPPORT BIT(15) + +#define HT_CAP_INFO_RX_STBC_NO_SUPPORTED 0 +#define HT_CAP_INFO_RX_STBC_1_SS BIT(8) +#define HT_CAP_INFO_RX_STBC_2_SS BIT(9) +#define HT_CAP_INFO_RX_STBC_3_SS HT_CAP_INFO_RX_STBC + +/* 7.3.2.56.3 A-MPDU Parameters field */ +#define AMPDU_PARAM_MAX_AMPDU_LEN_EXP BITS(0, 1) +#define AMPDU_PARAM_MIN_START_SPACING BITS(2, 4) + +#define AMPDU_PARAM_MAX_AMPDU_LEN_8K 0 +#define AMPDU_PARAM_MAX_AMPDU_LEN_16K BIT(0) +#define AMPDU_PARAM_MAX_AMPDU_LEN_32K BIT(1) +#define AMPDU_PARAM_MAX_AMPDU_LEN_64K BITS(0, 1) + +#define AMPDU_PARAM_MSS_NO_RESTRICIT 0 +#define AMPDU_PARAM_MSS_1_4_US BIT(2) +#define AMPDU_PARAM_MSS_1_2_US BIT(3) +#define AMPDU_PARAM_MSS_1_US BITS(2, 3) +#define AMPDU_PARAM_MSS_2_US BIT(4) +#define AMPDU_PARAM_MSS_4_US (BIT(4) | BIT(2)) +#define AMPDU_PARAM_MSS_8_US (BIT(4) | BIT(3)) +#define AMPDU_PARAM_MSS_16_US BITS(2, 4) + +/* 7.3.2.56.4 Supported MCS Set field (TX rate: octects 12~15) */ +#define SUP_MCS_TX_SET_DEFINED BIT(0) +#define SUP_MCS_TX_RX_SET_NOT_EQUAL BIT(1) +#define SUP_MCS_TX_MAX_NUM_SS BITS(2, 3) +#define SUP_MCS_TX_UNEQUAL_MODULATION BIT(4) + +#define SUP_MCS_TX_MAX_NUM_1_SS 0 +#define SUP_MCS_TX_MAX_NUM_2_SS BIT(2) +#define SUP_MCS_TX_MAX_NUM_3_SS BIT(3) +#define SUP_MCS_TX_MAX_NUM_4_SS BITS(2, 3) + +#define SUP_MCS_RX_BITMASK_OCTET_NUM 10 +#define SUP_MCS_RX_DEFAULT_HIGHEST_RATE 0 /* Not specify */ + +/* 7.3.2.56.5 HT Extended Capabilities field */ +#define HT_EXT_CAP_PCO BIT(0) +#define HT_EXT_CAP_PCO_TRANSITION_TIME BITS(1, 2) +#define HT_EXT_CAP_MCS_FEEDBACK BITS(8, 9) +#define HT_EXT_CAP_HTC_SUPPORT BIT(10) +#define HT_EXT_CAP_RD_RESPONDER BIT(11) + +#define HT_EXT_CAP_PCO_TRANS_TIME_NONE 0 +#define HT_EXT_CAP_PCO_TRANS_TIME_400US BIT(1) +#define HT_EXT_CAP_PCO_TRANS_TIME_1_5MS BIT(2) +#define HT_EXT_CAP_PCO_TRANS_TIME_5MS BITS(1, 2) + +#define HT_EXT_CAP_MCS_FEEDBACK_NO_FB 0 +#define HT_EXT_CAP_MCS_FEEDBACK_UNSOLICITED BIT(9) +#define HT_EXT_CAP_MCS_FEEDBACK_BOTH BITS(8, 9) + +/* 7.3.2.56.6 Transmit Beamforming Capabilities field */ + +/* 7.3.2.56.7 Antenna Selection Capability field */ +#define ASEL_CAP_CAPABLE BIT(0) +#define ASEL_CAP_CSI_FB_BY_TX_ASEL_CAPABLE BIT(1) +#define ASEL_CAP_ANT_INDICES_FB_BY_TX_ASEL_CAPABLE BIT(2) +#define ASEL_CAP_EXPLICIT_CSI_FB_CAPABLE BIT(3) +#define ASEL_CAP_ANT_INDICES_CAPABLE BIT(4) +#define ASEL_CAP_RX_ASEL_CAPABLE BIT(5) +#define ASEL_CAP_TX_SOUNDING_CAPABLE BIT(6) + +/* 7.3.2.57 HT Operation element */ +#define ELEM_MAX_LEN_HT_OP (24 - ELEM_HDR_LEN) /* sizeof(IE_HT_OP_T)-2 */ + +#define HT_OP_INFO1_SCO BITS(0, 1) +#define HT_OP_INFO1_STA_CHNL_WIDTH BIT(2) +#define HT_OP_INFO1_RIFS_MODE BIT(3) + +#define HT_OP_INFO2_HT_PROTECTION BITS(0, 1) +#define HT_OP_INFO2_NON_GF_HT_STA_PRESENT BIT(2) +#define HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT BIT(4) + +#define HT_OP_INFO3_DUAL_BEACON BIT(6) +#define HT_OP_INFO3_DUAL_CTS_PROTECTION BIT(7) +#define HT_OP_INFO3_STBC_BEACON BIT(8) +#define HT_OP_INFO3_LSIG_TXOP_FULL_SUPPORT BIT(9) +#define HT_OP_INFO3_PCO_ACTIVE BIT(10) +#define HT_OP_INFO3_PCO_PHASE BIT(11) + +/* 7.3.2.59 OBSS Scan Parameter element */ +#define ELEM_MAX_LEN_OBSS_SCAN (16 - ELEM_HDR_LEN) + +/* 7.3.2.60 20/40 BSS Coexistence element */ +#define ELEM_MAX_LEN_20_40_BSS_COEXIST (3 - ELEM_HDR_LEN) + +#define BSS_COEXIST_INFO_REQ BIT(0) +#define BSS_COEXIST_40M_INTOLERANT BIT(1) +#define BSS_COEXIST_20M_REQ BIT(2) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ BIT(3) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_GRANT BIT(4) + +/* 802.11u 7.3.2.92 Interworking IE */ +#define ELEM_MAX_LEN_INTERWORKING (11 - ELEM_HDR_LEN) + +/* 802.11u 7.3.2.93 Advertisement Protocol IE */ +#define ELEM_MAX_LEN_ADV_PROTOCOL (4 - ELEM_HDR_LEN) + +/* 802.11u 7.3.2.96 Roaming Consortium IE */ +#define ELEM_MAX_LEN_ROAMING_CONSORTIUM (19 - ELEM_HDR_LEN) + +#define IW_IE_LENGTH_ANO 1 +#define IW_IE_LENGTH_ANO_VENUE 3 +#define IW_IE_LENGTH_ANO_HESSID 7 +#define IW_IE_LENGTH_ANO_VENUE_HESSID 9 + +/* 3 Management frame body components (III): 7.4 Action frame format details. */ +/* 7.4.1 Spectrum Measurement Action frame details */ +#define ACTION_MEASUREMENT_REQ 0 /* Spectrum measurement request */ +#define ACTION_MEASUREMENT_REPORT 1 /* Spectrum measurement report */ +#define ACTION_TPC_REQ 2 /* TPC request */ +#define ACTION_TPC_REPORT 3 /* TPC report */ +#define ACTION_CHNL_SWITCH 4 /* Channel Switch Announcement */ + +/* 7.4.2 QoS Action frame details */ +#define ACTION_ADDTS_REQ 0 /* ADDTS request */ +#define ACTION_ADDTS_RSP 1 /* ADDTS response */ +#define ACTION_DELTS 2 /* DELTS */ +#define ACTION_SCHEDULE 3 /* Schedule */ + +#define ACTION_ADDTS_REQ_FRAME_LEN (24+3+63) /* WMM TSPEC IE: 63 */ +#define ACTION_ADDTS_RSP_FRAME_LEN (24+4+63) /* WMM Status Code: 1; WMM TSPEC IE: 63 */ + +/* 7.4.3 DLS Action frame details */ +#define ACTION_DLS_REQ 0 /* DLS request */ +#define ACTION_DLS_RSP 1 /* DLS response */ +#define ACTION_DLS_TEARDOWN 2 /* DLS teardown */ + +/* 7.4.4 Block ack Action frame details */ +#define ACTION_ADDBA_REQ 0 /* ADDBA request */ +#define ACTION_ADDBA_RSP 1 /* ADDBA response */ +#define ACTION_DELBA 2 /* DELBA */ + +#define ACTION_ADDBA_REQ_FRAME_LEN (24+9) +#define ACTION_ADDBA_RSP_FRAME_LEN (24+9) + +#define ACTION_DELBA_INITIATOR_MASK BIT(11) +#define ACTION_DELBA_TID_MASK BITS(12, 15) +#define ACTION_DELBA_TID_OFFSET 12 +#define ACTION_DELBA_FRAME_LEN (24+6) + +/* 7.4.6 Radio Measurement Action frame details */ +#define ACTION_RM_REQ 0 /* Radio measurement request */ +#define ACTION_RM_REPORT 1 /* Radio measurement report */ +#define ACTION_LM_REQ 2 /* Link measurement request */ +#define ACTION_LM_REPORT 3 /* Link measurement report */ +#define ACTION_NEIGHBOR_REPORT_REQ 4 /* Neighbor report request */ +#define ACTION_NEIGHBOR_REPORT_RSP 5 /* Neighbor report response */ + +/* 7.4.7 Public Action frame details */ +#define ACTION_PUBLIC_20_40_COEXIST 0 /* 20/40 BSS coexistence */ + +#if CFG_SUPPORT_802_11W +/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +#define ACTION_SA_QUERY_REQUEST 0 +#define ACTION_SA_QUERY_RESPONSE 1 + +#define ACTION_SA_QUERY_TR_ID_LEN 2 + +/* Timeout Interval Type */ +#define ACTION_SA_TIMEOUT_REASSOC_DEADLINE 1 +#define ACTION_SA_TIMEOUT_KEY_LIFETIME 2 +#define ACTION_SA_TIMEOUT_ASSOC_COMEBACK 3 +#endif + +/* 7.4.10.1 HT action frame details */ +#define ACTION_HT_NOTIFY_CHANNEL_WIDTH 0 /* Notify Channel Width */ +#define ACTION_HT_SM_POWER_SAVE 1 /* SM Power Save */ +#define ACTION_HT_PSMP 2 /* PSMP */ +#define ACTION_HT_SET_PCO_PHASE 3 /* Set PCO Phase */ +#define ACTION_HT_CSI 4 /* CSI */ +#define ACTION_HT_NON_COMPRESSED_BEAMFORM 5 /* Non-compressed Beamforming */ +#define ACTION_HT_COMPRESSED_BEAMFORM 6 /* Compressed Beamforming */ +#define ACTION_HT_ANT_SEL_INDICES_FB 7 /* Antenna Selection Indices Feedback */ + +/* 802.11v Wireless Network Management */ +#define ACTION_WNM_TIMING_MEASUREMENT_REQUEST 27 + +#define ACTION_UNPROTECTED_WNM_TIM 0 +#define ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT 1 + +#define ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN 12 + +/* 3 --------------- WFA frame body fields --------------- */ +#define VENDOR_OUI_WFA { 0x00, 0x50, 0xF2 } +#define VENDOR_OUI_WFA_SPECIFIC { 0x50, 0x6F, 0x9A } +#define VENDOR_OUI_TYPE_WPA 1 +#define VENDOR_OUI_TYPE_WMM 2 +#define VENDOR_OUI_TYPE_WPS 4 +#define VENDOR_OUI_TYPE_P2P 9 +#define VENDOR_OUI_TYPE_WFD 10 +#define VENDOR_OUI_TYPE_HS20 16 + +#define VENDOR_OUI_TYPE_LEN 4 /* Length of OUI and Type */ + +/* VERSION(2 octets for WPA) / SUBTYPE(1 octet)-VERSION(1 octet) fields for WMM in WFA IE */ +#define VERSION_WPA 0x0001 /* Little Endian Format */ +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_INFO 0x0100 +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_PARAM 0x0101 + +/* SUBTYPE(1 octet) for WMM */ +#define VENDOR_OUI_SUBTYPE_WMM_INFO 0x00 /* WMM Spec version 1.1 */ +#define VENDOR_OUI_SUBTYPE_WMM_PARAM 0x01 +#define VENDOR_OUI_SUBTYPE_WMM_TSPEC 0x02 + +/* VERSION(1 octet) for WMM */ +#define VERSION_WMM 0x01 /* WMM Spec version 1.1 */ + +/* WMM-2.1.6 QoS Control Field */ +#define WMM_QC_UP_MASK BITS(0, 2) +#define WMM_QC_EOSP BIT(4) +#define WMM_QC_ACK_POLICY_MASK BITS(5, 6) +#define WMM_QC_ACK_POLICY_OFFSET 5 +#define WMM_QC_ACK_POLICY_ACKNOWLEDGE 0 +#define WMM_QC_ACK_POLICY_NOT_ACKNOWLEDGE (1 << WMM_QC_ACK_POLICY_OFFSET) + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE 6 + +/* HOTSPOT 2.0 Indication IE*/ +#define ELEM_MAX_LEN_HS20_INDICATION 5 +#define ELEM_MIN_LEN_HS20_INDICATION 4 + +/* Hotspot Configuration*/ +#define ELEM_HS_CONFIG_DGAF_DISABLED_MASK BIT(0) /* Downstream Group-Addressed Forwarding */ + +/* 3 Control frame body */ +/* 7.2.1.7 BlockAckReq */ +#define CTRL_BAR_BAR_CONTROL_OFFSET 16 +#define CTRL_BAR_BAR_INFORMATION_OFFSET 18 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack(1) +#endif + +typedef struct _LLC_SNAP_HEADER_T { + UINT_8 ucDSAP; + UINT_8 ucSSAP; + UINT_8 ucControl; + UINT_8 aucCode[3]; + UINT_16 u2Type; +} __KAL_ATTRIB_PACKED__ LLC_SNAP_HEADER_T, *P_LLC_SNAP_HEADER_T; + +/* 3 MAC Header. */ +/* Ethernet Frame Header */ +typedef struct _ETH_FRAME_HEADER_T { + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_16 u2TypeLen; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_HEADER_T, *P_ETH_FRAME_HEADER_T; + +/* Ethernet Frame Structure */ +typedef struct _ETH_FRAME_T { + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_16 u2TypeLen; + UINT_8 aucData[1]; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_T, *P_ETH_FRAME_T; + +/* IEEE 802.11 WLAN Frame Structure */ +/* WLAN MAC Header (without Address 4 and QoS Control fields) */ +typedef struct _WLAN_MAC_HEADER_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_T, *P_WLAN_MAC_HEADER_T; + +/* WLAN MAC Header (QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_QOS_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_QOS_T, *P_WLAN_MAC_HEADER_QOS_T; + +/* WLAN MAC Header (HT Control fields included) */ +typedef struct _WLAN_MAC_HEADER_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_16 u2QosCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_HT_T, *P_WLAN_MAC_HEADER_HT_T; + +/* WLAN MAC Header (Address 4 included) */ +typedef struct _WLAN_MAC_HEADER_A4_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_T, *P_WLAN_MAC_HEADER_A4_T; + +/* WLAN MAC Header (Address 4 and QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_A4_QOS_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; + UINT_16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_QOS_T, *P_WLAN_MAC_HEADER_A4_QOS_T; + +typedef struct _WLAN_MAC_HEADER_A4_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_8 aucAddr4[MAC_ADDR_LEN]; + UINT_16 u2QosCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_HT_T, *P_WLAN_MAC_HEADER_A4_HT_T; + +/* 7.2.3 WLAN MAC Header for Management Frame - MMPDU */ +typedef struct _WLAN_MAC_MGMT_HEADER_T { + UINT_16 u2FrameCtrl; + UINT_16 u2Duration; + UINT_8 aucDestAddr[MAC_ADDR_LEN]; + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_T, *P_WLAN_MAC_MGMT_HEADER_T; + +/* WLAN MAC Header for Management Frame (HT Control fields included) */ +typedef struct _WLAN_MAC_MGMT_HEADER_HT_T { + UINT_16 u2FrameCtrl; + UINT_16 u2DurationID; + UINT_8 aucAddr1[MAC_ADDR_LEN]; + UINT_8 aucAddr2[MAC_ADDR_LEN]; + UINT_8 aucAddr3[MAC_ADDR_LEN]; + UINT_16 u2SeqCtrl; + UINT_32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_HT_T, *P_WLAN_MAC_MGMT_HEADER_HT_T; + +/* 3 WLAN CONTROL Frame */ +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +typedef struct _CTRL_PSPOLL_FRAME_T { + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2AID; /* AID */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_8 aucTA[MAC_ADDR_LEN]; /* TA */ +} __KAL_ATTRIB_PACKED__ CTRL_PSPOLL_FRAME_T, *P_CTRL_PSPOLL_FRAME_T; + +/* BAR */ +typedef struct _CTRL_BAR_FRAME_T { + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* RA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* TA */ + UINT_16 u2BarControl; + UINT_8 aucBarInfo[2]; /* Variable size */ +} __KAL_ATTRIB_PACKED__ CTRL_BAR_FRAME_T, *P_CTRL_BAR_FRAME_T; + +/* 3 WLAN Management Frame. */ +/* 7.2.3.1 WLAN Management Frame - Beacon Frame */ +typedef struct _WLAN_BEACON_FRAME_T { + /* Beacon header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_T, *P_WLAN_BEACON_FRAME_T; + +typedef struct _WLAN_BEACON_FRAME_BODY_T { + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_BODY_T, *P_WLAN_BEACON_FRAME_BODY_T; + +/* 7.2.3.3 WLAN Management Frame - Disassociation Frame */ +typedef struct _WLAN_DISASSOC_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Disassociation frame body */ + UINT_16 u2ReasonCode; /* Reason code */ + UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DISASSOC_FRAME_T, *P_WLAN_DISASSOC_FRAME_T; + +/* 7.2.3.4 WLAN Management Frame - Association Request frame */ +typedef struct _WLAN_ASSOC_REQ_FRAME_T { + /* Association Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Association Request frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2ListenInterval; /* Listen interval */ + UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_REQ_FRAME_T, *P_WLAN_ASSOC_REQ_FRAME_T; + +/* 7.2.3.5 WLAN Management Frame - Association Response frame */ +typedef struct _WLAN_ASSOC_RSP_FRAME_T { + /* Association Response MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Association Response frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2StatusCode; /* Status code */ + UINT_16 u2AssocId; /* Association ID */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + supported rates, and etc. */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_RSP_FRAME_T, *P_WLAN_ASSOC_RSP_FRAME_T; + +/* 7.2.3.6 WLAN Management Frame - Reassociation Request frame */ +typedef struct _WLAN_REASSOC_REQ_FRAME_T { + /* Reassociation Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Reassociation Request frame body */ + UINT_16 u2CapInfo; /* Capability information */ + UINT_16 u2ListenInterval; /* Listen interval */ + UINT_8 aucCurrentAPAddr[MAC_ADDR_LEN]; /* Current AP address */ + UINT_8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_REASSOC_REQ_FRAME_T, *P_WLAN_REASSOC_REQ_FRAME_T; + +/* 7.2.3.7 WLAN Management Frame - Reassociation Response frame + (the same as Association Response frame) */ +typedef WLAN_ASSOC_RSP_FRAME_T WLAN_REASSOC_RSP_FRAME_T, *P_WLAN_REASSOC_RSP_FRAME_T; + +/* 7.2.3.9 WLAN Management Frame - Probe Response Frame */ +typedef WLAN_BEACON_FRAME_T WLAN_PROBE_RSP_FRAME_T, *P_WLAN_PROBE_RSP_FRAME_T; + +/* 7.2.3.10 WLAN Management Frame - Authentication Frame */ +typedef struct _WLAN_AUTH_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Authentication frame body */ + UINT_16 u2AuthAlgNum; /* Authentication algorithm number */ + UINT_16 u2AuthTransSeqNo; /* Authentication transaction sequence number */ + UINT_16 u2StatusCode; /* Status code */ + UINT_8 aucInfoElem[1]; /* Various IEs for Fast BSS Transition */ +} __KAL_ATTRIB_PACKED__ WLAN_AUTH_FRAME_T, *P_WLAN_AUTH_FRAME_T; + +/* 7.2.3.11 WLAN Management Frame - Deauthentication Frame */ +typedef struct _WLAN_DEAUTH_FRAME_T { + /* Authentication MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Deauthentication frame body */ + UINT_16 u2ReasonCode; /* Reason code */ + UINT_8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DEAUTH_FRAME_T, *P_WLAN_DEAUTH_FRAME_T; + +/* 3 Information Elements. */ +/* 7.3.2 Generic element format */ +typedef struct _IE_HDR_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucInfo[1]; +} __KAL_ATTRIB_PACKED__ IE_HDR_T, *P_IE_HDR_T; + +/* 7.3.2.1 SSID element */ +typedef struct _IE_SSID_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; +} __KAL_ATTRIB_PACKED__ IE_SSID_T, *P_IE_SSID_T; + +/* 7.3.2.2 Supported Rates element */ +typedef struct _IE_SUPPORTED_RATE_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_T, *P_IE_SUPPORTED_RATE_T; + +/* 7.3.2.4 DS Parameter Set element */ +typedef struct _IE_DS_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCurrChnl; +} __KAL_ATTRIB_PACKED__ IE_DS_PARAM_SET_T, *P_IE_DS_PARAM_SET_T; + +/* 7.3.2.5 CF Parameter Set element */ +typedef struct _IE_CF_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCFPCount; + UINT_8 ucCFPPeriod; + UINT_16 u2CFPMaxDur; + UINT_16 u2DurRemaining; +} __KAL_ATTRIB_PACKED__ IE_CF_PARAM_SET_T, *P_IE_CF_PARAM_SET_T; + +/* 7.3.2.6 TIM */ +typedef struct _IE_TIM_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucDTIMCount; + UINT_8 ucDTIMPeriod; + UINT_8 ucBitmapControl; + UINT_8 aucPartialVirtualMap[1]; +} __KAL_ATTRIB_PACKED__ IE_TIM_T, *P_IE_TIM_T; + +/* 7.3.2.7 IBSS Parameter Set element */ +typedef struct _IE_IBSS_PARAM_SET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2ATIMWindow; +} __KAL_ATTRIB_PACKED__ IE_IBSS_PARAM_SET_T, *P_IE_IBSS_PARAM_SET_T; + +/* 7.3.2.8 Challenge Text element */ +typedef struct _IE_CHALLENGE_TEXT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucChallengeText[ELEM_MAX_LEN_CHALLENGE_TEXT]; +} __KAL_ATTRIB_PACKED__ IE_CHALLENGE_TEXT_T, *P_IE_CHALLENGE_TEXT_T; + +/* 7.3.2.9 Country information element */ +#if CFG_SUPPORT_802_11D +/*! \brief COUNTRY_INFO_TRIPLET is defined for the COUNTRY_INFO_ELEM structure. */ +typedef struct _COUNTRY_INFO_TRIPLET_T { + UINT_8 ucParam1; /*!< If param1 >= 201, this triplet is referred to as + Regulatory Triplet in 802_11J. */ + UINT_8 ucParam2; + UINT_8 ucParam3; +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_TRIPLET_T, *P_COUNTRY_INFO_TRIPLET_T; + +typedef struct _COUNTRY_INFO_SUBBAND_TRIPLET_T { + UINT_8 ucFirstChnlNum; /*!< First Channel Number */ + UINT_8 ucNumOfChnl; /*!< Number of Channels */ + INT_8 cMaxTxPwrLv; /*!< Maximum Transmit Power Level */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_SUBBAND_TRIPLET_T, *P_COUNTRY_INFO_SUBBAND_TRIPLET_T; + +typedef struct _COUNTRY_INFO_REGULATORY_TRIPLET_T { + UINT_8 ucRegExtId; /*!< Regulatory Extension Identifier, should + be greater than or equal to 201 */ + UINT_8 ucRegClass; /*!< Regulatory Class */ + UINT_8 ucCoverageClass; /*!< Coverage Class, unsigned 1-octet value 0~31 + , 32~255 reserved */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_REGULATORY_TRIPLET_T, *P_COUNTRY_INFO_REGULATORY_TRIPLET_T; + +typedef struct _IE_COUNTRY_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCountryStr[3]; + COUNTRY_INFO_SUBBAND_TRIPLET_T arCountryStr[1]; +} __KAL_ATTRIB_PACKED__ IE_COUNTRY_T, *P_IE_COUNTRY_T; +#endif /* CFG_SUPPORT_802_11D */ + +/* 7.3.2.13 ERP element */ +typedef struct _IE_ERP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucERP; +} __KAL_ATTRIB_PACKED__ IE_ERP_T, *P_IE_ERP_T; + +/* 7.3.2.14 Extended Supported Rates element */ +typedef struct _IE_EXT_SUPPORTED_RATE_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucExtSupportedRates[ELEM_MAX_LEN_EXTENDED_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_EXT_SUPPORTED_RATE_T, *P_IE_EXT_SUPPORTED_RATE_T; + +/* 7.3.2.15 Power Constraint element */ +typedef struct _IE_POWER_CONSTRAINT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucLocalPowerConstraint; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CONSTRAINT_T, *P_IE_POWER_CONSTRAINT_T; + +/* 7.3.2.16 Power Capability element */ +typedef struct _IE_POWER_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + INT_8 cMinTxPowerCap; /* Unit: dBm */ + INT_8 cMaxTxPowerCap; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CAP_T, *P_IE_POWER_CAP_T; + +/* 7.3.2.17 TPC request element */ +typedef struct _IE_TPC_REQ_T { + UINT_8 ucId; + UINT_8 ucLength; +} __KAL_ATTRIB_PACKED__ IE_TPC_REQ_T, *P_IE_TPC_REQ_T; + +/* 7.3.2.18 TPC report element */ +typedef struct _IE_TPC_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + INT_8 cTxPower; /* Unit: dBm */ + INT_8 cLinkMargin; /* Unit: dB */ +} __KAL_ATTRIB_PACKED__ IE_TPC_REPORT_T, *P_IE_TPC_REPORT_T; + +#if CFG_SUPPORT_DFS /* Add by Enlai */ +/* 7.3.2.19 Supported Channels element*/ +typedef struct _IE_SUPPORTED_CHANNELS_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucChannelNum[ELEM_MAX_LEN_SUPPORTED_CHANNELS * 2]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_CHANNELS_T, *P_IE_SUPPORTED_CHANNELS_T; + +/* 7.3.2.20 Channel Switch Announcement element*/ +typedef struct _IE_CHANNEL_SWITCH_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucChannelSwitchMode; + UINT_8 ucNewChannelNum; + UINT_8 ucChannelSwitchCount; +} __KAL_ATTRIB_PACKED__ IE_CHANNEL_SWITCH_T, *P_IE_CHANNEL_SWITCH_T; +#endif + +/* 7.3.2.21 Measurement Request element */ +typedef struct _IE_MEASUREMENT_REQ_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucToken; + UINT_8 ucRequestMode; + UINT_8 ucMeasurementType; + UINT_8 aucRequestFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REQ_T, *P_IE_MEASUREMENT_REQ_T; + +typedef struct _SM_BASIC_REQ_T { + UINT_8 ucChannel; + UINT_32 au4StartTime[2]; + UINT_16 u2Duration; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REQ_T, *P_SM_BASIC_REQ_T; + +/* SM_COMMON_REQ_T is not specified in Spec. Use it as common structure of SM */ +typedef SM_BASIC_REQ_T SM_REQ_COMMON_T, *P_SM_REQ_COMMON_T; +typedef SM_BASIC_REQ_T SM_CCA_REQ_T, *P_SM_CCA_REQ_T; +typedef SM_BASIC_REQ_T SM_RPI_HISTOGRAM_REQ_T, *P_SM_RPI_HISTOGRAM_REQ_T; + +typedef struct _RM_CHNL_LOAD_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REQ_T, *P_RM_CHNL_LOAD_REQ_T; + +typedef RM_CHNL_LOAD_REQ_T RM_NOISE_HISTOGRAM_REQ_T, *P_RM_NOISE_HISTOGRAM_REQ_T; + +typedef struct _RM_BCN_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucMeasurementMode; + UINT_8 aucBssid[6]; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_BCN_REQ_T, *P_RM_BCN_REQ_T; + +typedef struct _RM_FRAME_REQ_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucFrameReqType; + UINT_8 aucMacAddr[6]; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_FRAME_REQ_T, *P_RM_FRAME_REQ_T; + +typedef struct _RM_STA_STATS_REQ_T { + UINT_8 aucPeerMacAddr[6]; + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 ucGroupID; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_STA_STATS_REQ_T, *P_RM_STA_STATS_REQ_T; + +typedef struct _RM_LCI_REQ_T { + UINT_8 ucLocationSubject; + UINT_8 ucLatitudeResolution; + UINT_8 ucLongitudeResolution; + UINT_8 ucAltitudeResolution; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_LCI_REQ_T, *P_RM_LCI_REQ_T; + +typedef struct _RM_TS_MEASURE_REQ_T { + UINT_16 u2RandomInterval; + UINT_16 u2Duration; + UINT_8 aucPeerStaAddr[6]; + UINT_8 ucTrafficID; + UINT_8 ucBin0Range; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_TS_MEASURE_REQ_T, *P_RM_TS_MEASURE_REQ_T; + +typedef struct _RM_MEASURE_PAUSE_REQ_T { + UINT_16 u2PauseTime; + UINT_8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_MEASURE_PAUSE_REQ_T, *P_RM_MEASURE_PAUSE_REQ_T; + +/* 7.3.2.22 Measurement Report element */ +typedef struct _IE_MEASUREMENT_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucToken; + UINT_8 ucReportMode; + UINT_8 ucMeasurementType; + UINT_8 aucReportFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REPORT_T, *P_IE_MEASUREMENT_REPORT_T; + +typedef struct _SM_BASIC_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucMap; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REPORT_T, *P_SM_BASIC_REPORT_T; + +typedef struct _SM_CCA_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucCcaBusyFraction; +} __KAL_ATTRIB_PACKED__ SM_CCA_REPORT_T, *P_SM_CCA_REPORT_T; + +typedef struct _SM_RPI_REPORT_T { + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 aucRPI[8]; +} __KAL_ATTRIB_PACKED__ SM_RPI_REPORT_T, *P_SM_RPI_REPORT_T; + +typedef struct _RM_CHNL_LOAD_REPORT_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucChnlLoad; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REPORT_T, *P_RM_CHNL_LOAD_REPORT_T; + +typedef struct _RM_IPI_REPORT_T { + UINT_8 ucRegulatoryClass; + UINT_8 ucChannel; + UINT_32 u4StartTime[2]; + UINT_16 u2Duration; + UINT_8 ucAntennaId; + INT_8 cANPI; + UINT_8 aucIPI[11]; +} __KAL_ATTRIB_PACKED__ RM_IPI_REPORT_T, *P_RM_IPI_REPORT_T; + +/* 7.3.2.23 Quiet element */ +typedef struct _IE_QUIET_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCount; + UINT_8 ucPeriod; + UINT_16 u2Duration; + UINT_16 u2Offset; +} __KAL_ATTRIB_PACKED__ IE_QUIET_T, *P_IE_QUIET_T; + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_EXT_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCapabilities[5]; +} __KAL_ATTRIB_PACKED__ IE_EXT_CAP_T, *P_EXT_CAP_T; + +/* 7.3.2.27 hs20 Extended Capabilities element */ +typedef struct _IE_HS20_EXT_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCapabilities[6]; +} __KAL_ATTRIB_PACKED__ IE_HS20_EXT_CAP_T, *P_HS20_EXT_CAP_T; + + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_RRM_ENABLED_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucCap[5]; +} __KAL_ATTRIB_PACKED__ IE_RRM_ENABLED_CAP_T, *P_IE_RRM_ENABLED_CAP_T; + +/* 7.3.2.51 Timeout Interval element (TIE) */ +typedef struct _IE_TIMEOUT_INTERVAL_T { + UINT_8 ucId; + UINT_8 ucLength; +#define IE_TIMEOUT_INTERVAL_TYPE_RESERVED 0 +#define IE_TIMEOUT_INTERVAL_TYPE_REASSOC 1 +#define IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME 2 +#define IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK 3 + UINT_8 ucType; + UINT_32 u4Value; +} __KAL_ATTRIB_PACKED__ IE_TIMEOUT_INTERVAL_T; + +/* 7.3.2.56 HT Capabilities element */ +typedef struct _SUP_MCS_SET_FIELD { + UINT_8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + UINT_16 u2RxHighestSupportedRate; + UINT_32 u4TxRateInfo; +} __KAL_ATTRIB_PACKED__ SUP_MCS_SET_FIELD, *P_SUP_MCS_SET_FIELD; + +typedef struct _IE_HT_CAP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2HtCapInfo; + UINT_8 ucAmpduParam; + SUP_MCS_SET_FIELD rSupMcsSet; + UINT_16 u2HtExtendedCap; + UINT_32 u4TxBeamformingCap; + UINT_8 ucAselCap; +} __KAL_ATTRIB_PACKED__ IE_HT_CAP_T, *P_IE_HT_CAP_T; + +/* 7.3.2.57 HT Operation element */ +typedef struct _IE_HT_OP_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucPrimaryChannel; + UINT_8 ucInfo1; + UINT_16 u2Info2; + UINT_16 u2Info3; + UINT_8 aucBasicMcsSet[16]; +} __KAL_ATTRIB_PACKED__ IE_HT_OP_T, *P_IE_HT_OP_T; + +/* 7.3.2.25 RSN Information element format */ +typedef struct _RSN_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2PairwiseKeyCipherSuiteCount; + UCHAR aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ RSN_INFO_ELEM_T, *P_RSN_INFO_ELEM_T; + +/* 7.3.2.26 WPA Information element format */ +typedef struct _WPA_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UCHAR aucOui[3]; + UCHAR ucOuiType; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2PairwiseKeyCipherSuiteCount; + UCHAR aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ WPA_INFO_ELEM_T, *P_WPA_INFO_ELEM_T; + +/* 7.3.2.58 20/40 BSS Intolerant Channel Report element */ +typedef struct _IE_INTOLERANT_CHNL_REPORT_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucRegulatoryClass; + UINT_8 aucChannelList[1]; +} __KAL_ATTRIB_PACKED__ IE_INTOLERANT_CHNL_REPORT_T, *P_IE_INTOLERANT_CHNL_REPORT_T; + +/* 7.3.2.59 OBSS Scan Parameters element */ +typedef struct _IE_OBSS_SCAN_PARAM_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_16 u2ScanPassiveDwell; + UINT_16 u2ScanActiveDwell; + UINT_16 u2TriggerScanInterval; + UINT_16 u2ScanPassiveTotalPerChnl; + UINT_16 u2ScanActiveTotalPerChnl; + UINT_16 u2WidthTransDelayFactor; + UINT_16 u2ScanActivityThres; +} __KAL_ATTRIB_PACKED__ IE_OBSS_SCAN_PARAM_T, *P_IE_OBSS_SCAN_PARAM_T; + +/* 7.3.2.60 20/40 BSS Coexistence element */ +typedef struct _IE_20_40_COEXIST_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucData; +} __KAL_ATTRIB_PACKED__ IE_20_40_COEXIST_T, *P_IE_20_40_COEXIST_T; + +/* 7.3.2.60 20/40 BSS Coexistence element */ +typedef struct _IE_SUP_OPERATING_CLASS_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 ucCur; + UINT_8 ucSup[255]; +} __KAL_ATTRIB_PACKED__ IE_SUP_OPERATING_CLASS_T, *P_IE_SUP_OPERATING_CLASS_T; + +/* 3 7.4 Action Frame. */ +/* 7.4 Action frame format */ +typedef struct _WLAN_ACTION_FRAME { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucActionDetails[1]; /* Action details */ +} __KAL_ATTRIB_PACKED__ WLAN_ACTION_FRAME, *P_WLAN_ACTION_FRAME; + +/* 7.4.1.1 Spectrum Measurement Request frame format */ +typedef struct _ACTION_SM_REQ_FRAME { + /* ADDTS Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Information elements */ +} __KAL_ATTRIB_PACKED__ ACTION_SM_REQ_FRAME, *P_ACTION_SM_REQ_FRAME; + +/* 7.4.1.2 Spectrum Measurement Report frame format */ +typedef ACTION_SM_REQ_FRAME ACTION_SM_REPORT_FRAME, *P_ACTION_SM_REPORT_FRAME; + +/* 7.4.1.5 Channel Switch Announcement frame format */ +typedef struct _ACTION_CHANNEL_SWITCH_FRAME { + /* ADDTS Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 aucInfoElem[5]; /* Information elements */ +} __KAL_ATTRIB_PACKED__ _ACTION_CHANNEL_SWITCH_FRAME, *P_ACTION_CHANNEL_SWITCH_FRAME; + +/* 7.4.2.1 ADDTS Request frame format */ +typedef struct _ACTION_ADDTS_REQ_FRAME { + /* ADDTS Request MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_REQ_FRAME, *P_ACTION_ADDTS_REQ_FRAME; + +/* 7.4.2.2 ADDTS Response frame format */ +typedef struct _ACTION_ADDTS_RSP_FRAME { + /* ADDTS Response MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Response frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 ucStatusCode; /* WMM Status Code is of one byte */ + UINT_8 aucInfoElem[1]; /* Information elements, such as + TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_RSP_FRAME, *P_ACTION_ADDTS_RSP_FRAME; + +/* 7.4.2.3 DELTS frame format */ +typedef struct _ACTION_DELTS_FRAME { + /* DELTS MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* DELTS frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 aucTsInfo[3]; /* TS Info */ +} __KAL_ATTRIB_PACKED__ ACTION_DELTS_FRAME, *P_ACTION_DELTS_FRAME; + +/* 7.4.4.1 ADDBA Request frame format */ +typedef struct _ACTION_ADDBA_REQ_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + UINT_8 aucBATimeoutValue[2]; + UINT_8 aucBAStartSeqCtrl[2]; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_FRAME_T, *P_ACTION_ADDBA_REQ_FRAME_T; + +typedef struct _ACTION_ADDBA_REQ_BODY_T { + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; + UINT_16 u2BAStartSeqCtrl; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_BODY_T, *P_ACTION_ADDBA_REQ_BODY_T; + +/* 7.4.4.2 ADDBA Response frame format */ +typedef struct _ACTION_ADDBA_RSP_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_8 aucStatusCode[2]; + UINT_8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + UINT_8 aucBATimeoutValue[2]; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_FRAME_T, *P_ACTION_ADDBA_RSP_FRAME_T; + +typedef struct _ACTION_ADDBA_RSP_BODY_T { + UINT_16 u2StatusCode; + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_BODY_T, *P_ACTION_ADDBA_RSP_BODY_T; + +/* 7.4.4.3 DELBA frame format */ +typedef struct _ACTION_DELBA_FRAME_T { + /* Action MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2DurationID; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_16 u2DelBaParameterSet; /* Bit 11 Initiator, Bits 12-15 TID */ + UINT_16 u2ReasonCode; /* 7.3.1.7 */ +} __KAL_ATTRIB_PACKED__ ACTION_DELBA_FRAME_T, *P_ACTION_DELBA_FRAME_T; + +/* 7.4.6.1 Radio Measurement Request frame format */ +typedef struct _ACTION_RM_REQ_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Request frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_16 u2Repetitions; /* Number of repetitions */ + UINT_8 aucInfoElem[1]; /* Measurement Request elements, such as + channel load request, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REQ_FRAME, *P_ACTION_RM_REQ_FRAME; + +/* 7.4.6.2 Radio Measurement Report frame format */ +typedef struct _ACTION_RM_REPORT_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Report frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 aucInfoElem[1]; /* Measurement Report elements, such as + channel load report, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REPORT_FRAME, *P_ACTION_RM_REPORT_FRAME; + +/* 7.4.7.1a 20/40 BSS Coexistence Management frame format */ +typedef struct _ACTION_20_40_COEXIST_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + + IE_20_40_COEXIST_T rBssCoexist; /* 20/40 BSS coexistence element */ + IE_INTOLERANT_CHNL_REPORT_T rChnlReport; /* Intolerant channel report */ + +} __KAL_ATTRIB_PACKED__ ACTION_20_40_COEXIST_FRAME, *P_ACTION_20_40_COEXIST_FRAME; + +#if CFG_SUPPORT_802_11W +/* 7.4.9 SA Query Management frame format */ +typedef struct _ACTION_SA_QUERY_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + + UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; /* Transaction id */ + +} __KAL_ATTRIB_PACKED__ ACTION_SA_QUERY_FRAME, *P_ACTION_SA_QUERY_FRAME; +#endif + +/* 7.4.10 Notify Channel Width Management frame format */ +typedef struct _ACTION_NOTIFY_CHNL_WIDTH_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucChannelWidth; /* Channel Width */ +} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHNL_WIDTH_FRAME, *P_ACTION_NOTIFY_CHNL_WIDTH_FRAME; + +/* 802.11v Wireless Network Management: Timing Measurement Request */ +typedef struct _ACTION_WNM_TIMING_MEAS_REQ_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Timing Measurement Request Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucTrigger; /* Trigger */ +} __KAL_ATTRIB_PACKED__ ACTION_WNM_TIMING_MEAS_REQ_FRAME, *P_ACTION_WNM_TIMING_MEAS_REQ_FRAME; + +/* 802.11v Wireless Network Management: Timing Measurement */ +typedef struct _ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* Timing Measurement Management frame body */ + UINT_8 ucCategory; /* Category */ + UINT_8 ucAction; /* Action Value */ + UINT_8 ucDialogToken; /* Dialog Token */ + UINT_8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ + UINT_32 u4ToD; /* Timestamp of Departure [10ns] */ + UINT_32 u4ToA; /* Timestamp of Arrival [10ns] */ + UINT_8 ucMaxToDErr; /* Maximum of ToD Error [10ns] */ + UINT_8 ucMaxToAErr; /* Maximum of ToA Error [10ns] */ +} __KAL_ATTRIB_PACKED__ ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME, *P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME; + +/* 3 Information Elements from WFA. */ +typedef struct _IE_WFA_T { + UINT_8 ucId; + UINT_8 ucLength; + UINT_8 aucOui[3]; + UINT_8 ucOuiType; + UINT_8 aucOuiSubTypeVersion[2]; + /*!< Please be noted. WPA defines a 16 bit field version + instead of one subtype field and one version field */ +} __KAL_ATTRIB_PACKED__ IE_WFA_T, *P_IE_WFA_T; + +/* HS20 3.1 - HS 2.0 Indication Information Element */ +typedef struct _IE_HS20_INDICATION_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucType; /* Type */ + UINT_8 ucHotspotConfig; /* Hotspot Configuration */ +} __KAL_ATTRIB_PACKED__ IE_HS20_INDICATION_T, *P_IE_HS20_INDICATION_T; + +/* WAPI Information element format */ +typedef struct _WAPI_INFO_ELEM_T { + UCHAR ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_16 u2AuthKeyMgtSuiteCount; + UCHAR aucAuthKeyMgtSuite1[4]; +} __KAL_ATTRIB_PACKED__ WAPI_INFO_ELEM_T, *P_WAPI_INFO_ELEM_T; + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack() +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Convert the ECWmin(max) to CWmin(max) */ +#define ECW_TO_CW(_ECW) ((1 << (_ECW)) - 1) + +/* Convert the RCPI to dBm */ +#define RCPI_TO_dBm(_rcpi) \ + ((PARAM_RSSI)(((_rcpi) > RCPI_HIGH_BOUND ? RCPI_HIGH_BOUND : (_rcpi)) >> 1) - NDBM_LOW_BOUND_FOR_RCPI) + +/* Convert the dBm to RCPI */ +#define dBm_TO_RCPI(_dbm) \ + (RCPI)(((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) > RCPI_HIGH_BOUND) ? RCPI_HIGH_BOUND : \ + ((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) < RCPI_LOW_BOUND ? RCPI_LOW_BOUND : \ + (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1))) + +/* Convert an unsigned char pointer to an information element pointer */ +#define IE_ID(fp) (((P_IE_HDR_T) fp)->ucId) +#define IE_LEN(fp) (((P_IE_HDR_T) fp)->ucLength) +#define IE_SIZE(fp) (ELEM_HDR_LEN + IE_LEN(fp)) + +#define SSID_IE(fp) ((P_IE_SSID_T) fp) + +#define SUP_RATES_IE(fp) ((P_IE_SUPPORTED_RATE_T) fp) + +#define DS_PARAM_IE(fp) ((P_IE_DS_PARAM_SET_T) fp) + +#define TIM_IE(fp) ((P_IE_TIM_T) fp) + +#define IBSS_PARAM_IE(fp) ((P_IE_IBSS_PARAM_SET_T) fp) + +#define ERP_INFO_IE(fp) ((P_IE_ERP_T) fp) + +#define EXT_SUP_RATES_IE(fp) ((P_IE_EXT_SUPPORTED_RATE_T) fp) + +#define WFA_IE(fp) ((P_IE_WFA_T) fp) + +#if CFG_SUPPORT_802_11D +#define COUNTRY_IE(fp) ((P_IE_COUNTRY_T) fp) +#endif + +#define EXT_CAP_IE(fp) ((P_EXT_CAP_T) fp) + +#define HT_CAP_IE(fp) ((P_IE_HT_CAP_T) fp) + +#define HT_OP_IE(fp) ((P_IE_HT_OP_T) fp) + +#define OBSS_SCAN_PARAM_IE(fp) ((P_IE_OBSS_SCAN_PARAM_T) fp) + +#define BSS_20_40_COEXIST_IE(fp) ((P_IE_20_40_COEXIST_T) fp) + +#define SUP_OPERATING_CLASS_IE(fp) ((P_IE_SUP_OPERATING_CLASS_T) fp) + +#define QUIET_IE(fp) ((P_IE_QUIET_T) fp) + +#if CFG_SUPPORT_DFS /* Add by Enlai */ +#define SUPPORTED_CHANNELS_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp) +#endif + +#define TIMEOUT_INTERVAL_IE(fp) ((IE_TIMEOUT_INTERVAL_T *)fp) + +/* The macro to check if the MAC address is B/MCAST Address */ +#define IS_BMCAST_MAC_ADDR(_pucDestAddr) \ + ((BOOLEAN) (((PUINT_8)(_pucDestAddr))[0] & BIT(0))) + +/* The macro to check if the MAC address is UCAST Address */ +#define IS_UCAST_MAC_ADDR(_pucDestAddr) \ + ((BOOLEAN) !(((PUINT_8)(_pucDestAddr))[0] & BIT(0))) + +/* The macro to copy the MAC address */ +#define COPY_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + kalMemCopy(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN) + +/* The macro to check if two MAC addresses are equal */ +#define EQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (!kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + +/* The macro to check if two MAC addresses are not equal */ +#define UNEQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + +/* The macro to check whether two SSIDs are equal */ +#define EQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 <= ELEM_MAX_LEN_SSID) && \ + (ucSsidLen2 <= ELEM_MAX_LEN_SSID) && \ + ((ucSsidLen1) == (ucSsidLen2)) && \ + !kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to check whether two SSIDs are equal */ +#define UNEQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 > ELEM_MAX_LEN_SSID) || \ + (ucSsidLen2 > ELEM_MAX_LEN_SSID) || \ + ((ucSsidLen1) != (ucSsidLen2)) || \ + kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to copy the SSID, the length of pucDestSsid should have at least 32 bytes */ +#define COPY_SSID(pucDestSsid, ucDestSsidLen, pucSrcSsid, ucSrcSsidLen) \ + do { \ + ucDestSsidLen = ucSrcSsidLen; \ + if (ucSrcSsidLen) { \ + ASSERT(ucSrcSsidLen <= ELEM_MAX_LEN_SSID); \ + kalMemCopy(pucDestSsid, \ + pucSrcSsid, \ + ((ucSrcSsidLen > ELEM_MAX_LEN_SSID) ? ELEM_MAX_LEN_SSID : ucSrcSsidLen)); \ + } \ + } while (FALSE) + +/* The macro to copy the IE */ +#define COPY_IE(pucDestIE, pucSrcIE) \ + do { \ + kalMemCopy((PUINT_8)pucDestIE, \ + (PUINT_8)pucSrcIE,\ + IE_SIZE(pucSrcIE)); \ + } while (FALSE) + +#define IE_FOR_EACH(_pucIEsBuf, _u2IEsBufLen, _u2Offset) \ + for ((_u2Offset) = 0;\ + ((((_u2Offset) + 2) <= (_u2IEsBufLen)) && (((_u2Offset) + IE_SIZE(_pucIEsBuf)) <= (_u2IEsBufLen))); \ + (_u2Offset) += IE_SIZE(_pucIEsBuf), (_pucIEsBuf) += IE_SIZE(_pucIEsBuf)) + +#define SET_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ + do { \ + if ((_ucBit) < ((_ucFieldLength) * 8)) { \ + PUINT_8 aucExtCap = (PUINT_8)(_aucField); \ + ((aucExtCap)[(_ucBit) / 8]) |= BIT((_ucBit) % 8); \ + } \ + } while (FALSE) + +#define TEST_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ + ((((_ucFieldLength) * 8) > (_ucBit)) && (((_aucField)[(_ucBit) / 8]) & BIT((_ucBit) % 8))) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MAC_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h new file mode 100644 index 0000000000000..583923aed0100 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/mtreg.h @@ -0,0 +1,272 @@ +/* +** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/include/nic/mtreg.h#2 +*/ + +/*! \file "mtreg.h" + \brief The common register definition of mt5931 + + N/A +*/ + +/* +** Log: mtreg.h + * + * 01 28 2013 samp.lin + * [WCXRP00000851] [MT6582 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6582-specific definitions. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 07 13 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add initial version for MT6628 driver support. + * +*/ + +#ifndef _MTREG_H +#define _MTREG_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/* 1 MT6628 MCR Definition */ + +/* 2 Host Interface */ + +/* 4 CHIP ID Register */ +#define MCR_WCIR 0x0000 + +/* 4 HIF Low Power Control Register */ +#define MCR_WHLPCR 0x0004 + +/* 4 Control Status Register */ +#define MCR_WSDIOCSR 0x0008 +#define MCR_WSPICSR 0x0008 + +/* 4 HIF Control Register */ +#define MCR_WHCR 0x000C + +/* 4 HIF Interrupt Status Register */ +#define MCR_WHISR 0x0010 + +/* 4 HIF Interrupt Enable Register */ +#define MCR_WHIER 0x0014 + +/* 4 Abnormal Status Register */ +#define MCR_WASR 0x0018 + +/* 4 WLAN Software Interrupt Control Register */ +#define MCR_WSICR 0x001C + +/* 4 WLAN TX Status Register */ +#define MCR_WTSR0 0x0020 + +/* 4 WLAN TX Status Register */ +#define MCR_WTSR1 0x0024 + +/* 4 WLAN TX Data Register 0 */ +#define MCR_WTDR0 0x0028 + +/* 4 WLAN TX Data Register 1 */ +#define MCR_WTDR1 0x002C + +/* 4 WLAN RX Data Register 0 */ +#define MCR_WRDR0 0x0030 + +/* 4 WLAN RX Data Register 1 */ +#define MCR_WRDR1 0x0034 + +/* 4 Host to Device Send Mailbox 0 Register */ +#define MCR_H2DSM0R 0x0038 + +/* 4 Host to Device Send Mailbox 1 Register */ +#define MCR_H2DSM1R 0x003c + +/* 4 Device to Host Receive Mailbox 0 Register */ +#define MCR_D2HRM0R 0x0040 + +/* 4 Device to Host Receive Mailbox 1 Register */ +#define MCR_D2HRM1R 0x0044 + +/* 4 Device to Host Receive Mailbox 2 Register */ +#define MCR_D2HRM2R 0x0048 + +/* 4 WLAN RX Packet Length Register */ +#define MCR_WRPLR 0x0050 + +/* 4 HSIF Transaction Count Register */ +#define MCR_HSTCR 0x0058 + +/* #if CFG_SDIO_INTR_ENHANCE */ +typedef struct _ENHANCE_MODE_DATA_STRUCT_T { + UINT_32 u4WHISR; + union { + struct { + UINT_8 ucTQ0Cnt; + UINT_8 ucTQ1Cnt; + UINT_8 ucTQ2Cnt; + UINT_8 ucTQ3Cnt; + UINT_8 ucTQ4Cnt; + UINT_8 ucTQ5Cnt; + UINT_16 u2Rsrv; + } u; + UINT_32 au4WTSR[2]; + } rTxInfo; + union { + struct { + UINT_16 u2NumValidRx0Len; + UINT_16 u2NumValidRx1Len; + UINT_16 au2Rx0Len[16]; + UINT_16 au2Rx1Len[16]; + } u; + UINT_32 au4RxStatusRaw[17]; + } rRxInfo; + UINT_32 u4RcvMailbox0; + UINT_32 u4RcvMailbox1; +} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; +/* #endif */ /* ENHANCE_MODE_DATA_STRUCT_T */ + +/* 2 Definition in each register */ +/* 3 WCIR 0x0000 */ +#define WCIR_WLAN_READY BIT(21) +#define WCIR_POR_INDICATOR BIT(20) +#define WCIR_REVISION_ID BITS(16, 19) +#define WCIR_CHIP_ID BITS(0, 15) + +#define MTK_CHIP_REV_72 0x00006572 +#define MTK_CHIP_REV_82 0x00006582 +#define MTK_CHIP_REV_92 0x00006592 +#define MTK_CHIP_MP_REVERSION_ID 0x0 + +/* 3 WHLPCR 0x0004 */ +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +/* 3 WSDIOCSR 0x0008 */ +#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) + +/* 3 WSPICSR 0x0008 */ +#define WCSR_SPI_MODE_SEL BITS(3, 4) +#define WCSR_SPI_ENDIAN_BIG BIT(2) +#define WCSR_SPI_INT_OUT_MODE BIT(1) +#define WCSR_SPI_DATA_OUT_MODE BIT(0) + +/* 3 WHCR 0x000C */ +#define WHCR_RX_ENHANCE_MODE_EN BIT(16) +#define WHCR_MAX_HIF_RX_LEN_NUM BITS(4, 7) +#define WHCR_W_MAILBOX_RD_CLR_EN BIT(2) +#define WHCR_W_INT_CLR_CTRL BIT(1) +#define WHCR_MCU_DBG_EN BIT(0) +#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 4 + +/* 3 WHISR 0x0010 */ +#define WHISR_D2H_SW_INT BITS(8, 31) +#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) +#define WHISR_FW_OWN_BACK_INT BIT(4) +#define WHISR_ABNORMAL_INT BIT(3) +#define WHISR_RX1_DONE_INT BIT(2) +#define WHISR_RX0_DONE_INT BIT(1) +#define WHISR_TX_DONE_INT BIT(0) + +/* 3 WHIER 0x0014 */ +#define WHIER_D2H_SW_INT BITS(8, 31) +#define WHIER_FW_OWN_BACK_INT_EN BIT(4) +#define WHIER_ABNORMAL_INT_EN BIT(3) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT \ + ) + +/* 3 WASR 0x0018 */ +#define WASR_FW_OWN_INVALID_ACCESS BIT(4) +#define WASR_RX1_UNDER_FLOW BIT(3) +#define WASR_RX0_UNDER_FLOW BIT(2) +#define WASR_TX1_OVER_FLOW BIT(1) +#define WASR_TX0_OVER_FLOW BIT(0) + +/* 3 WSICR 0x001C */ +#define WSICR_H2D_SW_INT_SET BITS(16, 31) + +/* 3 WRPLR 0x0050 */ +#define WRPLR_RX1_PACKET_LENGTH BITS(16, 31) +#define WRPLR_RX0_PACKET_LENGTH BITS(0, 15) + +/* 3 HSTCR 0x0058 */ +#define HSTCR_AFF_BURST_LEN BITS(24, 25) +#define HSTCR_AFF_BURST_LEN_OFFSET 24 +#define HSTCR_TRANS_TARGET BITS(20, 22) +#define HSTCR_TRANS_TARGET_OFFSET 20 +#define HSTCR_HSIF_TRANS_CNT BITS(2, 19) +#define HSTCR_HSIF_TRANS_CNT_OFFSET 2 + +/* HSTCR_TRANS_TARGET */ +typedef enum _eTransTarget { + TRANS_TARGET_TXD0 = 0, + TRANS_TARGET_TXD1, + TRANS_TARGET_RXD0, + TRANS_TARGET_RXD1, + TRANS_TARGET_WHISR, + NUM_TRANS_TARGET +} E_TRANS_TARGET_T; + +typedef enum _E_AFF_BURST_LEN { + BURST_1_DW = 0, + BURST_4_DW, + BURST_8_DW, + BURST_RSV, + NUM_AFF_BURST_LEN +} E_AFF_BURST_LEN; + +#endif /* _MTREG_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h new file mode 100644 index 0000000000000..c059b707aee84 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic.h @@ -0,0 +1,498 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic.h#1 +*/ + +/*! \file "nic.h" + \brief The declaration of nic functions + + Detail description. +*/ + +/* +** Log: nic.h + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS + * cannot do the 4-way handshake to connect to the AP.. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right + * after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] + * Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced + * by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test + * with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always process TX interrupt first then RX interrupt. + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-10-13 21:58:58 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-24 21:12:55 GMT mtk01104 +** Add function prototype nicRestoreSpiDefMode() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-19 18:32:54 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:32 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_H +#define _NIC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct _REG_ENTRY_T { + UINT_32 u4Offset; + UINT_32 u4Value; +}; + +struct _TABLE_ENTRY_T { + P_REG_ENTRY_T pu4TablePtr; + UINT_16 u2Size; +}; + +/*! INT status to event map */ +typedef struct _INT_EVENT_MAP_T { + UINT_32 u4Int; + UINT_32 u4Event; +} INT_EVENT_MAP_T, *P_INT_EVENT_MAP_T; + +enum ENUM_INT_EVENT_T { + INT_EVENT_ABNORMAL, + INT_EVENT_SW_INT, + INT_EVENT_TX, + INT_EVENT_RX, + INT_EVENT_NUM +}; + +typedef enum _ENUM_IE_UPD_METHOD_T { + IE_UPD_METHOD_UPDATE_RANDOM, + IE_UPD_METHOD_UPDATE_ALL, + IE_UPD_METHOD_DELETE_ALL, +} ENUM_IE_UPD_METHOD_T, *P_ENUM_IE_UPD_METHOD_T; + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern BOOLEAN fgIsResetting; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in nic.c */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter); + +VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter); + +VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter); + +VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus); + +WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter); + +VOID nicMCRInit(IN P_ADAPTER_T prAdapter); + +BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter); + +#if CFG_SDIO_INTR_ENHANCE +VOID nicSDIOInit(IN P_ADAPTER_T prAdapter); + +VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus); +#endif + +BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter); + +VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt); + +BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter); + +BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter); + +#if defined(_HIF_SPI) +void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter); +#endif + +VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter); + +VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter); + +VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data); + +VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data); + +VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap); + +P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); + +P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum); + +P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx); + +VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); + +UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter); + +UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter); + +/* Media State Change */ +WLAN_STATUS +nicMediaStateChange(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); + +/* Utility function for channel number conversion */ +UINT_32 nicChannelNum2Freq(IN UINT_32 u4ChannelNum); + +UINT_32 nicFreq2ChannelNum(IN UINT_32 u4FreqInKHz); + +/* firmware command wrapper */ + /* NETWORK (WIFISYS) */ +WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + + /* BSS-INFO */ +WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + + /* BSS-INFO Indication (PM) */ +WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + + /* Beacon Template Update */ +WLAN_STATUS +nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen); + +WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam); + +/*----------------------------------------------------------------------------*/ +/* Calibration Control */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam); + +WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset); + +WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult); + +/*----------------------------------------------------------------------------*/ +/* PHY configuration */ +/*----------------------------------------------------------------------------*/ +VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* MGMT and System Service Control */ +/*----------------------------------------------------------------------------*/ +VOID nicInitSystemService(IN P_ADAPTER_T prAdapter); + +VOID nicResetSystemService(IN P_ADAPTER_T prAdapter); + +VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter); + +VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); + +VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent); + +WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent); +/*----------------------------------------------------------------------------*/ +/* Scan Result Processing */ +/*----------------------------------------------------------------------------*/ +VOID +nicAddScanResult(IN P_ADAPTER_T prAdapter, + IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, + IN UINT_32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf); + +VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx); + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) +/*----------------------------------------------------------------------------*/ +/* Workaround Control */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter); +#endif + +/*----------------------------------------------------------------------------*/ +/* Fixed Rate Hacking */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams(IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN PUINT_8 pucDesiredPhyTypeSet, + IN PUINT_16 pu2DesiredNonHTRateSet, + IN PUINT_16 pu2BSSBasicRateSet, + IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 u2HtCapInfo); + +/*----------------------------------------------------------------------------*/ +/* Write registers */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value); + +/*----------------------------------------------------------------------------*/ +/* Update auto rate */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4ArSysParam0, + IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3); + +/*----------------------------------------------------------------------------*/ +/* Enable/Disable Roaming */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming); + +VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Link Quality Updating */ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality); + +VOID +nicUpdateRSSI(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); + +VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed); + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam); +#endif + +#endif /* _NIC_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h new file mode 100644 index 0000000000000..86e2c84b07ffa --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_rx.h @@ -0,0 +1,420 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_rx.h#1 +*/ + +/*! \file "nic_rx.h" + \brief The declaration of the nic rx functions + +*/ + +/* +** Log: nic_rx.h + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 05 05 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * add delay after whole-chip resetting for MT5931 E1 ASIC. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode + * and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Change prototype of API of adding P2P device to scan result. + * Additional IE buffer is saved. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 05 2010 yuche.tsai + * NULL + * Modify data structure for P2P Scan result. + * + * 08 03 2010 cp.wu + * NULL + * newly added P2P API should be declared in header file. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * 2) firmware image length is now retrieved via NdisFileOpen + * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * 4) nicRxWaitResponse() revised + * * 5) another set of TQ counter default value is added for fw-download state + * * 6) Wi-Fi load address is now retrieved from registry too + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * and result is retrieved by get ATInfo instead + * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:49:09 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-12-09 14:02:37 GMT MTK02468 +** Added ucStaRecIdx in SW_RFB_T and HALF_SEQ_NO_COUNT definition (to replace HALF_SEQ_NO_CNOUT) +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-27 11:07:54 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-25 18:18:09 GMT mtk02752 +** modify nicRxAddScanResult() +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-24 22:42:22 GMT mtk02752 +** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-24 19:57:06 GMT mtk02752 +** adopt P_HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-16 21:43:04 GMT mtk02752 +** correct ENUM_RX_PKT_DESTINATION_T definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 15:28:25 GMT mtk02752 +** add ucQueuedPacketNum for indicating how many packet are queued by RX reordering buffer/forwarding path +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 15:05:01 GMT mtk02752 +** add eTC for SW_RFB_T and structure RX_MAILBOX +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-13 21:16:57 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-13 16:59:30 GMT mtk02752 +** add handler for event packet +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-13 13:45:50 GMT mtk02752 +** add port param for nicRxEnhanceReadBuffer() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-11 10:12:31 GMT mtk02752 +** nicSDIOReadIntStatus() always read sizeof(ENHANCE_MODE_DATA_STRUCT_T) for int response, +** thus the number should be set to 0(:=16) instead of 10 +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-10-29 19:53:32 GMT mtk01084 +** modify structure naming +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-23 16:08:23 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:01 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-20 12:23:33 GMT mtk01461 +** Add u4MaxEventBufferLen parameter to nicRxWaitResponse() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-05-18 21:00:48 GMT mtk01426 +** Update SDIO_MAXIMUM_RX_STATUS value +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-28 10:36:15 GMT mtk01461 +** Remove unused define - SDIO_MAXIMUM_TX_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:17 GMT mtk01461 +** Add function for HIF_LOOPBACK_PRE_TEST +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:56:19 GMT mtk01426 +** Add to support CFG_HIF_LOOPBACK and CFG_SDIO_RX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:19:56 GMT mtk01426 +** Add nicRxWaitResponse function proto type +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:35 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_RX_H +#define _NIC_RX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern P_SW_RFB_T g_arGscnResultsTempBuffer[]; +extern UINT_8 g_GscanResultsTempBufferIndex; +extern UINT_8 g_arGscanResultsIndicateNumber[]; +extern UINT_8 g_GetResultsBufferedCnt; +extern UINT_8 g_GetResultsCmdCnt; +extern void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define MAX_SEQ_NO 4095 +#define MAX_SEQ_NO_COUNT 4096 +#define HALF_SEQ_NO_CNOUT 2048 + +#define HALF_SEQ_NO_COUNT 2048 + +#define MT6620_FIXED_WIN_SIZE 64 +#define CFG_RX_MAX_BA_ENTRY 4 +#define CFG_RX_MAX_BA_TID_NUM 8 + +#define RX_STATUS_FLAG_MORE_PACKET BIT(30) +#define RX_STATUS_CHKSUM_MASK BITS(0, 10) + +#define RX_RFB_LEN_FIELD_LEN 4 +#define RX_HEADER_OFFSET 2 + +#define RX_RETURN_INDICATED_RFB_TIMEOUT_SEC 3 + +#if defined(_HIF_SDIO) && defined(WINDOWS_DDK) +/*! On XP, maximum Tx+Rx Statue <= 64-4(HISR)*/ +#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ +#else +#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_RX_STATISTIC_COUNTER_T { + RX_MPDU_TOTAL_COUNT = 0, + RX_SIZE_ERR_DROP_COUNT, + + RX_DATA_INDICATION_COUNT, + RX_DATA_RETURNED_COUNT, + RX_DATA_RETAINED_COUNT, + + RX_DROP_TOTAL_COUNT, + RX_TYPE_ERR_DROP_COUNT, + RX_CLASS_ERR_DROP_COUNT, + RX_DST_NULL_DROP_COUNT, + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + RX_CSUM_TCP_FAILED_COUNT, + RX_CSUM_UDP_FAILED_COUNT, + RX_CSUM_IP_FAILED_COUNT, + RX_CSUM_TCP_SUCCESS_COUNT, + RX_CSUM_UDP_SUCCESS_COUNT, + RX_CSUM_IP_SUCCESS_COUNT, + RX_CSUM_UNKNOWN_L4_PKT_COUNT, + RX_CSUM_UNKNOWN_L3_PKT_COUNT, + RX_IP_V6_PKT_CCOUNT, +#endif + RX_STATISTIC_COUNTER_NUM +} ENUM_RX_STATISTIC_COUNTER_T; + +typedef enum _ENUM_RX_PKT_DESTINATION_T { + RX_PKT_DESTINATION_HOST, /* to OS */ + RX_PKT_DESTINATION_FORWARD, /* to TX queue for forward, AP mode */ + RX_PKT_DESTINATION_HOST_WITH_FORWARD, /* to both TX and OS, AP mode broadcast packet */ + RX_PKT_DESTINATION_NULL, /* packet to be freed */ + RX_PKT_DESTINATION_NUM +} ENUM_RX_PKT_DESTINATION_T; + +struct _SW_RFB_T { + QUE_ENTRY_T rQueEntry; + PVOID pvPacket; /*!< ptr to rx Packet Descriptor */ + PUINT_8 pucRecvBuff; /*!< ptr to receive data buffer */ + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4HifRxHdrFlag; + PVOID pvHeader; + UINT_16 u2PacketLen; + UINT_16 u2HeaderLen; + UINT_16 u2SSN; + UINT_8 ucTid; + UINT_8 ucWlanIdx; + UINT_8 ucPacketType; + UINT_8 ucStaRecIdx; + + ENUM_CSUM_RESULT_T aeCSUM[CSUM_TYPE_NUM]; + ENUM_RX_PKT_DESTINATION_T eDst; + ENUM_TRAFFIC_CLASS_INDEX_T eTC; /* only valid when eDst == FORWARD */ + + UINT_64 rRxTime; +}; + +/*! RX configuration type structure */ +typedef struct _RX_CTRL_T { + UINT_32 u4RxCachedSize; + PUINT_8 pucRxCached; + QUE_T rFreeSwRfbList; + QUE_T rReceivedRfbList; + QUE_T rIndicatedRfbList; + +#if CFG_SDIO_RX_AGG + PUINT_8 pucRxCoalescingBufPtr; +#endif + + PVOID apvIndPacket[CFG_RX_MAX_PKT_NUM]; + PVOID apvRetainedPacket[CFG_RX_MAX_PKT_NUM]; + + UINT_8 ucNumIndPacket; + UINT_8 ucNumRetainedPacket; + UINT_64 au8Statistics[RX_STATISTIC_COUNTER_NUM]; /*!< RX Counters */ + +#if CFG_HIF_STATISTICS + UINT_32 u4TotalRxAccessNum; + UINT_32 u4TotalRxPacketNum; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + UINT_32 u4QueuedCnt; + UINT_32 u4DequeuedCnt; +#endif + +#if CFG_RX_PKTS_DUMP + UINT_32 u4RxPktsDumpTypeMask; +#endif + +} RX_CTRL_T, *P_RX_CTRL_T; + +typedef struct _RX_MAILBOX_T { + UINT_32 u4RxMailbox[2]; /* for Device-to-Host Mailbox */ +} RX_MAILBOX_T, *P_RX_MAILBOX_T; + +typedef WLAN_STATUS(*PROCESS_RX_MGT_FUNCTION) (P_ADAPTER_T, P_SW_RFB_T); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define RX_INC_CNT(prRxCtrl, eCounter) \ + {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]++; } + +#define RX_ADD_CNT(prRxCtrl, eCounter, u8Amount) \ + {((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] += (UINT_64)u8Amount; } + +#define RX_GET_CNT(prRxCtrl, eCounter) \ + (((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]) + +#define RX_RESET_ALL_CNTS(prRxCtrl) \ + {kalMemZero(&prRxCtrl->au8Statistics[0], sizeof(prRxCtrl->au8Statistics)); } + +#define RX_STATUS_TEST_MORE_FLAG(flag) \ + ((BOOLEAN)((flag & RX_STATUS_FLAG_MORE_PACKET) ? TRUE : FALSE)) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID nicRxInitialize(IN P_ADAPTER_T prAdapter); + +VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter); + +VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter); + +#if !CFG_SDIO_INTR_ENHANCE +VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +#else +VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb); +#endif /* CFG_SDIO_INTR_ENHANCE */ + +#if CFG_SDIO_RX_AGG +VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter); +#endif + +WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); + +VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); + +VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter); + +VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus); + +VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); + +VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter); + +VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count); + +WLAN_STATUS +nicRxWaitResponse(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length); + +VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter); + +VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +#endif /* _NIC_RX_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h new file mode 100644 index 0000000000000..e516468fcb16a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/nic_tx.h @@ -0,0 +1,642 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/nic_tx.h#1 +*/ + +/*! \file nic_tx.h + \brief Functions that provide TX operation in NIC's point of view. + + This file provides TX functions which are responsible for both Hardware and + Software Resource Management and keep their Synchronization. + +*/ + +/* +** Log: nic_tx.h + * + * 11 18 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add log counter for tx + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add TX_DONE status detail information. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing + * frame dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 02 16 2011 cp.wu + * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking + * available count and modify behavior + * 1. add new API: nicTxGetFreeCmdCount() + * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 12 15 2010 yuche.tsai + * NULL + * Update SLT Descriptor number configure in driver. + * + * 11 16 2010 yarco.yang + * [WCXRP00000177] [MT5931 F/W] Performance tuning for 1st connection + * Update TX buffer count + * + * 11 03 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * 1) use 8 buffers for MT5931 which is equipped with less memory + * 2) modify MT5931 debug level to TRACE when download is successful + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 07 26 2010 cp.wu + * + * change TC4 initial value from 2 to 4. + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under + * concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add MGMT Packet type for HIF_TX_HEADER + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add flag on MSDU_INFO_T for indicating BIP frame and forceBasicRate + * 2) add packet type for indicating management frames + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add TX_PACKET_MGMT to indicate the frame is coming from management modules + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 02 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Redistributed the initial TC resources for normal operation + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * 4) nicRxWaitResponse() revised + * * * 5) another set of TQ counter default value is added for fw-download state + * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * 4. correct some HAL implementation + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * and result is retrieved by get ATInfo instead + * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:53:28 GMT mtk02752 +** remove unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-27 11:08:00 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-24 19:56:49 GMT mtk02752 +** remove redundant eTC +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-23 22:01:08 GMT mtk02468 +** Added MSDU_INFO fields for composing HIF TX header +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-17 22:40:51 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-11-17 17:35:05 GMT mtk02752 +** + nicTxMsduInfoList() for sending MsduInfoList +** + NIC_TX_BUFF_COUNT_TC[0~5] +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-11-17 11:07:00 GMT mtk02752 +** add nicTxAdjustTcq() API +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-11-16 22:28:30 GMT mtk02752 +** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-11-16 21:44:50 GMT mtk02752 +** + nicTxReturnMsduInfo() +** + nicTxFillMsduInfo() +** + rFreeMsduInfoList field in TX_CTRL +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-11-16 18:00:43 GMT mtk02752 +** use P_PACKET_INFO_T for prPacket to avoid inventing another new structure for packet +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-11-16 15:28:49 GMT mtk02752 +** add ucQueuedPacketNum for indicating how many packets are queued by per STA/AC queue +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-16 10:52:01 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-14 23:39:24 GMT mtk02752 +** interface structure redefine +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-13 21:17:03 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-10-29 19:53:10 GMT mtk01084 +** remove strange code by Frog +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:59:04 GMT mtk01084 +** update for new HW architecture design +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-10-02 13:53:03 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-28 10:36:50 GMT mtk01461 +** Add declaration of nicTxReleaseResource() +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-17 19:58:39 GMT mtk01461 +** Move CMD_INFO_T related define and function to cmd_buf.h +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:53:53 GMT mtk01461 +** Add function for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:33:27 GMT mtk01461 +** Define constants for TX PATH and add nicTxPollingResource +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:09:32 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:38 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _NIC_TX_H +#define _NIC_TX_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define NIC_TX_RESOURCE_POLLING_TIMEOUT 256 +#define NIC_TX_RESOURCE_POLLING_DELAY_MSEC 50 + +/* Maximum buffer count for individual HIF TCQ */ + +#if defined(MT6620) +#if CFG_SLT_SUPPORT + /* 20101215 mtk01725 Redistributed the initial TC resources for SLT operation */ +#define NIC_TX_BUFF_COUNT_TC0 0 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC1 16 /* First connection: 32 */ +#define NIC_TX_BUFF_COUNT_TC2 0 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC3 0 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ +#define NIC_TX_BUFF_COUNT_TC5 0 /* First connection: 0 */ +#else + /* 20100302 mtk02468 Redistributed the initial TC resources for normal operation */ +#define NIC_TX_BUFF_COUNT_TC0 6 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC1 8 /* First connection: 32 */ +#define NIC_TX_BUFF_COUNT_TC2 8 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC3 8 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ +#define NIC_TX_BUFF_COUNT_TC5 2 /* First connection: 0 */ +#endif +#elif defined(MT6628) +#if (CFG_SRAM_SIZE_OPTION == 0) +#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC1 20 /* First connection: 32 */ +#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ +#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ +#elif (CFG_SRAM_SIZE_OPTION == 1) +#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC1 36 /* First connection: 32 */ +#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ +#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ +#elif (CFG_SRAM_SIZE_OPTION == 2) +#define NIC_TX_BUFF_COUNT_TC0 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC1 48 /* First connection: 32 */ +#define NIC_TX_BUFF_COUNT_TC2 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC3 1 /* First connection: 0 */ +#define NIC_TX_BUFF_COUNT_TC4 4 /* First connection: 2 */ +#define NIC_TX_BUFF_COUNT_TC5 1 /* First connection: 0 */ +#else +#error "> Set TX_BUFF_COUNT_TC error!" +#endif +#endif + +#define NIC_TX_BUFF_SUM (NIC_TX_BUFF_COUNT_TC0 + \ + NIC_TX_BUFF_COUNT_TC1 + \ + NIC_TX_BUFF_COUNT_TC2 + \ + NIC_TX_BUFF_COUNT_TC3 + \ + NIC_TX_BUFF_COUNT_TC4 + \ + NIC_TX_BUFF_COUNT_TC5) +#if CFG_ENABLE_FW_DOWNLOAD + +#define NIC_TX_INIT_BUFF_COUNT_TC0 8 +#define NIC_TX_INIT_BUFF_COUNT_TC1 0 +#define NIC_TX_INIT_BUFF_COUNT_TC2 0 +#define NIC_TX_INIT_BUFF_COUNT_TC3 0 +#define NIC_TX_INIT_BUFF_COUNT_TC4 0 +#define NIC_TX_INIT_BUFF_COUNT_TC5 0 + +#define NIC_TX_INIT_BUFF_SUM (NIC_TX_INIT_BUFF_COUNT_TC0 + \ + NIC_TX_INIT_BUFF_COUNT_TC1 + \ + NIC_TX_INIT_BUFF_COUNT_TC2 + \ + NIC_TX_INIT_BUFF_COUNT_TC3 + \ + NIC_TX_INIT_BUFF_COUNT_TC4 + \ + NIC_TX_INIT_BUFF_COUNT_TC5) + +#endif + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +#define NIC_TX_TIME_THRESHOLD 100 /* in unit of ms */ +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* 3 Session for TX QUEUES */ +/* The definition in this ENUM is used to categorize packet's Traffic Class according + * to the their TID(User Priority). + * In order to achieve QoS goal, a particular TC should not block the process of + * another packet with different TC. + * In current design we will have 5 categories(TCs) of SW resource. + */ +typedef enum _ENUM_TRAFFIC_CLASS_INDEX_T { + TC0_INDEX = 0, /* HIF TX0: AC0 packets */ + TC1_INDEX, /* HIF TX0: AC1 packets & non-QoS packets */ + TC2_INDEX, /* HIF TX0: AC2 packets */ + TC3_INDEX, /* HIF TX0: AC3 packets */ + TC4_INDEX, /* HIF TX1: Command packets or 802.1x packets */ + TC5_INDEX, /* HIF TX0: BMCAST packets */ + TC_NUM /* Maximum number of Traffic Classes. */ +} ENUM_TRAFFIC_CLASS_INDEX_T; + +typedef enum _ENUM_TX_STATISTIC_COUNTER_T { + TX_MPDU_TOTAL_COUNT = 0, + TX_INACTIVE_BSS_DROP, + TX_INACTIVE_STA_DROP, + TX_FORWARD_OVERFLOW_DROP, + TX_AP_BORADCAST_DROP, + TX_STATISTIC_COUNTER_NUM +} ENUM_TX_STATISTIC_COUNTER_T; + +typedef struct _TX_TCQ_STATUS_T { + UINT_8 aucFreeBufferCount[TC_NUM]; + UINT_8 aucMaxNumOfBuffer[TC_NUM]; +} TX_TCQ_STATUS_T, *P_TX_TCQ_STATUS_T; + +typedef struct _TX_TCQ_ADJUST_T { + INT_8 acVariation[TC_NUM]; +} TX_TCQ_ADJUST_T, *P_TX_TCQ_ADJUST_T; + +typedef struct _TX_CTRL_T { + UINT_32 u4TxCachedSize; + PUINT_8 pucTxCached; + +/* Elements below is classified according to TC (Traffic Class) value. */ + + TX_TCQ_STATUS_T rTc; + + PUINT_8 pucTxCoalescingBufPtr; + + QUE_T rFreeMsduInfoList; + + /* Management Frame Tracking */ + /* number of management frames to be sent */ + INT_32 i4TxMgmtPendingNum; + + /* to tracking management frames need TX done callback */ + QUE_T rTxMgmtTxingQueue; + +#if CFG_HIF_STATISTICS + UINT_32 u4TotalTxAccessNum; + UINT_32 u4TotalTxPacketNum; +#endif + UINT_32 au4Statistics[TX_STATISTIC_COUNTER_NUM]; + + /* Number to track forwarding frames */ + INT_32 i4PendingFwdFrameCount; + +} TX_CTRL_T, *P_TX_CTRL_T; + +typedef enum _ENUM_TX_PACKET_SRC_T { + TX_PACKET_OS, + TX_PACKET_OS_OID, + TX_PACKET_FORWARDING, + TX_PACKET_MGMT, + TX_PACKET_NUM +} ENUM_TX_PACKET_SRC_T; + +typedef enum _ENUM_HIF_TX_PACKET_TYPE_T { + HIF_TX_PACKET_TYPE_DATA = 0, + HIF_TX_PACKET_TYPE_COMMAND, + HIF_TX_PACKET_TYPE_HIF_LB, + HIF_TX_PACKET_TYPE_MGMT +} ENUM_HIF_TX_PACKET_TYPE_T, *P_ENUM_HIF_TX_PACKET_TYPE_T; + +typedef enum _ENUM_TX_RESULT_CODE_T { + TX_RESULT_SUCCESS = 0, + TX_RESULT_LIFE_TIMEOUT, + TX_RESULT_RTS_ERROR, + TX_RESULT_MPDU_ERROR, + TX_RESULT_AGING_TIMEOUT, + TX_RESULT_FLUSHED, + TX_RESULT_DROPPED_IN_DRIVER = 32, + TX_RESULT_NUM +} ENUM_TX_RESULT_CODE_T, *P_ENUM_TX_RESULT_CODE_T; + +struct _WLAN_CFG_ENTRY_T { + UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + WLAN_CFG_SET_CB pfSetCb; + PVOID pPrivate; + UINT_32 u4Flags; +}; + +struct _WLAN_CFG_T { + UINT_32 u4WlanCfgEntryNumMax; + UINT_32 u4WlanCfgKeyLenMax; + UINT_32 u4WlanCfgValueLenMax; + WLAN_CFG_ENTRY_T arWlanCfgBuf[WLAN_CFG_ENTRY_NUM_MAX]; +}; + +/* TX Call Back Function */ +typedef WLAN_STATUS(*PFN_TX_DONE_HANDLER) (IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +typedef struct _PKT_PROFILE_T { + BOOLEAN fgIsValid; +#if CFG_PRINT_RTP_PROFILE + BOOLEAN fgIsPrinted; + UINT_16 u2IpSn; + UINT_16 u2RtpSn; + UINT_8 ucTcxFreeCount; +#endif + OS_SYSTIME rHardXmitArrivalTimestamp; + OS_SYSTIME rEnqueueTimestamp; + OS_SYSTIME rDequeueTimestamp; + OS_SYSTIME rHifTxDoneTimestamp; +} PKT_PROFILE_T, *P_PKT_PROFILE_T; +#endif + +/* TX transactions could be divided into 4 kinds: + * + * 1) 802.1X / Bluetooth-over-Wi-Fi Security Frames + * [CMD_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + * + * 2) MMPDU + * [CMD_INFO_T] - [prPacket] - [MSDU_INFO_T] - [prPacket] - direct buffer for frame body + * + * 3) Command Packets + * [CMD_INFO_T] - [pucInfoBuffer] - direct buffer for content of command packet + * + * 4) Normal data frame + * [MSDU_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + */ + +/* PS_FORWARDING_TYPE_NON_PS means that the receiving STA is in Active Mode +* from the perspective of host driver (maybe not synchronized with FW --> SN is needed) +*/ + +struct _MSDU_INFO_T { + QUE_ENTRY_T rQueEntry; + P_NATIVE_PACKET prPacket; + + ENUM_TX_PACKET_SRC_T eSrc; /* specify OS/FORWARD packet */ + UINT_8 ucUserPriority; + + /* For composing HIF TX header */ + UINT_8 ucTC; /* Traffic Class: 0~4 (HIF TX0), 5 (HIF TX1) */ + UINT_8 ucPacketType; /* 0: Data, 1: Command, 2: HIF Loopback 3: Management Frame */ + UINT_8 ucStaRecIndex; + UINT_8 ucNetworkType; /* See ENUM_NETWORK_TYPE_T */ + UINT_8 ucFormatID; /* 0: MAUI, Linux, Windows NDIS 5.1 */ + BOOLEAN fgIs802_1x; /* TRUE: 802.1x frame */ + BOOLEAN fgIs802_11; /* TRUE: 802.11 header is present */ + UINT_16 u2PalLLH; /* PAL Logical Link Header (for BOW network) */ + UINT_16 u2AclSN; /* ACL Sequence Number (for BOW network) */ + UINT_8 ucPsForwardingType; /* See ENUM_PS_FORWARDING_TYPE_T */ + UINT_8 ucPsSessionID; /* PS Session ID specified by the FW for the STA */ + BOOLEAN fgIsBurstEnd; /* TRUE means this is the last packet of the burst for (STA, TID) */ + BOOLEAN fgIsBIP; /* Management Frame Protection */ + BOOLEAN fgIsBasicRate; /* Force Basic Rate Transmission */ + + /* flattened from PACKET_INFO_T */ + UINT_8 ucMacHeaderLength; + UINT_8 ucLlcLength; /* w/o EtherType */ + UINT_16 u2FrameLength; + UINT_8 aucEthDestAddr[MAC_ADDR_LEN]; /* Ethernet Destination Address */ + + /* for TX done tracking */ + UINT_8 ucTxSeqNum; + PFN_TX_DONE_HANDLER pfTxDoneHandler; + BOOLEAN fgNeedTxDoneStatus; + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + PKT_PROFILE_T rPktProfile; +#endif + COMMAND_TYPE eCmdType; + UINT_8 ucCID; + UINT_32 u4InqueTime; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define TX_INC_CNT(prTxCtrl, eCounter) \ + {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]++; } + +#define TX_ADD_CNT(prTxCtrl, eCounter, u8Amount) \ + {((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter] += (UINT_32)u8Amount; } + +#define TX_GET_CNT(prTxCtrl, eCounter) \ + (((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]) + +#define TX_RESET_ALL_CNTS(prTxCtrl) \ + {kalMemZero(&prTxCtrl->au4Statistics[0], sizeof(prTxCtrl->au4Statistics)); } + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +#define PRINT_PKT_PROFILE(_pkt_profile, _note) \ +{ \ + if (!(_pkt_profile)->fgIsPrinted) { \ + DBGLOG(TX, TRACE, "X[%u] E[%u] D[%u] HD[%u] B[%d] RTP[%d] %s\n", \ + (UINT_32)((_pkt_profile)->rHardXmitArrivalTimestamp), \ + (UINT_32)((_pkt_profile)->rEnqueueTimestamp), \ + (UINT_32)((_pkt_profile)->rDequeueTimestamp), \ + (UINT_32)((_pkt_profile)->rHifTxDoneTimestamp), \ + (UINT_8)((_pkt_profile)->ucTcxFreeCount), \ + (UINT_16)((_pkt_profile)->u2RtpSn), \ + (_note)); \ + (_pkt_profile)->fgIsPrinted = TRUE; \ + } \ +} + +#define CHK_PROFILES_DELTA(_pkt1, _pkt2, _delta) \ + (CHECK_FOR_TIMEOUT((_pkt1)->rHardXmitArrivalTimestamp, (_pkt2)->rHardXmitArrivalTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rEnqueueTimestamp, (_pkt2)->rEnqueueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rDequeueTimestamp, (_pkt2)->rDequeueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rHifTxDoneTimestamp, (_pkt2)->rHifTxDoneTimestamp, (_delta))) + +#define CHK_PROFILE_DELTA(_pkt, _delta) \ + (CHECK_FOR_TIMEOUT((_pkt)->rEnqueueTimestamp, (_pkt)->rHardXmitArrivalTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt)->rDequeueTimestamp, (_pkt)->rEnqueueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt)->rHifTxDoneTimestamp, (_pkt)->rDequeueTimestamp, (_delta))) +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID nicTxInitialize(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt); + +WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); + +BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN UINT_8 *aucTxRlsCnt); + +WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter); + +UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC); + +WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); + +WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue); + +WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); + +VOID nicTxRelease(IN P_ADAPTER_T prAdapter); + +VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter); + +VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); + +VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); + +BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prNdisPacket); + +WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter); + +#if CFG_ENABLE_FW_DOWNLOAD +WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC); + +WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter); +#endif + +WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_TX_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h new file mode 100644 index 0000000000000..d518aaf10eb56 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p.h @@ -0,0 +1,192 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p.h#3 +*/ + +/* +** Log: p2p.h + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * p2p interface revised to be sync. with HAL + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 18 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add parameter to control: + * 1) auto group owner + * 2) P2P-PS parameter (CTWindow, NoA descriptors) + * + * 05 18 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * correct WPS Device Password ID definition. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * +*/ + +#ifndef _P2P_H +#define _P2P_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* refer to 'Config Methods' in WPS */ +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC 0x0010 +#define WPS_CONFIG_INT_NFC 0x0020 +#define WPS_CONFIG_NFC 0x0040 +#define WPS_CONFIG_PBC 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 + +/* refer to 'Device Password ID' in WPS */ +#define WPS_DEV_PASSWORD_ID_PIN 0x0000 +#define WPS_DEV_PASSWORD_ID_USER 0x0001 +#define WPS_DEV_PASSWORD_ID_MACHINE 0x0002 +#define WPS_DEV_PASSWORD_ID_REKEY 0x0003 +#define WPS_DEV_PASSWORD_ID_PUSHBUTTON 0x0004 +#define WPS_DEV_PASSWORD_ID_REGISTRAR 0x0005 + +#define P2P_DEVICE_TYPE_NUM 2 +#define P2P_DEVICE_NAME_LENGTH 32 +#define P2P_NETWORK_NUM 8 +#define P2P_MEMBER_NUM 8 + +#define P2P_WILDCARD_SSID "DIRECT-" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct _P2P_INFO_T { + UINT_32 u4DeviceNum; + EVENT_P2P_DEV_DISCOVER_RESULT_T arP2pDiscoverResult[CFG_MAX_NUM_BSS_LIST]; + PUINT_8 pucCurrIePtr; + UINT_8 aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]; /* A common pool for IE of all scan results. */ +}; + +typedef enum { + ENUM_P2P_PEER_GROUP, + ENUM_P2P_PEER_DEVICE, + ENUM_P2P_PEER_NUM +} ENUM_P2P_PEER_TYPE, *P_ENUM_P2P_PEER_TYPE; + +typedef struct _P2P_DEVICE_INFO { + UINT_8 aucDevAddr[PARAM_MAC_ADDR_LEN]; + UINT_8 aucIfAddr[PARAM_MAC_ADDR_LEN]; + UINT_8 ucDevCapabilityBitmap; + INT_32 i4ConfigMethod; + UINT_8 aucPrimaryDeviceType[8]; + UINT_8 aucSecondaryDeviceType[8]; + UINT_8 aucDeviceName[P2P_DEVICE_NAME_LENGTH]; +} P2P_DEVICE_INFO, *P_P2P_DEVICE_INFO; + +typedef struct _P2P_GROUP_INFO { + PARAM_SSID_T rGroupID; + P2P_DEVICE_INFO rGroupOwnerInfo; + UINT_8 ucMemberNum; + P2P_DEVICE_INFO arMemberInfo[P2P_MEMBER_NUM]; +} P2P_GROUP_INFO, *P_P2P_GROUP_INFO; + +typedef struct _P2P_NETWORK_INFO { + ENUM_P2P_PEER_TYPE eNodeType; + + union { + P2P_GROUP_INFO rGroupInfo; + P2P_DEVICE_INFO rDeviceInfo; + } node; + +} P2P_NETWORK_INFO, *P_P2P_NETWORK_INFO; + +typedef struct _P2P_NETWORK_LIST { + UINT_8 ucNetworkNum; + P2P_NETWORK_INFO rP2PNetworkInfo[P2P_NETWORK_NUM]; +} P2P_NETWORK_LIST, *P_P2P_NETWORK_LIST; + +typedef struct _P2P_DISCONNECT_INFO { + UINT_8 ucRole; + UINT_8 ucRsv[3]; +} P2P_DISCONNECT_INFO, *P_P2P_DISCONNECT_INFO; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#endif /*_P2P_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h new file mode 100644 index 0000000000000..7f7a92584c7ce --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_cmd_buf.h @@ -0,0 +1,83 @@ +/* +** Id: +*/ + +/*! \file "p2p_cmd_buf.h" + \brief In this file we define the structure for Command Packet. + + In this file we define the structure for Command Packet and the control unit + of MGMT Memory Pool. +*/ + +/* +** Log: p2p_cmd_buf.h + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface + * for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks +*/ + +#ifndef _P2P_CMD_BUF_H +#define _P2P_CMD_BUF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Firmware Command Packer */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + BOOLEAN fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, + PUINT_8 pucInfoBuffer, OUT PVOID pvSetQueryBuffer, IN UINT_32 u4SetQueryBufferLen); + +#endif /* _P2P_CMD_BUF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h new file mode 100644 index 0000000000000..76115dabe1a1d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_mac.h @@ -0,0 +1,207 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_mac.h#2 +*/ + +/*! \file "p2p_mac.h" + \brief Brief description. + + Detail description. +*/ + +#ifndef _P2P_MAC_H +#define _P2P_MAC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define ACTION_PUBLIC_WIFI_DIRECT 9 +#define ACTION_GAS_INITIAL_REQUEST 10 +#define ACTION_GAS_INITIAL_RESPONSE 11 +#define ACTION_GAS_COMEBACK_REQUEST 12 +#define ACTION_GAS_COMEBACK_RESPONSE 13 + +/* P2P 4.2.8.1 - P2P Public Action Frame Type. */ +#define P2P_PUBLIC_ACTION_GO_NEGO_REQ 0 +#define P2P_PUBLIC_ACTION_GO_NEGO_RSP 1 +#define P2P_PUBLIC_ACTION_GO_NEGO_CFM 2 +#define P2P_PUBLIC_ACTION_INVITATION_REQ 3 +#define P2P_PUBLIC_ACTION_INVITATION_RSP 4 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ 5 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP 6 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ 7 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP 8 + +/* P2P 4.2.9.1 - P2P Action Frame Type */ +#define P2P_ACTION_NOTICE_OF_ABSENCE 0 +#define P2P_ACTION_P2P_PRESENCE_REQ 1 +#define P2P_ACTION_P2P_PRESENCE_RSP 2 +#define P2P_ACTION_GO_DISCOVER_REQ 3 + +#define P2P_PUBLIC_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+8) +#define P2P_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN+7) + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/* P2P 4.2.8.2 P2P Public Action Frame Format */ +typedef struct _P2P_PUBLIC_ACTION_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ + UINT_8 ucOuiType; /* 0x09 */ + UINT_8 ucOuiSubtype; /* GO Nego Req/Rsp/Cfm, P2P Invittion Req/Rsp, Device Discoverability Req/Rsp */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_8 aucInfoElem[1]; /* P2P IE, WSC IE. */ +} __KAL_ATTRIB_PACKED__ P2P_PUBLIC_ACTION_FRAME_T, *P_P2P_PUBLIC_ACTION_FRAME_T; + +/* P2P 4.2.9.1 - General Action Frame Format. */ +typedef struct _P2P_ACTION_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Action Frame Body */ + UINT_8 ucCategory; /* 0x7F */ + UINT_8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ + UINT_8 ucOuiType; /* 0x09 */ + UINT_8 ucOuiSubtype; /* */ + UINT_8 ucDialogToken; + UINT_8 aucInfoElem[1]; +} __KAL_ATTRIB_PACKED__ P2P_ACTION_FRAME_T, *P_P2P_ACTION_FRAME_T; + +/* P2P C.1 GAS Public Action Initial Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T; + +/* P2P C.2 GAS Public Action Initial Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_16 u2StatusCode; /* Initial Response. */ + UINT_16 u2ComebackDelay; /* Initial Response. *//* In unit of TU. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T; + +/* P2P C.3-1 GAS Public Action Comeback Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T; + +/* P2P C.3-2 GAS Public Action Comeback Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T { + /* MAC header */ + UINT_16 u2FrameCtrl; /* Frame Control */ + UINT_16 u2Duration; /* Duration */ + UINT_8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + UINT_8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + UINT_8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + UINT_16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + UINT_8 ucCategory; /* Category, 0x04 */ + UINT_8 ucAction; /* Action Value, 0x09 */ + UINT_8 ucDialogToken; /* Dialog Token. */ + UINT_16 u2StatusCode; /* Comeback Response. */ + UINT_8 ucFragmentID; /*Comeback Response. */ + UINT_16 u2ComebackDelay; /* Comeback Response. */ + UINT_8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T, *P_GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T; + +typedef struct _P2P_SD_VENDER_SPECIFIC_CONTENT_T { + /* Service Discovery Vendor-specific Content. */ + UINT_8 ucOuiSubtype; /* 0x09 */ + UINT_16 u2ServiceUpdateIndicator; + UINT_8 aucServiceTLV[1]; +} __KAL_ATTRIB_PACKED__ P2P_SD_VENDER_SPECIFIC_CONTENT_T, *P_P2P_SD_VENDER_SPECIFIC_CONTENT_T; + +typedef struct _P2P_SERVICE_REQUEST_TLV_T { + UINT_16 u2Length; + UINT_8 ucServiceProtocolType; + UINT_8 ucServiceTransID; + UINT_8 aucQueryData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_REQUEST_TLV_T, *P_P2P_SERVICE_REQUEST_TLV_T; + +typedef struct _P2P_SERVICE_RESPONSE_TLV_T { + UINT_16 u2Length; + UINT_8 ucServiceProtocolType; + UINT_8 ucServiceTransID; + UINT_8 ucStatusCode; + UINT_8 aucResponseData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_RESPONSE_TLV_T, *P_P2P_SERVICE_RESPONSE_TLV_T; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h new file mode 100644 index 0000000000000..0a87bd457a926 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic.h @@ -0,0 +1,62 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic.h#1 +*/ + +/*! \file "p2p_nic.h" + \brief The declaration of nic functions + + Detail description. +*/ + +#ifndef _P2P_NIC_H +#define _P2P_NIC_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +VOID +nicP2pMediaStateChange(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus); + +VOID +nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h new file mode 100644 index 0000000000000..cea77414ce357 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/p2p_nic_cmd_event.h @@ -0,0 +1,70 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/nic/p2p_nic_cmd_event.h#1 +*/ + +/*! \file p2p_nic_cmd_event.h + \brief +*/ + +#ifndef _P2P_NIC_CMD_EVENT_H +#define _P2P_NIC_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +typedef struct _EVENT_P2P_DEV_DISCOVER_RESULT_T { +/* UINT_8 aucCommunicateAddr[MAC_ADDR_LEN]; // Deprecated. */ + UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 ucDeviceCapabilityBitmap; + UINT_8 ucGroupCapabilityBitmap; + UINT_16 u2ConfigMethod; /* Configure Method. */ + P2P_DEVICE_TYPE_T rPriDevType; + UINT_8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T arSecDevType[2]; + UINT_16 u2NameLength; + UINT_8 aucName[32]; + PUINT_8 pucIeBuf; + UINT_16 u2IELength; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + /* TODO: Service Information or PasswordID valid? */ +} EVENT_P2P_DEV_DISCOVER_RESULT_T, *P_EVENT_P2P_DEV_DISCOVER_RESULT_T; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h new file mode 100644 index 0000000000000..dbfb90d94ee4c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/que_mgt.h @@ -0,0 +1,971 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/que_mgt.h#1 +*/ + +/*! \file "que_mgt.h" + \brief TX/RX queues management header file + + The main tasks of queue management include TC-based HIF TX flow control, + adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + forwarding control, RX packet reordering, and RX BA agreement management. +*/ + +/* +** Log: que_mgt.h + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 07 26 2011 eddie.chen + * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter + * API for query the RX reorder queued packets counter. + * + * 06 14 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Change the parameter for WMM pass. + * + * 05 31 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Fix the QM quota in MT5931. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 03 28 2011 eddie.chen + * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW + * Fix wmm parameters in beacon for BOW. + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Change GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * 1) Check Bss if support QoS before adding WMMIE + * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T + * and replaced by ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 07 22 2010 george.huang + * + * Update fgIsQoS information in BSS INFO by CMD + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 yarco.yang + * + * [WPD00003849] + * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 30 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled adaptive TC resource control + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 19 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * By default enabling dynamic STA_REC activation and decactivation + * + * 03 17 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) + * + * 03 11 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed buffer leak when processing BAR frames + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled multi-STA TX path with fairness + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled dynamically activating and deactivating STA_RECs + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for dynamic activating and deactivating STA_RECs. + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-12-09 14:04:53 GMT MTK02468 +** Added RX buffer reordering function prototypes +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-02 22:08:44 GMT MTK02468 +** Added macro QM_INIT_STA_REC for initialize a STA_REC +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 21:58:43 GMT mtk02468 +** Initial version +** +*/ + +#ifndef _QUE_MGT_H +#define _QUE_MGT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* Queue Manager Features */ +/* 1: Indicate the last TX packet to the FW for each burst */ +#define QM_BURST_END_INFO_ENABLED 1 +/* 1: To fairly share TX resource among active STAs */ +#define QM_FORWARDING_FAIRNESS 1 +/* 1: To adaptively adjust resource for each TC */ +#define QM_ADAPTIVE_TC_RESOURCE_CTRL 1 +/* 1: To print TC resource adjustment results */ +#define QM_PRINT_TC_RESOURCE_CTRL 0 +/* 1: If pkt with SSN is missing, auto advance the RX reordering window */ +#define QM_RX_WIN_SSN_AUTO_ADVANCING 1 +/* 1: Indicate the packets falling behind to OS before the frame with SSN is received */ +#define QM_RX_INIT_FALL_BEHIND_PASS 1 +/* 1: Count times of TC resource empty happened */ +#define QM_TC_RESOURCE_EMPTY_COUNTER 1 +/* Parameters */ + +/* + In TDLS or AP mode, peer maybe enter "sleep mode". + + If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, + we need to wait 60 * u4TimeToAdjustTcResource = 180 packets + u4TimeToAdjustTcResource = 3, + then we will adjust TC resouce for VI or VO. + + But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, + we will to wait about 12 seconds to collect 180 packets. + but the test time is only 20 seconds. +*/ +#define QM_INIT_TIME_TO_UPDATE_QUE_LEN 60 /* p: Update queue lengths when p TX packets are enqueued */ +#define QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN 5 + +#define QM_INIT_TIME_TO_ADJUST_TC_RSC 3 /* s: Adjust the TC resource every s updates of queue lengths */ +#define QM_QUE_LEN_MOVING_AVE_FACTOR 3 /* Factor for Que Len averaging */ + +#define QM_MIN_RESERVED_TC0_RESOURCE 1 +#define QM_MIN_RESERVED_TC1_RESOURCE 1 +#define QM_MIN_RESERVED_TC2_RESOURCE 1 +#define QM_MIN_RESERVED_TC3_RESOURCE 1 +#define QM_MIN_RESERVED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_MIN_RESERVED_TC5_RESOURCE 1 + +#if defined(MT6620) + +#define QM_GUARANTEED_TC0_RESOURCE 4 +#define QM_GUARANTEED_TC1_RESOURCE 4 +#define QM_GUARANTEED_TC2_RESOURCE 9 +#define QM_GUARANTEED_TC3_RESOURCE 11 +#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_GUARANTEED_TC5_RESOURCE 4 + +#elif defined(MT6628) + +#define QM_GUARANTEED_TC0_RESOURCE 4 +#define QM_GUARANTEED_TC1_RESOURCE 4 +#define QM_GUARANTEED_TC2_RESOURCE 6 +#define QM_GUARANTEED_TC3_RESOURCE 6 +#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_GUARANTEED_TC5_RESOURCE 4 + +#else +#error +#endif + +#define QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY 0 + +#define QM_TOTAL_TC_RESOURCE (\ + NIC_TX_BUFF_COUNT_TC0 + NIC_TX_BUFF_COUNT_TC1 +\ + NIC_TX_BUFF_COUNT_TC2 + NIC_TX_BUFF_COUNT_TC3 +\ + NIC_TX_BUFF_COUNT_TC5) +#define QM_AVERAGE_TC_RESOURCE 6 + +/* Note: QM_INITIAL_RESIDUAL_TC_RESOURCE shall not be less than 0 */ +/* for 6628: QM_TOTAL_TC_RESOURCE = 28, RESIDUAL = 4 4 6 6 2 4 = 26 */ +#define QM_INITIAL_RESIDUAL_TC_RESOURCE (QM_TOTAL_TC_RESOURCE - \ + (QM_GUARANTEED_TC0_RESOURCE +\ + QM_GUARANTEED_TC1_RESOURCE +\ + QM_GUARANTEED_TC2_RESOURCE +\ + QM_GUARANTEED_TC3_RESOURCE +\ + QM_GUARANTEED_TC5_RESOURCE \ + )) + +/* Hard-coded network type for Phase 3: NETWORK_TYPE_AIS/P2P/BOW */ +#define QM_OPERATING_NETWORK_TYPE NETWORK_TYPE_AIS + +#define QM_TEST_MODE 0 +#define QM_TEST_TRIGGER_TX_COUNT 50 +#define QM_TEST_STA_REC_DETERMINATION 0 +#define QM_TEST_STA_REC_DEACTIVATION 0 +#define QM_TEST_FAIR_FORWARDING 0 + +#define QM_DEBUG_COUNTER 0 + +/* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3, [4] 802.1x */ +/* Per-Type Queues: [0] BMCAST */ +#define NUM_OF_PER_STA_TX_QUEUES 5 +#define NUM_OF_PER_TYPE_TX_QUEUES 1 + +/* These two constants are also used for FW to verify the STA_REC index */ +#define STA_REC_INDEX_BMCAST 0xFF +#define STA_REC_INDEX_NOT_FOUND 0xFE + +/* TX Queue Index */ +#define TX_QUEUE_INDEX_BMCAST 0 +#define TX_QUEUE_INDEX_NO_STA_REC 0 +#define TX_QUEUE_INDEX_AC0 0 +#define TX_QUEUE_INDEX_AC1 1 +#define TX_QUEUE_INDEX_AC2 2 +#define TX_QUEUE_INDEX_AC3 3 +#define TX_QUEUE_INDEX_802_1X 4 +#define TX_QUEUE_INDEX_NON_QOS 1 + +/* 1 WMM-related */ +/* WMM FLAGS */ +#define WMM_FLAG_SUPPORT_WMM BIT(0) +#define WMM_FLAG_SUPPORT_WMMSA BIT(1) +#define WMM_FLAG_AC_PARAM_PRESENT BIT(2) +#define WMM_FLAG_SUPPORT_UAPSD BIT(3) + +/* WMM Admission Control Mandatory FLAGS */ +#define ACM_FLAG_ADM_NOT_REQUIRED 0 +#define ACM_FLAG_ADM_GRANTED BIT(0) +#define ACM_FLAG_ADM_REQUIRED BIT(1) + +/* WMM Power Saving FLAGS */ +#define AC_FLAG_TRIGGER_ENABLED BIT(1) +#define AC_FLAG_DELIVERY_ENABLED BIT(2) + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/* WMM-2.2.2 WMM Parameter Element */ +#define ELEM_MAX_LEN_WMM_PARAM 24 + +/* WMM-2.2.1 WMM QoS Info field */ +#define WMM_QOS_INFO_PARAM_SET_CNT BITS(0, 3) /* Sent by AP */ +#define WMM_QOS_INFO_UAPSD BIT(7) + +#define WMM_QOS_INFO_VO_UAPSD BIT(0) /* Sent by non-AP STA */ +#define WMM_QOS_INFO_VI_UAPSD BIT(1) +#define WMM_QOS_INFO_BK_UAPSD BIT(2) +#define WMM_QOS_INFO_BE_UAPSD BIT(3) +#define WMM_QOS_INFO_MAX_SP_LEN_MASK BITS(5, 6) +#define WMM_QOS_INFO_MAX_SP_ALL 0 +#define WMM_QOS_INFO_MAX_SP_2 BIT(5) +#define WMM_QOS_INFO_MAX_SP_4 BIT(6) +#define WMM_QOS_INFO_MAX_SP_6 BITS(5, 6) + +/* -- definitions for Max SP length field */ +#define WMM_MAX_SP_LENGTH_ALL 0 +#define WMM_MAX_SP_LENGTH_2 2 +#define WMM_MAX_SP_LENGTH_4 4 +#define WMM_MAX_SP_LENGTH_6 6 + +/* WMM-2.2.2 WMM ACI/AIFSN field */ +/* -- subfields in the ACI/AIFSN field */ +#define WMM_ACIAIFSN_AIFSN BITS(0, 3) +#define WMM_ACIAIFSN_ACM BIT(4) +#define WMM_ACIAIFSN_ACI BITS(5, 6) +#define WMM_ACIAIFSN_ACI_OFFSET 5 + +/* -- definitions for ACI field */ +#define WMM_ACI_AC_BE 0 +#define WMM_ACI_AC_BK BIT(5) +#define WMM_ACI_AC_VI BIT(6) +#define WMM_ACI_AC_VO BITS(5, 6) + +#define WMM_ACI(_AC) (_AC << WMM_ACIAIFSN_ACI_OFFSET) + +/* -- definitions for ECWmin/ECWmax field */ +#define WMM_ECW_WMIN_MASK BITS(0, 3) +#define WMM_ECW_WMAX_MASK BITS(4, 7) +#define WMM_ECW_WMAX_OFFSET 4 + +#define TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME 0 /* Unit: 64 us */ + +#define QM_RX_BA_ENTRY_MISS_TIMEOUT_MS (1000) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +enum { + QM_DBG_CNT_00 = 0, + QM_DBG_CNT_01, + QM_DBG_CNT_02, + QM_DBG_CNT_03, + QM_DBG_CNT_04, + QM_DBG_CNT_05, + QM_DBG_CNT_06, + QM_DBG_CNT_07, + QM_DBG_CNT_08, + QM_DBG_CNT_09, + QM_DBG_CNT_10, + QM_DBG_CNT_11, + QM_DBG_CNT_12, + QM_DBG_CNT_13, + QM_DBG_CNT_14, + QM_DBG_CNT_15, + QM_DBG_CNT_16, + QM_DBG_CNT_17, + QM_DBG_CNT_18, + QM_DBG_CNT_19, + QM_DBG_CNT_20, + QM_DBG_CNT_21, + QM_DBG_CNT_22, + QM_DBG_CNT_23, + QM_DBG_CNT_24, + QM_DBG_CNT_25, + QM_DBG_CNT_26, + QM_DBG_CNT_27, + QM_DBG_CNT_28, + QM_DBG_CNT_29, + QM_DBG_CNT_30, + QM_DBG_CNT_31, + QM_DBG_CNT_NUM +}; + +/* Used for MAC TX */ +typedef enum _ENUM_MAC_TX_QUEUE_INDEX_T { + MAC_TX_QUEUE_AC0_INDEX = 0, + MAC_TX_QUEUE_AC1_INDEX, + MAC_TX_QUEUE_AC2_INDEX, + MAC_TX_QUEUE_AC3_INDEX, + MAC_TX_QUEUE_AC4_INDEX, + MAC_TX_QUEUE_AC5_INDEX, + MAC_TX_QUEUE_AC6_INDEX, + MAC_TX_QUEUE_BCN_INDEX, + MAC_TX_QUEUE_BMC_INDEX, + MAC_TX_QUEUE_NUM +} ENUM_MAC_TX_QUEUE_INDEX_T; + +typedef struct _RX_BA_ENTRY_T { + BOOLEAN fgIsValid; + QUE_T rReOrderQue; + UINT_16 u2WinStart; + UINT_16 u2WinEnd; + UINT_16 u2WinSize; + + /* For identifying the RX BA agreement */ + UINT_8 ucStaRecIdx; + UINT_8 ucTid; + + BOOLEAN fgIsWaitingForPktWithSsn; + + /* UINT_8 ucTxBufferSize; */ + /* BOOL fgIsAcConstrain; */ + /* BOOL fgIsBaEnabled; */ +} RX_BA_ENTRY_T, *P_RX_BA_ENTRY_T; + +/* The mailbox message (could be used for Host-To-Device or Device-To-Host Mailbox) */ +typedef struct _MAILBOX_MSG_T { + UINT_32 u4Msg[2]; /* [0]: D2HRM0R or H2DRM0R, [1]: D2HRM1R or H2DRM1R */ +} MAILBOX_MSG_T, *P_MAILBOX_MSG_T; + +/* Used for adaptively adjusting TC resources */ +typedef struct _TC_RESOURCE_CTRL_T { + /* TC0, TC1, TC2, TC3, TC5 */ + UINT_32 au4AverageQueLen[TC_NUM - 1]; +} TC_RESOURCE_CTRL_T, *P_TC_RESOURCE_CTRL_T; + +typedef struct _QUE_MGT_T { /* Queue Management Control Info */ + + /* Per-Type Queues: [0] BMCAST or UNKNOWN-STA packets */ + QUE_T arTxQueue[NUM_OF_PER_TYPE_TX_QUEUES]; + +#if 0 + /* For TX Scheduling */ + UINT_8 arRemainingTxOppt[NUM_OF_PER_STA_TX_QUEUES]; + UINT_8 arCurrentTxStaIndex[NUM_OF_PER_STA_TX_QUEUES]; + +#endif + + /* Reordering Queue Parameters */ + RX_BA_ENTRY_T arRxBaTable[CFG_NUM_OF_RX_BA_AGREEMENTS]; + + /* Current number of activated RX BA agreements <= CFG_NUM_OF_RX_BA_AGREEMENTS */ + UINT_8 ucRxBaCount; + +#if QM_TEST_MODE + UINT_32 u4PktCount; + P_ADAPTER_T prAdapter; + +#if QM_TEST_FAIR_FORWARDING + UINT_32 u4CurrentStaRecIndexToEnqueue; +#endif + +#endif + +#if QM_FORWARDING_FAIRNESS + /* The current TX count for a STA with respect to a TC index */ + UINT_32 au4ForwardCount[NUM_OF_PER_STA_TX_QUEUES]; + + /* The current serving STA with respect to a TC index */ + UINT_32 au4HeadStaRecIndex[NUM_OF_PER_STA_TX_QUEUES]; +#endif + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + UINT_32 au4AverageQueLen[TC_NUM]; + UINT_32 au4CurrentTcResource[TC_NUM]; + UINT_32 au4MinReservedTcResource[TC_NUM]; /* The minimum amount of resource no matter busy or idle */ + UINT_32 au4GuaranteedTcResource[TC_NUM]; /* The minimum amount of resource when extremely busy */ + + UINT_32 u4TimeToAdjustTcResource; + UINT_32 u4TimeToUpdateQueLen; + UINT_32 u4TxNumOfVi, u4TxNumOfVo; /* number of VI/VO packets */ + + /* Set to TRUE if the last TC adjustment has not been completely applied (i.e., waiting more TX-Done events + to align the TC quotas to the TC resource assignment) */ + BOOLEAN fgTcResourcePostAnnealing; + +#endif + +#if QM_DEBUG_COUNTER + UINT_32 au4QmDebugCounters[QM_DBG_CNT_NUM]; +#endif +#if QM_TC_RESOURCE_EMPTY_COUNTER + UINT_32 au4QmTcResourceEmptyCounter[NET_TYPE_NUM][TC_NUM]; + UINT_32 au4QmTcResourceBackCounter[TC_NUM]; + UINT_32 au4DequeueNoTcResourceCounter[TC_NUM]; + + UINT_32 au4ResourceUsedCounter[TC_NUM]; + + UINT_32 au4ResourceWantedCounter[TC_NUM]; + + UINT_32 u4EnqeueuCounter; + UINT_32 u4DequeueCounter; +#endif +} QUE_MGT_T, *P_QUE_MGT_T; + +typedef struct _EVENT_RX_ADDBA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Fields not present in the received ADDBA_REQ */ + UINT_8 ucStaRecIdx; + + /* Fields that are present in the received ADDBA_REQ */ + UINT_8 ucDialogToken; /* Dialog Token chosen by the sender */ + UINT_16 u2BAParameterSet; /* BA policy, TID, buffer size */ + UINT_16 u2BATimeoutValue; + UINT_16 u2BAStartSeqCtrl; /* SSN */ + +} EVENT_RX_ADDBA_T, *P_EVENT_RX_ADDBA_T; + +typedef struct _EVENT_RX_DELBA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Fields not present in the received ADDBA_REQ */ + UINT_8 ucStaRecIdx; + UINT_8 ucTid; +} EVENT_RX_DELBA_T, *P_EVENT_RX_DELBA_T; + +typedef struct _EVENT_BSS_ABSENCE_PRESENCE_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucNetTypeIdx; + BOOLEAN fgIsAbsent; + UINT_8 ucBssFreeQuota; + UINT_8 aucReserved[1]; +} EVENT_BSS_ABSENCE_PRESENCE_T, *P_EVENT_BSS_ABSENCE_PRESENCE_T; + +typedef struct _EVENT_STA_CHANGE_PS_MODE_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucStaRecIdx; + BOOLEAN fgIsInPs; + UINT_8 ucUpdateMode; + UINT_8 ucFreeQuota; +} EVENT_STA_CHANGE_PS_MODE_T, *P_EVENT_STA_CHANGE_PS_MODE_T; + +/* The free quota is used by PS only now */ +/* The event may be used by per STA flow conttrol in general */ +typedef struct _EVENT_STA_UPDATE_FREE_QUOTA_T { + /* Event header */ + UINT_16 u2Length; + UINT_16 u2Reserved1; /* Must be filled with 0x0001 (EVENT Packet) */ + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + /* Event Body */ + UINT_8 ucStaRecIdx; + UINT_8 ucUpdateMode; + UINT_8 ucFreeQuota; + UINT_8 aucReserved[1]; +} EVENT_STA_UPDATE_FREE_QUOTA_T, *P_EVENT_STA_UPDATE_FREE_QUOTA_T; + +/* WMM-2.2.1 WMM Information Element */ +typedef struct _IE_WMM_INFO_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + UINT_8 ucQosInfo; /* QoS Info field */ + UINT_8 ucDummy[3]; /* Dummy for pack */ +} IE_WMM_INFO_T, *P_IE_WMM_INFO_T; + +/* WMM-2.2.2 WMM Parameter Element */ +typedef struct _IE_WMM_PARAM_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + + /* IE Body */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + + /* WMM IE Body */ + UINT_8 ucQosInfo; /* QoS Info field */ + UINT_8 ucReserved; + + /* AC Parameters */ + UINT_8 ucAciAifsn_BE; + UINT_8 ucEcw_BE; + UINT_8 aucTxopLimit_BE[2]; + + UINT_8 ucAciAifsn_BG; + UINT_8 ucEcw_BG; + UINT_8 aucTxopLimit_BG[2]; + + UINT_8 ucAciAifsn_VI; + UINT_8 ucEcw_VI; + UINT_8 aucTxopLimit_VI[2]; + + UINT_8 ucAciAifsn_VO; + UINT_8 ucEcw_VO; + UINT_8 aucTxopLimit_VO[2]; + +} IE_WMM_PARAM_T, *P_IE_WMM_PARAM_T; + +typedef struct _IE_WMM_TSPEC_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + /* WMM TSPEC body */ + UINT_8 aucTsInfo[3]; /* TS Info */ + UINT_8 aucTspecBodyPart[1]; /* Note: Utilize PARAM_QOS_TSPEC to fill (memory copy) */ +} IE_WMM_TSPEC_T, *P_IE_WMM_TSPEC_T; + +typedef struct _IE_WMM_HDR_T { + UINT_8 ucId; /* Element ID */ + UINT_8 ucLength; /* Length */ + UINT_8 aucOui[3]; /* OUI */ + UINT_8 ucOuiType; /* OUI Type */ + UINT_8 ucOuiSubtype; /* OUI Subtype */ + UINT_8 ucVersion; /* Version */ + UINT_8 aucBody[1]; /* IE body */ +} IE_WMM_HDR_T, *P_IE_WMM_HDR_T; + +typedef struct _AC_QUE_PARMS_T { + UINT_16 u2CWmin; /*!< CWmin */ + UINT_16 u2CWmax; /*!< CWmax */ + UINT_16 u2TxopLimit; /*!< TXOP limit */ + UINT_16 u2Aifsn; /*!< AIFSN */ + UINT_8 ucGuradTime; /*!< GuardTime for STOP/FLUSH. */ + BOOLEAN fgIsACMSet; +} AC_QUE_PARMS_T, *P_AC_QUE_PARMS_T; + +/* WMM ACI (AC index) */ +typedef enum _ENUM_WMM_ACI_T { + WMM_AC_BE_INDEX = 0, + WMM_AC_BK_INDEX, + WMM_AC_VI_INDEX, + WMM_AC_VO_INDEX, + WMM_AC_INDEX_NUM +} ENUM_WMM_ACI_T, *P_ENUM_WMM_ACI_T; + +/* Used for CMD Queue Operation */ +typedef enum _ENUM_FRAME_ACTION_T { + FRAME_ACTION_DROP_PKT = 0, + FRAME_ACTION_QUEUE_PKT, + FRAME_ACTION_TX_PKT, + FRAME_ACTION_NUM +} ENUM_FRAME_ACTION_T; + +typedef enum _ENUM_FRAME_TYPE_IN_CMD_Q_T { + FRAME_TYPE_802_1X = 0, + FRAME_TYPE_MMPDU, + FRAME_TYPE_NUM +} ENUM_FRAME_TYPE_IN_CMD_Q_T; + +typedef enum _ENUM_FREE_QUOTA_MODET_T { + FREE_QUOTA_UPDATE_MODE_INIT = 0, + FREE_QUOTA_UPDATE_MODE_OVERWRITE, + FREE_QUOTA_UPDATE_MODE_INCREASE, + FREE_QUOTA_UPDATE_MODE_DECREASE +} ENUM_FREE_QUOTA_MODET_T, *P_ENUM_FREE_QUOTA_MODET_T; + +typedef struct _CMD_UPDATE_WMM_PARMS_T { + AC_QUE_PARMS_T arACQueParms[AC_NUM]; + UINT_8 ucNetTypeIndex; + UINT_8 fgIsQBSS; + UINT_8 aucReserved[2]; +} CMD_UPDATE_WMM_PARMS_T, *P_CMD_UPDATE_WMM_PARMS_T; + +typedef struct _CMD_TX_AMPDU_T { + BOOLEAN fgEnable; + UINT_8 aucReserved[3]; +} CMD_TX_AMPDU_T, *P_CMD_TX_AMPDU_T; + +typedef struct _CMD_ADDBA_REJECT { + BOOLEAN fgEnable; + UINT_8 aucReserved[3]; +} CMD_ADDBA_REJECT_T, *P_CMD_ADDBA_REJECT_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define QM_TX_SET_NEXT_MSDU_INFO(_prMsduInfoPreceding, _prMsduInfoNext) \ + ((((_prMsduInfoPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prMsduInfoNext)) + +#define QM_TX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) + +#define QM_TX_GET_NEXT_MSDU_INFO(_prMsduInfo) \ + ((P_MSDU_INFO_T)(((_prMsduInfo)->rQueEntry).prNext)) + +#define QM_RX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = (P_QUE_ENTRY_T)(_prSwRfbNext)) + +#define QM_RX_GET_NEXT_SW_RFB(_prSwRfb) \ + ((P_SW_RFB_T)(((_prSwRfb)->rQueEntry).prNext)) + +#if 0 +#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ + ((((_ucIndex) != STA_REC_INDEX_BMCAST) && ((_ucIndex) != STA_REC_INDEX_NOT_FOUND)) ?\ + &(_prAdapter->arStaRec[_ucIndex]) : NULL) +#endif + +#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ + cnmGetStaRecByIndex(_prAdapter, _ucIndex) + +#define QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(\ + _prMsduInfo,\ + _ucTC,\ + _ucPacketType,\ + _ucFormatID,\ + _fgIs802_1x,\ + _fgIs802_11,\ + _u2PalLLH,\ + _u2AclSN,\ + _ucPsForwardingType,\ + _ucPsSessionID\ + ) \ +{\ + ASSERT(_prMsduInfo);\ + (_prMsduInfo)->ucTC = (_ucTC);\ + (_prMsduInfo)->ucPacketType = (_ucPacketType);\ + (_prMsduInfo)->ucFormatID = (_ucFormatID);\ + (_prMsduInfo)->fgIs802_1x = (_fgIs802_1x);\ + (_prMsduInfo)->fgIs802_11 = (_fgIs802_11);\ + (_prMsduInfo)->u2PalLLH = (_u2PalLLH);\ + (_prMsduInfo)->u2AclSN = (_u2AclSN);\ + (_prMsduInfo)->ucPsForwardingType = (_ucPsForwardingType);\ + (_prMsduInfo)->ucPsSessionID = (_ucPsSessionID);\ + (_prMsduInfo)->fgIsBurstEnd = (FALSE);\ +} + +#define QM_INIT_STA_REC(\ + _prStaRec,\ + _fgIsValid,\ + _fgIsQoS,\ + _pucMacAddr\ + )\ +{\ + ASSERT(_prStaRec);\ + (_prStaRec)->fgIsValid = (_fgIsValid);\ + (_prStaRec)->fgIsQoS = (_fgIsQoS);\ + (_prStaRec)->fgIsInPS = FALSE; \ + (_prStaRec)->ucPsSessionID = 0xFF;\ + COPY_MAC_ADDR((_prStaRec)->aucMacAddr, (_pucMacAddr));\ +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +#define QM_GET_TX_QUEUE_LEN(_prAdapter, _u4QueIdx) \ + ((_prAdapter->rQM.au4AverageQueLen[(_u4QueIdx)] >> QM_QUE_LEN_MOVING_AVE_FACTOR)) +#endif + +#define WMM_IE_OUI_TYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiType) +#define WMM_IE_OUI_SUBTYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiSubtype) +#define WMM_IE_OUI(fp) (((P_IE_WMM_HDR_T)(fp))->aucOui) + +#if QM_DEBUG_COUNTER +#define QM_DBG_CNT_INC(_prQM, _index) { (_prQM)->au4QmDebugCounters[(_index)]++; } +#else +#define QM_DBG_CNT_INC(_prQM, _index) {} +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Queue Management and STA_REC Initialization */ +/*----------------------------------------------------------------------------*/ + +VOID qmInit(IN P_ADAPTER_T prAdapter); + +#if QM_TEST_MODE +VOID qmTestCases(IN P_ADAPTER_T prAdapter); +#endif + +VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); + +/*----------------------------------------------------------------------------*/ +/* TX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter); + +P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx); + +P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); + +P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus); + +VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter); + +VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter); +#endif + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter); + +P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter); + +P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); + +VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); + +VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue); + +VOID +qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); + +VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); + +BOOLEAN +qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout); + +VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue); + +VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg); + +BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater); + +VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); + +VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); + +P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid); + +BOOLEAN +qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize); + +VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost); + +VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); + +VOID +mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride); + +VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams); + +VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec); + +/* Utility function: for deciding STA-REC index */ +UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); + +UINT_32 +mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, + UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf); + +VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode); + +VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +ENUM_FRAME_ACTION_T +qmGetFrameAction(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType); + +VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); + +VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); + +VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength); + +VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent); + +VOID +qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone); + +VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter); + +#if ARP_MONITER_ENABLE +VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); +VOID qmResetArpDetect(VOID); +VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _QUE_MGT_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h new file mode 100644 index 0000000000000..2804b0387f5f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic/wlan_def.h @@ -0,0 +1,1010 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic/wlan_def.h#1 +*/ + +/*! \file "wlan_def.h" + \brief This file includes the basic definition of WLAN + +*/ + +/* +** Log: wlan_def.h +** +** 09 02 2013 cp.wu +** add path to handle reassociation request + * + * 12 05 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * add CONNECT_BY_BSSID policy + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 06 22 2011 wh.su + * [WCXRP00000806] [MT6620 Wi-Fi][Driver] Move the WPA/RSN IE and WAPI IE structure to mac.h and let the sw + * structure not align at byte + * Move the WAPI/RSN IE to mac.h and SW structure not align to byte, + * Notice needed update P2P.ko. + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 03 17 2011 yuche.tsai + * NULL + * Resize the Secondary Device Type array when WiFi Direct is enabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Add new station type MACRO. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 11 2010 kevin.huang + * [WCXRP00000068] [MT6620 Wi-Fi][Driver][FW] Fix STA RECORD sync issue and remove unused code + * Update ENUM_STA_ROLE_INDEX_T by using a fixed base value + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by + * ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 14 2010 chinghwa.yu + * NULL + * Update OP_MODE_BOW and include bow_fsm.h. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * Change P2P Descriptor List to a pointer and allocate it dynamically to avoid structure corrupt by BssDescriptor free. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Add a pointer in BSS Descriptor for P2P Descriptor. + * + * 08 11 2010 yuche.tsai + * NULL + * Add an Interface in BSS Descriptor. + * + * 08 05 2010 yuche.tsai + * NULL + * Modify data structure for P2P Scan result. + * + * 07 26 2010 yuche.tsai + * + * Add an operation mode for P2P device. + * + * 07 23 2010 cp.wu + * + * P2P/RSN/WAPI IEs need to be declared with compact structure. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, other request will be directly + * dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Add P2P present boolean flag in BSS & Pre-BSS descriptor. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * move bss related data types to wlan_def.h to avoid recursive dependency. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:16:40 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_DEF_H +#define _WLAN_DEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* disconnect reason */ +#define DISCONNECT_REASON_CODE_RESERVED 0 +#define DISCONNECT_REASON_CODE_RADIO_LOST 1 +#define DISCONNECT_REASON_CODE_DEAUTHENTICATED 2 +#define DISCONNECT_REASON_CODE_DISASSOCIATED 3 +#define DISCONNECT_REASON_CODE_NEW_CONNECTION 4 +#define DISCONNECT_REASON_CODE_REASSOCIATION 5 +#define DISCONNECT_REASON_CODE_ROAMING 6 + +/* The rate definitions */ +#define TX_MODE_CCK 0x00 +#define TX_MODE_OFDM 0x40 +#define TX_MODE_HT_MM 0x80 +#define TX_MODE_HT_GF 0xC0 + +#define RATE_CCK_SHORT_PREAMBLE 0x10 +#define RATE_OFDM 0x20 + +#define PHY_RATE_1M 0x0 +#define PHY_RATE_2M 0x1 +#define PHY_RATE_5_5M 0x2 +#define PHY_RATE_11M 0x3 +#define PHY_RATE_6M 0xB +#define PHY_RATE_9M 0xF +#define PHY_RATE_12M 0xA +#define PHY_RATE_18M 0xE +#define PHY_RATE_24M 0x9 +#define PHY_RATE_36M 0xD +#define PHY_RATE_48M 0x8 +#define PHY_RATE_54M 0xC +#define PHY_RATE_MCS0 0x0 +#define PHY_RATE_MCS1 0x1 +#define PHY_RATE_MCS2 0x2 +#define PHY_RATE_MCS3 0x3 +#define PHY_RATE_MCS4 0x4 +#define PHY_RATE_MCS5 0x5 +#define PHY_RATE_MCS6 0x6 +#define PHY_RATE_MCS7 0x7 +#define PHY_RATE_MCS32 0x20 + +#define RATE_CCK_1M_LONG (TX_MODE_CCK | PHY_RATE_1M) +#define RATE_CCK_2M_LONG (TX_MODE_CCK | PHY_RATE_2M) +#define RATE_CCK_5_5M_LONG (TX_MODE_CCK | PHY_RATE_5_5M) +#define RATE_CCK_11M_LONG (TX_MODE_CCK | PHY_RATE_11M) +#define RATE_CCK_2M_SHORT (TX_MODE_CCK | PHY_RATE_2M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_5_5M_SHORT (TX_MODE_CCK | PHY_RATE_5_5M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_11M_SHORT (TX_MODE_CCK | PHY_RATE_11M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_OFDM_6M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_6M) +#define RATE_OFDM_9M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_9M) +#define RATE_OFDM_12M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_12M) +#define RATE_OFDM_18M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_18M) +#define RATE_OFDM_24M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_24M) +#define RATE_OFDM_36M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_36M) +#define RATE_OFDM_48M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_48M) +#define RATE_OFDM_54M (TX_MODE_OFDM | RATE_OFDM | PHY_RATE_54M) + +#define RATE_MM_MCS_0 (TX_MODE_HT_MM | PHY_RATE_MCS0) +#define RATE_MM_MCS_1 (TX_MODE_HT_MM | PHY_RATE_MCS1) +#define RATE_MM_MCS_2 (TX_MODE_HT_MM | PHY_RATE_MCS2) +#define RATE_MM_MCS_3 (TX_MODE_HT_MM | PHY_RATE_MCS3) +#define RATE_MM_MCS_4 (TX_MODE_HT_MM | PHY_RATE_MCS4) +#define RATE_MM_MCS_5 (TX_MODE_HT_MM | PHY_RATE_MCS5) +#define RATE_MM_MCS_6 (TX_MODE_HT_MM | PHY_RATE_MCS6) +#define RATE_MM_MCS_7 (TX_MODE_HT_MM | PHY_RATE_MCS7) +#define RATE_MM_MCS_32 (TX_MODE_HT_MM | PHY_RATE_MCS32) + +#define RATE_GF_MCS_0 (TX_MODE_HT_GF | PHY_RATE_MCS0) +#define RATE_GF_MCS_1 (TX_MODE_HT_GF | PHY_RATE_MCS1) +#define RATE_GF_MCS_2 (TX_MODE_HT_GF | PHY_RATE_MCS2) +#define RATE_GF_MCS_3 (TX_MODE_HT_GF | PHY_RATE_MCS3) +#define RATE_GF_MCS_4 (TX_MODE_HT_GF | PHY_RATE_MCS4) +#define RATE_GF_MCS_5 (TX_MODE_HT_GF | PHY_RATE_MCS5) +#define RATE_GF_MCS_6 (TX_MODE_HT_GF | PHY_RATE_MCS6) +#define RATE_GF_MCS_7 (TX_MODE_HT_GF | PHY_RATE_MCS7) +#define RATE_GF_MCS_32 (TX_MODE_HT_GF | PHY_RATE_MCS32) + +#define RATE_TX_MODE_MASK BITS(6, 7) +#define RATE_TX_MODE_OFFSET 6 +#define RATE_CODE_GET_TX_MODE(_ucRateCode) ((_ucRateCode & RATE_TX_MODE_MASK) >> RATE_TX_MODE_OFFSET) +#define RATE_PHY_RATE_MASK BITS(0, 5) +#define RATE_PHY_RATE_OFFSET 0 +#define RATE_CODE_GET_PHY_RATE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_MASK) >> RATE_PHY_RATE_OFFSET) +#define RATE_PHY_RATE_SHORT_PREAMBLE BIT(4) +#define RATE_CODE_IS_SHORT_PREAMBLE(_ucRateCode) ((_ucRateCode & RATE_PHY_RATE_SHORT_PREAMBLE)?TRUE:FALSE) + +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + +/*! CNM(STA_RECORD_T) related definition */ +#define CFG_STA_REC_NUM 20 + +/* PHY TYPE bit definitions */ +#define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) /* HR/DSSS PHY (clause 18) */ +#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) /* ERP PHY (clause 19) */ +#define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) /* OFDM 5 GHz PHY (clause 17) */ +#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) /* HT PHY (clause 20) */ + +/* PHY TYPE set definitions */ +#define PHY_TYPE_SET_802_11ABGN (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11BGN (PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11GN (PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11AN (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11ABG (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11BG (PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11A (PHY_TYPE_BIT_OFDM) + +#define PHY_TYPE_SET_802_11G (PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11B (PHY_TYPE_BIT_HR_DSSS) + +#define PHY_TYPE_SET_802_11N (PHY_TYPE_BIT_HT) + +/* Rate set bit definitions */ +#define RATE_SET_BIT_1M BIT(RATE_1M_INDEX) /* Bit 0: 1M */ +#define RATE_SET_BIT_2M BIT(RATE_2M_INDEX) /* Bit 1: 2M */ +#define RATE_SET_BIT_5_5M BIT(RATE_5_5M_INDEX) /* Bit 2: 5.5M */ +#define RATE_SET_BIT_11M BIT(RATE_11M_INDEX) /* Bit 3: 11M */ +#define RATE_SET_BIT_22M BIT(RATE_22M_INDEX) /* Bit 4: 22M */ +#define RATE_SET_BIT_33M BIT(RATE_33M_INDEX) /* Bit 5: 33M */ +#define RATE_SET_BIT_6M BIT(RATE_6M_INDEX) /* Bit 6: 6M */ +#define RATE_SET_BIT_9M BIT(RATE_9M_INDEX) /* Bit 7: 9M */ +#define RATE_SET_BIT_12M BIT(RATE_12M_INDEX) /* Bit 8: 12M */ +#define RATE_SET_BIT_18M BIT(RATE_18M_INDEX) /* Bit 9: 18M */ +#define RATE_SET_BIT_24M BIT(RATE_24M_INDEX) /* Bit 10: 24M */ +#define RATE_SET_BIT_36M BIT(RATE_36M_INDEX) /* Bit 11: 36M */ +#define RATE_SET_BIT_48M BIT(RATE_48M_INDEX) /* Bit 12: 48M */ +#define RATE_SET_BIT_54M BIT(RATE_54M_INDEX) /* Bit 13: 54M */ +#define RATE_SET_BIT_HT_PHY BIT(RATE_HT_PHY_INDEX) /* Bit 14: BSS Selector */ + +/* Rate set definitions */ +#define RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define RATE_SET_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_OFDM (RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | \ + RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | \ + RATE_SET_BIT_54M) + +#define RATE_SET_HT (RATE_SET_ERP) +/* #define RATE_SET_HT (RATE_SET_ERP | RATE_SET_BIT_HT_PHY) *//* NOTE(Kevin): TBD */ + +#define RATE_SET_ALL_ABG RATE_SET_ERP + +#define BASIC_RATE_SET_HR_DSSS (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M) + +#define BASIC_RATE_SET_HR_DSSS_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define BASIC_RATE_SET_ERP (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_OFDM (RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_ERP_P2P (RATE_SET_BIT_6M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_100 RATE_SET_ALL_ABG + +#define INITIAL_RATE_SET_RCPI_80 (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M | \ + RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_60 (RATE_SET_BIT_1M | \ + RATE_SET_BIT_2M | \ + RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | \ + RATE_SET_BIT_6M) + +#define INITIAL_RATE_SET(_rcpi) (INITIAL_RATE_SET_ ## _rcpi) + +#define RCPI_100 100 /* -60 dBm */ +#define RCPI_80 80 /* -70 dBm */ +#define RCPI_60 60 /* -80 dBm */ + +/* The number of RCPI records used to calculate their average value */ +#define MAX_NUM_RCPI_RECORDS 10 + +/* The number of RCPI records used to calculate their average value */ +#define NO_RCPI_RECORDS -128 +#define MAX_RCPI_DBM 0 +#define MIN_RCPI_DBM -100 + +#define MAC_TX_RESERVED_FIELD 0 /* NOTE(Kevin): Should defined in tx.h */ + +#define MAX_ASSOC_ID (CFG_STA_REC_NUM) /* Available AID: 1 ~ 20(STA_REC_NUM) */ + +#define MAX_DEAUTH_INFO_COUNT 4 /* NOTE(Kevin): Used in auth.c */ +#define MIN_DEAUTH_INTERVAL_MSEC 500 /* The minimum interval if continuously send Deauth Frame */ + +/* Authentication Type */ +#define AUTH_TYPE_OPEN_SYSTEM BIT(AUTH_ALGORITHM_NUM_OPEN_SYSTEM) +#define AUTH_TYPE_SHARED_KEY BIT(AUTH_ALGORITHM_NUM_SHARED_KEY) +#define AUTH_TYPE_FAST_BSS_TRANSITION BIT(AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION) + +/* Authentication Retry Limit */ +#define TX_AUTH_ASSOCI_RETRY_LIMIT 2 +#define TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING 1 + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef UINT_16 PHY_TYPE, *P_PHY_TYPE; +typedef UINT_8 RCPI, *P_RCPI; +typedef UINT_8 ALC_VAL, *P_ALC_VAL; + +typedef enum _ENUM_HW_BSSID_T { + BSSID_0 = 0, + BSSID_1, + BSSID_NUM +} ENUM_HW_BSSID_T; + +typedef enum _ENUM_HW_MAC_ADDR_T { + MAC_ADDR_0 = 0, + MAC_ADDR_1, + MAC_ADDR_NUM +} ENUM_HW_MAC_ADDR_T; + +typedef enum _ENUM_HW_OP_MODE_T { + HW_OP_MODE_STA = 0, + HW_OP_MODE_AP, + HW_OP_MODE_ADHOC, + HW_OP_MODE_NUM +} ENUM_HW_OP_MODE_T; + +typedef enum _ENUM_TSF_T { + ENUM_LOCAL_TSF_0, + ENUM_LOCAL_TSF_1, + ENUM_LOCAL_TSF_NUM +} ENUM_LOCAL_TSF_T, *P_ENUM_LOCAL_TSF_T; + +typedef enum _HAL_TS_HW_UPDATE_MODE { + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME, + HAL_TSF_HW_UPDATE_BY_TICK_ONLY, + HAL_TSF_HW_UPDATE_BY_RECEIVED_FRAME_ONLY, + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME_AD_HOC +} HAL_TSF_HW_UPDATE_MODE; + +typedef enum _ENUM_AC_T { + AC0 = 0, + AC1, + AC2, + AC3, + AC_NUM +} ENUM_AC_T, *P_ENUM_AC_T; + +/* The Type of Network been activated */ +typedef enum _ENUM_NETWORK_TYPE_INDEX_T { + NETWORK_TYPE_AIS_INDEX = 0, + NETWORK_TYPE_P2P_INDEX, + NETWORK_TYPE_BOW_INDEX, + NETWORK_TYPE_INDEX_NUM +} ENUM_NETWORK_TYPE_INDEX_T; + +/* The Type of STA Type. */ +typedef enum _ENUM_STA_TYPE_INDEX_T { + STA_TYPE_LEGACY_INDEX = 0, + STA_TYPE_P2P_INDEX, + STA_TYPE_BOW_INDEX, + STA_TYPE_INDEX_NUM +} ENUM_STA_TYPE_INDEX_T; + +#define STA_ROLE_BASE_INDEX 4 + +typedef enum _ENUM_STA_ROLE_INDEX_T { + STA_ROLE_ADHOC_INDEX = STA_ROLE_BASE_INDEX, /* 4 */ + STA_ROLE_CLIENT_INDEX, + STA_ROLE_AP_INDEX, + STA_ROLE_TDLS_INDEX, + STA_ROLE_DLS_INDEX /* Note: need to extend P_CMD_UPDATE_STA_RECORD_T */ +} ENUM_STA_ROLE_INDEX_T; + +/* The Power State of a specific Network */ +typedef enum _ENUM_PWR_STATE_T { + PWR_STATE_IDLE = 0, + PWR_STATE_ACTIVE, + PWR_STATE_PS, + PWR_STATE_NUM +} ENUM_PWR_STATE_T; + +typedef enum _ENUM_PHY_TYPE_INDEX_T { + /* PHY_TYPE_DSSS_INDEX, *//* DSSS PHY (clause 15) -- Not used anymore */ + PHY_TYPE_HR_DSSS_INDEX = 0, /* HR/DSSS PHY (clause 18) */ + PHY_TYPE_ERP_INDEX, /* ERP PHY (clause 19) */ + PHY_TYPE_ERP_P2P_INDEX, /* ERP PHY (clause 19) w/o HR/DSSS */ + PHY_TYPE_OFDM_INDEX, /* OFDM 5 GHz PHY (clause 17) */ + PHY_TYPE_HT_INDEX, /* HT PHY (clause 20) */ + PHY_TYPE_INDEX_NUM /* 5 */ +} ENUM_PHY_TYPE_INDEX_T, *P_ENUM_PHY_TYPE_INDEX_T; + +typedef enum _ENUM_ACPI_STATE_T { + ACPI_STATE_D0 = 0, + ACPI_STATE_D1, + ACPI_STATE_D2, + ACPI_STATE_D3 +} ENUM_ACPI_STATE_T; + +/* The operation mode of a specific Network */ +typedef enum _ENUM_OP_MODE_T { + OP_MODE_INFRASTRUCTURE = 0, /* Infrastructure/GC */ + OP_MODE_IBSS, /* AdHoc */ + OP_MODE_ACCESS_POINT, /* For GO */ + OP_MODE_P2P_DEVICE, /* P2P Device */ + OP_MODE_BOW, + OP_MODE_NUM +} ENUM_OP_MODE_T, *P_ENUM_OP_MODE_T; + +typedef enum _ENUM_CHNL_EXT_T { + CHNL_EXT_SCN = 0, + CHNL_EXT_SCA = 1, + CHNL_EXT_RES = 2, + CHNL_EXT_SCB = 3 +} ENUM_CHNL_EXT_T, *P_ENUM_CHNL_EXT_T; + +/* This starting freq of the band is unit of kHz */ +typedef enum _ENUM_BAND_T { + BAND_NULL, + BAND_2G4, + BAND_5G, + BAND_NUM +} ENUM_BAND_T, *P_ENUM_BAND_T; + +/* Provide supported channel list to other components in array format */ +typedef struct _RF_CHANNEL_INFO_T { + ENUM_BAND_T eBand; + UINT_8 ucChannelNum; +} RF_CHANNEL_INFO_T, *P_RF_CHANNEL_INFO_T; + +typedef enum _ENUM_RATE_INDEX_T { + RATE_1M_INDEX = 0, /* 1M */ + RATE_2M_INDEX, /* 2M */ + RATE_5_5M_INDEX, /* 5.5M */ + RATE_11M_INDEX, /* 11M */ + RATE_22M_INDEX, /* 22M */ + RATE_33M_INDEX, /* 33M */ + RATE_6M_INDEX, /* 6M */ + RATE_9M_INDEX, /* 9M */ + RATE_12M_INDEX, /* 12M */ + RATE_18M_INDEX, /* 18M */ + RATE_24M_INDEX, /* 24M */ + RATE_36M_INDEX, /* 36M */ + RATE_48M_INDEX, /* 48M */ + RATE_54M_INDEX, /* 54M */ + RATE_HT_PHY_INDEX, /* BSS Selector - HT PHY */ + RATE_NUM /* 15 */ +} ENUM_RATE_INDEX_T, *P_ENUM_RATE_INDEX_T; + +typedef enum _ENUM_HT_RATE_INDEX_T { + HT_RATE_MCS0_INDEX = 0, + HT_RATE_MCS1_INDEX, + HT_RATE_MCS2_INDEX, + HT_RATE_MCS3_INDEX, + HT_RATE_MCS4_INDEX, + HT_RATE_MCS5_INDEX, + HT_RATE_MCS6_INDEX, + HT_RATE_MCS7_INDEX, + HT_RATE_MCS32_INDEX, + HT_RATE_NUM /* 9 */ +} ENUM_HT_RATE_INDEX_T, *P_ENUM_HT_RATE_INDEX_T; + +typedef enum _ENUM_PREMABLE_OPTION_T { + PREAMBLE_DEFAULT_LONG_NONE = 0, /* LONG for PHY_TYPE_HR_DSSS, NONE for PHY_TYPE_OFDM */ + PREAMBLE_OPTION_SHORT, /* SHORT mandatory for PHY_TYPE_ERP, SHORT option for PHY_TYPE_HR_DSSS */ + PREAMBLE_HT_MIXED_MODE, + PREAMBLE_HT_GREEN_FIELD, + PREAMBLE_OPTION_NUM +} ENUM_PREMABLE_OPTION_T, *P_ENUM_PREMABLE_OPTION_T; + +typedef enum _ENUM_CHANNEL_WIDTH_T { + CW_20_40MHZ = 0, + CW_80MHZ = 1, + CW_160MHZ = 2, + CW_80P80MHZ = 3 +} ENUM_CHANNEL_WIDTH_T, *P_ENUM_CHANNEL_WIDTH_P; + +typedef enum _ENUM_MODULATION_SYSTEM_T { + MODULATION_SYSTEM_CCK = 0, + MODULATION_SYSTEM_OFDM, + MODULATION_SYSTEM_HT20, + MODULATION_SYSTEM_HT40, + MODULATION_SYSTEM_NUM +} ENUM_MODULATION_SYSTEM_T, *P_ENUM_MODULATION_SYSTEM_T; + +typedef enum _ENUM_MODULATION_TYPE_T { + MODULATION_TYPE_CCK_BPSK = 0, + MODULATION_TYPE_QPSK, + MODULATION_TYPE_16QAM, + MODULATION_TYPE_64QAM, + MODULATION_TYPE_NUM +} ENUM_MODULATION_TYPE_T, *P_ENUM_MODULATION_TYPE_T; + +typedef enum _ENUM_PS_FORWARDING_TYPE_T { + PS_FORWARDING_TYPE_NON_PS = 0, + PS_FORWARDING_TYPE_DELIVERY_ENABLED, + PS_FORWARDING_TYPE_NON_DELIVERY_ENABLED, + PS_FORWARDING_MORE_DATA_ENABLED, + PS_FORWARDING_TYPE_NUM +} ENUM_PS_FORWARDING_TYPE_T, *P_ENUM_PS_FORWARDING_TYPE_T; + +typedef struct _DEAUTH_INFO_T { + UINT_8 aucRxAddr[MAC_ADDR_LEN]; + OS_SYSTIME rLastSendTime; +} DEAUTH_INFO_T, *P_DEAUTH_INFO_T; + +/*----------------------------------------------------------------------------*/ +/* Information Element (IE) handlers */ +/*----------------------------------------------------------------------------*/ +typedef VOID(*PFN_APPEND_IE_FUNC) (P_ADAPTER_T, P_MSDU_INFO_T); +typedef VOID(*PFN_HANDLE_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T); +typedef VOID(*PFN_VERIFY_IE_FUNC) (P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T, PUINT_16); +typedef UINT_32(*PFN_CALCULATE_VAR_IE_LEN_FUNC) (P_ADAPTER_T, ENUM_NETWORK_TYPE_INDEX_T, P_STA_RECORD_T); + +typedef struct _APPEND_IE_ENTRY_T { + UINT_16 u2EstimatedIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_IE_ENTRY_T, *P_APPEND_IE_ENTRY_T; + +typedef struct _APPEND_VAR_IE_ENTRY_T { + UINT_16 u2EstimatedFixedIELen; /* For Fixed Length */ + PFN_CALCULATE_VAR_IE_LEN_FUNC pfnCalculateVariableIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_VAR_IE_ENTRY_T, *P_APPEND_VAR_IE_ENTRY_T; + +typedef struct _HANDLE_IE_ENTRY_T { + UINT_8 ucElemID; + PFN_HANDLE_IE_FUNC pfnHandleIE; +} HANDLE_IE_ENTRY_T, *P_HANDLE_IE_ENTRY_T; + +typedef struct _VERIFY_IE_ENTRY_T { + UINT_8 ucElemID; + PFN_VERIFY_IE_FUNC pfnVarifyIE; +} VERIFY_IE_ENTRY_T, *P_VERIFY_IE_ENTRY_T; + +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration */ +/*----------------------------------------------------------------------------*/ +typedef enum _ENUM_PARAM_CONNECTION_POLICY_T { + CONNECT_BY_SSID_BEST_RSSI = 0, + CONNECT_BY_SSID_GOOD_RSSI_MIN_CH_LOAD, + CONNECT_BY_SSID_ANY, /* NOTE(Kevin): Needed by WHQL */ + CONNECT_BY_BSSID, + CONNECT_BY_CUSTOMIZED_RULE /* NOTE(Kevin): TBD */ +} ENUM_PARAM_CONNECTION_POLICY_T, *P_ENUM_PARAM_CONNECTION_POLICY_T; + +typedef enum _ENUM_PARAM_PREAMBLE_TYPE_T { + PREAMBLE_TYPE_LONG = 0, + PREAMBLE_TYPE_SHORT, + PREAMBLE_TYPE_AUTO /*!< Try preamble short first, if fail tray preamble long. */ +} ENUM_PARAM_PREAMBLE_TYPE_T, *P_ENUM_PARAM_PREAMBLE_TYPE_T; + +/* This is enum defined for user to select a phy config listed in combo box */ +typedef enum _ENUM_PARAM_PHY_CONFIG_T { + /*!< Can associated with 802.11abg AP but without n capability, Scan dual band. */ + PHY_CONFIG_802_11ABG = 0, + PHY_CONFIG_802_11BG, /*!< Can associated with 802_11bg AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11G, /*!< Can associated with 802_11g only AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11A, /*!< Can associated with 802_11a only AP, Scan single band and not report 2.4G BSSs. */ + PHY_CONFIG_802_11B, /*!< Can associated with 802_11b only AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11ABGN, /*!< Can associated with 802.11abgn AP, Scan dual band. */ + PHY_CONFIG_802_11BGN, /*!< Can associated with 802_11bgn AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_802_11AN, /*!< Can associated with 802_11an AP, Scan single band and not report 2.4G BSSs. */ + PHY_CONFIG_802_11GN, /*!< Can associated with 802_11gn AP, Scan single band and not report 5G BSSs. */ + PHY_CONFIG_NUM /* 9 */ +} ENUM_PARAM_PHY_CONFIG_T, *P_ENUM_PARAM_PHY_CONFIG_T; + +/* This is enum defined for user to select an AP Mode */ +typedef enum _ENUM_PARAM_AP_MODE_T { + AP_MODE_11B = 0, /*!< Create 11b BSS if we support 802.11abg/802.11bg. */ + AP_MODE_MIXED_11BG, /*!< Create 11bg mixed BSS if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G, /*!< Create 11g only BSS if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G_P2P, /*!< Create 11g only BSS for P2P if we support 802.11abg/802.11bg/802.11g. */ + AP_MODE_11A, /*!< Create 11a only BSS if we support 802.11abg. */ + AP_MODE_NUM /* 4 */ +} ENUM_PARAM_AP_MODE_T, *P_ENUM_PARAM_AP_MODE_T; + +/* Masks for determining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ +#define NETWORK_TYPE_AIS_MASK BIT(NETWORK_TYPE_AIS_INDEX) +#define NETWORK_TYPE_P2P_MASK BIT(NETWORK_TYPE_P2P_INDEX) +#define NETWORK_TYPE_BOW_MASK BIT(NETWORK_TYPE_BOW_INDEX) +#define STA_TYPE_LEGACY_MASK BIT(STA_TYPE_LEGACY_INDEX) +#define STA_TYPE_P2P_MASK BIT(STA_TYPE_P2P_INDEX) +#define STA_TYPE_BOW_MASK BIT(STA_TYPE_BOW_INDEX) +#define STA_TYPE_ADHOC_MASK BIT(STA_ROLE_ADHOC_INDEX) +#define STA_TYPE_CLIENT_MASK BIT(STA_ROLE_CLIENT_INDEX) +#define STA_TYPE_AP_MASK BIT(STA_ROLE_AP_INDEX) +#define STA_TYPE_DLS_MASK BIT(STA_ROLE_DLS_INDEX) +#define STA_TYPE_TDLS_MASK BIT(STA_ROLE_TDLS_INDEX) + +/* Macros for obtaining the Network Type or the Station Role, given the ENUM_STA_TYPE_T */ +#define IS_STA_IN_AIS(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) +#define IS_STA_IN_P2P(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) +#define IS_STA_IN_BOW(_prStaRec) ((_prStaRec)->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) +#define IS_STA_LEGACY_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_LEGACY_MASK) +#define IS_STA_P2P_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_P2P_MASK) +#define IS_STA_BOW_TYPE(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_BOW_MASK) +#define IS_ADHOC_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_ADHOC_MASK) +#define IS_CLIENT_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_CLIENT_MASK) +#define IS_AP_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_AP_MASK) +#define IS_DLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_DLS_MASK) +#define IS_TDLS_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_TDLS_MASK) + +/* The ENUM_STA_TYPE_T accounts for ENUM_NETWORK_TYPE_T and ENUM_STA_ROLE_INDEX_T. + * * It is a merged version of Network Type and STA Role. + * */ +typedef enum _ENUM_STA_TYPE_T { + STA_TYPE_LEGACY_AP = (STA_TYPE_LEGACY_MASK | STA_TYPE_AP_MASK), + STA_TYPE_LEGACY_CLIENT = (STA_TYPE_LEGACY_MASK | STA_TYPE_CLIENT_MASK), + STA_TYPE_ADHOC_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_ADHOC_MASK), +#if CFG_ENABLE_WIFI_DIRECT + STA_TYPE_P2P_GO = (STA_TYPE_P2P_MASK | STA_TYPE_AP_MASK), + STA_TYPE_P2P_GC = (STA_TYPE_P2P_MASK | STA_TYPE_CLIENT_MASK), +#endif +#if CFG_ENABLE_BT_OVER_WIFI + STA_TYPE_BOW_AP = (STA_TYPE_BOW_MASK | STA_TYPE_AP_MASK), + STA_TYPE_BOW_CLIENT = (STA_TYPE_BOW_MASK | STA_TYPE_CLIENT_MASK), +#endif + STA_TYPE_DLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_DLS_MASK), + STA_TYPE_TDLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_TDLS_MASK) +} ENUM_STA_TYPE_T, *P_ENUM_STA_TYPE_T; + +/* The type of BSS we discovered */ +typedef enum _ENUM_BSS_TYPE_T { + BSS_TYPE_INFRASTRUCTURE = 1, + BSS_TYPE_IBSS, + BSS_TYPE_P2P_DEVICE, + BSS_TYPE_BOW_DEVICE, + BSS_TYPE_NUM +} ENUM_BSS_TYPE_T, *P_ENUM_BSS_TYPE_T; + +/*----------------------------------------------------------------------------*/ +/* RSN structures */ +/*----------------------------------------------------------------------------*/ +/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ +/* #pragma pack(1) */ +/* #endif */ + +#define MAX_NUM_SUPPORTED_CIPHER_SUITES 8 /* max number of supported cipher suites */ +#if CFG_SUPPORT_802_11W +#define MAX_NUM_SUPPORTED_AKM_SUITES 8 /* max number of supported AKM suites */ +#else +#define MAX_NUM_SUPPORTED_AKM_SUITES 6 /* max number of supported AKM suites */ +#endif + +/* Structure of RSN Information */ +typedef struct _RSN_INFO_T { + UINT_8 ucElemId; + UINT_16 u2Version; + UINT_32 u4GroupKeyCipherSuite; + UINT_32 u4PairwiseKeyCipherSuiteCount; + UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_CIPHER_SUITES]; + UINT_32 u4AuthKeyMgtSuiteCount; + UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_AKM_SUITES]; + UINT_16 u2RsnCap; + BOOLEAN fgRsnCapPresent; +} /*__KAL_ATTRIB_PACKED__*/ RSN_INFO_T, *P_RSN_INFO_T; + +#define MAX_NUM_SUPPORTED_WAPI_AKM_SUITES 1 /* max number of supported AKM suites */ +#define MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES 1 /* max number of supported cipher suites */ + +/* Structure of WAPI Information */ +typedef struct _WAPI_INFO_T { + UINT_8 ucElemId; + UCHAR ucLength; + UINT_16 u2Version; + UINT_32 u4AuthKeyMgtSuiteCount; + UINT_32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_WAPI_AKM_SUITES]; + UINT_32 u4PairwiseKeyCipherSuiteCount; + UINT_32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES]; + UINT_32 u4GroupKeyCipherSuite; + UINT_16 u2WapiCap; + UINT_16 u2Bkid; + UINT_8 aucBkid[1][16]; +} /* __KAL_ATTRIB_PACKED__ */ WAPI_INFO_T, *P_WAPI_INFO_T; + +/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ +/* #pragma pack() */ +/* #endif */ + +#if CFG_ENABLE_WIFI_DIRECT + +typedef struct _P2P_DEVICE_TYPE_T { + UINT_16 u2CategoryID; + UINT_16 u2SubCategoryID; +} P2P_DEVICE_TYPE_T, *P_P2P_DEVICE_TYPE_T; + +typedef struct _P2P_DEVICE_DESC_T { + LINK_ENTRY_T rLinkEntry; + BOOLEAN fgDevInfoValid; + UINT_8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + UINT_8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Interface Address. */ + UINT_8 ucDeviceCapabilityBitmap; + UINT_8 ucGroupCapabilityBitmap; + UINT_16 u2ConfigMethod; /* Configure Method support. */ + P2P_DEVICE_TYPE_T rPriDevType; + UINT_8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T arSecDevType[8]; /* Reference to P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT */ + UINT_16 u2NameLength; + UINT_8 aucName[32]; /* Reference to WPS_ATTRI_MAX_LEN_DEVICE_NAME */ + /* TODO: Service Information or PasswordID valid? */ +} P2P_DEVICE_DESC_T, *P_P2P_DEVICE_DESC_T; + +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static const UINT_8 aucRateIndex2RateCode[PREAMBLE_OPTION_NUM][RATE_NUM] = { + { /* Long Preamble */ + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_LONG, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_LONG, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_LONG, /* RATE_11M_INDEX */ + RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ + RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ + RATE_OFDM_6M, /* RATE_6M_INDEX */ + RATE_OFDM_9M, /* RATE_9M_INDEX */ + RATE_OFDM_12M, /* RATE_12M_INDEX */ + RATE_OFDM_18M, /* RATE_18M_INDEX */ + RATE_OFDM_24M, /* RATE_24M_INDEX */ + RATE_OFDM_36M, /* RATE_36M_INDEX */ + RATE_OFDM_48M, /* RATE_48M_INDEX */ + RATE_OFDM_54M, /* RATE_54M_INDEX */ + }, + { /* Short Preamble */ + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_SHORT, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_SHORT, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_SHORT, /* RATE_11M_INDEX */ + RATE_CCK_1M_LONG, /* RATE_22M_INDEX - Not supported */ + RATE_CCK_1M_LONG, /* RATE_33M_INDEX - Not supported */ + RATE_OFDM_6M, /* RATE_6M_INDEX */ + RATE_OFDM_9M, /* RATE_9M_INDEX */ + RATE_OFDM_12M, /* RATE_12M_INDEX */ + RATE_OFDM_18M, /* RATE_18M_INDEX */ + RATE_OFDM_24M, /* RATE_24M_INDEX */ + RATE_OFDM_36M, /* RATE_36M_INDEX */ + RATE_OFDM_48M, /* RATE_48M_INDEX */ + RATE_OFDM_54M, /* RATE_54M_INDEX */ + }, + { /* Mixed Mode(Option) */ + RATE_MM_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_MM_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_MM_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_MM_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_MM_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_MM_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_MM_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_MM_MCS_7, /* RATE_MCS7_INDEX, */ + RATE_MM_MCS_32 /* RATE_MCS32_INDEX, */ + }, + { /* Green Field(Option) */ + RATE_GF_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_GF_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_GF_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_GF_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_GF_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_GF_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_GF_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_GF_MCS_7, /* RATE_MCS7_INDEX, */ + RATE_GF_MCS_32 /* RATE_MCS32_INDEX, */ + } +}; + +static const UINT_8 aucRateTableSize[PREAMBLE_OPTION_NUM] = { + RATE_HT_PHY_INDEX, + RATE_HT_PHY_INDEX, + HT_RATE_NUM, + HT_RATE_NUM +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Macros to get and set the wireless LAN frame fields those are 16/32 bits in + length. */ +#define WLAN_GET_FIELD_16(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_16)(_value_p) = ((UINT_16) __cp[0]) | ((UINT_16) __cp[1] << 8); \ + } + +#define WLAN_GET_FIELD_BE16(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_16)(_value_p) = ((UINT_16) __cp[0] << 8) | ((UINT_16) __cp[1]); \ + } + +#define WLAN_GET_FIELD_32(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_32)(_value_p) = ((UINT_32) __cp[0]) | ((UINT_32) __cp[1] << 8) | \ + ((UINT_32) __cp[2] << 16) | ((UINT_32) __cp[3] << 24); \ + } + +#define WLAN_GET_FIELD_64(_memAddr_p, _value_p) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + *(PUINT_64)(_value_p) = \ + ((UINT_64) __cp[0]) | ((UINT_64) __cp[1] << 8) | \ + ((UINT_64) __cp[2] << 16) | ((UINT_64) __cp[3] << 24) | \ + ((UINT_64) __cp[4] << 32) | ((UINT_64) __cp[5] << 40) | \ + ((UINT_64) __cp[6] << 48) | ((UINT_64) __cp[7] << 56); \ + } + +#define WLAN_SET_FIELD_16(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) (_value); \ + __cp[1] = (UINT_8) ((_value) >> 8); \ + } + +#define WLAN_SET_FIELD_BE16(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) ((_value) >> 8); \ + __cp[1] = (UINT_8) (_value); \ + } + +#define WLAN_SET_FIELD_32(_memAddr_p, _value) \ + { \ + PUINT_8 __cp = (PUINT_8) (_memAddr_p); \ + __cp[0] = (UINT_8) (_value); \ + __cp[1] = (UINT_8) ((_value) >> 8); \ + __cp[2] = (UINT_8) ((_value) >> 16); \ + __cp[3] = (UINT_8) ((_value) >> 24); \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WLAN_DEF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h new file mode 100644 index 0000000000000..aba2e040c1949 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_cmd_event.h @@ -0,0 +1,2290 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_cmd_event.h#1 +*/ + +/*! \file "nic_cmd_event.h" + \brief This file contains the declairation file of the WLAN OID processing routines + of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: nic_cmd_event.h + * + * 03 29 2012 eason.tsai + * [WCXRP00001216] [MT6628 Wi-Fi][Driver]add conditional define + * add conditional define. + * + * 03 04 2012 eason.tsai + * NULL + * modify the cal fail report code. + * + * 01 06 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * redefine the CMD_ID_SET_TXPWR_CTRL value. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 11 30 2011 cm.chang + * [WCXRP00001128] [MT5931 Wi-Fi][FW] Update BB/RF setting based on RF doc v0.7 for LGE spec + * 1. Add a new CMD for driver to set device mode + * 2. Update calibration parameters + * + * 11 19 2011 yuche.tsai + * NULL + * Update RSSI for P2P. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add TX_DONE status detail information. + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * check if CFG_SUPPORT_SWCR is defined to aoid compiler error. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 10 26 2011 cp.wu + * [WCXRP00001065] [MT6620 Wi-Fi][MT5931][FW][DRV] Adding parameter for controlling + * minimum channel dwell time for scanning + * add interface for control minimum channel dwell time for scanning. + * + * 09 20 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * New CMD definition about RLM parameters + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 08 25 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add DFS switch. + * + * 08 24 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Update RDD test mode cases. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 08 09 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * add CCK-DSSS TX-PWR control field in NVRAM and CMD definition for MT5931-MP + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 22 2011 jeffrey.chang + * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time + * add osc stable time command structure + * + * 07 22 2011 jeffrey.chang + * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time + * modify driver to set OSC stable time after f/w download + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search for more than + * one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID + * support as well as uProbeDelay in NDIS 6.x driver model + * + * 06 23 2011 cp.wu + * [WCXRP00000812] [MT6620 Wi-Fi][Driver] not show NVRAM when there is no valid MAC address in NVRAM content + * check with firmware for valid MAC address. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 31 2011 chinglan.wang + * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. + * . + * + * 03 18 2011 cm.chang + * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command + * As CR title + * + * 03 17 2011 yarco.yang + * [WCXRP00000569] [MT6620 Wi-Fi][F/W][Driver] Set multicast address support current network usage + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 02 16 2011 cm.chang + * [WCXRP00000447] [MT6620 Wi-Fi][FW] Support new NVRAM update mechanism + * . + * + * 02 10 2011 cp.wu + * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers + * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Update cmd format of BSS INFO, always sync OwnMac to FW no matter P2P is enabled or not.. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 15 2011 puff.wen + * NULL + * Add Stress test + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Sync HT operation element information from host to FW + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * report EEPROM used flag via NIC_CAPABILITY + * + * 12 28 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * integrate with 'EEPROM used' flag for reporting correct capability to Engineer Mode/META and other tools + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC for + * initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 cp.wu + * [WCXRP00000133] [MT6620 Wi-Fi] [FW][Driver] Change TX power offset band definition + * follow-up for CMD_5G_PWR_OFFSET_T definition change + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 15 2010 cm.chang + * NULL + * Add new CMD for TX power, 5G power offset and power parameters + * + * 09 07 2010 yuche.tsai + * NULL + * Add a pointer in P2P SCAN RESULT structure. This pointer + * is pointed to a IE buffer for this P2p device. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 16 2010 george.huang + * NULL + * add new CMD ID definition + * + * 08 16 2010 yuche.tsai + * NULL + * Add a field in BSS INFO cmd to change interface address for P2P. (switching between Device Addr & Interface Addr) + * + * 08 12 2010 yuche.tsai + * NULL + * Add interface address indication when indicate connection status. + * It is requested by supplicant to do 4 way handshake. + * + * 08 07 2010 wh.su + * NULL + * adding the privacy related code for P2P network + * + * 08 05 2010 yuche.tsai + * NULL + * Change data structure for P2P Device scan result, all channel time for scan command. + * + * 08 04 2010 george.huang + * NULL + * handle change PS mode OID/ CMD + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 28 2010 cp.wu + * NULL + * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. + * + * 07 26 2010 yuche.tsai + * + * Add P2P Device Found Event. + * Channel extension option in scan abort command. + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 yuche.tsai + * + * Add for P2P Scan Result Parsing & Saving. + * + * 07 20 2010 george.huang + * + * DWORD align for the CMD data structure + * + * 07 20 2010 cp.wu + * + * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 09 2010 cp.wu + * + * reorder members of CMD_SET_BSS_INFO. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * update prStaRecOfAP with BSS-INFO. + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 28 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add BSS/STA_REC commands for integration. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add TX Done Event handle entry + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sync statistics data structure definition with firmware implementation + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * the frequency is used for adhoc connection only + * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00003824][MT6620 Wi-Fi][New Feature] Add support of large scan list + * Implement feature needed by CR: WPD00003824: refining association command by pasting scanning result + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 15 2010 kevin.huang + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Add event for activate STA_RECORD_T + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c + * 'cause it involves OS dependent data structure handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * send CMD_ID_INFRASTRUCTURE when handling OID_802_11_INFRASTRUCTURE_MODE set. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * 4. correct some HAL implementation + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * OID_802_11_RSSI, + * * * OID_802_11_RSSI_TRIGGER, + * * * OID_802_11_STATISTICS, + * * * OID_802_11_DISASSOCIATE, + * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * and result is retrieved by get ATInfo instead + * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-12-11 18:35:07 GMT mtk02752 +** add CMD added in CMD/EVEN document v0.8 +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-12-10 16:39:37 GMT mtk02752 +** eliminate unused definitions +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-12-10 09:55:11 GMT mtk02752 +** command ID/event ID revised +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-12-09 13:57:37 GMT MTK02468 +** Added event ids (EVENT_ID_RX_ADDBA and EVENT_ID_RX_DELBA) +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-12-08 17:35:39 GMT mtk02752 +** + add event ID for EVENT_ID_TEST_STATUS (rf test) +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-12-07 23:01:09 GMT mtk02752 +** add data structure for RF_TEST +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-12-03 16:22:56 GMT mtk01461 +** Modify the element - i4RSSI in EVENT of SCAN RESULT +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-11-30 10:54:44 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T, while 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-11-26 10:16:58 GMT mtk02752 +** resync EVENT_CONNECTION_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-11-25 21:34:01 GMT mtk02752 +** sync. EVENT_SCAN_RESULT_T with firmware +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-11-25 21:03:48 GMT mtk02752 +** refine MGMT_FRAME +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-11-25 18:17:47 GMT mtk02752 +** refine GL_WLAN_INFO_T for buffering scan result and presume max. ie length = 600 bytes +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-24 22:41:20 GMT mtk02752 +** add EVENT_SCAN_RESULT_T definition +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-11-23 20:29:16 GMT mtk02752 +** fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-11-23 14:46:01 GMT mtk02752 +** add new command/event structure upon CM@SD1's documentation +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-13 15:13:40 GMT mtk02752 +** add command definition for CMD_BUILD_CONNECTION and EVENT_CONNECTION_STATUS +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-20 12:22:22 GMT mtk01461 +** Add SeqNum field to Event Header +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:11 GMT mtk01461 +** Update structure of HIF_EVENT_HEADER_T and EVENT_HDR_SIZE +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 12:10:36 GMT mtk01461 +** Add Common Set CMD Callback for MCR Write and other Set OID +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:17 GMT mtk01461 +** Command Done Handler +*/ +#ifndef _NIC_CMD_EVENT_H +#define _NIC_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CMD_STATUS_SUCCESS 0 +#define CMD_STATUS_REJECTED 1 +#define CMD_STATUS_UNKNOWN 2 + +#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) + +#define MAX_IE_LENGTH (600) +#define MAX_WSC_IE_LENGTH (400) + +/* Action field in structure CMD_CH_PRIVILEGE_T */ +#define CMD_CH_ACTION_REQ 0 +#define CMD_CH_ACTION_ABORT 1 + +/* Status field in structure EVENT_CH_PRIVILEGE_T */ +#define EVENT_CH_STATUS_GRANT 0 + +#define SCN_PSCAN_SWC_RSSI_WIN_MAX 75 +#define SCN_PSCAN_SWC_MAX_NUM 8 +#define SCN_PSCAN_HOTLIST_REPORT_MAX_NUM 8 + +typedef enum _ENUM_CMD_ID_T { + CMD_ID_TEST_MODE = 1, /* 0x01 (Set) */ + CMD_ID_RESET_REQUEST, /* 0x02 (Set) */ + CMD_ID_BUILD_CONNECTION, /* 0x03 (Set) */ + CMD_ID_SCAN_REQ_V2, /* 0x04 (Set) */ + CMD_ID_NIC_POWER_CTRL, /* 0x05 (Set) */ + CMD_ID_POWER_SAVE_MODE, /* 0x06 (Set) */ + CMD_ID_LINK_ATTRIB, /* 0x07 (Set) */ + CMD_ID_ADD_REMOVE_KEY, /* 0x08 (Set) */ + CMD_ID_DEFAULT_KEY_ID, /* 0x09 (Set) */ + CMD_ID_INFRASTRUCTURE, /* 0x0a (Set) */ + CMD_ID_SET_RX_FILTER, /* 0x0b (Set) */ + CMD_ID_DOWNLOAD_BUF, /* 0x0c (Set) */ + CMD_ID_WIFI_START, /* 0x0d (Set) */ + CMD_ID_CMD_BT_OVER_WIFI, /* 0x0e (Set) */ + CMD_ID_SET_MEDIA_CHANGE_DELAY_TIME, /* 0x0f (Set) */ + CMD_ID_SEND_ADDBA_RSP, /* 0x10 (Set) */ + CMD_ID_WAPI_MODE, /* 0x11 (Set) (obsolete) */ + CMD_ID_WAPI_ASSOC_INFO, /* 0x12 (Set) (obsolete) */ + CMD_ID_SET_DOMAIN_INFO, /* 0x13 (Set) */ + CMD_ID_SET_IP_ADDRESS, /* 0x14 (Set) */ + CMD_ID_BSS_ACTIVATE_CTRL, /* 0x15 (Set) */ + CMD_ID_SET_BSS_INFO, /* 0x16 (Set) */ + CMD_ID_UPDATE_STA_RECORD, /* 0x17 (Set) */ + CMD_ID_REMOVE_STA_RECORD, /* 0x18 (Set) */ + CMD_ID_INDICATE_PM_BSS_CREATED, /* 0x19 (Set) */ + CMD_ID_INDICATE_PM_BSS_CONNECTED, /* 0x1a (Set) */ + CMD_ID_INDICATE_PM_BSS_ABORT, /* 0x1b (Set) */ + CMD_ID_UPDATE_BEACON_CONTENT, /* 0x1c (Set) */ + CMD_ID_SET_BSS_RLM_PARAM, /* 0x1d (Set) */ + CMD_ID_SCAN_REQ, /* 0x1e (Set) */ + CMD_ID_SCAN_CANCEL, /* 0x1f (Set) */ + CMD_ID_CH_PRIVILEGE, /* 0x20 (Set) */ + CMD_ID_UPDATE_WMM_PARMS, /* 0x21 (Set) */ + CMD_ID_SET_WMM_PS_TEST_PARMS, /* 0x22 (Set) */ + CMD_ID_TX_AMPDU, /* 0x23 (Set) */ + CMD_ID_ADDBA_REJECT, /* 0x24 (Set) */ + CMD_ID_SET_PS_PROFILE_ADV, /* 0x25 (Set) */ + CMD_ID_SET_RAW_PATTERN, /* 0x26 (Set) */ + CMD_ID_CONFIG_PATTERN_FUNC, /* 0x27 (Set) */ + CMD_ID_SET_TX_PWR, /* 0x28 (Set) */ + CMD_ID_SET_5G_PWR_OFFSET, /* 0x29 (Set) */ + CMD_ID_SET_PWR_PARAM, /* 0x2A (Set) */ + CMD_ID_P2P_ABORT, /* 0x2B (Set) */ +#if CFG_STRESS_TEST_SUPPORT + CMD_ID_RANDOM_RX_RESET_EN = 0x2C, /* 0x2C (Set ) */ + CMD_ID_RANDOM_RX_RESET_DE = 0x2D, /* 0x2D (Set ) */ + CMD_ID_SAPP_EN = 0x2E, /* 0x2E (Set ) */ + CMD_ID_SAPP_DE = 0x2F, /* 0x2F (Set ) */ +#endif + CMD_ID_ROAMING_TRANSIT = 0x30, /* 0x30 (Set) */ + CMD_ID_SET_PHY_PARAM, /* 0x31 (Set) */ + CMD_ID_SET_NOA_PARAM, /* 0x32 (Set) */ + CMD_ID_SET_OPPPS_PARAM, /* 0x33 (Set) */ + CMD_ID_SET_UAPSD_PARAM, /* 0x34 (Set) */ + CMD_ID_SET_SIGMA_STA_SLEEP, /* 0x35 (Set) */ + CMD_ID_SET_EDGE_TXPWR_LIMIT, /* 0x36 (Set) */ + CMD_ID_SET_DEVICE_MODE, /* 0x37 (Set) */ + CMD_ID_SET_TXPWR_CTRL, /* 0x38 (Set) */ + CMD_ID_SET_AUTOPWR_CTRL, /* 0x39 (Set) */ + CMD_ID_SET_WFD_CTRL, /* 0x3A (Set) */ + CMD_ID_SET_5G_EDGE_TXPWR_LIMIT, /* 0x3B (Set) */ + CMD_ID_SET_RSSI_COMPENSATE, /* 0x3C (Set) */ + CMD_ID_SET_BAND_SUPPORT = 0x3D, /* 0x3D (Set) */ + CMD_ID_SET_NLO_REQ, /* 0x3E (Set) */ + CMD_ID_SET_NLO_CANCEL, /* 0x3F (Set) */ + CMD_ID_SET_BATCH_REQ, /* 0x40 (Set) */ + CMD_ID_SET_WOWLAN, /* 0x41 (Set) */ /*CFG_SUPPORT_WOWLAN */ + CMD_ID_GET_PSCAN_CAPABILITY = 0x42, /* 0x42 (Set) */ + CMD_ID_SET_PSCN_ENABLE = 0x43, /* 0x43 (Set) */ + CMD_ID_SET_PSCAN_PARAM = 0x44, /* 0x44 (Set) */ + CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID = 0x45, /* 0x45 (Set) */ + CMD_ID_SET_PSCN_ADD_SW_BSSID = 0x46, /* 0x46 (Set) */ + CMD_ID_SET_PSCN_MAC_ADDR = 0x47, /* 0x47 (Set) */ + CMD_ID_GET_GSCN_SCN_RESULT = 0x48, /* 0x48 (Get) */ + CMD_ID_SET_COUNTRY_POWER_LIMIT = 0x4A, /* 0x4A (Set) */ + CMD_ID_SET_SYSTEM_SUSPEND = 0x60, /* 0x60 (Set) */ + CMD_ID_GET_NIC_CAPABILITY = 0x80, /* 0x80 (Query) */ + CMD_ID_GET_LINK_QUALITY, /* 0x81 (Query) */ + CMD_ID_GET_STATISTICS, /* 0x82 (Query) */ + CMD_ID_GET_CONNECTION_STATUS, /* 0x83 (Query) */ + CMD_ID_GET_ASSOC_INFO, /* 0x84 (Query) (obsolete) */ + CMD_ID_GET_STA_STATISTICS = 0x85, /* 0x85 (Query) */ + CMD_ID_GET_DEBUG_CODE = 0x86, /* 0x86 (Query) */ + CMD_ID_GET_LTE_CHN = 0x87, /* 0x87 (Query) */ + CMD_ID_GET_CHN_LOADING = 0x88, /* 0x88 (Query) */ + CMD_ID_GET_STATISTICS_PL = 0x89, /* 0x87 (Query) */ + CMD_ID_BASIC_CONFIG = 0xc1, /* 0xc1 (Set / Query) */ + CMD_ID_ACCESS_REG, /* 0xc2 (Set / Query) */ + CMD_ID_MAC_MCAST_ADDR, /* 0xc3 (Set / Query) */ + CMD_ID_802_11_PMKID, /* 0xc4 (Set / Query) */ + CMD_ID_ACCESS_EEPROM, /* 0xc5 (Set / Query) */ + CMD_ID_SW_DBG_CTRL, /* 0xc6 (Set / Query) */ +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + CMD_ID_SEC_CHECK, /* 0xc7 (Set / Query) */ +#endif + CMD_ID_DUMP_MEM, /* 0xc8 (Query) */ + + CMD_ID_CHIP_CONFIG = 0xCA, /* 0xca (Set / Query) */ + +#if CFG_SUPPORT_RDD_TEST_MODE + CMD_ID_SET_RDD_CH = 0xE1, +#endif + + CMD_ID_SET_BWCS = 0xF1, + CMD_ID_SET_ROAMING_INFO = 0xF3, + +#if CFG_SUPPORT_BUILD_DATE_CODE + CMD_ID_GET_BUILD_DATE_CODE = 0xF8, +#endif + CMD_ID_GET_BSS_INFO = 0xF9, +#if 1 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ + CMD_ID_SET_HOTSPOT_OPTIMIZATION = 0xFA, /* 0xFA (Set) */ +#endif + + CMD_ID_TDLS_CORE = 0xFC, + CMD_ID_STATS = 0xFD, + CMD_ID_TX_AR_ERR_CONFIG = 0xFF +} ENUM_CMD_ID_T, *P_ENUM_CMD_ID_T; + +typedef enum _ENUM_EVENT_ID_T { + EVENT_ID_CMD_RESULT = 1, /* 0x01 (Query) */ + EVENT_ID_NIC_CAPABILITY, /* 0x02 (Query) */ + EVENT_ID_CONNECTION_STATUS, /* 0x03 (Query / Unsolicited) (obsolete) */ + EVENT_ID_SCAN_RESULT, /* 0x04 (Query / Unsolicited) (obselete) */ + EVENT_ID_LINK_QUALITY, /* 0x05 (Query / Unsolicited) */ + EVENT_ID_STATISTICS, /* 0x06 (Query) */ + EVENT_ID_MIC_ERR_INFO, /* 0x07 (Unsolicited) */ + EVENT_ID_ASSOC_INFO, /* 0x08 (Query - CMD_ID_GET_ASSOC_INFO) */ + EVENT_ID_BASIC_CONFIG, /* 0x09 (Query - CMD_ID_BASIC_CONFIG) */ + EVENT_ID_ACCESS_REG, /* 0x0a (Query - CMD_ID_ACCESS_REG) */ + EVENT_ID_MAC_MCAST_ADDR, /* 0x0b (Query - CMD_ID_MAC_MCAST_ADDR) */ + EVENT_ID_802_11_PMKID, /* 0x0c (Query - CMD_ID_802_11_PMKID) */ + EVENT_ID_ACCESS_EEPROM, /* 0x0d (Query - CMD_ID_ACCESS_EEPROM) */ + EVENT_ID_SLEEPY_NOTIFY, /* 0x0e (Query) */ + EVENT_ID_BT_OVER_WIFI, /* 0x0f (Unsolicited) */ + EVENT_ID_TEST_STATUS, /* 0x10 (Query - CMD_ID_TEST_MODE) */ + EVENT_ID_RX_ADDBA, /* 0x11 (Unsolicited) (obsolete) */ + EVENT_ID_RX_DELBA, /* 0x12 (Unsolicited) (obsolete) */ + EVENT_ID_ACTIVATE_STA_REC_T, /* 0x13 (Unsolicited) */ + EVENT_ID_DEACTIVATE_STA_REC_T, /* 0x14 (Unsolicited) */ + EVENT_ID_SCAN_DONE, /* 0x15 (Unsoiicited) */ + EVENT_ID_RX_FLUSH, /* 0x16 (Unsolicited) */ + EVENT_ID_TX_DONE, /* 0x17 (Unsolicited) */ + EVENT_ID_CH_PRIVILEGE, /* 0x18 (Unsolicited) */ + EVENT_ID_BSS_ABSENCE_PRESENCE = 0x19, /* 0x19 (Unsolicited) */ + EVENT_ID_STA_CHANGE_PS_MODE, /* 0x1A (Unsolicited) */ + EVENT_ID_BSS_BEACON_TIMEOUT, /* 0x1B (Unsolicited) */ + EVENT_ID_UPDATE_NOA_PARAMS, /* 0x1C (Unsolicited) */ + EVENT_ID_AP_OBSS_STATUS, /* 0x1D (Unsolicited) */ + EVENT_ID_STA_UPDATE_FREE_QUOTA, /* 0x1E (Unsolicited) */ + EVENT_ID_SW_DBG_CTRL, /* 0x1F (Query - CMD_ID_SW_DBG_CTRL) */ + EVENT_ID_ROAMING_STATUS, /* 0x20 (Unsolicited) */ + EVENT_ID_STA_AGING_TIMEOUT, /* 0x21 (Unsolicited) */ +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + EVENT_ID_SEC_CHECK_RSP, /* 0x22 (Unsolicited) */ +#endif + EVENT_ID_SEND_DEAUTH, /* 0x23 (Unsolicited) */ + +#if CFG_SUPPORT_RDD_TEST_MODE + EVENT_ID_UPDATE_RDD_STATUS, /* 0x24 (Unsolicited) */ +#endif + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + EVENT_ID_UPDATE_BWCS_STATUS = 0x25, /* 0x25 (Unsolicited) */ + EVENT_ID_UPDATE_BCM_DEBUG, /* 0x26 (Unsolicited) */ +#endif + EVENT_ID_RX_ERR, + EVENT_ID_DUMP_MEM, + EVENT_ID_STA_STATISTICS = 0x29, /* 0x29 (Query ) */ + EVENT_ID_STA_STATISTICS_UPDATE, /* 0x2A (Unsolicited) */ + EVENT_ID_NLO_DONE = 0x2b, + + EVENT_ID_GSCAN_CAPABILITY = 0x30, + EVENT_ID_GSCAN_SCAN_COMPLETE = 0x31, + EVENT_ID_GSCAN_FULL_RESULT = 0x32, + EVENT_ID_GSCAN_SIGNIFICANT_CHANGE = 0x33, + EVENT_ID_GSCAN_GEOFENCE_FOUND = 0x34, + EVENT_ID_GSCAN_SCAN_AVAILABLE = 0x35, + EVENT_ID_GSCAN_RESULT = 0x36, + EVENT_ID_BATCH_RESULT = 0x37, + + EVENT_ID_TDLS = 0x80, + EVENT_ID_STATS_ENV = 0x81, + +#if CFG_SUPPORT_BUILD_DATE_CODE + EVENT_ID_BUILD_DATE_CODE = 0xF8, +#endif + EVENT_ID_GET_AIS_BSS_INFO = 0xF9, + EVENT_ID_DEBUG_CODE = 0xFB, + EVENT_ID_RFTEST_READY = 0xFC, /* 0xFC */ + EVENT_ID_TX_DONE_STATUS = 0xFD, + EVENT_ID_FW_LOG_ENV = 0xFE, /* 0xFE, FW real time debug log */ +} ENUM_EVENT_ID_T, *P_ENUM_EVENT_ID_T; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifndef LINUX +typedef UINT_8 CMD_STATUS; +#endif + +typedef struct _EVENT_TX_DONE_STATUS_T { + UINT_8 ucPacketSeq; + UINT_8 ucStatus; + UINT_16 u2SequenceNumber; + UINT_32 au4Reserved1; + UINT_32 au4Reserved2; + UINT_32 au4Reserved3; + UINT_32 u4PktBufInfo; + UINT_8 aucPktBuf[200]; +} EVENT_TX_DONE_STATUS_T, *P_EVENT_TX_DONE_STATUS_T; + +/* for Event Packet (via HIF-RX) */ + /* following CM's documentation v0.7 */ +typedef struct _WIFI_CMD_T { + UINT_16 u2TxByteCount_UserPriority; + UINT_8 ucEtherTypeOffset; + UINT_8 ucResource_PktType_CSflags; + UINT_8 ucCID; + UINT_8 ucSetQuery; + UINT_8 ucSeqNum; + UINT_8 aucReserved2; + + UINT_8 aucBuffer[0]; +} WIFI_CMD_T, *P_WIFI_CMD_T; + +/* for Command Packet (via HIF-TX) */ + /* following CM's documentation v0.7 */ +typedef struct _WIFI_EVENT_T { + UINT_16 u2PacketLen; + UINT_16 u2PacketType; + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucReserved2[2]; + + UINT_8 aucBuffer[0]; +} WIFI_EVENT_T, *P_WIFI_EVENT_T; + +/* CMD_ID_TEST_MODE */ +typedef struct _CMD_TEST_CTRL_T { + UINT_8 ucAction; + UINT_8 aucReserved[3]; + union { + UINT_32 u4OpMode; + UINT_32 u4ChannelFreq; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + } u; +} CMD_TEST_CTRL_T, *P_CMD_TEST_CTRL_T; + +/* EVENT_TEST_STATUS */ +typedef struct _PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T { + UINT_32 u4PktSentStatus; + UINT_32 u4PktSentCount; + UINT_16 u2AvgAlc; + UINT_8 ucCckGainControl; + UINT_8 ucOfdmGainControl; +} PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T; + +typedef struct _PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T { + UINT_32 u4IntRxOk; /*!< number of packets that Rx ok from interrupt */ + UINT_32 u4IntCrcErr; /*!< number of packets that CRC error from interrupt */ + UINT_32 u4IntShort; /*!< number of packets that is short preamble from interrupt */ + UINT_32 u4IntLong; /*!< number of packets that is long preamble from interrupt */ + UINT_32 u4PauRxPktCount; /*!< number of packets that Rx ok from PAU */ + UINT_32 u4PauCrcErrCount; /*!< number of packets that CRC error from PAU */ + UINT_32 u4PauRxFifoFullCount; /*!< number of packets that is short preamble from PAU */ + UINT_32 u4PauCCACount; /*!< CCA rising edge count */ +} PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T, *P_PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T; + +typedef union _EVENT_TEST_STATUS { + PARAM_MTK_WIFI_TEST_STRUCT_T rATInfo; +/* PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T rTxStatus; */ +/* PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T rRxStatus; */ +} EVENT_TEST_STATUS, *P_EVENT_TEST_STATUS; + +/* CMD_BUILD_CONNECTION */ +typedef struct _CMD_BUILD_CONNECTION { + UINT_8 ucInfraMode; + UINT_8 ucAuthMode; + UINT_8 ucEncryptStatus; + UINT_8 ucSsidLen; + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; + UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; + + /* Ad-hoc mode */ + UINT_16 u2BeaconPeriod; + UINT_16 u2ATIMWindow; + UINT_8 ucJoinOnly; + UINT_8 ucReserved; + UINT_32 u4FreqInKHz; + + /* for faster connection */ + UINT_8 aucScanResult[0]; +} CMD_BUILD_CONNECTION, *P_CMD_BUILD_CONNECTION; + +/* CMD_ADD_REMOVE_KEY */ +typedef struct _CMD_802_11_KEY { + UINT_8 ucAddRemove; + UINT_8 ucTxKey; + UINT_8 ucKeyType; + UINT_8 ucIsAuthenticator; + UINT_8 aucPeerAddr[6]; + UINT_8 ucNetType; + UINT_8 ucAlgorithmId; + UINT_8 ucKeyId; + UINT_8 ucKeyLen; + UINT_8 aucReverved[2]; + UINT_8 aucKeyMaterial[32]; + UINT_8 aucKeyRsc[16]; +} CMD_802_11_KEY, *P_CMD_802_11_KEY; + +/* WPA2 PMKID cache structure */ +typedef struct _PMKID_ENTRY_T { + PARAM_BSSID_INFO_T rBssidInfo; + BOOLEAN fgPmkidExist; +} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; + +typedef struct _CMD_802_11_PMKID { + ULONG u4BSSIDInfoCount; + P_PMKID_ENTRY_T arPMKIDInfo[1]; +} CMD_802_11_PMKID, *P_CMD_802_11_PMKID; + +/* CMD_BASIC_CONFIG */ +typedef struct _CMD_CSUM_OFFLOAD { + UINT_16 u2RxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ + UINT_16 u2TxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ +} CMD_CSUM_OFFLOAD, *P_CMD_CSUM_OFFLOAD; + +typedef struct _CMD_BASIC_CONFIG { + PARAM_MAC_ADDRESS rMyMacAddr; + UINT_8 ucNative80211; + UINT_8 aucReserved[1]; + + CMD_CSUM_OFFLOAD rCsumOffload; +} CMD_BASIC_CONFIG, *P_CMD_BASIC_CONFIG, EVENT_BASIC_CONFIG, *P_EVENT_BASIC_CONFIG; + +/* CMD_MAC_MCAST_ADDR */ +typedef struct _CMD_MAC_MCAST_ADDR { + UINT_32 u4NumOfGroupAddr; + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[3]; + PARAM_MAC_ADDRESS arAddress[MAX_NUM_GROUP_ADDR]; +} CMD_MAC_MCAST_ADDR, *P_CMD_MAC_MCAST_ADDR, EVENT_MAC_MCAST_ADDR, *P_EVENT_MAC_MCAST_ADDR; + +/* CMD_ACCESS_EEPROM */ +typedef struct _CMD_ACCESS_EEPROM { + UINT_16 u2Offset; + UINT_16 u2Data; +} CMD_ACCESS_EEPROM, *P_CMD_ACCESS_EEPROM, EVENT_ACCESS_EEPROM, *P_EVENT_ACCESS_EEPROM; + +typedef struct _CMD_CUSTOM_NOA_PARAM_STRUCT_T { + UINT_32 u4NoaDurationMs; + UINT_32 u4NoaIntervalMs; + UINT_32 u4NoaCount; +} CMD_CUSTOM_NOA_PARAM_STRUCT_T, *P_CMD_CUSTOM_NOA_PARAM_STRUCT_T; + +typedef struct _CMD_CUSTOM_OPPPS_PARAM_STRUCT_T { + UINT_32 u4CTwindowMs; +} CMD_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_CMD_CUSTOM_OPPPS_PARAM_STRUCT_T; + +typedef struct _CMD_CUSTOM_UAPSD_PARAM_STRUCT_T { + UINT_8 fgEnAPSD; + UINT_8 fgEnAPSD_AcBe; + UINT_8 fgEnAPSD_AcBk; + UINT_8 fgEnAPSD_AcVo; + UINT_8 fgEnAPSD_AcVi; + UINT_8 ucMaxSpLen; + UINT_8 aucResv[2]; +} CMD_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_CMD_CUSTOM_UAPSD_PARAM_STRUCT_T; + +/* EVENT_CONNECTION_STATUS */ +typedef struct _EVENT_CONNECTION_STATUS { + UINT_8 ucMediaStatus; + UINT_8 ucReasonOfDisconnect; + + UINT_8 ucInfraMode; + UINT_8 ucSsidLen; + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; + UINT_8 aucBssid[PARAM_MAC_ADDR_LEN]; + UINT_8 ucAuthenMode; + UINT_8 ucEncryptStatus; + UINT_16 u2BeaconPeriod; + UINT_16 u2AID; + UINT_16 u2ATIMWindow; + UINT_8 ucNetworkType; + UINT_8 aucReserved[1]; + UINT_32 u4FreqInKHz; + +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 aucInterfaceAddr[PARAM_MAC_ADDR_LEN]; +#endif + +} EVENT_CONNECTION_STATUS, *P_EVENT_CONNECTION_STATUS; + +/* EVENT_NIC_CAPABILITY */ +typedef struct _EVENT_NIC_CAPABILITY { + UINT_16 u2ProductID; + UINT_16 u2FwVersion; + UINT_16 u2DriverVersion; + UINT_8 ucHw5GBandDisabled; + UINT_8 ucEepromUsed; + UINT_8 ucEfuseValid; + UINT_8 ucMacAddrValid; +#if CFG_REPORT_RFBB_VERSION + UINT_8 ucRfVersion; + UINT_8 ucPhyVersion; +#endif +#if CFG_ENABLE_CAL_LOG + UINT_8 ucRfCalFail; + UINT_8 ucBbCalFail; +#endif + +#define FEATURE_SET_OFFSET_TDLS 0 +#define FEATURE_SET_OFFSET_5G_SUPPORT 1 + UINT_8 ucFeatureSet; /* bit0: TDLS */ + + UINT_8 aucReserved[1]; +#if CFG_EMBED_FIRMWARE_BUILD_DATE_CODE + UINT_8 aucDateCode[16]; +#endif +} EVENT_NIC_CAPABILITY, *P_EVENT_NIC_CAPABILITY; + +/* modified version of WLAN_BEACON_FRAME_BODY_T for simplier buffering */ +typedef struct _WLAN_BEACON_FRAME_BODY_T_LOCAL { + /* Beacon frame body */ + UINT_32 au4Timestamp[2]; /* Timestamp */ + UINT_16 u2BeaconInterval; /* Beacon Interval */ + UINT_16 u2CapInfo; /* Capability */ + UINT_8 aucInfoElem[MAX_IE_LENGTH]; /* Various IEs, start from SSID */ + UINT_16 u2IELength; /* This field is *NOT* carried by F/W but caculated by nic_rx */ +} WLAN_BEACON_FRAME_BODY_T_LOCAL, *P_WLAN_BEACON_FRAME_BODY_T_LOCAL; + +/* EVENT_SCAN_RESULT */ +typedef struct _EVENT_SCAN_RESULT_T { + INT_32 i4RSSI; + UINT_32 u4LinkQuality; + UINT_32 u4DSConfig; /* Center frequency */ + UINT_32 u4DomainInfo; /* Require CM opinion */ + UINT_32 u4Reserved; + UINT_8 ucNetworkType; + UINT_8 ucOpMode; + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + WLAN_BEACON_FRAME_BODY_T_LOCAL rBeaconFrameBody; +} EVENT_SCAN_RESULT_T, *P_EVENT_SCAN_RESULT_T; + +/* event of tkip mic error */ +typedef struct _EVENT_MIC_ERR_INFO { + UINT_32 u4Flags; +} EVENT_MIC_ERR_INFO, *P_EVENT_MIC_ERR_INFO; + +typedef struct _EVENT_PMKID_CANDIDATE_LIST_T { + UINT_32 u4Version; /*!< Version */ + UINT_32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} EVENT_PMKID_CANDIDATE_LIST_T, *P_EVENT_PMKID_CANDIDATE_LIST_T; + +typedef struct _EVENT_CMD_RESULT { + UINT_8 ucCmdID; + UINT_8 ucStatus; + UINT_8 aucReserved[2]; +} EVENT_CMD_RESULT, *P_EVENT_CMD_RESULT; + +/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ +typedef struct _CMD_ACCESS_REG { + UINT_32 u4Address; + UINT_32 u4Data; +} CMD_ACCESS_REG, *P_CMD_ACCESS_REG; + +/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + +typedef struct _CMD_ACCESS_CHN_LOAD { + UINT_32 u4Address; + UINT_32 u4Data; + UINT_16 u2Channel; + UINT_8 aucReserved[2]; +} CMD_ACCESS_CHN_LOAD, *P_ACCESS_CHN_LOAD; + +#endif +/* CMD_DUMP_MEMORY */ +typedef struct _CMD_DUMP_MEM { + UINT_32 u4Address; + UINT_32 u4Length; + UINT_32 u4RemainLength; + UINT_8 ucFragNum; +} CMD_DUMP_MEM, *P_CMD_DUMP_MEM; + +typedef struct _EVENT_DUMP_MEM_T { + UINT_32 u4Address; + UINT_32 u4Length; + UINT_32 u4RemainLength; + UINT_8 ucFragNum; + UINT_8 aucBuffer[1]; +} EVENT_DUMP_MEM_T, *P_EVENT_DUMP_MEM_T; + +typedef struct _CMD_SW_DBG_CTRL_T { + UINT_32 u4Id; + UINT_32 u4Data; + /* Debug Support */ + UINT_32 u4DebugCnt[64]; +} CMD_SW_DBG_CTRL_T, *P_CMD_SW_DBG_CTRL_T; + +/* CMD_ID_LINK_ATTRIB */ +typedef struct _CMD_LINK_ATTRIB { + INT_8 cRssiTrigger; + UINT_8 ucDesiredRateLen; + UINT_16 u2DesiredRate[32]; + UINT_8 ucMediaStreamMode; + UINT_8 aucReserved[1]; +} CMD_LINK_ATTRIB, *P_CMD_LINK_ATTRIB; + +/* CMD_ID_NIC_POWER_CTRL */ +typedef struct _CMD_NIC_POWER_CTRL { + UINT_8 ucPowerMode; + UINT_8 aucReserved[3]; +} CMD_NIC_POWER_CTRL, *P_CMD_NIC_POWER_CTRL; + +/* CMD_ID_POWER_SAVE_MODE */ +typedef struct _CMD_PS_PROFILE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucPsProfile; + UINT_8 aucReserved[2]; +} CMD_PS_PROFILE_T, *P_CMD_PS_PROFILE_T; + +/* EVENT_LINK_QUALITY */ +typedef struct _EVENT_LINK_QUALITY { + INT_8 cRssi; + INT_8 cLinkQuality; + UINT_16 u2LinkSpeed; + UINT_8 ucMediumBusyPercentage; +} EVENT_LINK_QUALITY, *P_EVENT_LINK_QUALITY; + +#if CFG_SUPPORT_P2P_RSSI_QUERY +/* EVENT_LINK_QUALITY */ +typedef struct _EVENT_LINK_QUALITY_EX { + INT_8 cRssi; + INT_8 cLinkQuality; + UINT_16 u2LinkSpeed; + UINT_8 ucMediumBusyPercentage; + UINT_8 ucIsLQ0Rdy; + INT_8 cRssiP2P; /* For P2P Network. */ + INT_8 cLinkQualityP2P; + UINT_16 u2LinkSpeedP2P; + UINT_8 ucMediumBusyPercentageP2P; + UINT_8 ucIsLQ1Rdy; +} EVENT_LINK_QUALITY_EX, *P_EVENT_LINK_QUALITY_EX; +#endif + +/* EVENT_ID_STATISTICS */ +typedef struct _EVENT_STATISTICS { + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; +} EVENT_STATISTICS, *P_EVENT_STATISTICS; + +/* EVENT_ID_FW_SLEEPY_NOTIFY */ +typedef struct _EVENT_SLEEPY_NOTIFY { + UINT_8 ucSleepyState; + UINT_8 aucReserved[3]; +} EVENT_SLEEPY_NOTIFY, *P_EVENT_SLEEPY_NOTIFY; + +typedef struct _EVENT_ACTIVATE_STA_REC_T { + UINT_8 aucMacAddr[6]; + UINT_8 ucStaRecIdx; + UINT_8 ucNetworkTypeIndex; + BOOLEAN fgIsQoS; + BOOLEAN fgIsAP; + UINT_8 aucReserved[2]; +} EVENT_ACTIVATE_STA_REC_T, *P_EVENT_ACTIVATE_STA_REC_T; + +typedef struct _EVENT_DEACTIVATE_STA_REC_T { + UINT_8 ucStaRecIdx; + UINT_8 aucReserved[3]; +} EVENT_DEACTIVATE_STA_REC_T, *P_EVENT_DEACTIVATE_STA_REC_T; + +/* CMD_BT_OVER_WIFI */ +typedef struct _CMD_BT_OVER_WIFI { + UINT_8 ucAction; /* 0: query, 1: setup, 2: destroy */ + UINT_8 ucChannelNum; + PARAM_MAC_ADDRESS rPeerAddr; + UINT_16 u2BeaconInterval; + UINT_8 ucTimeoutDiscovery; + UINT_8 ucTimeoutInactivity; + UINT_8 ucRole; + UINT_8 PAL_Capabilities; + UINT_8 cMaxTxPower; + UINT_8 ucChannelBand; + UINT_8 ucReserved[1]; +} CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI; + +/* EVENT_BT_OVER_WIFI */ +typedef struct _EVENT_BT_OVER_WIFI { + UINT_8 ucLinkStatus; + UINT_8 ucSelectedChannel; + INT_8 cRSSI; + UINT_8 ucReserved[1]; +} EVENT_BT_OVER_WIFI, *P_EVENT_BT_OVER_WIFI; + +/* Same with DOMAIN_SUBBAND_INFO */ +typedef struct _CMD_SUBBAND_INFO { + UINT_8 ucRegClass; + UINT_8 ucBand; + UINT_8 ucChannelSpan; + UINT_8 ucFirstChannelNum; + UINT_8 ucNumChannels; + UINT_8 aucReserved[3]; +} CMD_SUBBAND_INFO, *P_CMD_SUBBAND_INFO; + +/* CMD_SET_DOMAIN_INFO */ +typedef struct _CMD_SET_DOMAIN_INFO_T { + UINT_16 u2CountryCode; + UINT_16 u2IsSetPassiveScan; /* 0: set channel domain; 1: set passive scan channel domain */ + CMD_SUBBAND_INFO rSubBand[6]; + + UINT_8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + UINT_8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + UINT_8 aucReserved[2]; +} CMD_SET_DOMAIN_INFO_T, *P_CMD_SET_DOMAIN_INFO_T; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +/* CMD_SET_PWR_LIMIT_TABLE */ +typedef struct _CMD_CHANNEL_POWER_LIMIT { + UINT_8 ucCentralCh; + INT_8 cPwrLimitCCK; + INT_8 cPwrLimit20; + INT_8 cPwrLimit40; + INT_8 cPwrLimit80; + INT_8 cPwrLimit160; + UINT_8 ucFlag; + UINT_8 aucReserved[1]; +} CMD_CHANNEL_POWER_LIMIT, *P_CMD_CHANNEL_POWER_LIMIT; + +typedef struct _CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T { + UINT_16 u2CountryCode; + UINT_8 ucCountryFlag; + UINT_8 ucNum; + UINT_8 aucReserved[4]; + CMD_CHANNEL_POWER_LIMIT rChannelPowerLimit[1]; +} CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T, *P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T; + +#endif + +/* CMD_SET_IP_ADDRESS */ +typedef struct _IPV4_NETWORK_ADDRESS { + UINT_8 aucIpAddr[4]; +} IPV4_NETWORK_ADDRESS, *P_IPV4_NETWORK_ADDRESS; + +typedef struct _CMD_SET_NETWORK_ADDRESS_LIST { + UINT_8 ucNetTypeIndex; + UINT_8 ucAddressCount; + UINT_8 ucReserved[2]; + IPV4_NETWORK_ADDRESS arNetAddress[1]; +} CMD_SET_NETWORK_ADDRESS_LIST, *P_CMD_SET_NETWORK_ADDRESS_LIST; + +typedef struct _PATTERN_DESCRIPTION { + UINT_8 fgCheckBcA1; + UINT_8 fgCheckMcA1; + UINT_8 ePatternHeader; + UINT_8 fgAndOp; + UINT_8 fgNotOp; + UINT_8 ucPatternMask; + UINT_16 ucPatternOffset; + UINT_8 aucPattern[8]; +} PATTERN_DESCRIPTION, *P_PATTERN_DESCRIPTION; + +typedef struct _CMD_RAW_PATTERN_CONFIGURATION_T { + PATTERN_DESCRIPTION arPatternDesc[4]; +} CMD_RAW_PATTERN_CONFIGURATION_T, *P_CMD_RAW_PATTERN_CONFIGURATION_T; + +typedef struct _CMD_PATTERN_FUNC_CONFIG { + BOOLEAN fgBcA1En; + BOOLEAN fgMcA1En; + BOOLEAN fgBcA1MatchDrop; + BOOLEAN fgMcA1MatchDrop; +} CMD_PATTERN_FUNC_CONFIG, *P_CMD_PATTERN_FUNC_CONFIG; + +typedef struct _EVENT_TX_DONE_T { + UINT_8 ucPacketSeq; + UINT_8 ucStatus; + UINT_16 u2SequenceNumber; + UINT_32 au4Reserved1; + UINT_32 au4Reserved2; + UINT_32 au4Reserved3; +} EVENT_TX_DONE_T, *P_EVENT_TX_DONE_T; + +typedef struct _CMD_BSS_ACTIVATE_CTRL { + UINT_8 ucNetTypeIndex; + UINT_8 ucActive; + UINT_8 aucReserved[2]; +} CMD_BSS_ACTIVATE_CTRL, *P_CMD_BSS_ACTIVATE_CTRL; + +typedef struct _CMD_SET_BSS_RLM_PARAM_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucRfBand; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucErpProtectMode; + UINT_8 ucHtProtectMode; + UINT_8 ucGfOperationMode; + UINT_8 ucTxRifsMode; + UINT_16 u2HtOpInfo3; + UINT_16 u2HtOpInfo2; + UINT_8 ucHtOpInfo1; + UINT_8 ucUseShortPreamble; + UINT_8 ucUseShortSlotTime; + UINT_8 ucCheckId; /* Fixed value: 0x72 */ +} CMD_SET_BSS_RLM_PARAM_T, *P_CMD_SET_BSS_RLM_PARAM_T; + +typedef struct _CMD_SET_BSS_INFO { + UINT_8 ucNetTypeIndex; + UINT_8 ucConnectionState; + UINT_8 ucCurrentOPMode; + UINT_8 ucSSIDLen; + UINT_8 aucSSID[32]; + UINT_8 aucBSSID[6]; + UINT_8 ucIsQBSS; + UINT_8 ucReserved1; + UINT_16 u2OperationalRateSet; + UINT_16 u2BSSBasicRateSet; + UINT_8 ucStaRecIdxOfAP; + UINT_8 ucReserved2; + UINT_8 ucReserved3; + UINT_8 ucNonHTBasicPhyType; /* For Slot Time and CWmin */ + UINT_8 ucAuthMode; + UINT_8 ucEncStatus; + UINT_8 ucPhyTypeSet; + UINT_8 aucOwnMac[6]; + UINT_8 fgWapiMode; + UINT_8 fgIsApMode; + UINT_8 fgHiddenSsidMode; + CMD_SET_BSS_RLM_PARAM_T rBssRlmParam; +} CMD_SET_BSS_INFO, *P_CMD_SET_BSS_INFO; + +typedef struct _CMD_UPDATE_STA_RECORD_T { + UINT_8 ucIndex; + UINT_8 ucStaType; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + UINT_16 u2AssocId; + UINT_16 u2ListenInterval; + UINT_8 ucNetTypeIndex; + UINT_8 ucDesiredPhyTypeSet; + UINT_16 u2DesiredNonHTRateSet; + UINT_16 u2BSSBasicRateSet; + UINT_8 ucIsQoS; + UINT_8 ucIsUapsdSupported; + UINT_8 ucStaState; + UINT_8 ucMcsSet; + UINT_8 ucSupMcs32; + UINT_8 ucAmpduParam; + UINT_16 u2HtCapInfo; + UINT_16 u2HtExtendedCap; + UINT_32 u4TxBeamformingCap; + UINT_8 ucAselCap; + UINT_8 ucRCPI; + UINT_8 ucNeedResp; + UINT_8 ucUapsdAc; /* b0~3: Trigger enabled, b4~7: Delivery enabled */ + UINT_8 ucUapsdSp; /* 0: all, 1: max 2, 2: max 4, 3: max 6 */ + UINT_8 aucReserved[3]; + /* TBD */ +} CMD_UPDATE_STA_RECORD_T, *P_CMD_UPDATE_STA_RECORD_T; + +typedef struct _CMD_REMOVE_STA_RECORD_T { + UINT_8 ucIndex; + UINT_8 ucReserved; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; +} CMD_REMOVE_STA_RECORD_T, *P_CMD_REMOVE_STA_RECORD_T; + +typedef struct _CMD_INDICATE_PM_BSS_CREATED_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucDtimPeriod; + UINT_16 u2BeaconInterval; + UINT_16 u2AtimWindow; + UINT_8 aucReserved[2]; +} CMD_INDICATE_PM_BSS_CREATED, *P_CMD_INDICATE_PM_BSS_CREATED; + +typedef struct _CMD_INDICATE_PM_BSS_CONNECTED_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucDtimPeriod; + UINT_16 u2AssocId; + UINT_16 u2BeaconInterval; + UINT_16 u2AtimWindow; + UINT_8 fgIsUapsdConnection; + UINT_8 ucBmpDeliveryAC; + UINT_8 ucBmpTriggerAC; + UINT_8 aucReserved[1]; +} CMD_INDICATE_PM_BSS_CONNECTED, *P_CMD_INDICATE_PM_BSS_CONNECTED; + +typedef struct _CMD_INDICATE_PM_BSS_ABORT { + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[3]; +} CMD_INDICATE_PM_BSS_ABORT, *P_CMD_INDICATE_PM_BSS_ABORT; + +typedef struct _CMD_BEACON_TEMPLATE_UPDATE { + UINT_8 ucUpdateMethod; /* 0: update randomly, + * 1: update all, + * 2: delete all (1 and 2 will update directly without search) + */ + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[2]; + UINT_16 u2Capability; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_BEACON_TEMPLATE_UPDATE, *P_CMD_BEACON_TEMPLATE_UPDATE; + +typedef struct _CMD_SET_WMM_PS_TEST_STRUCT_T { + UINT_8 ucNetTypeIndex; + UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ + UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ +} CMD_SET_WMM_PS_TEST_STRUCT_T, *P_CMD_SET_WMM_PS_TEST_STRUCT_T; + +/* Definition for CHANNEL_INFO.ucBand: + * 0: Reserved + * 1: BAND_2G4 + * 2: BAND_5G + * Others: Reserved + */ +typedef struct _CHANNEL_INFO_T { + UINT_8 ucBand; + UINT_8 ucChannelNum; +} CHANNEL_INFO_T, *P_CHANNEL_INFO_T; + +typedef struct _CMD_SCAN_REQ_EXT_CH_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDLength; + UINT_8 aucReserved[1]; + UINT_16 u2ChannelMinDwellTime; + UINT_8 aucSSID[32]; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ_EXT_CH, *P_CMD_SCAN_REQ_EXT_CH; + +typedef struct _CMD_SCAN_REQ_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) specific */ + UINT_8 ucSSIDLength; + UINT_8 aucReserved[1]; + UINT_16 u2ChannelMinDwellTime; + UINT_8 aucSSID[32]; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[32]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ, *P_CMD_SCAN_REQ; + +typedef struct _CMD_SCAN_REQ_V2_EXT_CH_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; + PARAM_SSID_T arSSID[4]; + UINT_16 u2ProbeDelayTime; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ_V2_EXT_CH, *P_CMD_SCAN_REQ_V2_EXT_CH; + +typedef struct _CMD_SCAN_REQ_V2_T { + UINT_8 ucSeqNum; + UINT_8 ucNetworkType; + UINT_8 ucScanType; + UINT_8 ucSSIDType; + PARAM_SSID_T arSSID[4]; + UINT_16 u2ProbeDelayTime; + UINT_16 u2ChannelDwellTime; /* For P2P */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + CHANNEL_INFO_T arChannelList[32]; + UINT_16 u2IELen; + UINT_8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ_V2, *P_CMD_SCAN_REQ_V2; + +typedef struct _CMD_SCAN_CANCEL_T { + UINT_8 ucSeqNum; + UINT_8 ucIsExtChannel; /* For P2P channel extension. */ + UINT_8 aucReserved[2]; +} CMD_SCAN_CANCEL, *P_CMD_SCAN_CANCEL; + +typedef struct _EVENT_SCAN_DONE_T { + UINT_8 ucSeqNum; + UINT_8 ucSparseChannelValid; + CHANNEL_INFO_T rSparseChannel; +} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; + +#if CFG_SUPPORT_GET_CH_ENV +typedef struct _CH_ENV_T { + UINT_8 ucChNum; + UINT_8 ucApNum; +} CH_ENV_T, *P_CH_ENV_T; +#endif + +#if 0 /* CFG_SUPPORT_BATCH_SCAN */ +typedef struct _CMD_BATCH_REQ_T { + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + UINT_8 ucCmd; /* Start/ Stop */ + UINT_8 ucMScan; /* an integer number of scans per batch */ + UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ + UINT_8 ucRtt; /* an integer number of highest-strength AP for which we'd + like approximate distance reported */ + UINT_8 ucChannel; /* channels */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + UINT_8 aucReserved[3]; + UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ + CHANNEL_INFO_T arChannelList[32]; /* channels */ +} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; + +typedef struct _EVENT_BATCH_RESULT_ENTRY_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + UINT_8 ucSSIDLen; + INT_8 cRssi; + UINT_32 ucFreq; + UINT_32 u4Age; + UINT_32 u4Dist; + UINT_32 u4Distsd; +} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; + +typedef struct _EVENT_BATCH_RESULT_T { + UINT_8 ucScanCount; + UINT_8 aucReserved[3]; + EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ +} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; +#endif + +typedef struct _CMD_CH_PRIVILEGE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucAction; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucRfBand; + UINT_8 ucReqType; + UINT_8 ucReserved; + UINT_32 u4MaxInterval; /* In unit of ms */ + UINT_8 aucBSSID[6]; + UINT_8 aucReserved[2]; +} CMD_CH_PRIVILEGE_T, *P_CMD_CH_PRIVILEGE_T; + +typedef struct _CMD_TX_PWR_T { + INT_8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ +#if defined(MT6620) + INT_8 acReserved[3]; +#elif defined(MT6628) + INT_8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + INT_8 acReserved[2]; +#else +#error "No valid definition!" +#endif + + INT_8 cTxPwr2G4OFDM_BPSK; + INT_8 cTxPwr2G4OFDM_QPSK; + INT_8 cTxPwr2G4OFDM_16QAM; + INT_8 cTxPwr2G4OFDM_Reserved; + INT_8 cTxPwr2G4OFDM_48Mbps; + INT_8 cTxPwr2G4OFDM_54Mbps; + + INT_8 cTxPwr2G4HT20_BPSK; + INT_8 cTxPwr2G4HT20_QPSK; + INT_8 cTxPwr2G4HT20_16QAM; + INT_8 cTxPwr2G4HT20_MCS5; + INT_8 cTxPwr2G4HT20_MCS6; + INT_8 cTxPwr2G4HT20_MCS7; + + INT_8 cTxPwr2G4HT40_BPSK; + INT_8 cTxPwr2G4HT40_QPSK; + INT_8 cTxPwr2G4HT40_16QAM; + INT_8 cTxPwr2G4HT40_MCS5; + INT_8 cTxPwr2G4HT40_MCS6; + INT_8 cTxPwr2G4HT40_MCS7; + + INT_8 cTxPwr5GOFDM_BPSK; + INT_8 cTxPwr5GOFDM_QPSK; + INT_8 cTxPwr5GOFDM_16QAM; + INT_8 cTxPwr5GOFDM_Reserved; + INT_8 cTxPwr5GOFDM_48Mbps; + INT_8 cTxPwr5GOFDM_54Mbps; + + INT_8 cTxPwr5GHT20_BPSK; + INT_8 cTxPwr5GHT20_QPSK; + INT_8 cTxPwr5GHT20_16QAM; + INT_8 cTxPwr5GHT20_MCS5; + INT_8 cTxPwr5GHT20_MCS6; + INT_8 cTxPwr5GHT20_MCS7; + + INT_8 cTxPwr5GHT40_BPSK; + INT_8 cTxPwr5GHT40_QPSK; + INT_8 cTxPwr5GHT40_16QAM; + INT_8 cTxPwr5GHT40_MCS5; + INT_8 cTxPwr5GHT40_MCS6; + INT_8 cTxPwr5GHT40_MCS7; +} CMD_TX_PWR_T, *P_CMD_TX_PWR_T; + +typedef struct _CMD_5G_PWR_OFFSET_T { + INT_8 cOffsetBand0; /* 4.915-4.980G */ + INT_8 cOffsetBand1; /* 5.000-5.080G */ + INT_8 cOffsetBand2; /* 5.160-5.180G */ + INT_8 cOffsetBand3; /* 5.200-5.280G */ + INT_8 cOffsetBand4; /* 5.300-5.340G */ + INT_8 cOffsetBand5; /* 5.500-5.580G */ + INT_8 cOffsetBand6; /* 5.600-5.680G */ + INT_8 cOffsetBand7; /* 5.700-5.825G */ +} CMD_5G_PWR_OFFSET_T, *P_CMD_5G_PWR_OFFSET_T; + +typedef struct _CMD_PWR_PARAM_T { + UINT_32 au4Data[28]; + UINT_32 u4RefValue1; + UINT_32 u4RefValue2; +} CMD_PWR_PARAM_T, *P_CMD_PWR_PARAM_T; + +typedef struct _CMD_PHY_PARAM_T { + UINT_8 aucData[144]; /* eFuse content */ +} CMD_PHY_PARAM_T, *P_CMD_PHY_PARAM_T; + +typedef struct _CMD_AUTO_POWER_PARAM_T { + UINT_8 ucType; /* 0: Disable 1: Enalbe 0x10: Change parameters */ + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[2]; + UINT_8 aucLevelRcpiTh[3]; + UINT_8 aucReserved2[1]; + INT_8 aicLevelPowerOffset[3]; /* signed, in unit of 0.5dBm */ + UINT_8 aucReserved3[1]; + UINT_8 aucReserved4[8]; +} CMD_AUTO_POWER_PARAM_T, *P_CMD_AUTO_POWER_PARAM_T; + +typedef struct _EVENT_CH_PRIVILEGE_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucTokenID; + UINT_8 ucStatus; + UINT_8 ucPrimaryChannel; + UINT_8 ucRfSco; + UINT_8 ucRfBand; + UINT_8 ucReqType; + UINT_8 ucReserved; + UINT_32 u4GrantInterval; /* In unit of ms */ +} EVENT_CH_PRIVILEGE_T, *P_EVENT_CH_PRIVILEGE_T; + +typedef enum _ENUM_BEACON_TIMEOUT_TYPE_T { + BEACON_TIMEOUT_LOST_BEACON = 0, + BEACON_TIMEOUT_AGE, + BEACON_TIMEOUT_CONNECT, + BEACON_TIMEOUT_BEACON_INTERVAL, + BEACON_TIMEOUT_ABORT, + BEACON_TIMEOUT_TX_ERROR, + BEACON_TIMEOUT_TYPE_NUM +} ENUM_BEACON_TIMEOUT_TYPE_T, *P_ENUM_BEACON_TIMEOUT_TYPE_T; + +typedef struct _EVENT_BSS_BEACON_TIMEOUT_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucReason; /* ENUM_BEACON_TIMEOUT_TYPE_T */ + UINT_8 aucReserved[2]; +} EVENT_BSS_BEACON_TIMEOUT_T, *P_EVENT_BSS_BEACON_TIMEOUT_T; + +typedef struct _EVENT_STA_AGING_TIMEOUT_T { + UINT_8 ucStaRecIdx; + UINT_8 aucReserved[3]; +} EVENT_STA_AGING_TIMEOUT_T, *P_EVENT_STA_AGING_TIMEOUT_T; + +typedef struct _EVENT_NOA_TIMING_T { + UINT_8 fgIsInUse; /* Indicate if this entry is in use or not */ + UINT_8 ucCount; /* Count */ + UINT_8 aucReserved[2]; + + UINT_32 u4Duration; /* Duration */ + UINT_32 u4Interval; /* Interval */ + UINT_32 u4StartTime; /* Start Time */ +} EVENT_NOA_TIMING_T, *P_EVENT_NOA_TIMING_T; + +typedef struct _EVENT_UPDATE_NOA_PARAMS_T { + UINT_8 ucNetTypeIndex; + UINT_8 aucReserved[2]; + UINT_8 fgEnableOppPS; + UINT_16 u2CTWindow; + + UINT_8 ucNoAIndex; + UINT_8 ucNoATimingCount; /* Number of NoA Timing */ + EVENT_NOA_TIMING_T arEventNoaTiming[8 /*P2P_MAXIMUM_NOA_COUNT */]; +} EVENT_UPDATE_NOA_PARAMS_T, *P_EVENT_UPDATE_NOA_PARAMS_T; + +typedef struct _EVENT_AP_OBSS_STATUS_T { + UINT_8 ucNetTypeIndex; + UINT_8 ucObssErpProtectMode; + UINT_8 ucObssHtProtectMode; + UINT_8 ucObssGfOperationMode; + UINT_8 ucObssRifsOperationMode; + UINT_8 ucObssBeaconForcedTo20M; + UINT_8 aucReserved[2]; +} EVENT_AP_OBSS_STATUS_T, *P_EVENT_AP_OBSS_STATUS_T; + +typedef struct _CMD_EDGE_TXPWR_LIMIT_T { + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + INT_8 cReserved; +} CMD_EDGE_TXPWR_LIMIT_T, *P_CMD_EDGE_TXPWR_LIMIT_T; + +typedef struct _CMD_RSSI_COMPENSATE_T { + UINT_8 uc2GRssiCompensation; + UINT_8 uc5GRssiCompensation; + UINT_8 ucRssiCompensationValidbit; + UINT_8 cReserved; +} CMD_RSSI_COMPENSATE_T, *P_CMD_RSSI_COMPENSATE_T; + +typedef struct _CMD_BAND_SUPPORT_T { + UINT_8 uc5GBandSupport; + UINT_8 cReserved[3]; +} CMD_BAND_SUPPORT_T, *P_CMD_BAND_SUPPORT_T; + +typedef struct _CMD_TX_PWR_CE_T { + INT_8 cTxPwrCckLmt; /* signed, in unit of 0.5dBm */ + INT_8 cTxPwrOfdmLmt; /* signed, in unit of 0.5dBm */ + INT_8 cTxPwrHt20Lmt; + INT_8 cTxPwrHt40Lmt; +} CMD_TX_PWR_CE_T, *P_CMD_TX_PWR_CE_T; + +typedef struct _CMD_SET_DEVICE_MODE_T { + UINT_16 u2ChipID; + UINT_16 u2Mode; +} CMD_SET_DEVICE_MODE_T, *P_CMD_SET_DEVICE_MODE_T; + +#if CFG_SUPPORT_RDD_TEST_MODE +typedef struct _CMD_RDD_CH_T { + UINT_8 ucRddTestMode; + UINT_8 ucRddShutCh; + UINT_8 ucRddStartCh; + UINT_8 ucRddStopCh; + UINT_8 ucRddDfs; + UINT_8 ucReserved; + UINT_8 ucReserved1; + UINT_8 ucReserved2; +} CMD_RDD_CH_T, *P_CMD_RDD_CH_T; + +typedef struct _EVENT_RDD_STATUS_T { + UINT_8 ucRddStatus; + UINT_8 aucReserved[3]; +} EVENT_RDD_STATUS_T, *P_EVENT_RDD_STATUS_T; +#endif + +typedef struct _EVENT_AIS_BSS_INFO_T { + ENUM_PARAM_MEDIA_STATE_T eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ + ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ + BOOLEAN fgIsNetActive; /* TRUE if this network has been actived */ + UINT_8 ucReserved[3]; +} EVENT_AIS_BSS_INFO_T, *P_EVENT_AIS_BSS_INFO_T; + +typedef struct _CMD_SET_TXPWR_CTRL_T { + INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + INT_8 c2GHotspotPwrOffset; + INT_8 c2GP2pPwrOffset; + INT_8 c2GBowPwrOffset; + INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + INT_8 c5GHotspotPwrOffset; + INT_8 c5GP2pPwrOffset; + INT_8 c5GBowPwrOffset; + UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence + in the same channel + 0: Highest power has priority + 1: Lowest power has priority */ + INT_8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ + INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + INT_8 acReserved2[2]; /* Must be zero */ +} CMD_SET_TXPWR_CTRL_T, *P_CMD_SET_TXPWR_CTRL_T; + +#if CFG_SUPPORT_BUILD_DATE_CODE +typedef struct _CMD_GET_BUILD_DATE_CODE { + UINT_8 aucReserved[4]; +} CMD_GET_BUILD_DATE_CODE, *P_CMD_GET_BUILD_DATE_CODE; + +typedef struct _EVENT_BUILD_DATE_CODE { + UINT_8 aucDateCode[16]; +} EVENT_BUILD_DATE_CODE, *P_EVENT_BUILD_DATE_CODE; +#endif + +typedef struct _CMD_GET_STA_STATISTICS_T { + UINT_8 ucIndex; + UINT_8 ucFlags; + UINT_8 ucReadClear; + UINT_8 aucReserved0[1]; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + UINT_8 aucReserved1[2]; + UINT_8 aucReserved2[16]; +} CMD_GET_STA_STATISTICS_T, *P_CMD_GET_STA_STATISTICS_T; + +/* CFG_SUPPORT_WFD */ +typedef struct _EVENT_STA_STATISTICS_T { + /* Event header */ + /* UINT_16 u2Length; */ + /* UINT_16 u2Reserved1; *//* Must be filled with 0x0001 (EVENT Packet) */ + /* UINT_8 ucEID; */ + /* UINT_8 ucSeqNum; */ + /* UINT_8 aucReserved2[2]; */ + + /* Event Body */ + UINT_8 ucVersion; + UINT_8 aucReserved1[3]; + UINT_32 u4Flags; /* Bit0: valid */ + + UINT_8 ucStaRecIdx; + UINT_8 ucNetworkTypeIndex; + UINT_8 ucWTEntry; + UINT_8 aucReserved4[1]; + + UINT_8 ucMacAddr[MAC_ADDR_LEN]; + UINT_8 ucPer; /* base: 128 */ + UINT_8 ucRcpi; + + UINT_32 u4PhyMode; /* SGI BW */ + UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ + UINT_8 ucLinkQuality; + UINT_8 ucLinkReserved; + + UINT_32 u4TxCount; + UINT_32 u4TxFailCount; + UINT_32 u4TxLifeTimeoutCount; + UINT_32 u4TxDoneAirTime; + + UINT_8 aucReserved[64]; +} EVENT_STA_STATISTICS_T, *P_EVENT_STA_STATISTICS_T; + +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION +typedef struct _CMD_HOTSPOT_OPTIMIZATION_CONFIG { + UINT_32 fgHotspotOptimizationEn; + UINT_32 u4Level; +} CMD_HOTSPOT_OPTIMIZATION_CONFIG, *P_HOTSPOT_OPTIMIZATION_CONFIG; +#endif +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + +/* 4 Auto Channel Selection */ + +typedef struct _CMD_GET_CHN_LOAD_T { + UINT_8 ucIndex; + UINT_8 ucFlags; + UINT_8 ucReadClear; + UINT_8 aucReserved0[1]; + + UINT_8 ucChannel; + UINT_16 u2ChannelLoad; + UINT_8 aucReserved1[1]; + UINT_8 aucReserved2[16]; +} CMD_GET_CHN_LOAD_T, *P_CMD_GET_CHN_LOAD_T; +/* 4 Auto Channel Selection */ + +typedef struct _EVENT_CHN_LOAD_T { + /* Event Body */ + UINT_8 ucVersion; + UINT_8 aucReserved1[3]; + UINT_32 u4Flags; /* Bit0: valid */ + + UINT_8 ucChannel; + UINT_16 u2ChannelLoad; + UINT_8 aucReserved4[1]; + + UINT_8 aucReserved[64]; + +} EVENT_CHN_LOAD_T, *P_EVENT_CHN_LOAD_T; +typedef struct _CMD_GET_LTE_SAFE_CHN_T { + UINT_8 ucIndex; + UINT_8 ucFlags; + UINT_8 aucReserved0[2]; + + UINT_8 aucReserved2[16]; +} CMD_GET_LTE_SAFE_CHN_T, *P_CMD_GET_LTE_SAFE_CHN_T; + +typedef struct _EVENT_LTE_MODE_T { + /* Event Body */ + UINT_8 ucVersion; + UINT_8 aucReserved1[3]; + UINT_32 u4Flags; /* Bit0: valid */ + + LTE_SAFE_CH_INFO_T rLteSafeChn; + UINT_8 aucReserved4[3]; + + UINT_8 aucReserved[4]; + +} EVENT_LTE_MODE_T, *P_EVENT_LTE_MODE_T; +#endif +typedef struct _CMD_ROAMING_INFO_T { + UINT_32 fgIsFastRoamingApplied; + UINT_32 Reserved[9]; +} CMD_ROAMING_INFO_T; + +typedef struct _CMD_WFD_DEBUG_MODE_INFO_T { + UINT_8 ucDebugMode; + UINT_16 u2PeriodInteval; + UINT_8 Reserved; +} CMD_WFD_DEBUG_MODE_INFO_T, *P_CMD_WFD_DEBUG_MODE_INFO_T; + +typedef struct _EVENT_FW_LOG_T { + UINT_8 fileName[64]; + UINT_32 lineNo; + UINT_32 WifiUpTime; + UINT_8 log[896]; /* total size is aucBuffer in WIFI_EVENT_T */ +} EVENT_FW_LOG_T, *P_EVENT_FW_LOG_T; + +typedef enum _ENUM_NLO_CIPHER_ALGORITHM { + NLO_CIPHER_ALGO_NONE = 0x00, + NLO_CIPHER_ALGO_WEP40 = 0x01, + NLO_CIPHER_ALGO_TKIP = 0x02, + NLO_CIPHER_ALGO_CCMP = 0x04, + NLO_CIPHER_ALGO_WEP104 = 0x05, + NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, + NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + NLO_CIPHER_ALGO_WEP = 0x101, +} ENUM_NLO_CIPHER_ALGORITHM, *P_ENUM_NLO_CIPHER_ALGORITHM; + +typedef enum _ENUM_NLO_AUTH_ALGORITHM { + NLO_AUTH_ALGO_80211_OPEN = 1, + NLO_AUTH_ALGO_80211_SHARED_KEY = 2, + NLO_AUTH_ALGO_WPA = 3, + NLO_AUTH_ALGO_WPA_PSK = 4, + NLO_AUTH_ALGO_WPA_NONE = 5, + NLO_AUTH_ALGO_RSNA = 6, + NLO_AUTH_ALGO_RSNA_PSK = 7, +} ENUM_NLO_AUTH_ALGORITHM, *P_ENUM_NLO_AUTH_ALGORITHM; + +typedef struct _NLO_NETWORK { + UINT_8 ucNumChannelHint[4]; + UINT_8 ucSSIDLength; + UINT_8 ucCipherAlgo; + UINT_16 u2AuthAlgo; + UINT_8 aucSSID[32]; +} NLO_NETWORK, *P_NLO_NETWORK; + +typedef struct _CMD_NLO_REQ { + UINT_8 ucSeqNum; + UINT_8 ucBssIndex; + UINT_8 ucNetworkType; + UINT_8 fgStopAfterIndication; + UINT_8 ucFastScanIteration; + UINT_16 u2FastScanPeriod; + UINT_16 u2SlowScanPeriod; + UINT_8 ucEntryNum; + UINT_8 ucReserved; + UINT_16 u2IELen; + NLO_NETWORK arNetworkList[16]; + UINT_8 aucIE[0]; + UINT_8 ucScanType; +} CMD_NLO_REQ, *P_CMD_NLO_REQ; + +typedef struct _CMD_NLO_CANCEL_T { + UINT_8 ucSeqNum; + UINT_8 aucReserved[3]; +} CMD_NLO_CANCEL, *P_CMD_NLO_CANCEL; + +typedef struct _EVENT_NLO_DONE_T { + UINT_8 ucSeqNum; + UINT_8 ucStatus; + UINT_8 aucReserved[2]; +} EVENT_NLO_DONE_T, *P_EVENT_NLO_DONE_T; + +typedef struct _EVENT_GSCAN_CAPABILITY_T { + UINT_8 ucVersion; + UINT_8 aucReserved1[3]; + UINT_32 u4MaxScanCacheSize; + UINT_32 u4MaxScanBuckets; + UINT_32 u4MaxApCachePerScan; + UINT_32 u4MaxRssiSampleSize; + UINT_32 u4MaxScanReportingThreshold; + UINT_32 u4MaxHotlistAps; + UINT_32 u4MaxSignificantWifiChangeAps; + UINT_32 au4Reserved[4]; +} EVENT_GSCAN_CAPABILITY_T, *P_EVENT_GSCAN_CAPABILITY_T; + +typedef struct _EVENT_GSCAN_SCAN_AVAILABLE_T { + UINT_16 u2Num; + UINT_8 aucReserved[2]; +} EVENT_GSCAN_SCAN_AVAILABLE_T, *P_EVENT_GSCAN_SCAN_AVAILABLE_T; + +typedef struct _EVENT_GSCAN_SCAN_COMPLETE_T { + UINT_8 ucScanState; + UINT_8 aucReserved[3]; +} EVENT_GSCAN_SCAN_COMPLETE_T, *P_EVENT_GSCAN_SCAN_COMPLETE_T; + +typedef struct WIFI_GSCAN_RESULT { + UINT_64 u8Ts; /* Time of discovery */ + UINT_8 arSsid[ELEM_MAX_LEN_SSID + 1]; /* null terminated */ + UINT_8 arMacAddr[6]; /* BSSID */ + UINT_32 u4Channel; /* channel frequency in MHz */ + INT_32 i4Rssi; /* in db */ + UINT_64 u8Rtt; /* in nanoseconds */ + UINT_64 u8RttSd; /* standard deviation in rtt */ + UINT_16 u2BeaconPeriod; /* units are Kusec */ + UINT_16 u2Capability; /* Capability information */ + UINT_32 u4IeLength; /* byte length of Information Elements */ + UINT_8 ucIeData[1]; /* IE data to follow */ +} WIFI_GSCAN_RESULT_T, *P_WIFI_GSCAN_RESULT_T; + +typedef struct _EVENT_GSCAN_RESULT_T { + UINT_8 ucVersion; + UINT_8 aucReserved[3]; + UINT_16 u2ScanId; + UINT_16 u2ScanFlags; + UINT_16 u2NumOfResults; + WIFI_GSCAN_RESULT_T rResult[1]; +} EVENT_GSCAN_RESULT_T, *P_EVENT_GSCAN_RESULT_T; + +typedef struct _EVENT_GSCAN_FULL_RESULT_T { + UINT_8 ucVersion; + UINT_8 aucReserved[3]; + WIFI_GSCAN_RESULT_T rResult; +} EVENT_GSCAN_FULL_RESULT_T, *P_EVENT_GSCAN_FULL_RESULT_T; + +typedef struct GSCAN_SWC_NET { + UINT_16 u2Flags; + UINT_16 u2Channel; + UINT_8 arBssid[6]; + INT_8 aicRssi[SCN_PSCAN_SWC_RSSI_WIN_MAX]; +} GSCAN_SWC_NET_T, P_GSCAN_SWC_NET_T; + +typedef struct _EVENT_GSCAN_SIGNIFICANT_CHANGE_T { + UINT_8 ucVersion; + UINT_8 aucReserved[3]; + GSCAN_SWC_NET_T arNet[SCN_PSCAN_SWC_MAX_NUM]; +} EVENT_GSCAN_SIGNIFICANT_CHANGE_T, *P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T; + +typedef struct _EVENT_GSCAN_GEOFENCE_FOUND_T { + UINT_8 ucVersion; + UINT_8 aucReserved[3]; + WIFI_GSCAN_RESULT_T rResult[SCN_PSCAN_HOTLIST_REPORT_MAX_NUM]; +} EVENT_GSCAN_GEOFENCE_FOUND_T, *P_EVENT_GSCAN_GEOFENCE_FOUND_T; + +#if CFG_SUPPORT_BATCH_SCAN + +#if 0 /* !CFG_SUPPORT_GSCN */ +typedef struct _CMD_BATCH_REQ_T { + UINT_8 ucSeqNum; + UINT_8 ucNetTypeIndex; + UINT_8 ucCmd; /* Start/ Stop */ + UINT_8 ucMScan; /* an integer number of scans per batch */ + UINT_8 ucBestn; /* an integer number of the max AP to remember per scan */ + UINT_8 ucRtt; /* an integer number of highest-strength AP for which + we'd like approximate distance reported */ + UINT_8 ucChannel; /* channels */ + UINT_8 ucChannelType; + UINT_8 ucChannelListNum; + UINT_8 aucReserved[3]; + UINT_32 u4Scanfreq; /* an integer number of seconds between scans */ + CHANNEL_INFO_T arChannelList[32]; /* channels */ +} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; + +#endif + +typedef struct _EVENT_BATCH_RESULT_ENTRY_T { + UINT_8 aucBssid[MAC_ADDR_LEN]; + UINT_8 aucSSID[ELEM_MAX_LEN_SSID]; + UINT_8 ucSSIDLen; + INT_8 cRssi; + UINT_32 ucFreq; + UINT_32 u4Age; + UINT_32 u4Dist; + UINT_32 u4Distsd; +} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; + +typedef struct _EVENT_BATCH_RESULT_T { + UINT_8 ucScanCount; + UINT_8 aucReserved[3]; + EVENT_BATCH_RESULT_ENTRY_T arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ +} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; +#endif + +typedef struct _CMD_RLM_INFO_T { + UINT_32 u4Version; + UINT_32 fgIsErrRatioEnhanceApplied; + UINT_8 ucErrRatio2LimitMinRate; + /* + 0:1M, 1:2M, 2:5.5M, 3:11M, 6:6M, 7:9M, 8:12M, 9:18M, 10:24M, 11:36M, 12:48M, 13:54M + */ + UINT_8 ucMinLegacyRateIdx; + INT_8 cMinRssiThreshold; + BOOLEAN fgIsRtsApplied; + UINT_8 ucRecoverTime; + + UINT_32 u4Reserved[0]; +} CMD_RLM_INFO_T; + +typedef struct _WIFI_SYSTEM_SUSPEND_CMD_T { + BOOLEAN fgIsSystemSuspend; + UINT_8 reserved[3]; +} WIFI_SYSTEM_SUSPEND_CMD_T, *P_WIFI_SYSTEM_SUSPEND_CMD_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +/* Statistics responder */ +VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +/* for timeout check */ +VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +#if CFG_SUPPORT_BUILD_DATE_CODE +VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); +#endif + +VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +/* 4 Auto Channel Selection */ +VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); +#endif + +#if CFG_SUPPORT_BATCH_SCAN +VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); +#endif + +VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_CMD_EVENT_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h new file mode 100644 index 0000000000000..994c589190dee --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/nic_init_cmd_event.h @@ -0,0 +1,177 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/nic_init_cmd_event.h#1 +*/ + +/*! \file "nic_init_cmd_event.h" + \brief This file contains the declairation file of the WLAN initialization routines + for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: nic_init_cmd_event.h + * + * 09 26 2011 cp.wu + * [WCXRP00001011] [MT6628 Wi-Fi] Firmware Download Agent: make CRC validation as an optional feature + * add definition for disabling CRC32 validation (for MT6628 only) + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 03 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add command/event definitions for initial states + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * +*/ +#ifndef _NIC_INIT_CMD_EVENT_H +#define _NIC_INIT_CMD_EVENT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define INIT_CMD_STATUS_SUCCESS 0 +#define INIT_CMD_STATUS_REJECTED_INVALID_PARAMS 1 +#define INIT_CMD_STATUS_REJECTED_CRC_ERROR 2 +#define INIT_CMD_STATUS_REJECTED_DECRYPT_FAIL 3 +#define INIT_CMD_STATUS_UNKNOWN 4 + +#define EVENT_HDR_SIZE OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) + +typedef enum _ENUM_INIT_CMD_ID { + INIT_CMD_ID_DOWNLOAD_BUF = 1, + INIT_CMD_ID_WIFI_START, + INIT_CMD_ID_ACCESS_REG, + INIT_CMD_ID_QUERY_PENDING_ERROR +} ENUM_INIT_CMD_ID, *P_ENUM_INIT_CMD_ID; + +typedef enum _ENUM_INIT_EVENT_ID { + INIT_EVENT_ID_CMD_RESULT = 1, + INIT_EVENT_ID_ACCESS_REG, + INIT_EVENT_ID_PENDING_ERROR +} ENUM_INIT_EVENT_ID, *P_ENUM_INIT_EVENT_ID; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef UINT_8 CMD_STATUS; + +/* commands */ +typedef struct _INIT_WIFI_CMD_T { + UINT_8 ucCID; + UINT_8 ucSeqNum; + UINT_16 u2Reserved; + UINT_8 aucBuffer[0]; +} INIT_WIFI_CMD_T, *P_INIT_WIFI_CMD_T; + +typedef struct _INIT_HIF_TX_HEADER_T { + UINT_16 u2TxByteCount; + UINT_8 ucEtherTypeOffset; + UINT_8 ucCSflags; + INIT_WIFI_CMD_T rInitWifiCmd; +} INIT_HIF_TX_HEADER_T, *P_INIT_HIF_TX_HEADER_T; + +#define DOWNLOAD_BUF_ENCRYPTION_MODE BIT(0) +#define DOWNLOAD_BUF_NO_CRC_CHECKING BIT(30) +#define DOWNLOAD_BUF_ACK_OPTION BIT(31) +typedef struct _INIT_CMD_DOWNLOAD_BUF { + UINT_32 u4Address; + UINT_32 u4Length; + UINT_32 u4CRC32; + UINT_32 u4DataMode; + UINT_8 aucBuffer[0]; +} INIT_CMD_DOWNLOAD_BUF, *P_INIT_CMD_DOWNLOAD_BUF; + +typedef struct _INIT_CMD_WIFI_START { + UINT_32 u4Override; + UINT_32 u4Address; +} INIT_CMD_WIFI_START, *P_INIT_CMD_WIFI_START; + +typedef struct _INIT_CMD_ACCESS_REG { + UINT_8 ucSetQuery; + UINT_8 aucReserved[3]; + UINT_32 u4Address; + UINT_32 u4Data; +} INIT_CMD_ACCESS_REG, *P_INIT_CMD_ACCESS_REG; + +/* Events */ +typedef struct _INIT_WIFI_EVENT_T { + UINT_16 u2RxByteCount; + UINT_8 ucEID; + UINT_8 ucSeqNum; + UINT_8 aucBuffer[0]; +} INIT_WIFI_EVENT_T, *P_INIT_WIFI_EVENT_T; + +typedef struct _INIT_HIF_RX_HEADER_T { + INIT_WIFI_EVENT_T rInitWifiEvent; +} INIT_HIF_RX_HEADER_T, *P_INIT_HIF_RX_HEADER_T; + +typedef struct _INIT_EVENT_CMD_RESULT { + UINT_8 ucStatus; /* 0: success */ + /* 1: rejected by invalid param */ + /* 2: rejected by incorrect CRC */ + /* 3: rejected by decryption failure */ + /* 4: unknown CMD */ + UINT_8 aucReserved[3]; +} INIT_EVENT_CMD_RESULT, *P_INIT_EVENT_CMD_RESULT, INIT_EVENT_PENDING_ERROR, *P_INIT_EVENT_PENDING_ERROR; + +typedef struct _INIT_EVENT_ACCESS_REG { + UINT_32 u4Address; + UINT_32 u4Data; +} INIT_EVENT_ACCESS_REG, *P_INIT_EVENT_ACCESS_REG; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _NIC_INIT_CMD_EVENT_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h new file mode 100644 index 0000000000000..85af819f4e624 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_precomp.h @@ -0,0 +1,201 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/p2p_precomp.h#1 +*/ + +/*! \file p2p_precomp.h + \brief Collection of most compiler flags for p2p driver are described here. + + In this file we collect all compiler flags and detail the p2p driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +#ifndef _P2P_PRECOMP_H +#define _P2P_PRECOMP_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" /* Include "config.h" */ + +#include "gl_p2p_os.h" + +#include "debug.h" + +#include "link.h" +#include "queue.h" + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#include "roaming_fsm.h" + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "que_mgt.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#include "p2p_cmd_buf.h" +#include "p2p_nic_cmd_event.h" +#include "p2p_mac.h" +#include "p2p_nic.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" +#include "bss.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_bow.h" + +#include "wlan_p2p.h" + +#include "hal.h" + +#if defined(MT6620) +#include "mt6620_reg.h" +#endif + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#if CFG_ENABLE_BT_OVER_WIFI +#include "bow.h" +#include "bow_fsm.h" +#endif + +#include "pwr_mgt.h" + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + +#include "p2p_rlm_obss.h" +#include "p2p_bss.h" +#include "p2p.h" +/* Dependency: cnm_timer.h (TIMER_T) */ +#include "p2p_fsm.h" +#include "p2p_scan.h" +#include "p2p_state.h" +#include "p2p_func.h" +#include "p2p_rlm.h" +#include "p2p_assoc.h" +#include "p2p_ie.h" + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + +#include "ais_fsm.h" + +#include "adapter.h" + +#include "que_mgt.h" +#include "rftest.h" + +#if CFG_RSN_MIGRATION +#include "rsn.h" +#include "sec_fsm.h" +#endif + +#if CFG_SUPPORT_WAPI +#include "wapi.h" +#endif + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +#include "gl_p2p_kal.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /*_P2P_PRECOMP_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h new file mode 100644 index 0000000000000..a02d391d36430 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/p2p_typedef.h @@ -0,0 +1,165 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/p2p_typedef.h#1 +*/ + +/*! \file p2p_typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to all MGMT Protocol Stack. +*/ + +#ifndef _P2P_TYPEDEF_H +#define _P2P_TYPEDEF_H + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* +* type definition of pointer to p2p structure +*/ +/* typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; */ +typedef struct _P2P_INFO_T P2P_INFO_T, *P_P2P_INFO_T; + +typedef struct _P2P_FSM_INFO_T P2P_FSM_INFO_T, *P_P2P_FSM_INFO_T; + +typedef struct _P2P_CONNECTION_SETTINGS_T P2P_CONNECTION_SETTINGS_T, *P_P2P_CONNECTION_SETTINGS_T; + +/* Type definition for function pointer to p2p function*/ +typedef BOOLEAN(*P2P_LAUNCH) (P_GLUE_INFO_T prGlueInfo); + +typedef BOOLEAN(*P2P_REMOVE) (P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsWlanLaunched); + +typedef BOOLEAN(*KAL_P2P_GET_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); + +typedef BOOLEAN(*KAL_P2P_GET_TKIP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); + +typedef BOOLEAN(*KAL_P2P_GET_CCMP_CIPHER) (IN P_GLUE_INFO_T prGlueInfo); + +typedef BOOLEAN(*KAL_P2P_GET_WSC_MODE) (IN P_GLUE_INFO_T prGlueInfo); + +typedef struct net_device *(*KAL_P2P_GET_DEV_HDLR) (P_GLUE_INFO_T prGlueInfo); + +typedef VOID(*KAL_P2P_SET_MULTICAST_WORK_ITEM) (P_GLUE_INFO_T prGlueInfo); + +typedef VOID(*P2P_NET_REGISTER) (P_GLUE_INFO_T prGlueInfo); + +typedef VOID(*P2P_NET_UNREGISTER) (P_GLUE_INFO_T prGlueInfo); + +typedef VOID(*KAL_P2P_UPDATE_ASSOC_INFO) (IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, + IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); + +typedef BOOLEAN(*P2P_VALIDATE_AUTH) (IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); + +typedef BOOLEAN(*P2P_VALIDATE_ASSOC_REQ) (IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu4ControlFlags); + +typedef VOID(*P2P_RUN_EVENT_AAA_TX_FAIL) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +typedef BOOLEAN(*P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM) (IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType); + +typedef WLAN_STATUS(*P2P_RUN_EVENT_AAA_COMPLETE) (IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +typedef VOID(*P2P_PROCESS_EVENT_UPDATE_NOA_PARAM) (IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam); + +typedef VOID(*SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP) (IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); + +typedef VOID(*P2P_RX_PUBLIC_ACTION_FRAME) (P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +typedef VOID(*RLM_RSP_GENERATE_OBSS_SCAN_IE) (P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +typedef VOID(*RLM_UPDATE_BW_BY_CH_LIST_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +typedef VOID(*RLM_PROCESS_PUBLIC_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +typedef VOID(*RLM_PROCESS_HT_ACTION) (P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +typedef VOID(*RLM_UPDATE_PARAMS_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon); + +typedef VOID(*RLM_HANDLE_OBSS_STATUS_EVENT_PKT) (P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus); + +typedef BOOLEAN(*P2P_FUNC_VALIDATE_PROBE_REQ) (IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); + +typedef VOID(*RLM_BSS_INIT_FOR_AP) (P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +typedef UINT_32(*P2P_GET_PROB_RSP_IE_TABLE_SIZE) (VOID); + +typedef PUINT_8(*P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES) (IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer); + +typedef VOID(*P2P_FUNC_DISCONNECT) (IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode); + +typedef VOID(*P2P_FSM_RUN_EVENT_RX_DEAUTH) (IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); + +typedef VOID(*P2P_FSM_RUN_EVENT_RX_DISASSOC) (IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); + +typedef BOOLEAN(*P2P_FUN_IS_AP_MODE) (IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +typedef VOID(*P2P_FSM_RUN_EVENT_BEACON_TIMEOUT) (IN P_ADAPTER_T prAdapter); + +typedef VOID(*P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER) (IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +typedef VOID(*P2P_GENERATE_P2P_IE) (IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +typedef UINT_32(*P2P_CALCULATE_P2P_IE_LEN) (IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /*CFG_ENABLE_WIFI_DIRECT */ + +#endif /* _P2P_TYPEDEF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h new file mode 100644 index 0000000000000..1b7e7ede66e1a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/precomp.h @@ -0,0 +1,388 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/precomp.h#2 +*/ + +/*! \file precomp.h + \brief Collection of most compiler flags are described here. + + In this file we collect all compiler flags and detail the driver behavior if + enable/disable such switch or adjust numeric parameters. +*/ + +/* +** Log: precomp.h + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628-specific definitions. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Isolate P2P related function for Hardware Software Bundle + * + * 09 14 2010 chinghwa.yu + * NULL + * Fix BOW_FSM_INFO_T dependence. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 28 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * 1st draft code for RLM module + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge cnm_scan.h and hem_mbox.h + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 03 16 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * build up basic data structure and definitions to support BT-over-WiFi + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 11:30:58 GMT mtk02752 +** add rftest.h for implementing RF test mode in driver land +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-11-23 22:02:00 GMT mtk02468 +** Added que_mgt.h +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-10-13 21:58:36 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-21 09:40:11 GMT mtk01461 +** Add nic_cmd_event.h +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-17 20:00:26 GMT mtk01461 +** Add cmd_buf.h +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-19 18:32:44 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:25 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:38 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _PRECOMP_H +#define _PRECOMP_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" /* Include "config.h" */ + +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_os.h" +#endif + +#include "debug.h" + +#include "link.h" +#include "queue.h" + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#if CFG_SUPPORT_SWCR +#include "swcr.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "que_mgt.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#include "p2p_cmd_buf.h" +#include "p2p_nic_cmd_event.h" +#include "p2p_mac.h" +#include "p2p_nic.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" +#include "bss.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_bow.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "wlan_p2p.h" +#endif + +#include "hal.h" + +#if defined(MT6620) +#include "mt6620_reg.h" +#elif defined(MT6628) +/* #include "mt6628_reg.h" */ +#include "mtreg.h" +#endif + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" +#if CFG_SUPPORT_802_11V +#include "wnm.h" +#endif + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#if CFG_ENABLE_BT_OVER_WIFI +#include "bow.h" +#include "bow_fsm.h" +#endif + +#include "pwr_mgt.h" + +#if (CFG_SUPPORT_STATISTICS == 1) +#include "stats.h" +#endif /* CFG_SUPPORT_STATISTICS */ + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_rlm_obss.h" +#include "p2p_bss.h" +#include "p2p.h" +#include "p2p_fsm.h" +#include "p2p_scan.h" +#include "p2p_state.h" +#include "p2p_func.h" +#include "p2p_rlm.h" +#include "p2p_assoc.h" +#include "p2p_ie.h" +#endif + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + +#if CFG_SUPPORT_ROAMING +#include "roaming_fsm.h" +#endif /* CFG_SUPPORT_ROAMING */ + +#include "ais_fsm.h" + +#include "adapter.h" + +#include "que_mgt.h" +#include "rftest.h" + +#if CFG_RSN_MIGRATION +#include "rsn.h" +#include "sec_fsm.h" +#endif + +#if CFG_SUPPORT_WAPI +#include "wapi.h" +#endif + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_kal.h" +#endif + +typedef int (*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); +typedef void (*set_dbg_level) (unsigned char modules[DBG_MODULE_NUM]); + +extern void wlanRegisterNotifier(void); +extern void wlanUnregisterNotifier(void); +extern void register_set_p2p_mode_handler(set_p2p_mode handler); +extern void register_set_dbg_level_handler(set_dbg_level handler); + +#if CFG_TC1_FEATURE +#define NIC_INF_NAME_IN_AP_MODE "legacy%d" +extern volatile int wlan_if_changed; +#endif +extern BOOLEAN fgIsResetting; + +extern UINT_8 g_aucBufIpAddr[32]; +extern UINT_8 aucDebugModule[]; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PRECOMP_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h new file mode 100644 index 0000000000000..40f52dcc9d681 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/pwr_mgt.h @@ -0,0 +1,141 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/pwr_mgt.h#1 +*/ + +/*! \file "pwr_mgt.h" + \brief In this file we define the STATE and EVENT for Power Management FSM. + + The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter + ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail + description. +*/ + +/* +** Log: pwr_mgt.h + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL + * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. + + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * firmware download load address & start address are now configured from config.h + * * * due to the different configurations on FPGA and ASIC +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-10 16:39:10 GMT mtk02752 +** disable PM macros temporally +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-29 19:48:37 GMT mtk01084 +** temp remove power management macro +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-08 16:51:11 GMT mtk01084 +** update for power management control macro +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-04-03 14:59:58 GMT mtk01426 +** Add #if CFG_HIF_LOOPBACK_PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:53:10 GMT mtk01084 +** modify ACQUIRE_POWER_CONTROL_FROM_PM() and RECLAIM_POWER_CONTROL_TO_PM() macro +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:32:47 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:20 GMT mtk01084 +** Initial version +** +*/ + +#ifndef _PWR_MGT_H +#define _PWR_MGT_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define PM_UAPSD_AC0 (BIT(0)) +#define PM_UAPSD_AC1 (BIT(1)) +#define PM_UAPSD_AC2 (BIT(2)) +#define PM_UAPSD_AC3 (BIT(3)) + +#define PM_UAPSD_ALL (PM_UAPSD_AC0 | PM_UAPSD_AC1 | PM_UAPSD_AC2 | PM_UAPSD_AC3) +#define PM_UAPSD_NONE 0 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _PM_PROFILE_SETUP_INFO_T { + /* Profile setup */ + UINT_8 ucBmpDeliveryAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + UINT_8 ucBmpTriggerAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + + UINT_8 ucUapsdSp; /* Number of triggered packets in UAPSD */ + +} PM_PROFILE_SETUP_INFO_T, *P_PM_PROFILE_SETUP_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if !CFG_ENABLE_FULL_PM +#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) +#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) +#else +#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) \ + { \ + if (_prAdapter->fgIsFwOwn) { \ + nicpmSetDriverOwn(_prAdapter); \ + } \ + /* Increase Block to Enter Low Power Semaphore count */ \ + GLUE_INC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ + } + +#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) \ + { \ + ASSERT(_prAdapter->u4PwrCtrlBlockCnt != 0); \ + /* Decrease Block to Enter Low Power Semaphore count */ \ + GLUE_DEC_REF_CNT(_prAdapter->u4PwrCtrlBlockCnt); \ + if (_prAdapter->fgWiFiInSleepyState && (_prAdapter->u4PwrCtrlBlockCnt == 0)) { \ + nicpmSetFWOwn(_prAdapter, _fgEnableGINT_in_IST); \ + } \ + } +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PWR_MGT_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h new file mode 100644 index 0000000000000..a9e74b58a8c97 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/queue.h @@ -0,0 +1,195 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/queue.h#1 +*/ + +/*! \file queue.h + \brief Definition for singly queue operations. + + In this file we define the singly queue data structure and its + queue operation MACROs. +*/ + +/* +** Log: queue.h + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:46 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Singly Queue Structures - Entry Part */ +typedef struct _QUE_ENTRY_T { + struct _QUE_ENTRY_T *prNext; + struct _QUE_ENTRY_T *prPrev; /* For Rx buffer reordering used only */ +} QUE_ENTRY_T, *P_QUE_ENTRY_T; + +/* Singly Queue Structures - Queue Part */ +typedef struct _QUE_T { + P_QUE_ENTRY_T prHead; + P_QUE_ENTRY_T prTail; + UINT_32 u4NumElem; +} QUE_T, *P_QUE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/* + * To resolve compiler warning of address check -Waddress + * Redefine a ASSERT dedicate for queue operation + */ +#if DBG +#define QUE_ASSERT ASSERT +#else +#define QUE_ASSERT(_exp) +#endif + +#define QUEUE_INITIALIZE(prQueue) \ + { \ + (prQueue)->prHead = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->u4NumElem = 0; \ + } + +#define QUEUE_IS_EMPTY(prQueue) (((P_QUE_T)(prQueue))->prHead == (P_QUE_ENTRY_T)NULL) + +#define QUEUE_IS_NOT_EMPTY(prQueue) ((prQueue)->u4NumElem > 0) + +#define QUEUE_GET_HEAD(prQueue) ((prQueue)->prHead) + +#define QUEUE_GET_TAIL(prQueue) ((prQueue)->prTail) + +#define QUEUE_GET_NEXT_ENTRY(prQueueEntry) ((prQueueEntry)->prNext) + +#define QUEUE_INSERT_HEAD(prQueue, prQueueEntry) \ + { \ + QUE_ASSERT(prQueue); \ + QUE_ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (prQueue)->prHead; \ + (prQueue)->prHead = (prQueueEntry); \ + if ((prQueue)->prTail == (P_QUE_ENTRY_T)NULL) { \ + (prQueue)->prTail = (prQueueEntry); \ + } \ + ((prQueue)->u4NumElem)++; \ + } + +#define QUEUE_INSERT_TAIL(prQueue, prQueueEntry) \ + { \ + QUE_ASSERT(prQueue); \ + QUE_ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (P_QUE_ENTRY_T)NULL; \ + if ((prQueue)->prTail) { \ + ((prQueue)->prTail)->prNext = (prQueueEntry); \ + } else { \ + (prQueue)->prHead = (prQueueEntry); \ + } \ + (prQueue)->prTail = (prQueueEntry); \ + ((prQueue)->u4NumElem)++; \ + } + +/* NOTE: We assume the queue entry located at the beginning of "prQueueEntry Type", + * so that we can cast the queue entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define QUEUE_REMOVE_HEAD(prQueue, prQueueEntry, _P_TYPE) \ + { \ + QUE_ASSERT(prQueue); \ + prQueueEntry = (_P_TYPE)((prQueue)->prHead); \ + if (prQueueEntry) { \ + (prQueue)->prHead = ((P_QUE_ENTRY_T)(prQueueEntry))->prNext; \ + if ((prQueue)->prHead == (P_QUE_ENTRY_T)NULL) { \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + } \ + ((P_QUE_ENTRY_T)(prQueueEntry))->prNext = (P_QUE_ENTRY_T)NULL; \ + ((prQueue)->u4NumElem)--; \ + } \ + } + +#define QUEUE_MOVE_ALL(prDestQueue, prSrcQueue) \ + { \ + QUE_ASSERT(prDestQueue); \ + QUE_ASSERT(prSrcQueue); \ + *(P_QUE_T)prDestQueue = *(P_QUE_T)prSrcQueue; \ + QUEUE_INITIALIZE(prSrcQueue); \ + } + +#define QUEUE_CONCATENATE_QUEUES(prDestQueue, prSrcQueue) \ + { \ + QUE_ASSERT(prDestQueue); \ + QUE_ASSERT(prSrcQueue); \ + if (prSrcQueue->u4NumElem > 0) { \ + if ((prDestQueue)->prTail) { \ + ((prDestQueue)->prTail)->prNext = (prSrcQueue)->prHead; \ + } else { \ + (prDestQueue)->prHead = (prSrcQueue)->prHead; \ + } \ + (prDestQueue)->prTail = (prSrcQueue)->prTail; \ + ((prDestQueue)->u4NumElem) += ((prSrcQueue)->u4NumElem); \ + QUEUE_INITIALIZE(prSrcQueue); \ + } \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _QUEUE_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h new file mode 100644 index 0000000000000..4489e56013025 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/rftest.h @@ -0,0 +1,294 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/rftest.h#1 +*/ + +/*! \file "rftest.h" + \brief definitions for RF Productino test + +*/ + +/* +** Log: rftest.h + * + * 12 20 2011 cp.wu + * [WCXRP00001144] [MT6620 Wi-Fi][Driver][Firmware] Add RF_FUNC_ID for exposing device and related version information + * add driver implementations for RF_AT_FUNCID_FW_INFO & RF_AT_FUNCID_DRV_INFO + * to expose version information + * + * 08 04 2010 cp.wu + * NULL + * add an extra parameter to rftestQueryATInfo 'cause it's necessary to pass u4FuncData for query request. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-12-08 17:35:11 GMT mtk02752 +** * comment out RF test which is not supported on MT6620 +** + API decalre for rftest +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-12-08 11:29:07 GMT mtk02752 +** definitions for RF test mode +** +*/ +#ifndef _RFTEST_H +#define _RFTEST_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Table Version */ +#define RF_AUTO_TEST_FUNCTION_TABLE_VERSION 0x01000001 + +/* Power */ +#define RF_AT_PARAM_POWER_MASK BITS(0, 7) +#define RF_AT_PARAM_POWER_MAX RF_AT_PARAM_POWER_MASK + +/* Rate */ +#define RF_AT_PARAM_RATE_MCS_MASK BIT(31) +#define RF_AT_PARAM_RATE_MASK BITS(0, 7) +#define RF_AT_PARAM_RATE_CCK_MAX 3 +#define RF_AT_PARAM_RATE_1M 0 +#define RF_AT_PARAM_RATE_2M 1 +#define RF_AT_PARAM_RATE_5_5M 2 +#define RF_AT_PARAM_RATE_11M 3 +#define RF_AT_PARAM_RATE_6M 4 +#define RF_AT_PARAM_RATE_9M 5 +#define RF_AT_PARAM_RATE_12M 6 +#define RF_AT_PARAM_RATE_18M 7 +#define RF_AT_PARAM_RATE_24M 8 +#define RF_AT_PARAM_RATE_36M 9 +#define RF_AT_PARAM_RATE_48M 10 +#define RF_AT_PARAM_RATE_54M 11 + +/* Antenna */ +#define RF_AT_PARAM_ANTENNA_ID_MASK BITS(0, 7) +#define RF_AT_PARAM_ANTENNA_ID_MAX 1 + +/* Packet Length */ +#define RF_AT_PARAM_TX_80211HDR_BYTE_MAX (32) +#define RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX (2048) + +#define RF_AT_PARAM_TX_PKTLEN_BYTE_DEFAULT 1024 +#define RF_AT_PARAM_TX_PKTLEN_BYTE_MAX \ + ((UINT_16)(RF_AT_PARAM_TX_80211HDR_BYTE_MAX + RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX)) + +/* Packet Count */ +#define RF_AT_PARAM_TX_PKTCNT_DEFAULT 1000 +#define RF_AT_PARAM_TX_PKTCNT_UNLIMITED 0 + +/* Packet Interval */ +#define RF_AT_PARAM_TX_PKT_INTERVAL_US_DEFAULT 50 + +/* ALC */ +#define RF_AT_PARAM_ALC_DISABLE 0 +#define RF_AT_PARAM_ALC_ENABLE 1 + +/* TXOP */ +#define RF_AT_PARAM_TXOP_DEFAULT 0 +#define RF_AT_PARAM_TXOPQUE_QMASK BITS(16, 31) +#define RF_AT_PARAM_TXOPQUE_TMASK BITS(0, 15) +#define RF_AT_PARAM_TXOPQUE_AC0 (0<<16) +#define RF_AT_PARAM_TXOPQUE_AC1 (1<<16) +#define RF_AT_PARAM_TXOPQUE_AC2 (2<<16) +#define RF_AT_PARAM_TXOPQUE_AC3 (3<<16) +#define RF_AT_PARAM_TXOPQUE_AC4 (4<<16) +#define RF_AT_PARAM_TXOPQUE_QOFFSET 16 + +/* Retry Limit */ +#define RF_AT_PARAM_TX_RETRY_DEFAULT 0 +#define RF_AT_PARAM_TX_RETRY_MAX 6 + +/* QoS Queue */ +#define RF_AT_PARAM_QOSQUE_AC0 0 +#define RF_AT_PARAM_QOSQUE_AC1 1 +#define RF_AT_PARAM_QOSQUE_AC2 2 +#define RF_AT_PARAM_QOSQUE_AC3 3 +#define RF_AT_PARAM_QOSQUE_AC4 4 +#define RF_AT_PARAM_QOSQUE_DEFAULT RF_AT_PARAM_QOSQUE_AC0 + +/* Bandwidth */ +#define RF_AT_PARAM_BANDWIDTH_20MHZ 0 +#define RF_AT_PARAM_BANDWIDTH_40MHZ 1 +#define RF_AT_PARAM_BANDWIDTH_U20_IN_40MHZ 2 +#define RF_AT_PARAM_BANDWIDTH_D20_IN_40MHZ 3 +#define RF_AT_PARAM_BANDWIDTH_DEFAULT RF_AT_PARAM_BANDWIDTH_20MHZ + +/* GI (Guard Interval) */ +#define RF_AT_PARAM_GI_800NS 0 +#define RF_AT_PARAM_GI_400NS 1 +#define RF_AT_PARAM_GI_DEFAULT RF_AT_PARAM_GI_800NS + +/* STBC */ +#define RF_AT_PARAM_STBC_DISABLE 0 +#define RF_AT_PARAM_STBC_ENABLE 1 + +/* RIFS */ +#define RF_AT_PARAM_RIFS_DISABLE 0 +#define RF_AT_PARAM_RIFS_ENABLE 1 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Function ID List */ +typedef enum _ENUM_RF_AT_FUNCID_T { + RF_AT_FUNCID_VERSION = 0, + RF_AT_FUNCID_COMMAND, + RF_AT_FUNCID_POWER, + RF_AT_FUNCID_RATE, + RF_AT_FUNCID_PREAMBLE, + RF_AT_FUNCID_ANTENNA, + RF_AT_FUNCID_PKTLEN, + RF_AT_FUNCID_PKTCNT, + RF_AT_FUNCID_PKTINTERVAL, + RF_AT_FUNCID_TEMP_COMPEN, + RF_AT_FUNCID_TXOPLIMIT, + RF_AT_FUNCID_ACKPOLICY, + RF_AT_FUNCID_PKTCONTENT, + RF_AT_FUNCID_RETRYLIMIT, + RF_AT_FUNCID_QUEUE, + RF_AT_FUNCID_BANDWIDTH, + RF_AT_FUNCID_GI, + RF_AT_FUNCID_STBC, + RF_AT_FUNCID_CHNL_FREQ, + RF_AT_FUNCID_RIFS, + RF_AT_FUNCID_TRSW_TYPE, + RF_AT_FUNCID_RF_SX_SHUTDOWN, + RF_AT_FUNCID_PLL_SHUTDOWN, + RF_AT_FUNCID_SLOW_CLK_MODE, + RF_AT_FUNCID_ADC_CLK_MODE, + RF_AT_FUNCID_MEASURE_MODE, + RF_AT_FUNCID_VOLT_COMPEN, + RF_AT_FUNCID_DPD_TX_GAIN, + RF_AT_FUNCID_DPD_MODE, + RF_AT_FUNCID_TSSI_MODE, + RF_AT_FUNCID_TX_GAIN_CODE, + RF_AT_FUNCID_TX_PWR_MODE, + + /* Query command */ + RF_AT_FUNCID_TXED_COUNT = 32, + RF_AT_FUNCID_TXOK_COUNT, + RF_AT_FUNCID_RXOK_COUNT, + RF_AT_FUNCID_RXERROR_COUNT, + RF_AT_FUNCID_RESULT_INFO, + RF_AT_FUNCID_TRX_IQ_RESULT, + RF_AT_FUNCID_TSSI_RESULT, + RF_AT_FUNCID_DPD_RESULT, + RF_AT_FUNCID_RXV_DUMP, + RF_AT_FUNCID_RX_PHY_STATIS, + RF_AT_FUNCID_MEASURE_RESULT, + RF_AT_FUNCID_TEMP_SENSOR, + RF_AT_FUNCID_VOLT_SENSOR, + RF_AT_FUNCID_READ_EFUSE, + RF_AT_FUNCID_RX_RSSI, + RF_AT_FUNCID_FW_INFO, + RF_AT_FUNCID_DRV_INFO, + + /* Set command */ + RF_AT_FUNCID_SET_DPD_RESULT = 64, + RF_AT_FUNCID_SET_CW_MODE, + RF_AT_FUNCID_SET_JAPAN_CH14_FILTER, + RF_AT_FUNCID_WRITE_EFUSE, + RF_AT_FUNCID_SET_MAC_ADDRESS +} ENUM_RF_AT_FUNCID_T; + +/* Command */ +typedef enum _ENUM_RF_AT_COMMAND_T { + RF_AT_COMMAND_STOPTEST = 0, + RF_AT_COMMAND_STARTTX, + RF_AT_COMMAND_STARTRX, + RF_AT_COMMAND_RESET, + RF_AT_COMMAND_OUTPUT_POWER, /* Payload */ + RF_AT_COMMAND_LO_LEAKAGE, /* Local freq is renamed to Local leakage */ + RF_AT_COMMAND_CARRIER_SUPPR, /* OFDM (LTF/STF), CCK (PI,PI/2) */ + RF_AT_COMMAND_TRX_IQ_CAL, + RF_AT_COMMAND_TSSI_CAL, + RF_AT_COMMAND_DPD_CAL, + RF_AT_COMMAND_CW, + RF_AT_COMMAND_NUM +} ENUM_RF_AT_COMMAND_T; + +/* Preamble */ +typedef enum _ENUM_RF_AT_PREAMBLE_T { + RF_AT_PREAMBLE_NORMAL = 0, + RF_AT_PREAMBLE_CCK_SHORT, + RF_AT_PREAMBLE_11N_MM, + RF_AT_PREAMBLE_11N_GF, + RF_AT_PREAMBLE_NUM +} ENUM_RF_AT_PREAMBLE_T; + +/* Ack Policy */ +typedef enum _ENUM_RF_AT_ACK_POLICY_T { + RF_AT_ACK_POLICY_NORMAL = 0, + RF_AT_ACK_POLICY_NOACK, + RF_AT_ACK_POLICY_NOEXPLICTACK, + RF_AT_ACK_POLICY_BLOCKACK, + RF_AT_ACK_POLICY_NUM +} ENUM_RF_AT_ACK_POLICY_T; + +typedef enum _ENUM_RF_AUTOTEST_STATE_T { + RF_AUTOTEST_STATE_STANDBY = 0, + RF_AUTOTEST_STATE_TX, + RF_AUTOTEST_STATE_RX, + RF_AUTOTEST_STATE_RESET, + RF_AUTOTEST_STATE_OUTPUT_POWER, + RF_AUTOTEST_STATE_LOCA_FREQUENCY, + RF_AUTOTEST_STATE_CARRIER_SUPRRESION, + RF_AUTOTEST_STATE_NUM +} ENUM_RF_AUTOTEST_STATE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, UINT_32 u4FuncIndex, UINT_32 u4FuncData); + +WLAN_STATUS +rftestQueryATInfo(IN P_ADAPTER_T prAdapter, + UINT_32 u4FuncIndex, UINT_32 u4FuncData, OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); + +WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN UINT_32 u4FreqInKHz, IN PUINT_32 pu4SetInfoLen); + +#endif /* _RFTEST_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h new file mode 100644 index 0000000000000..8ee184591fc2f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/tdls_extr.h @@ -0,0 +1,427 @@ +/* +** Id: include/tdls_extr.h#1 +*/ + +/*! \file "tdls_extr.h" + \brief This file contains the external used in other modules + for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: tdls_extr.h + * + * 11 18 2013 vend_samp.lin + * NULL + * Initial version. + * + ** + */ + +#ifndef _TDLS_EXTR_H +#define _TDLS_EXTR_H + +#if (CFG_SUPPORT_TDLS == 1) + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#define TDLS_TX_QUOTA_EMPTY_TIMEOUT 10 + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* protocol */ +#define TDLS_FRM_PROT_TYPE 0x890d + +/* TDLS uses Ethertype 89-0d frames. The UP shall be AC_VI, unless otherwise specified. */ +#define USER_PRIORITY_TDLS 5 + +/* Status code */ +#define TDLS_STATUS WLAN_STATUS + +#define TDLS_STATUS_SUCCESS WLAN_STATUS_SUCCESS +#define TDLS_STATUS_FAILURE WLAN_STATUS_FAILURE +#define TDLS_STATUS_INVALID_LENGTH WLAN_STATUS_INVALID_LENGTH +#define TDLS_STATUS_RESOURCES WLAN_STATUS_RESOURCES + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#define TDLS_U32 UINT32 +#define TDLS_U16 UINT16 +#define TDLS_U8 UINT8 + +typedef enum _TDLS_REASON_CODE { + TDLS_REASON_CODE_UNREACHABLE = 25, + TDLS_REASON_CODE_UNSPECIFIED = 26, + + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN = 0x80, /* 128 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WIFI_OFF = 0x81, /* 129 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING = 0x82, /* 130 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT = 0x83, /* 131 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT = 0x84, /* 132 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY = 0x85, /* 133 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL = 0x86, /* 134 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL = 0x87, /* 135 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX = 0x88, /* 136 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3 = 0x89, /* 137 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY = 0x8a, /* 138 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN = 0x8b /* 139 */ +} TDLS_REASON_CODE; + +/* TDLS FSM */ +typedef struct _TDLS_CMD_PEER_ADD_T { + + TDLS_U8 aucPeerMac[6]; + +#if 0 + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + UINT_16 u2CapInfo; + + UINT_16 u2OperationalRateSet; + UINT_16 u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + + UINT_8 ucPhyTypeSet; +#endif +} TDLS_CMD_PEER_ADD_T; + +typedef struct _TDLS_CMD_LINK_T { + + TDLS_U8 aucPeerMac[6]; + BOOLEAN fgIsEnabled; +} TDLS_CMD_LINK_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T { + TDLS_U8 arRxMask[10]; + TDLS_U16 u2RxHighest; + TDLS_U8 ucTxParams; + TDLS_U8 Reserved[3]; +} TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_T { + TDLS_U16 u2CapInfo; + TDLS_U8 ucAmpduParamsInfo; + + /* 16 bytes MCS information */ + TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T rMCS; + + TDLS_U16 u2ExtHtCapInfo; + TDLS_U32 u4TxBfCapInfo; + TDLS_U8 ucAntennaSelInfo; +} TDLS_CMD_PEER_UPDATE_HT_CAP_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_T { + + TDLS_U8 aucPeerMac[6]; + +#define TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX 50 + TDLS_U8 aucSupChan[TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX]; + + TDLS_U16 u2StatusCode; + +#define TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX 50 + TDLS_U8 aucSupRate[TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX]; + TDLS_U16 u2SupRateLen; + + TDLS_U8 UapsdBitmap; + TDLS_U8 UapsdMaxSp; /* MAX_SP */ + + TDLS_U16 u2Capability; +#define TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN 5 + TDLS_U8 aucExtCap[TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN]; + TDLS_U16 u2ExtCapLen; + + TDLS_CMD_PEER_UPDATE_HT_CAP_T rHtCap; + BOOLEAN fgIsSupHt; + +} TDLS_CMD_PEER_UPDATE_T; + +/* Command to TDLS core module */ +typedef enum _TDLS_CMD_CORE_ID { + TDLS_CORE_CMD_TEST_NULL_RCV = 0x00, + TDLS_CORE_CMD_TEST_PTI_RSP = 0x01, + TDLS_CORE_CMD_MIB_UPDATE = 0x02, + TDLS_CORE_CMD_TEST_TX_FAIL_SKIP = 0x03, + TDLS_CORE_CMD_UAPSD_CONF = 0x04, + TDLS_CORE_CMD_TEST_DATA_RCV = 0x05, + TDLS_CORE_CMD_TEST_PTI_REQ = 0x06, + TDLS_CORE_CMD_TEST_CHSW_REQ = 0x07, + TDLS_CORE_CMD_CHSW_CONF = 0x08, + TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP = 0x09, + TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP = 0x0a, + TDLS_CORE_CMD_TEST_CHSW_RSP = 0x0b, + TDLS_CORE_CMD_TEST_SCAN_SKIP = 0x0c, + TDLS_CORE_CMD_SETUP_CONF = 0x0d, + TDLS_CORE_CMD_TEST_TEAR_DOWN = 0x0e, + TDLS_CORE_CMD_KEY_INFO = 0x0f, + TDLS_CORE_CMD_TEST_PTI_TX_FAIL = 0x10 +} TDLS_CMD_CORE_ID; + +typedef struct _TDLS_CMD_CORE_TEST_NULL_RCV_T { + + TDLS_U32 u4PM; +} TDLS_CMD_CORE_TEST_NULL_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T { + + TDLS_U32 u4DialogToken; +} TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T { + + TDLS_U32 u4DialogToken; + TDLS_U32 u4PM; +} TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T { + + TDLS_U32 u4ReasonCode; +} TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T { + + TDLS_U32 u4Chan; + TDLS_U32 u4RegClass; + TDLS_U32 u4SecChanOff; + TDLS_U32 u4SwitchTime; + TDLS_U32 u4SwitchTimeout; +} TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T { + + TDLS_U32 u4Chan; + TDLS_U32 u4SwitchTime; + TDLS_U32 u4SwitchTimeout; + TDLS_U32 u4StatusCode; +} TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T; + +typedef struct _TDLS_CMD_CORE_TEST_DATA_RCV_T { + + TDLS_U32 u4PM; + TDLS_U32 u4UP; + TDLS_U32 u4EOSP; + TDLS_U32 u4IsNull; +} TDLS_CMD_CORE_TEST_DATA_RCV_T; + +typedef struct _TDLS_CMD_CORE_MIB_PARAM_UPDATE_T { + + BOOLEAN Tdlsdot11TunneledDirectLinkSetupImplemented; + BOOLEAN Tdlsdot11TDLSPeerUAPSDBufferSTAActivated; + BOOLEAN Tdlsdot11TDLSPeerPSMActivated; + TDLS_U16 Tdlsdot11TDLSPeerUAPSDIndicationWindow; + BOOLEAN Tdlsdot11TDLSChannelSwitchingActivated; + TDLS_U8 Tdlsdot11TDLSPeerSTAMissingAckRetryLimit; + TDLS_U8 Tdlsdot11TDLSResponseTimeout; + TDLS_U16 Tdlsdot11TDLSProbeDelay; + TDLS_U8 Tdlsdot11TDLSDiscoveryRequestWindow; + TDLS_U8 Tdlsdot11TDLSACDeterminationInterval; +} TDLS_CMD_CORE_MIB_PARAM_UPDATE_T; + +typedef struct _TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T { + + BOOLEAN fgIsEnable; +} TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T; + +typedef struct _TDLS_CMD_CORE_UAPSD_CONFIG_T { + + BOOLEAN fgIsSpTimeoutSkip; + BOOLEAN fgIsPtiTimeoutSkip; +} TDLS_CMD_CORE_UAPSD_CONFIG_T; + +typedef struct _TDLS_CMD_CORE_SETUP_CONFIG_T { + + BOOLEAN fgIs2040Supported; +} TDLS_CMD_CORE_SETUP_CONFIG_T; + +typedef struct _TDLS_CMD_CORE_CHSW_CONFIG_T { + + TDLS_U8 ucNetTypeIndex; + BOOLEAN fgIsChSwEnabled; + BOOLEAN fgIsChSwStarted; + TDLS_U8 ucRegClass; + TDLS_U8 ucTargetChan; + TDLS_U8 ucSecChanOff; + BOOLEAN fgIsChSwRegular; +} TDLS_CMD_CORE_CHSW_CONFIG_T; + +typedef struct _TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T { + + BOOLEAN fgIsEnable; +} TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T; + +typedef struct _TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T { + + BOOLEAN fgIsEnable; +} TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T; + +typedef struct _TDLS_CMD_CORE_TEST_PROHIBIT_T { + + BOOLEAN fgIsEnable; + BOOLEAN fgIsSet; +} TDLS_CMD_CORE_TEST_PROHIBIT_T; + +typedef struct _TDLS_CMD_CORE_TEST_SCAN_SKIP_T { + + BOOLEAN fgIsEnable; +} TDLS_CMD_CORE_TEST_SCAN_SKIP_T; + +typedef struct _TDLS_CMD_CORE_INFO_DISPLAY_T { + + BOOLEAN fgIsToClearAllHistory; +} TDLS_CMD_CORE_INFO_DISPLAY_T; + +typedef struct _TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T { + + BOOLEAN fgIsEnable; +} TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T; + +typedef struct _TDLS_CMD_CORE_T { + + TDLS_U32 u4Command; /* TDLS_CMD_CORE_ID */ + + TDLS_U8 aucPeerMac[6]; + TDLS_U8 ucNetTypeIndex; + +#define TDLS_CMD_CORE_RESERVED_SIZE 50 + union { + TDLS_CMD_CORE_TEST_NULL_RCV_T rCmdNullRcv; + TDLS_CMD_CORE_TEST_PTI_REQ_RCV_T rCmdPtiReqRcv; + TDLS_CMD_CORE_TEST_PTI_RSP_RCV_T rCmdPtiRspRcv; + TDLS_CMD_CORE_TEST_TEAR_DOWN_RCV_T rCmdTearDownRcv; + TDLS_CMD_CORE_TEST_CHST_REQ_RCV_T rCmdChStReqRcv; + TDLS_CMD_CORE_TEST_CHST_RSP_RCV_T rCmdChStRspRcv; + TDLS_CMD_CORE_TEST_DATA_RCV_T rCmdDatRcv; + TDLS_CMD_CORE_TEST_TX_FAIL_SKIP_T rCmdTxFailSkip; + TDLS_CMD_CORE_TEST_KEEP_ALIVE_SKIP_T rCmdKeepAliveSkip; + TDLS_CMD_CORE_TEST_CHSW_TIMEOUT_SKIP_T rCmdChSwTimeoutSkip; + TDLS_CMD_CORE_TEST_PROHIBIT_T rCmdProhibit; + TDLS_CMD_CORE_TEST_SCAN_SKIP_T rCmdScanSkip; + TDLS_CMD_CORE_TEST_PTI_TX_FAIL_T rCmdPtiTxFail; + + TDLS_CMD_CORE_MIB_PARAM_UPDATE_T rCmdMibUpdate; + TDLS_CMD_CORE_UAPSD_CONFIG_T rCmdUapsdConf; + TDLS_CMD_CORE_CHSW_CONFIG_T rCmdChSwConf; + TDLS_CMD_CORE_SETUP_CONFIG_T rCmdSetupConf; + TDLS_CMD_CORE_INFO_DISPLAY_T rCmdInfoDisplay; + TDLS_U8 Reserved[TDLS_CMD_CORE_RESERVED_SIZE]; + } Content; +} TDLS_CMD_CORE_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* + assign station record idx for the packet only when STA_STATE_3 + Or we will try to send data frame when the TDLS peer's state is STA_STATE_1 + EX: + 1. mtk_cfg80211_add_station: First create the STA_RECORD_T; + 2. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. + 3. mtk_cfg80211_add_station: Change state to STA_STATE_1. + 4. TdlsexCfg80211TdlsMgmt: Send a TDLS request frame. +*/ +#define TDLSEX_STA_REC_IDX_GET(__prAdapter__, __MsduInfo__) \ +{ \ + STA_RECORD_T *__StaRec__; \ + __MsduInfo__->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; \ + __StaRec__ = cnmGetStaRecByAddress(__prAdapter__, \ + (UINT_8) NETWORK_TYPE_AIS_INDEX, \ + __MsduInfo__->aucEthDestAddr); \ + if ((__StaRec__ != NULL) && \ + ((__StaRec__)->ucStaState == STA_STATE_3) && \ + (IS_TDLS_STA(__StaRec__))) { \ + __MsduInfo__->ucStaRecIndex = __StaRec__->ucIndex; \ + } \ +} + +/* fill wiphy flag */ +#define TDLSEX_WIPHY_FLAGS_INIT(__fgFlag__)\ +{ \ + __fgFlag__ |= (WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP);\ +} + +/* assign user priority of a TDLS action frame */ +/* + According to 802.11z: Setup req/resp are sent in AC_BK, otherwise we should default + to AC_VI. +*/ +#define TDLSEX_UP_ASSIGN(__UserPriority__) \ +{ \ + __UserPriority__ = USER_PRIORITY_TDLS; \ +} + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int +TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *buf, size_t len); + +int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, enum nl80211_tdls_operation oper); + +VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE); + +VOID TdlsexEventHandle(P_GLUE_INFO_T prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); + +TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey); + +VOID TdlsexInit(ADAPTER_T *prAdapter); + +BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter); + +TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +VOID +TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, + BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode); + +TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +TDLS_STATUS TdlsexPeerAdd(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); + +TDLS_STATUS TdlsexPeerUpdate(P_ADAPTER_T prAdapter, PVOID pvSetBuffer, UINT_32 u4SetBufferLen, PUINT_32 pu4SetInfoLen); + +BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt); + +VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen); + +TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo); + +VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota); + +VOID TdlsexUninit(ADAPTER_T *prAdapter); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* CFG_SUPPORT_TDLS */ + +#endif /* _TDLS_EXTR_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h new file mode 100644 index 0000000000000..7ab62dae8813e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/typedef.h @@ -0,0 +1,244 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/typedef.h#1 +*/ + +/*! \file typedef.h + \brief Declaration of data type and return values of internal protocol stack. + + In this file we declare the data type and return values which will be exported + to the GLUE Layer. +*/ + +/* +** Log: typedef.h + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add necessary changes to driver data paths. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add definitions for module migration. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add aa_fsm.h, ais_fsm.h, bss.h, mib.h and scan.h. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add Ethernet destination address information in packet info for TX + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:41:37 GMT mtk01461 +** Update PACKET_INFO_INIT for TX Path +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:30:17 GMT mtk01461 +** Add parameter in PACKET_INFO_T for HIF Loopback +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:22 GMT mtk01461 +** Fix LINT warning +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:28 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:11:54 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _TYPEDEF_H +#define _TYPEDEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* ieee80211.h of linux has duplicated definitions */ +#if defined(WLAN_STATUS_SUCCESS) +#undef WLAN_STATUS_SUCCESS +#endif + +#define WLAN_STATUS_SUCCESS ((WLAN_STATUS) 0x00000000L) +#define WLAN_STATUS_PENDING ((WLAN_STATUS) 0x00000103L) +#define WLAN_STATUS_NOT_ACCEPTED ((WLAN_STATUS) 0x00010003L) + +#define WLAN_STATUS_MEDIA_CONNECT ((WLAN_STATUS) 0x4001000BL) +#define WLAN_STATUS_MEDIA_DISCONNECT ((WLAN_STATUS) 0x4001000CL) +#define WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ((WLAN_STATUS) 0x4001000DL) + +#define WLAN_STATUS_MEDIA_SPECIFIC_INDICATION ((WLAN_STATUS) 0x40010012L) + +#define WLAN_STATUS_SCAN_COMPLETE ((WLAN_STATUS) 0x60010001L) +#define WLAN_STATUS_MSDU_OK ((WLAN_STATUS) 0x60010002L) + +/* TODO(Kevin): double check if 0x60010001 & 0x60010002 is proprietary */ +#define WLAN_STATUS_ROAM_OUT_FIND_BEST ((WLAN_STATUS) 0x60010101L) +#define WLAN_STATUS_ROAM_DISCOVERY ((WLAN_STATUS) 0x60010102L) + +#define WLAN_STATUS_FAILURE ((WLAN_STATUS) 0xC0000001L) +#define WLAN_STATUS_RESOURCES ((WLAN_STATUS) 0xC000009AL) +#define WLAN_STATUS_NOT_SUPPORTED ((WLAN_STATUS) 0xC00000BBL) + +#define WLAN_STATUS_MULTICAST_FULL ((WLAN_STATUS) 0xC0010009L) +#define WLAN_STATUS_INVALID_PACKET ((WLAN_STATUS) 0xC001000FL) +#define WLAN_STATUS_ADAPTER_NOT_READY ((WLAN_STATUS) 0xC0010011L) +#define WLAN_STATUS_NOT_INDICATING ((WLAN_STATUS) 0xC0010013L) +#define WLAN_STATUS_INVALID_LENGTH ((WLAN_STATUS) 0xC0010014L) +#define WLAN_STATUS_INVALID_DATA ((WLAN_STATUS) 0xC0010015L) +#define WLAN_STATUS_BUFFER_TOO_SHORT ((WLAN_STATUS) 0xC0010016L) + +#define WLAN_STATUS_BWCS_UPDATE ((WLAN_STATUS) 0xC0010017L) + +#define WLAN_STATUS_CONNECT_INDICATION ((WLAN_STATUS) 0xC0010018L) + +/* NIC status flags */ +#define ADAPTER_FLAG_HW_ERR 0x00400000 + +/* Type Length */ +#define TL_IPV4 0x0008 +#define TL_IPV6 0xDD86 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for GLUE_INFO structure */ +typedef struct _GLUE_INFO_T GLUE_INFO_T, *P_GLUE_INFO_T; + +/* Type definition for WLAN STATUS */ +typedef UINT_32 WLAN_STATUS, *P_WLAN_STATUS; + +/* Type definition for ADAPTER structure */ +typedef struct _ADAPTER_T ADAPTER_T, *P_ADAPTER_T; + +/* Type definition for MESSAGE HEADER structure */ +typedef struct _MSG_HDR_T MSG_HDR_T, *P_MSG_HDR_T; + +/* Type definition for WLAN configuration */ +typedef struct _WLAN_CFG_T WLAN_CFG_T, *P_WLAN_CFG_T; + +/* Type definition for WLAN configuration entry */ +typedef struct _WLAN_CFG_ENTRY_T WLAN_CFG_ENTRY_T, *P_WLAN_CFG_ENTRY_T; + +/* Type definition for WLAN configuration callback */ +typedef WLAN_STATUS(*WLAN_CFG_SET_CB) (P_ADAPTER_T prAdapter, + PUINT_8 pucKey, PUINT_8 pucValue, PVOID pPrivate, UINT_32 u4Flags); + +/* Type definition for Pointer to OS Native Packet */ +typedef void *P_NATIVE_PACKET; + +/* Type definition for STA_RECORD_T structure to handle the connectivity and packet reception + * for a particular STA. + */ +typedef struct _STA_RECORD_T STA_RECORD_T, *P_STA_RECORD_T, **PP_STA_RECORD_T; + +/* CMD_INFO_T is used by Glue Layer to send a cluster of Command(OID) information to + * the TX Path to reduce the parameters of a function call. + */ +typedef struct _CMD_INFO_T CMD_INFO_T, *P_CMD_INFO_T; + +/* Following typedef should be removed later, because Glue Layer should not + * be aware of following data type. + */ +typedef struct _SW_RFB_T SW_RFB_T, *P_SW_RFB_T, **PP_SW_RFB_T; + +typedef struct _MSDU_INFO_T MSDU_INFO_T, *P_MSDU_INFO_T; + +typedef struct _REG_ENTRY_T REG_ENTRY_T, *P_REG_ENTRY_T; + +/* IST handler definition */ +typedef VOID(*IST_EVENT_FUNCTION) (P_ADAPTER_T); + +/* Type definition for function pointer of timer handler */ +typedef VOID(*PFN_TIMER_CALLBACK) (IN P_GLUE_INFO_T); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _TYPEDEF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h new file mode 100644 index 0000000000000..e8937166dc4f3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_bow.h @@ -0,0 +1,352 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_bow.h#1 +*/ + +/*! \file "wlan_bow.h" + \brief This file contains the declairations of 802.11 PAL + command processing routines for + MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_bow.h + * + * 05 25 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add BoW Cancel Scan Request and Turn On deactive network function. + * + * 05 23 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Add some BoW error handling. + * + * 05 21 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Protect BoW connection establishment. + * + * 05 17 2011 terry.wu + * [WCXRP00000730] [MT6620 Wi-Fi][BoW] Send deauth while disconnecting + * Send deauth while disconnecting BoW link. + * + * 05 06 2011 terry.wu + * [WCXRP00000707] [MT6620 Wi-Fi][Driver] Fix BoW Multiple Physical Link connect/disconnect issue + * Fix BoW Multiple Physical Link connect/disconnect issue. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW table. + * + * 02 16 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add bowNotifyAllLinkDisconnected interface and change channel grant procedure for bow starting.. + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update bowString and channel grant. + * + * 01 11 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update BOW Activity Report structure and bug fix. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * 1) all BT physical handles shares the same RSSI/Link Quality. + * 2) simplify BT command composing + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose +** +*/ + +#ifndef _WLAN_BOW_H +#define _WLAN_BOW_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "nic/bow.h" +#include "nic/cmd_buf.h" + +#if CFG_ENABLE_BT_OVER_WIFI + +#if CFG_BOW_TEST +extern UINT_32 g_arBowRevPalPacketTime[32]; +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define BOWCMD_STATUS_SUCCESS 0 +#define BOWCMD_STATUS_FAILURE 1 +#define BOWCMD_STATUS_UNACCEPTED 2 +#define BOWCMD_STATUS_INVALID 3 +#define BOWCMD_STATUS_TIMEOUT 4 + +#define BOW_WILDCARD_SSID "AMP" +#define BOW_WILDCARD_SSID_LEN 3 +#define BOW_SSID_LEN 21 + + /* 0: query, 1: setup, 2: destroy */ +#define BOW_QUERY_CMD 0 +#define BOW_SETUP_CMD 1 +#define BOW_DESTROY_CMD 2 + +#define BOW_INITIATOR 0 +#define BOW_RESPONDER 1 + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +typedef struct _BOW_TABLE_T { + UINT_8 ucAcquireID; + BOOLEAN fgIsValid; + ENUM_BOW_DEVICE_STATE eState; + UINT_8 aucPeerAddress[6]; + /* UINT_8 ucRole; */ + /* UINT_8 ucChannelNum; */ + UINT_16 u2Reserved; +} BOW_TABLE_T, *P_BOW_TABLE_T; + +typedef WLAN_STATUS(*PFN_BOW_CMD_HANDLE) (P_ADAPTER_T, P_AMPC_COMMAND); + +typedef struct _BOW_CMD_T { + UINT_8 uCmdID; + PFN_BOW_CMD_HANDLE pfCmdHandle; +} BOW_CMD_T, *P_BOW_CMD_T; + +typedef struct _BOW_EVENT_ACTIVITY_REPORT_T { + UINT_8 ucReason; + UINT_8 aucReserved; + UINT_8 aucPeerAddress[6]; +} BOW_EVENT_ACTIVITY_REPORT_T, *P_BOW_EVENT_ACTIVITY_REPORT_T; + +/* +ucReason: 0: success + 1: general failure + 2: too much time (> 2/3 second totally) requested for scheduling. + Others: reserved. +*/ + +typedef struct _BOW_EVENT_SYNC_TSF_T { + UINT_64 u4TsfTime; + UINT_32 u4TsfSysTime; + UINT_32 u4ScoTime; + UINT_32 u4ScoSysTime; +} BOW_EVENT_SYNC_TSF_T, *P_BOW_EVENT_SYNC_TSF_T; + +typedef struct _BOW_ACTIVITY_REPORT_BODY_T { + UINT_32 u4StartTime; + UINT_32 u4Duration; + UINT_32 u4Periodicity; +} BOW_ACTIVITY_REPORT_BODY_T, *P_BOW_ACTIVITY_REPORT_BODY_T; + +typedef struct _BOW_ACTIVITY_REPORT_T { + UINT_8 aucPeerAddress[6]; + UINT_8 ucScheduleKnown; + UINT_8 ucNumReports; + BOW_ACTIVITY_REPORT_BODY_T arBowActivityReportBody[MAX_ACTIVITY_REPORT]; +} BOW_ACTIVITY_REPORT_T, *P_BOW_ACTIVITY_REPORT_T; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*--------------------------------------------------------------*/ +/* Firmware Command Packer */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryBowCmd(IN P_ADAPTER_T prAdapter, + UINT_8 ucCID, + BOOLEAN fgSetQuery, + BOOLEAN fgNeedResp, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + UINT_32 u4SetQueryInfoLen, PUINT_8 pucInfoBuffer, IN UINT_8 ucSeqNumber); + +/*--------------------------------------------------------------*/ +/* Command Dispatcher */ +/*--------------------------------------------------------------*/ +WLAN_STATUS wlanbowHandleCommand(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +/*--------------------------------------------------------------*/ +/* Routines to handle command */ +/*--------------------------------------------------------------*/ +WLAN_STATUS bowCmdGetMacStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdSetupConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdDestroyConnection(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdSetPTK(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdReadRSSI(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdShortRangeMode(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +WLAN_STATUS bowCmdGetChannelList(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd); + +VOID wlanbowCmdEventSetStatus(IN P_ADAPTER_T prAdapter, IN P_AMPC_COMMAND prCmd, IN UINT_8 ucEventBuf); + +/*--------------------------------------------------------------*/ +/* Callbacks for event indication */ +/*--------------------------------------------------------------*/ +VOID wlanbowCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdEventLinkConnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdEventLinkDisconnected(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdEventSetSetupConnection(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdEventReadLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdEventReadRssi(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanbowCmdTimeoutHandler(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +VOID bowStopping(IN P_ADAPTER_T prAdapter); + +VOID bowStarting(IN P_ADAPTER_T prAdapter); + +VOID bowAssignSsid(IN PUINT_8 pucSsid, IN PUINT_8 pucSsidLen); + +BOOLEAN bowValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags); + +VOID bowSendBeacon(IN P_ADAPTER_T prAdapter, ULONG ulParam); + +VOID bowResponderScan(IN P_ADAPTER_T prAdapter); + +VOID bowResponderScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID bowResponderCancelScan(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsChannelExtention); + +VOID bowResponderJoin(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +VOID bowFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID +bowIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication); + +VOID bowRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS bowRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS bowRunEventRxDeAuth(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb); + +VOID bowDisconnectLink(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +BOOLEAN bowValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode); + +BOOLEAN +bowValidateAuth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode); + +VOID bowRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +VOID bowRequestCh(IN P_ADAPTER_T prAdapter); + +VOID bowReleaseCh(IN P_ADAPTER_T prAdapter); + +VOID bowChGrantedTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam); + +BOOLEAN bowNotifyAllLinkDisconnected(IN P_ADAPTER_T prAdapter); + +BOOLEAN bowCheckBowTableIfVaild(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); + +BOOLEAN bowGetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, OUT P_BOW_TABLE_T prBowTable); + +BOOLEAN +bowGetBowTableEntryByPeerAddress(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], OUT PUINT_8 pucBowTableIdx); + +BOOLEAN bowGetBowTableFreeEntry(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucBowTableIdx); + +ENUM_BOW_DEVICE_STATE bowGetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6]); + +BOOLEAN bowSetBowTableState(IN P_ADAPTER_T prAdapter, IN UINT_8 aucPeerAddress[6], IN ENUM_BOW_DEVICE_STATE eState); + +BOOLEAN bowSetBowTableContent(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBowTableIdx, IN P_BOW_TABLE_T prBowTable); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif +#endif /* _WLAN_BOW_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h new file mode 100644 index 0000000000000..87259397a93d1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_lib.h @@ -0,0 +1,1001 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_lib.h#1 +*/ + +/*! \file "wlan_lib.h" + \brief The declaration of the functions of the wlanAdpater objects + + Detail description. +*/ + +/* +** Log: wlan_lib.h + * + * 06 08 2012 eason.tsai + * NULL + * Nvram context covert from 6620 to 6628 for old 6620 meta tool + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for + * preferred band configuration with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for + * setting preferred band configuration corresponding to network type. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * eliminate win32 native data types. + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware download path in divided scatters. + * + * 10 03 2011 cp.wu + * [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware downloading aggregated path. + * + * 09 20 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * change window registry of driver for roaming. + * + * 09 08 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 08 25 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add DFS switch. + * + * 08 24 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Update RDD test mode cases. + * + * 08 15 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * support to load different firmware image for E3/E4/E5 and E6 ASIC on win32 platforms. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, + * TX deauth to a disconnecting device issue. + * Fix GO send deauth frame issue. + * + * 07 22 2011 jeffrey.chang + * [WCXRP00000864] [MT5931] Add command to adjust OSC stable time + * modify driver to set OSC stable time after f/w download + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 04 18 2011 cp.wu + * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) + * 1) add API for glue layer to query ACPI state + * 2) Windows glue should not access to hardware after switched into D3 state + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Support current measure mode, assigned by registry (XP only). + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result + * in OID handling layer when the corresponding BSS is disconnected due to beacon timeout + * remove from scanning result when the BSS is disconnected due to beacon timeout. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to + * disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000137] [MT6620 Wi-Fi] [FW] Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * divide a single function into 2 part to surpress a weird compiler warning from gcc-4.4.0 + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 09 24 2010 cp.wu + * [WCXRP00000057] [MT6620 Wi-Fi][Driver] Modify online scan to a run-time switchable feature + * Modify online scan as a run-time adjustable option (for Windows, in registry) + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 26 2010 yuche.tsai + * NULL + * Add AT GO test configure mode under WinXP. + * Please enable 1. CFG_ENABLE_WIFI_DIRECT, 2. CFG_TEST_WIFI_DIRECT_GO, 3. CFG_SUPPORT_AAA + * + * 08 25 2010 george.huang + * NULL + * . + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid + * descriptor underflow under concurrent network operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * simplify timer usage. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add extra 64 adjustable parameters for CoEX scenario. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * 2) add 2 kal API for later integration + * + * 04 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change to use WIFI_TCM_ALWAYS_ON as firmware image + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add two option for ACK and ENCRYPTION for firmware download + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * separate wlanProcesQueuePacket() into 2 APIs upon request + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add new API: wlanProcessQueuedPackets() + * + * 02 11 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. add logic for firmware download + * * * 2. firmware image filename and start/load address are now retrieved from registry + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * 4) nicRxWaitResponse() revised + * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * 4. correct some HAL implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:39:55 GMT mtk02752 +** eliminate unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-10-13 21:58:41 GMT mtk01084 +** update for new macro define +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-05-19 10:43:06 GMT mtk01461 +** Add wlanReleasePendingOid() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-13 16:38:44 GMT mtk01084 +** add WIFI start function +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-08 16:51:14 GMT mtk01084 +** Update for the image download part +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-04-01 10:57:38 GMT mtk01461 +** Add wlanSendLeftClusteredFrames() for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-23 00:31:02 GMT mtk01461 +** Add declaration of FW Image download reference code +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:08:31 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:04 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_LIB_H +#define _WLAN_LIB_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "CFG_Wifi_File.h" +#include "rlm_domain.h" +#include "wlan_typedef.h" + + +extern BOOLEAN fgIsResetting; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define MAX_NUM_GROUP_ADDR 32 /* max number of group addresses */ + +#define TX_CS_TCP_UDP_GEN BIT(1) +#define TX_CS_IP_GEN BIT(0) + +#define CSUM_OFFLOAD_EN_TX_TCP BIT(0) +#define CSUM_OFFLOAD_EN_TX_UDP BIT(1) +#define CSUM_OFFLOAD_EN_TX_IP BIT(2) +#define CSUM_OFFLOAD_EN_RX_TCP BIT(3) +#define CSUM_OFFLOAD_EN_RX_UDP BIT(4) +#define CSUM_OFFLOAD_EN_RX_IPv4 BIT(5) +#define CSUM_OFFLOAD_EN_RX_IPv6 BIT(6) +#define CSUM_OFFLOAD_EN_TX_MASK BITS(0, 2) +#define CSUM_OFFLOAD_EN_ALL BITS(0, 6) + +/* TCP, UDP, IP Checksum */ +#define RX_CS_TYPE_UDP BIT(7) +#define RX_CS_TYPE_TCP BIT(6) +#define RX_CS_TYPE_IPv6 BIT(5) +#define RX_CS_TYPE_IPv4 BIT(4) + +#define RX_CS_STATUS_UDP BIT(3) +#define RX_CS_STATUS_TCP BIT(2) +#define RX_CS_STATUS_IP BIT(0) + +#define CSUM_NOT_SUPPORTED 0x0 + +#define TXPWR_USE_PDSLOPE 0 + +/* NVRAM error code definitions */ +#define NVRAM_ERROR_VERSION_MISMATCH BIT(1) +#define NVRAM_ERROR_INVALID_TXPWR BIT(2) +#define NVRAM_ERROR_INVALID_DPD BIT(3) +#define NVRAM_ERROR_INVALID_MAC_ADDR BIT(4) +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY +#define NVRAM_POWER_LIMIT_TABLE_INVALID BIT(5) +#endif + +#define NUM_TC_RESOURCE_TO_STATISTICS 4 + +#define WLAN_CFG_ARGV_MAX 8 +#define WLAN_CFG_ENTRY_NUM_MAX 128 +#define WLAN_CFG_KEY_LEN_MAX 32 /* include \x00 EOL */ +#define WLAN_CFG_VALUE_LEN_MAX 32 /* include \x00 EOL */ +#define WLAN_CFG_FLAG_SKIP_CB BIT(0) +#define WLAN_CFG_FILE_BUF_SIZE 2048 + +#define WLAN_CFG_SET_CHIP_LEN_MAX 10 +#define WLAN_CFG_SET_DEBUG_LEVEL_LEN_MAX 10 +#define WLAN_CFG_SET_SW_CTRL_LEN_MAX 10 + +#define WLAN_OID_TIMEOUT_THRESHOLD 2000 /* OID timeout (in ms) */ +#define WLAN_OID_TIMEOUT_THRESHOLD_IN_RESETTING 300 /* OID timeout during chip-resetting (in ms) */ + +#define WLAN_OID_NO_ACK_THRESHOLD 3 + +#define WLAN_TX_THREAD_TASK_PRIORITY 0 /* If not setting the priority, 0 is the default */ +#define WLAN_TX_THREAD_TASK_NICE (-10) /* If not setting the nice, -10 is the default */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC) (IN P_ADAPTER_T prAdapter, + IN PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); + +typedef enum _ENUM_CSUM_TYPE_T { + CSUM_TYPE_IPV4, + CSUM_TYPE_IPV6, + CSUM_TYPE_TCP, + CSUM_TYPE_UDP, + CSUM_TYPE_NUM +} ENUM_CSUM_TYPE_T, *P_ENUM_CSUM_TYPE_T; + +typedef enum _ENUM_CSUM_RESULT_T { + CSUM_RES_NONE, + CSUM_RES_SUCCESS, + CSUM_RES_FAILED, + CSUM_RES_NUM +} ENUM_CSUM_RESULT_T, *P_ENUM_CSUM_RESULT_T; + +typedef enum _ENUM_PHY_MODE_T { + ENUM_PHY_2G4_CCK, + ENUM_PHY_2G4_OFDM_BPSK, + ENUM_PHY_2G4_OFDM_QPSK, + ENUM_PHY_2G4_OFDM_16QAM, + ENUM_PHY_2G4_OFDM_48M, + ENUM_PHY_2G4_OFDM_54M, + ENUM_PHY_2G4_HT20_BPSK, + ENUM_PHY_2G4_HT20_QPSK, + ENUM_PHY_2G4_HT20_16QAM, + ENUM_PHY_2G4_HT20_MCS5, + ENUM_PHY_2G4_HT20_MCS6, + ENUM_PHY_2G4_HT20_MCS7, + ENUM_PHY_2G4_HT40_BPSK, + ENUM_PHY_2G4_HT40_QPSK, + ENUM_PHY_2G4_HT40_16QAM, + ENUM_PHY_2G4_HT40_MCS5, + ENUM_PHY_2G4_HT40_MCS6, + ENUM_PHY_2G4_HT40_MCS7, + ENUM_PHY_5G_OFDM_BPSK, + ENUM_PHY_5G_OFDM_QPSK, + ENUM_PHY_5G_OFDM_16QAM, + ENUM_PHY_5G_OFDM_48M, + ENUM_PHY_5G_OFDM_54M, + ENUM_PHY_5G_HT20_BPSK, + ENUM_PHY_5G_HT20_QPSK, + ENUM_PHY_5G_HT20_16QAM, + ENUM_PHY_5G_HT20_MCS5, + ENUM_PHY_5G_HT20_MCS6, + ENUM_PHY_5G_HT20_MCS7, + ENUM_PHY_5G_HT40_BPSK, + ENUM_PHY_5G_HT40_QPSK, + ENUM_PHY_5G_HT40_16QAM, + ENUM_PHY_5G_HT40_MCS5, + ENUM_PHY_5G_HT40_MCS6, + ENUM_PHY_5G_HT40_MCS7, + ENUM_PHY_MODE_NUM +} ENUM_PHY_MODE_T, *P_ENUM_PHY_MODE_T; + +typedef enum _ENUM_POWER_SAVE_POLL_MODE_T { + ENUM_POWER_SAVE_POLL_DISABLE, + ENUM_POWER_SAVE_POLL_LEGACY_NULL, + ENUM_POWER_SAVE_POLL_QOS_NULL, + ENUM_POWER_SAVE_POLL_NUM +} ENUM_POWER_SAVE_POLL_MODE_T, *P_ENUM_POWER_SAVE_POLL_MODE_T; + +typedef enum _ENUM_AC_TYPE_T { + ENUM_AC_TYPE_AC0, + ENUM_AC_TYPE_AC1, + ENUM_AC_TYPE_AC2, + ENUM_AC_TYPE_AC3, + ENUM_AC_TYPE_AC4, + ENUM_AC_TYPE_AC5, + ENUM_AC_TYPE_AC6, + ENUM_AC_TYPE_BMC, + ENUM_AC_TYPE_NUM +} ENUM_AC_TYPE_T, *P_ENUM_AC_TYPE_T; + +typedef enum _ENUM_ADV_AC_TYPE_T { + ENUM_ADV_AC_TYPE_RX_NSW, + ENUM_ADV_AC_TYPE_RX_PTA, + ENUM_ADV_AC_TYPE_RX_SP, + ENUM_ADV_AC_TYPE_TX_PTA, + ENUM_ADV_AC_TYPE_TX_RSP, + ENUM_ADV_AC_TYPE_NUM +} ENUM_ADV_AC_TYPE_T, *P_ENUM_ADV_AC_TYPE_T; + +typedef enum _ENUM_REG_CH_MAP_T { + REG_CH_MAP_COUNTRY_CODE, + REG_CH_MAP_TBL_IDX, + REG_CH_MAP_CUSTOMIZED, + REG_CH_MAP_NUM +} ENUM_REG_CH_MAP_T, *P_ENUM_REG_CH_MAP_T; + +#define CHIP_CONFIG_RESP_SIZE 320 +enum { + CHIP_CONFIG_TYPE_WO_RESPONSE = 0x00, + CHIP_CONFIG_TYPE_MEM8 = 0x01, + CHIP_CONFIG_TYPE_MEM32 = 0x02, + CHIP_CONFIG_TYPE_ASCII = 0x03, + CHIP_CONFIG_TYPE_BINARY = 0x04, + CHIP_CONFIG_TYPE_DRV_PASSTHROUGH = 0x05, + CHIP_CONFIG_TYPE_END +}; + +typedef struct _SET_TXPWR_CTRL_T { + INT_8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + INT_8 c2GHotspotPwrOffset; + INT_8 c2GP2pPwrOffset; + INT_8 c2GBowPwrOffset; + INT_8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + INT_8 c5GHotspotPwrOffset; + INT_8 c5GP2pPwrOffset; + INT_8 c5GBowPwrOffset; + UINT_8 ucConcurrencePolicy; /* TX power policy when concurrence + in the same channel + 0: Highest power has priority + 1: Lowest power has priority */ + INT_8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + INT_8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ + INT_8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + INT_8 acReserved2[2]; /* Must be zero */ +} SET_TXPWR_CTRL_T, *P_SET_TXPWR_CTRL_T; + +/* For storing driver initialization value from glue layer */ +typedef struct _REG_INFO_T { + UINT_32 u4SdBlockSize; /* SDIO block size */ + UINT_32 u4SdBusWidth; /* SDIO bus width. 1 or 4 */ + UINT_32 u4SdClockRate; /* SDIO clock rate. (in unit of HZ) */ + UINT_32 u4StartAddress; /* Starting address of Wi-Fi Firmware */ + UINT_32 u4LoadAddress; /* Load address of Wi-Fi Firmware */ + UINT_16 aucFwImgFilename[65]; /* Firmware filename */ + UINT_16 aucFwImgFilenameE6[65]; /* Firmware filename for E6 */ + UINT_32 u4StartFreq; /* Start Frequency for Ad-Hoc network : in unit of KHz */ + UINT_32 u4AdhocMode; /* Default mode for Ad-Hoc network : ENUM_PARAM_AD_HOC_MODE_T */ + UINT_32 u4RddStartFreq; + UINT_32 u4RddStopFreq; + UINT_32 u4RddTestMode; + UINT_32 u4RddShutFreq; + UINT_32 u4RddDfs; + INT_32 i4HighRssiThreshold; + INT_32 i4MediumRssiThreshold; + INT_32 i4LowRssiThreshold; + INT_32 au4TxPriorityTag[ENUM_AC_TYPE_NUM]; + INT_32 au4RxPriorityTag[ENUM_AC_TYPE_NUM]; + INT_32 au4AdvPriorityTag[ENUM_ADV_AC_TYPE_NUM]; + UINT_32 u4FastPSPoll; + UINT_32 u4PTA; /* 0: disable, 1: enable */ + UINT_32 u4TXLimit; /* 0: disable, 1: enable */ + UINT_32 u4SilenceWindow; /* range: 100 - 625, unit: us */ + UINT_32 u4TXLimitThreshold; /* range: 250 - 1250, unit: us */ + UINT_32 u4PowerMode; + UINT_32 fgEnArpFilter; + UINT_32 u4PsCurrentMeasureEn; + UINT_32 u4UapsdAcBmp; + UINT_32 u4MaxSpLen; + UINT_32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online scan */ + UINT_32 fgDisBcnLostDetection; /* 0: enable online scan, non-zero: disable online scan */ + UINT_32 u4FixedRate; /* 0: automatic, non-zero: fixed rate */ + UINT_32 u4ArSysParam0; + UINT_32 u4ArSysParam1; + UINT_32 u4ArSysParam2; + UINT_32 u4ArSysParam3; + UINT_32 fgDisRoaming; /* 0:enable roaming 1:disable */ + + /* NVRAM - MP Data -START- */ + UINT_8 aucMacAddr[6]; + UINT_16 au2CountryCode[4]; /* Country code (in ISO 3166-1 expression, ex: "US", "TW") */ + TX_PWR_PARAM_T rTxPwr; + UINT_8 aucEFUSE[144]; + UINT_8 ucTxPwrValid; + UINT_8 ucSupport5GBand; + UINT_8 fg2G4BandEdgePwrUsed; + INT_8 cBandEdgeMaxPwrCCK; + INT_8 cBandEdgeMaxPwrOFDM20; + INT_8 cBandEdgeMaxPwrOFDM40; + ENUM_REG_CH_MAP_T eRegChannelListMap; + UINT_8 ucRegChannelListIndex; + DOMAIN_INFO_ENTRY rDomainInfo; + /* NVRAM - MP Data -END- */ + + /* NVRAM - Functional Data -START- */ + UINT_8 uc2G4BwFixed20M; + UINT_8 uc5GBwFixed20M; + UINT_8 ucEnable5GBand; + UINT_8 uc2GRssiCompensation; + UINT_8 uc5GRssiCompensation; + UINT_8 fgRssiCompensationValidbit; + UINT_8 ucRxAntennanumber; + /* NVRAM - Functional Data -END- */ + +} REG_INFO_T, *P_REG_INFO_T; + +/* for divided firmware loading */ +typedef struct _FWDL_SECTION_INFO_T { + UINT_32 u4Offset; + UINT_32 u4Reserved; + UINT_32 u4Length; + UINT_32 u4DestAddr; +} FWDL_SECTION_INFO_T, *P_FWDL_SECTION_INFO_T; + +typedef struct _FIRMWARE_DIVIDED_DOWNLOAD_T { + UINT_32 u4Signature; + UINT_32 u4CRC; /* CRC calculated without first 8 bytes included */ + UINT_32 u4NumOfEntries; + UINT_32 u4Reserved; + FWDL_SECTION_INFO_T arSection[]; +} FIRMWARE_DIVIDED_DOWNLOAD_T, *P_FIRMWARE_DIVIDED_DOWNLOAD_T; + +typedef struct _PARAM_MCR_RW_STRUCT_T { + UINT_32 u4McrOffset; + UINT_32 u4McrData; +} PARAM_MCR_RW_STRUCT_T, *P_PARAM_MCR_RW_STRUCT_T; + +typedef struct _PARAM_GET_STA_STATISTICS { + UINT_8 ucInvalid; + UINT_8 ucVersion; + /* Per-STA statistic */ + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + UINT_32 u4LinkScore; + UINT_32 u4Flag; + + /* From FW */ + UINT_8 ucPer; /* base: 128 */ + UINT_8 ucRcpi; + UINT_32 u4PhyMode; + UINT_16 u2LinkSpeed; /* unit is 0.5 Mbits */ + + UINT_32 u4TxFailCount; + UINT_32 u4TxLifeTimeoutCount; + UINT_32 u4TxAverageAirTime; + + /* From driver */ + UINT_32 u4TxTotalCount; + UINT_32 u4TxExceedThresholdCount; + UINT_32 u4TxAverageProcessTime; + + UINT_32 u4TxMaxTime; + UINT_32 u4TxMaxHifTime; + UINT_32 u4TxAverageHifTime; + + /* + * How many packages Enqueue/Deqeue during statistics interval + */ + UINT_32 u4EnqueueCounter; + UINT_32 u4DequeueCounter; + + UINT_32 u4EnqueueStaCounter; + UINT_32 u4DequeueStaCounter; + + UINT_32 IsrCnt; + UINT_32 IsrPassCnt; + UINT_32 TaskIsrCnt; + + UINT_32 IsrAbnormalCnt; + UINT_32 IsrSoftWareCnt; + UINT_32 IsrRxCnt; + UINT_32 IsrTxCnt; + + UINT_32 au4TcResourceEmptyCount[NUM_TC_RESOURCE_TO_STATISTICS]; + UINT_32 au4DequeueNoTcResource[NUM_TC_RESOURCE_TO_STATISTICS]; + UINT_32 au4TcResourceBackCount[NUM_TC_RESOURCE_TO_STATISTICS]; + + UINT_32 au4TcResourceUsedCount[NUM_TC_RESOURCE_TO_STATISTICS]; + UINT_32 au4TcResourceWantedCount[NUM_TC_RESOURCE_TO_STATISTICS]; + + UINT_32 au4TcQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + /* Global queue management statistic */ + UINT_32 au4TcAverageQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + UINT_32 au4TcCurrentQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + + /* Reserved fields */ + UINT_8 au4Reserved[32]; +} PARAM_GET_STA_STA_STATISTICS, *P_PARAM_GET_STA_STATISTICS; + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR { + NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, + NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, + + NL80211_TESTMODE_AVAILABLE_CHAN_NUM, +} ENUM_TESTMODE_AVAILABLE_CHAN_ATTR; + +typedef struct _LTE_SAFE_CH_INFO_T { + UINT_32 au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1]; +} LTE_SAFE_CH_INFO_T, *P_CMD_LTE_SAFE_CH_INFO_T; + + /* Record Each CH Load */ +typedef struct _PARAM_CHN_LOAD_INFO { + /* Per-CHN Load */ + UINT_32 u4Flag; + + UINT_8 ucChannel; + UINT_16 u2ChannelLoad; + UINT_8 au4Reserved[1]; + + UINT_16 u2APNum; + UINT_16 u2APNumTmpCountingBuf; + + /* Reserved fields */ + UINT_8 au4Reserved1[8]; +} PARAM_CHN_LOAD_INFO, *P_PARAM_CHN_LOAD_INFO; + +typedef struct _PARAM_GET_CHN_LOAD { + LTE_SAFE_CH_INFO_T rLteSafeChnList; + PARAM_CHN_LOAD_INFO rEachChnLoad[MAX_AUTO_CHAL_NUM]; + BOOLEAN fgDataReadyBit; + UINT_8 au4Reserved1[3]; +} PARAM_GET_CHN_LOAD, *P_PARAM_GET_CHN_LOAD; + +typedef struct _PARAM_PREFER_CHN_INFO { + + UINT_8 ucChannel; + UINT_16 u2APNum; + UINT_8 au4Reserved1[1]; +} PARAM_PREFER_CHN_INFO, *P_PARAM_PREFER_CHN_INFO; + +typedef struct _PARAM_GET_LTE_MODE { + /* Event Body */ + UINT_8 ucVersion; + UINT_8 aucReserved1[3]; + UINT_32 u4Flags; /* Bit0: valid */ + + LTE_SAFE_CH_INFO_T LTE_MODE; + UINT_8 aucReserved4[3]; + + UINT_8 aucReserved[4]; + +} PARAM_GET_LTE_MODE, *P_PARAM_GET_LTE_MODE; + +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ + ((UINT_32)(UINT_8)(ch0) | ((UINT_32)(UINT_8)(ch1) << 8) | \ + ((UINT_32)(UINT_8)(ch2) << 16) | ((UINT_32)(UINT_8)(ch3) << 24)) + +#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo); + +VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter); + +VOID wlanCardEjected(IN P_ADAPTER_T prAdapter); + +VOID wlanIST(IN P_ADAPTER_T prAdapter); + +BOOLEAN wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl); + +WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue); + +WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulData); + +VOID wlanReleasePendingCMDbyNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType); + +VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket); + +VOID wlanReturnIndicatedPacketsTimeOut(IN P_ADAPTER_T prAdapter, IN ULONG ulData); + +WLAN_STATUS +wlanQueryInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidQryHandler, + IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen); + +WLAN_STATUS +wlanSetInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidSetHandler, + IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanAdapterStart(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo, IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength); + +WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter); + +#if CFG_SUPPORT_WAPI +BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter); +#endif + +VOID wlanReturnRxPacket(IN PVOID pvAdapter, IN PVOID pvPacket); + +VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast); + +BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); + +VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode); + +#if CFG_ENABLE_FW_DOWNLOAD +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION +WLAN_STATUS +wlanImageSectionDownloadAggregated(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); +#endif + +WLAN_STATUS +wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf); + +#if !CFG_ENABLE_FW_DOWNLOAD_ACK +WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter); +#else +WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum); +#endif + +WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress); + +UINT_32 wlanCRC32(PUINT_8 buf, UINT_32 len); + +#endif + +WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode); + +BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo); + +WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead); + +WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead); + +BOOLEAN wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, IN PFN_OID_HANDLER_FUNC pfnOidHandler); + +VOID wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter); + +BOOLEAN wlanQueryTestMode(IN P_ADAPTER_T prAdapter); + +/* Security Frame Handling */ +BOOLEAN wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket); + +VOID wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf); + +VOID wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +VOID wlanClearScanningResult(IN P_ADAPTER_T prAdapter); + +VOID wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN PUINT_8 arBSSID); + +#if CFG_TEST_WIFI_DIRECT_GO +VOID wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter); + +VOID wlanEnableATGO(IN P_ADAPTER_T prAdapter); +#endif + +/*----------------------------------------------------------------------------*/ +/* Address Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPermanentAddress(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* NIC Capability Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* NIC Capability Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryDebugCode(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Compiler Flags Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryCompileFlags(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* PD MCR Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, IN P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo); +/*----------------------------------------------------------------------------*/ +/* Loading Manufacture Data */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); + +/*----------------------------------------------------------------------------*/ +/* Media Stream Mode */ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Timer Timeout Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* TX Pending Packets Handling (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prNativePacket); + +WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, IN OUT PBOOLEAN pfgHwAccess); + +/*----------------------------------------------------------------------------*/ +/* Low Power Acquire/Release (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Pending Packets Number Reporting (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +UINT_32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* ACPI state inquiry (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter); + +VOID wlanSetAcpiState(IN P_ADAPTER_T prAdapter, IN ENUM_ACPI_STATE_T ePowerState); + +VOID wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* get ECO version from Revision ID register (for Win32) */ +/*----------------------------------------------------------------------------*/ +UINT_8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* set preferred band configuration corresponding to network type */ +/*----------------------------------------------------------------------------*/ +VOID +wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +/*----------------------------------------------------------------------------*/ +/* get currently operating channel information */ +/*----------------------------------------------------------------------------*/ +UINT_8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +/*----------------------------------------------------------------------------*/ +/* get BSS Descriptor information */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T wlanGetTargetBssDescByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex); + +/*----------------------------------------------------------------------------*/ +/* check for system configuration to generate message on scan list */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* query sta statistics information from driver and firmware */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS wlanCfgParseArgument(CHAR *cmdLine, INT_32 *argc, CHAR *argv[]); + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const PCHAR pucKey); + +WLAN_STATUS +wlanCfgGet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, PCHAR pucValueDef, UINT_32 u4Flags); + +UINT_32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4ValueDef); + +INT_32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, INT_32 i4ValueDef); + +WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, UINT_32 u4Value); + +WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, PCHAR pucValue, UINT_32 u4Flags); + +WLAN_STATUS +wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const PCHAR pucKey, WLAN_CFG_SET_CB pfSetCb, void *pPrivate, UINT_32 u4Flags); + +#if CFG_SUPPORT_CFG_FILE +WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, PUINT_8 pucConfigBuf, UINT_32 u4ConfigBufLen, UINT_32 u4Flags); + +VOID wlanCfgApply(IN P_ADAPTER_T prAdapter); +#endif /* CFG_SUPPORT_CFG_FILE */ + +extern VOID mtk_wcn_wmt_set_wifi_ver(UINT_32 Value); + +#endif /* _WLAN_LIB_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h new file mode 100644 index 0000000000000..45919df996e95 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_oid.h @@ -0,0 +1,1715 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/include/wlan_oid.h#2 +*/ + +/*! \file "wlan_oid.h" + \brief This file contains the declairation file of the WLAN OID processing routines + of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_oid.h + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 02 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * Support UAPSD/OppPS/NoA parameter setting + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wifi_var.h, precomp.h, cnm_timer.h (data type only) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move timer callback to glue layer. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 18 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement Wakeup-on-LAN except firmware integration part + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. + * + + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add NULL OID implementation for WOL-related OIDs. + * + * 04 22 2010 cp.wu + * [WPD00003830]add OID_802_11_PRIVACY_FILTER support + * enable RX filter OID + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) implement timeout mechanism when OID is pending for longer than 1 second + * * * 2) allow OID_802_11_CONFIGURATION to be executed when RF test mode is turned on + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * OID_802_11_RSSI, + * * * * OID_802_11_RSSI_TRIGGER, + * * * * OID_802_11_STATISTICS, + * * * * OID_802_11_DISASSOCIATE, + * * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_SUPPORTED_RATES / OID_802_11_DESIRED_RATES +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-08 11:38:11 GMT mtk02752 +** add declares for RF test related APIs +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-24 22:41:53 GMT mtk02752 +** remove u4SysTime, MSDN 10-second will be implemented in FW side +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 20:30:13 GMT mtk02752 +** add u4SysTime field in PARAM_BSSID_EX_T +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-12 19:48:35 GMT mtk02752 +** allow upper layer to set a packet filter with PROMISCUOUS mode +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:12:12 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _WLAN_OID_H +#define _WLAN_OID_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if DBG +extern UINT_8 aucDebugModule[DBG_MODULE_NUM]; +extern UINT_32 u4DebugModule; +UINT_32 u4DebugModuleTemp; +#endif /* DBG */ +extern int sprintf(char *buf, const char *fmt, ...); + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define PARAM_MAX_LEN_SSID 32 + +#define PARAM_MAC_ADDR_LEN 6 + +#define ETHERNET_HEADER_SZ 14 +#define ETHERNET_MIN_PKT_SZ 60 +#define ETHERNET_MAX_PKT_SZ 1514 + +#define PARAM_MAX_LEN_RATES 8 +#define PARAM_MAX_LEN_RATES_EX 16 + +#define PARAM_AUTH_REQUEST_REAUTH 0x01 +#define PARAM_AUTH_REQUEST_KEYUPDATE 0x02 +#define PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E + +#define PARAM_EEPROM_READ_METHOD_READ 1 +#define PARAM_EEPROM_READ_METHOD_GETSIZE 0 + +#define PARAM_WHQL_RSSI_MAX_DBM (-10) +#define PARAM_WHQL_RSSI_MIN_DBM (-200) + +#define PARAM_DEVICE_WAKE_UP_ENABLE 0x00000001 +#define PARAM_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 +#define PARAM_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 + +#define PARAM_WAKE_UP_MAGIC_PACKET 0x00000001 +#define PARAM_WAKE_UP_PATTERN_MATCH 0x00000002 +#define PARAM_WAKE_UP_LINK_CHANGE 0x00000004 + +/* Packet filter bit definitioin (UINT_32 bit-wise definition) */ +#define PARAM_PACKET_FILTER_DIRECTED 0x00000001 +#define PARAM_PACKET_FILTER_MULTICAST 0x00000002 +#define PARAM_PACKET_FILTER_ALL_MULTICAST 0x00000004 +#define PARAM_PACKET_FILTER_BROADCAST 0x00000008 +#define PARAM_PACKET_FILTER_PROMISCUOUS 0x00000020 +#define PARAM_PACKET_FILTER_ALL_LOCAL 0x00000080 +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#define PARAM_PACKET_FILTER_P2P_MASK 0xC0000000 +#define PARAM_PACKET_FILTER_PROBE_REQ 0x80000000 +#define PARAM_PACKET_FILTER_ACTION_FRAME 0x40000000 +#endif + +#if CFG_SLT_SUPPORT +#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ + PARAM_PACKET_FILTER_MULTICAST | \ + PARAM_PACKET_FILTER_BROADCAST | \ + PARAM_PACKET_FILTER_ALL_MULTICAST) +#else +#define PARAM_PACKET_FILTER_SUPPORTED (PARAM_PACKET_FILTER_DIRECTED | \ + PARAM_PACKET_FILTER_MULTICAST | \ + PARAM_PACKET_FILTER_BROADCAST) +#endif + +#define PARAM_MEM_DUMP_MAX_SIZE 2048 + +#define BT_PROFILE_PARAM_LEN 8 +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration which match to NDIS5.1 */ +/*----------------------------------------------------------------------------*/ +/* NDIS_802_11_AUTHENTICATION_MODE */ +typedef enum _ENUM_PARAM_AUTH_MODE_T { + AUTH_MODE_OPEN, /*!< Open system */ + AUTH_MODE_SHARED, /*!< Shared key */ + AUTH_MODE_AUTO_SWITCH, /*!< Either open system or shared key */ + AUTH_MODE_WPA, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA_NONE, /*!< For Ad hoc */ + AUTH_MODE_WPA2, + AUTH_MODE_WPA2_PSK, + AUTH_MODE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_AUTH_MODE_T, *P_ENUM_PARAM_AUTH_MODE_T; + +/* NDIS_802_11_ENCRYPTION_STATUS *//* Encryption types */ +typedef enum _ENUM_WEP_STATUS_T { + ENUM_WEP_ENABLED, + ENUM_ENCRYPTION1_ENABLED = ENUM_WEP_ENABLED, + ENUM_WEP_DISABLED, + ENUM_ENCRYPTION_DISABLED = ENUM_WEP_DISABLED, + ENUM_WEP_KEY_ABSENT, + ENUM_ENCRYPTION1_KEY_ABSENT = ENUM_WEP_KEY_ABSENT, + ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION_NOT_SUPPORTED = ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION2_ENABLED, + ENUM_ENCRYPTION2_KEY_ABSENT, + ENUM_ENCRYPTION3_ENABLED, + ENUM_ENCRYPTION3_KEY_ABSENT +} ENUM_PARAM_ENCRYPTION_STATUS_T, *P_ENUM_PARAM_ENCRYPTION_STATUS_T; + +typedef UINT_8 PARAM_MAC_ADDRESS[PARAM_MAC_ADDR_LEN]; + +typedef UINT_32 PARAM_KEY_INDEX; +typedef UINT_64 PARAM_KEY_RSC; +typedef INT_32 PARAM_RSSI; + +typedef UINT_32 PARAM_FRAGMENTATION_THRESHOLD; +typedef UINT_32 PARAM_RTS_THRESHOLD; + +typedef UINT_8 PARAM_RATES[PARAM_MAX_LEN_RATES]; +typedef UINT_8 PARAM_RATES_EX[PARAM_MAX_LEN_RATES_EX]; + +typedef enum _ENUM_PARAM_PHY_TYPE_T { + PHY_TYPE_802_11ABG = 0, /*!< Can associated with 802.11abg AP, + Scan dual band. */ + PHY_TYPE_802_11BG, /*!< Can associated with 802_11bg AP, + Scan single band and not report 802_11a BSSs. */ + PHY_TYPE_802_11G, /*!< Can associated with 802_11g only AP, + Scan single band and not report 802_11ab BSSs. */ + PHY_TYPE_802_11A, /*!< Can associated with 802_11a only AP, + Scan single band and not report 802_11bg BSSs. */ + PHY_TYPE_802_11B, /*!< Can associated with 802_11b only AP, + Scan single band and not report 802_11ag BSSs. */ + PHY_TYPE_NUM /* 5 */ +} ENUM_PARAM_PHY_TYPE_T, *P_ENUM_PARAM_PHY_TYPE_T; + +typedef enum _ENUM_PARAM_OP_MODE_T { + NET_TYPE_IBSS = 0, /*!< Try to merge/establish an AdHoc, do periodic SCAN for merging. */ + NET_TYPE_INFRA, /*!< Try to join an Infrastructure, do periodic SCAN for joining. */ + NET_TYPE_AUTO_SWITCH, /*!< Try to join an Infrastructure, if fail then try to merge or + establish an AdHoc, do periodic SCAN for joining or merging. */ + NET_TYPE_DEDICATED_IBSS, /*!< Try to merge an AdHoc first, + if fail then establish AdHoc permanently, no more SCAN. */ + NET_TYPE_NUM /* 4 */ +} ENUM_PARAM_OP_MODE_T, *P_ENUM_PARAM_OP_MODE_T; + +typedef struct _PARAM_SSID_T { + UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ + UINT_8 aucSsid[PARAM_MAX_LEN_SSID]; + UINT_32 u4CenterFreq; +} PARAM_SSID_T, *P_PARAM_SSID_T; + +typedef struct _PARAM_CONNECT_T { + UINT_32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) SSID */ + UINT_8 *pucSsid; + UINT_8 *pucBssid; + UINT_32 u4CenterFreq; +} PARAM_CONNECT_T, *P_PARAM_CONNECT_T; + +/* This is enum defined for user to select an AdHoc Mode */ +typedef enum _ENUM_PARAM_AD_HOC_MODE_T { + AD_HOC_MODE_11B = 0, /*!< Create 11b IBSS if we support 802.11abg/802.11bg. */ + AD_HOC_MODE_MIXED_11BG, /*!< Create 11bg mixed IBSS if we support 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11G, /*!< Create 11g only IBSS if we support 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11A, /*!< Create 11a only IBSS if we support 802.11abg. */ + AD_HOC_MODE_NUM /* 4 */ +} ENUM_PARAM_AD_HOC_MODE_T, *P_ENUM_PARAM_AD_HOC_MODE_T; + +typedef enum _ENUM_PARAM_MEDIA_STATE_T { + PARAM_MEDIA_STATE_CONNECTED, + PARAM_MEDIA_STATE_DISCONNECTED, + PARAM_MEDIA_STATE_TO_BE_INDICATED /* for following MSDN re-association behavior */ +} ENUM_PARAM_MEDIA_STATE_T, *P_ENUM_PARAM_MEDIA_STATE_T; + +typedef enum _ENUM_PARAM_NETWORK_TYPE_T { + PARAM_NETWORK_TYPE_FH, + PARAM_NETWORK_TYPE_DS, + PARAM_NETWORK_TYPE_OFDM5, + PARAM_NETWORK_TYPE_OFDM24, + PARAM_NETWORK_TYPE_AUTOMODE, + PARAM_NETWORK_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_NETWORK_TYPE_T, *P_ENUM_PARAM_NETWORK_TYPE_T; + +typedef struct _PARAM_NETWORK_TYPE_LIST { + UINT_32 NumberOfItems; /*!< At least 1 */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkType[1]; +} PARAM_NETWORK_TYPE_LIST, *PPARAM_NETWORK_TYPE_LIST; + +typedef enum _ENUM_PARAM_PRIVACY_FILTER_T { + PRIVACY_FILTER_ACCEPT_ALL, + PRIVACY_FILTER_8021xWEP, + PRIVACY_FILTER_NUM +} ENUM_PARAM_PRIVACY_FILTER_T, *P_ENUM_PARAM_PRIVACY_FILTER_T; + +typedef enum _ENUM_RELOAD_DEFAULTS { + ENUM_RELOAD_WEP_KEYS +} PARAM_RELOAD_DEFAULTS, *P_PARAM_RELOAD_DEFAULTS; + +typedef struct _PARAM_PM_PACKET_PATTERN { + UINT_32 Priority; /* Importance of the given pattern. */ + UINT_32 Reserved; /* Context information for transports. */ + UINT_32 MaskSize; /* Size in bytes of the pattern mask. */ + UINT_32 PatternOffset; /* Offset from beginning of this */ + /* structure to the pattern bytes. */ + UINT_32 PatternSize; /* Size in bytes of the pattern. */ + UINT_32 PatternFlags; /* Flags (TBD). */ +} PARAM_PM_PACKET_PATTERN, *P_PARAM_PM_PACKET_PATTERN; + +/*--------------------------------------------------------------*/ +/*! \brief Struct definition to indicate specific event. */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_STATUS_TYPE_T { + ENUM_STATUS_TYPE_AUTHENTICATION, + ENUM_STATUS_TYPE_MEDIA_STREAM_MODE, + ENUM_STATUS_TYPE_CANDIDATE_LIST, + ENUM_STATUS_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_STATUS_TYPE_T, *P_ENUM_STATUS_TYPE_T; + +typedef struct _PARAM_802_11_CONFIG_FH_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4HopPattern; /*!< Defined as 802.11 */ + UINT_32 u4HopSet; /*!< to one if non-802.11 */ + UINT_32 u4DwellTime; /*!< In unit of Kusec */ +} PARAM_802_11_CONFIG_FH_T, *P_PARAM_802_11_CONFIG_FH_T; + +typedef struct _PARAM_802_11_CONFIG_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4BeaconPeriod; /*!< In unit of Kusec */ + UINT_32 u4ATIMWindow; /*!< In unit of Kusec */ + UINT_32 u4DSConfig; /*!< Channel frequency in unit of kHz */ + PARAM_802_11_CONFIG_FH_T rFHConfig; +} PARAM_802_11_CONFIG_T, *P_PARAM_802_11_CONFIG_T; + +typedef struct _PARAM_STATUS_INDICATION_T { + ENUM_STATUS_TYPE_T eStatusType; +} PARAM_STATUS_INDICATION_T, *P_PARAM_STATUS_INDICATION_T; + +typedef struct _PARAM_AUTH_REQUEST_T { + UINT_32 u4Length; /*!< Length of this struct */ + PARAM_MAC_ADDRESS arBssid; + UINT_32 u4Flags; /*!< Definitions are as follows */ +} PARAM_AUTH_REQUEST_T, *P_PARAM_AUTH_REQUEST_T; + +typedef struct _PARAM_AUTH_EVENT_T { + PARAM_STATUS_INDICATION_T rStatus; + PARAM_AUTH_REQUEST_T arRequest[1]; +} PARAM_AUTH_EVENT_T, *P_PARAM_AUTH_EVENT_T; + +/*! \brief Capabilities, privacy, rssi and IEs of each BSSID */ +typedef struct _PARAM_BSSID_EX_T { + UINT_32 u4Length; /*!< Length of structure */ + PARAM_MAC_ADDRESS arMacAddress; /*!< BSSID */ + UINT_8 Reserved[2]; + PARAM_SSID_T rSsid; /*!< SSID */ + UINT_32 u4Privacy; /*!< Need WEP encryption */ + PARAM_RSSI rRssi; /*!< in dBm */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkTypeInUse; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + PARAM_RATES_EX rSupportedRates; + UINT_32 u4IELength; + UINT_8 aucIEs[1]; +} PARAM_BSSID_EX_T, *P_PARAM_BSSID_EX_T; + +typedef struct _PARAM_BSSID_LIST_EX { + UINT_32 u4NumberOfItems; /*!< at least 1 */ + PARAM_BSSID_EX_T arBssid[1]; +} PARAM_BSSID_LIST_EX_T, *P_PARAM_BSSID_LIST_EX_T; + +typedef struct _PARAM_WEP_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< 0: pairwise key, others group keys */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} PARAM_WEP_T, *P_PARAM_WEP_T; + +/*! \brief Key mapping of BSSID */ +typedef struct _PARAM_KEY_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} PARAM_KEY_T, *P_PARAM_KEY_T; + +typedef struct _PARAM_REMOVE_KEY_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ +} PARAM_REMOVE_KEY_T, *P_PARAM_REMOVE_KEY_T; + +#if CFG_SUPPORT_WAPI +typedef enum _ENUM_KEY_TYPE { + ENUM_WPI_PAIRWISE_KEY = 0, + ENUM_WPI_GROUP_KEY +} ENUM_KEY_TYPE; + +typedef enum _ENUM_WPI_PROTECT_TYPE { + ENUM_WPI_NONE, + ENUM_WPI_RX, + ENUM_WPI_TX, + ENUM_WPI_RX_TX +} ENUM_WPI_PROTECT_TYPE; + +typedef struct _PARAM_WPI_KEY_T { + ENUM_KEY_TYPE eKeyType; + ENUM_WPI_PROTECT_TYPE eDirection; + UINT_8 ucKeyID; + UINT_8 aucRsv[3]; + UINT_8 aucAddrIndex[12]; + UINT_32 u4LenWPIEK; + UINT_8 aucWPIEK[256]; + UINT_32 u4LenWPICK; + UINT_8 aucWPICK[256]; + UINT_8 aucPN[16]; +} PARAM_WPI_KEY_T, *P_PARAM_WPI_KEY_T; +#endif + +typedef enum _PARAM_POWER_MODE { + Param_PowerModeCAM, + Param_PowerModeMAX_PSP, + Param_PowerModeFast_PSP, +#if CFG_SUPPORT_DBG_POWERMODE + Param_PowerModeKeepActiveOn, /* privilege mode, always active */ + Param_PowerModeKeepActiveOff, /* to leave privilege mode */ +#endif + Param_PowerModeMax /* Upper bound, not real case */ +} PARAM_POWER_MODE, *PPARAM_POWER_MODE; + +typedef enum _PARAM_DEVICE_POWER_STATE { + ParamDeviceStateUnspecified = 0, + ParamDeviceStateD0, + ParamDeviceStateD1, + ParamDeviceStateD2, + ParamDeviceStateD3, + ParamDeviceStateMaximum +} PARAM_DEVICE_POWER_STATE, *PPARAM_DEVICE_POWER_STATE; + +#if CFG_SUPPORT_802_11D + +/*! \brief The enumeration definitions for OID_IPN_MULTI_DOMAIN_CAPABILITY */ +typedef enum _PARAM_MULTI_DOMAIN_CAPABILITY { + ParamMultiDomainCapDisabled, + ParamMultiDomainCapEnabled +} PARAM_MULTI_DOMAIN_CAPABILITY, *P_PARAM_MULTI_DOMAIN_CAPABILITY; +#endif + +typedef struct _COUNTRY_STRING_ENTRY { + UINT_8 aucCountryCode[2]; + UINT_8 aucEnvironmentCode[2]; +} COUNTRY_STRING_ENTRY, *P_COUNTRY_STRING_ENTRY; + +/* Power management related definition and enumerations */ +#define UAPSD_NONE 0 +#define UAPSD_AC0 (BIT(0) | BIT(4)) +#define UAPSD_AC1 (BIT(1) | BIT(5)) +#define UAPSD_AC2 (BIT(2) | BIT(6)) +#define UAPSD_AC3 (BIT(3) | BIT(7)) +#define UAPSD_ALL (UAPSD_AC0 | UAPSD_AC1 | UAPSD_AC2 | UAPSD_AC3) + +typedef enum _ENUM_POWER_SAVE_PROFILE_T { + ENUM_PSP_CONTINUOUS_ACTIVE = 0, + ENUM_PSP_CONTINUOUS_POWER_SAVE, + ENUM_PSP_FAST_SWITCH, + ENUM_PSP_NUM +} ENUM_POWER_SAVE_PROFILE_T, *PENUM_POWER_SAVE_PROFILE_T; + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query testing type. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_802_11_TEST_T { + UINT_32 u4Length; + UINT_32 u4Type; + union { + PARAM_AUTH_EVENT_T AuthenticationEvent; + PARAM_RSSI RssiTrigger; + } u; +} PARAM_802_11_TEST_T, *P_PARAM_802_11_TEST_T; + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query authentication and encryption capability. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_AUTH_ENCRYPTION_T { + ENUM_PARAM_AUTH_MODE_T eAuthModeSupported; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncryptStatusSupported; +} PARAM_AUTH_ENCRYPTION_T, *P_PARAM_AUTH_ENCRYPTION_T; + +typedef struct _PARAM_CAPABILITY_T { + UINT_32 u4Length; + UINT_32 u4Version; + UINT_32 u4NoOfPMKIDs; + UINT_32 u4NoOfAuthEncryptPairsSupported; + PARAM_AUTH_ENCRYPTION_T arAuthenticationEncryptionSupported[1]; +} PARAM_CAPABILITY_T, *P_PARAM_CAPABILITY_T; + +typedef UINT_8 PARAM_PMKID_VALUE[16]; + +typedef struct _PARAM_BSSID_INFO_T { + PARAM_MAC_ADDRESS arBSSID; + PARAM_PMKID_VALUE arPMKID; +} PARAM_BSSID_INFO_T, *P_PARAM_BSSID_INFO_T; + +typedef struct _PARAM_PMKID_T { + UINT_32 u4Length; + UINT_32 u4BSSIDInfoCount; + PARAM_BSSID_INFO_T arBSSIDInfo[1]; +} PARAM_PMKID_T, *P_PARAM_PMKID_T; + +/*! \brief PMKID candidate lists. */ +typedef struct _PARAM_PMKID_CANDIDATE_T { + PARAM_MAC_ADDRESS arBSSID; + UINT_32 u4Flags; +} PARAM_PMKID_CANDIDATE_T, *P_PARAM_PMKID_CANDIDATE_T; + +/* #ifdef LINUX */ +typedef struct _PARAM_PMKID_CANDIDATE_LIST_T { + UINT_32 u4Version; /*!< Version */ + UINT_32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} PARAM_PMKID_CANDIDATE_LIST_T, *P_PARAM_PMKID_CANDIDATE_LIST_T; +/* #endif */ + +typedef struct _PARAM_CUSTOM_MCR_RW_STRUCT_T { + UINT_32 u4McrOffset; + UINT_32 u4McrData; +} PARAM_CUSTOM_MCR_RW_STRUCT_T, *P_PARAM_CUSTOM_MCR_RW_STRUCT_T; + +typedef struct _PARAM_CUSTOM_MEM_DUMP_STRUCT_T { + UINT_32 u4Address; + UINT_32 u4Length; + UINT_32 u4RemainLength; + UINT_8 ucFragNum; +} PARAM_CUSTOM_MEM_DUMP_STRUCT_T, *P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T; + +typedef struct _PARAM_CUSTOM_SW_CTRL_STRUCT_T { + UINT_32 u4Id; + UINT_32 u4Data; +} PARAM_CUSTOM_SW_CTRL_STRUCT_T, *P_PARAM_CUSTOM_SW_CTRL_STRUCT_T; + +typedef struct _CMD_CHIP_CONFIG_T { + UINT_16 u2Id; + UINT_8 ucType; + UINT_8 ucRespType; + UINT_16 u2MsgSize; + UINT_8 aucReserved0[2]; + UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; +} CMD_CHIP_CONFIG_T, *P_CMD_CHIP_CONFIG_T; + +typedef struct _PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T { + UINT_16 u2Id; + UINT_8 ucType; + UINT_8 ucRespType; + UINT_16 u2MsgSize; + UINT_8 aucReserved0[2]; + UINT_8 aucCmd[CHIP_CONFIG_RESP_SIZE]; +} PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T, *P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T; + +typedef struct _PARAM_CUSTOM_KEY_CFG_STRUCT_T { + UINT_8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + UINT_8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; +} PARAM_CUSTOM_KEY_CFG_STRUCT_T, *P_PARAM_CUSTOM_KEY_CFG_STRUCT_T; + +typedef struct _PARAM_CUSTOM_EEPROM_RW_STRUCT_T { + UINT_8 ucEepromMethod; /* For read only read: 1, query size: 0 */ + UINT_8 ucEepromIndex; + UINT_8 reserved; + UINT_16 u2EepromData; +} PARAM_CUSTOM_EEPROM_RW_STRUCT_T, *P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T, +PARAM_CUSTOM_NVRAM_RW_STRUCT_T, *P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T; + +typedef struct _PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T { + UINT_8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + UINT_8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard after connected */ + UINT_8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched (under U-APSD) */ + UINT_8 reserved; +} PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T, *P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T; + +typedef struct _PARAM_CUSTOM_NOA_PARAM_STRUCT_T { + UINT_32 u4NoaDurationMs; + UINT_32 u4NoaIntervalMs; + UINT_32 u4NoaCount; +} PARAM_CUSTOM_NOA_PARAM_STRUCT_T, *P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T { + UINT_32 u4CTwindowMs; +} PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T { + UINT_8 fgEnAPSD; + UINT_8 fgEnAPSD_AcBe; + UINT_8 fgEnAPSD_AcBk; + UINT_8 fgEnAPSD_AcVo; + UINT_8 fgEnAPSD_AcVi; + UINT_8 ucMaxSpLen; + UINT_8 aucResv[2]; +} PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { + UINT_32 u4Enable; + UINT_32 u4Mode; +} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; + +typedef enum _ENUM_CFG_SRC_TYPE_T { + CFG_SRC_TYPE_EEPROM, + CFG_SRC_TYPE_NVRAM, + CFG_SRC_TYPE_UNKNOWN, + CFG_SRC_TYPE_NUM +} ENUM_CFG_SRC_TYPE_T, *P_ENUM_CFG_SRC_TYPE_T; + +typedef enum _ENUM_EEPROM_TYPE_T { + EEPROM_TYPE_NO, + EEPROM_TYPE_PRESENT, + EEPROM_TYPE_NUM +} ENUM_EEPROM_TYPE_T, *P_ENUM_EEPROM_TYPE_T; + +typedef struct _PARAM_QOS_TSINFO { + UINT_8 ucTrafficType; /* Traffic Type: 1 for isochronous 0 for asynchronous */ + UINT_8 ucTid; /* TSID: must be between 8 ~ 15 */ + UINT_8 ucDirection; /* direction */ + UINT_8 ucAccessPolicy; /* access policy */ + UINT_8 ucAggregation; /* aggregation */ + UINT_8 ucApsd; /* APSD */ + UINT_8 ucuserPriority; /* user priority */ + UINT_8 ucTsInfoAckPolicy; /* TSINFO ACK policy */ + UINT_8 ucSchedule; /* Schedule */ +} PARAM_QOS_TSINFO, *P_PARAM_QOS_TSINFO; + +typedef struct _PARAM_QOS_TSPEC { + PARAM_QOS_TSINFO rTsInfo; /* TS info field */ + UINT_16 u2NominalMSDUSize; /* nominal MSDU size */ + UINT_16 u2MaxMSDUsize; /* maximum MSDU size */ + UINT_32 u4MinSvcIntv; /* minimum service interval */ + UINT_32 u4MaxSvcIntv; /* maximum service interval */ + UINT_32 u4InactIntv; /* inactivity interval */ + UINT_32 u4SpsIntv; /* suspension interval */ + UINT_32 u4SvcStartTime; /* service start time */ + UINT_32 u4MinDataRate; /* minimum Data rate */ + UINT_32 u4MeanDataRate; /* mean data rate */ + UINT_32 u4PeakDataRate; /* peak data rate */ + UINT_32 u4MaxBurstSize; /* maximum burst size */ + UINT_32 u4DelayBound; /* delay bound */ + UINT_32 u4MinPHYRate; /* minimum PHY rate */ + UINT_16 u2Sba; /* surplus bandwidth allowance */ + UINT_16 u2MediumTime; /* medium time */ +} PARAM_QOS_TSPEC, *P_PARAM_QOS_TSPEC; + +typedef struct _PARAM_QOS_ADDTS_REQ_INFO { + PARAM_QOS_TSPEC rTspec; +} PARAM_QOS_ADDTS_REQ_INFO, *P_PARAM_QOS_ADDTS_REQ_INFO; + +typedef struct _PARAM_VOIP_CONFIG { + UINT_32 u4VoipTrafficInterval; /* 0: disable VOIP configuration */ +} PARAM_VOIP_CONFIG, *P_PARAM_VOIP_CONFIG; + +/*802.11 Statistics Struct*/ +typedef struct _PARAM_802_11_STATISTICS_STRUCT_T { + UINT_32 u4Length; /* Length of structure */ + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; + LARGE_INTEGER rTKIPLocalMICFailures; + LARGE_INTEGER rTKIPICVErrors; + LARGE_INTEGER rTKIPCounterMeasuresInvoked; + LARGE_INTEGER rTKIPReplays; + LARGE_INTEGER rCCMPFormatErrors; + LARGE_INTEGER rCCMPReplays; + LARGE_INTEGER rCCMPDecryptErrors; + LARGE_INTEGER rFourWayHandshakeFailures; + LARGE_INTEGER rWEPUndecryptableCount; + LARGE_INTEGER rWEPICVErrorCount; + LARGE_INTEGER rDecryptSuccessCount; + LARGE_INTEGER rDecryptFailureCount; +} PARAM_802_11_STATISTICS_STRUCT_T, *P_PARAM_802_11_STATISTICS_STRUCT_T; + +/* Linux Network Device Statistics Struct */ +typedef struct _PARAM_LINUX_NETDEV_STATISTICS_T { + UINT_32 u4RxPackets; + UINT_32 u4TxPackets; + UINT_32 u4RxBytes; + UINT_32 u4TxBytes; + UINT_32 u4RxErrors; + UINT_32 u4TxErrors; + UINT_32 u4Multicast; +} PARAM_LINUX_NETDEV_STATISTICS_T, *P_PARAM_LINUX_NETDEV_STATISTICS_T; + +typedef struct _PARAM_MTK_WIFI_TEST_STRUCT_T { + UINT_32 u4FuncIndex; + UINT_32 u4FuncData; +} PARAM_MTK_WIFI_TEST_STRUCT_T, *P_PARAM_MTK_WIFI_TEST_STRUCT_T; + +/* 802.11 Media stream constraints */ +typedef enum _ENUM_MEDIA_STREAM_MODE { + ENUM_MEDIA_STREAM_OFF, + ENUM_MEDIA_STREAM_ON +} ENUM_MEDIA_STREAM_MODE, *P_ENUM_MEDIA_STREAM_MODE; + +/* for NDIS 5.1 Media Streaming Change */ +typedef struct _PARAM_MEDIA_STREAMING_INDICATION { + PARAM_STATUS_INDICATION_T rStatus; + ENUM_MEDIA_STREAM_MODE eMediaStreamMode; +} PARAM_MEDIA_STREAMING_INDICATION, *P_PARAM_MEDIA_STREAMING_INDICATION; + +#define PARAM_PROTOCOL_ID_DEFAULT 0x00 +#define PARAM_PROTOCOL_ID_TCP_IP 0x02 +#define PARAM_PROTOCOL_ID_IPX 0x06 +#define PARAM_PROTOCOL_ID_NBF 0x07 +#define PARAM_PROTOCOL_ID_MAX 0x0F +#define PARAM_PROTOCOL_ID_MASK 0x0F + +/* for NDIS OID_GEN_NETWORK_LAYER_ADDRESSES */ +typedef struct _PARAM_NETWORK_ADDRESS_IP { + UINT_16 sin_port; + UINT_32 in_addr; + UINT_8 sin_zero[8]; +} PARAM_NETWORK_ADDRESS_IP, *P_PARAM_NETWORK_ADDRESS_IP; + +typedef struct _PARAM_NETWORK_ADDRESS { + UINT_16 u2AddressLength; /* length in bytes of Address[] in this */ + UINT_16 u2AddressType; /* type of this address (PARAM_PROTOCOL_ID_XXX above) */ + UINT_8 aucAddress[1]; /* actually AddressLength bytes long */ +} PARAM_NETWORK_ADDRESS, *P_PARAM_NETWORK_ADDRESS; + +/* The following is used with OID_GEN_NETWORK_LAYER_ADDRESSES to set network layer addresses on an interface */ + +typedef struct _PARAM_NETWORK_ADDRESS_LIST { + UINT_32 u4AddressCount; /* number of addresses following */ + UINT_16 u2AddressType; /* type of this address (NDIS_PROTOCOL_ID_XXX above) */ + PARAM_NETWORK_ADDRESS arAddress[1]; /* actually AddressCount elements long */ +} PARAM_NETWORK_ADDRESS_LIST, *P_PARAM_NETWORK_ADDRESS_LIST; + +#if CFG_SLT_SUPPORT + +#define FIXED_BW_LG20 0x0000 +#define FIXED_BW_UL20 0x2000 +#define FIXED_BW_DL40 0x3000 + +#define FIXED_EXT_CHNL_U20 0x4000 /* For AGG register. */ +#define FIXED_EXT_CHNL_L20 0xC000 /* For AGG regsiter. */ + +typedef enum _ENUM_MTK_LP_TEST_MODE_T { + ENUM_MTK_LP_TEST_NORMAL, + ENUM_MTK_LP_TEST_GOLDEN_SAMPLE, + ENUM_MTK_LP_TEST_DUT, + ENUM_MTK_LP_TEST_MODE_NUM +} ENUM_MTK_LP_TEST_MODE_T, *P_ENUM_MTK_LP_TEST_MODE_T; + +typedef enum _ENUM_MTK_SLT_FUNC_IDX_T { + ENUM_MTK_SLT_FUNC_DO_NOTHING, + ENUM_MTK_SLT_FUNC_INITIAL, + ENUM_MTK_SLT_FUNC_RATE_SET, + ENUM_MTK_SLT_FUNC_LP_SET, + ENUM_MTK_SLT_FUNC_NUM +} ENUM_MTK_SLT_FUNC_IDX_T, *P_ENUM_MTK_SLT_FUNC_IDX_T; + +typedef struct _PARAM_MTK_SLT_LP_TEST_STRUCT_T { + ENUM_MTK_LP_TEST_MODE_T rLpTestMode; + UINT_32 u4BcnRcvNum; +} PARAM_MTK_SLT_LP_TEST_STRUCT_T, *P_PARAM_MTK_SLT_LP_TEST_STRUCT_T; + +typedef struct _PARAM_MTK_SLT_TR_TEST_STRUCT_T { + ENUM_PARAM_NETWORK_TYPE_T rNetworkType; /* Network Type OFDM5G or OFDM2.4G */ + UINT_32 u4FixedRate; /* Fixed Rate including BW */ +} PARAM_MTK_SLT_TR_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TR_TEST_STRUCT_T; + +typedef struct _PARAM_MTK_SLT_INITIAL_STRUCT_T { + UINT_8 aucTargetMacAddr[PARAM_MAC_ADDR_LEN]; + UINT_16 u2SiteID; +} PARAM_MTK_SLT_INITIAL_STRUCT_T, *P_PARAM_MTK_SLT_INITIAL_STRUCT_T; + +typedef struct _PARAM_MTK_SLT_TEST_STRUCT_T { + ENUM_MTK_SLT_FUNC_IDX_T rSltFuncIdx; + UINT_32 u4Length; /* Length of structure, + including myself */ + UINT_32 u4FuncInfoLen; /* Include following content + field and myself */ + union { + PARAM_MTK_SLT_INITIAL_STRUCT_T rMtkInitTest; + PARAM_MTK_SLT_LP_TEST_STRUCT_T rMtkLpTest; + PARAM_MTK_SLT_TR_TEST_STRUCT_T rMtkTRTest; + } unFuncInfoContent; + +} PARAM_MTK_SLT_TEST_STRUCT_T, *P_PARAM_MTK_SLT_TEST_STRUCT_T; + +#endif + +/*--------------------------------------------------------------*/ +/*! \brief For Fixed Rate Configuration (Registry) */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_REGISTRY_FIXED_RATE_T { + FIXED_RATE_NONE, + FIXED_RATE_1M, + FIXED_RATE_2M, + FIXED_RATE_5_5M, + FIXED_RATE_11M, + FIXED_RATE_6M, + FIXED_RATE_9M, + FIXED_RATE_12M, + FIXED_RATE_18M, + FIXED_RATE_24M, + FIXED_RATE_36M, + FIXED_RATE_48M, + FIXED_RATE_54M, + FIXED_RATE_MCS0_20M_800NS, + FIXED_RATE_MCS1_20M_800NS, + FIXED_RATE_MCS2_20M_800NS, + FIXED_RATE_MCS3_20M_800NS, + FIXED_RATE_MCS4_20M_800NS, + FIXED_RATE_MCS5_20M_800NS, + FIXED_RATE_MCS6_20M_800NS, + FIXED_RATE_MCS7_20M_800NS, + FIXED_RATE_MCS0_20M_400NS, + FIXED_RATE_MCS1_20M_400NS, + FIXED_RATE_MCS2_20M_400NS, + FIXED_RATE_MCS3_20M_400NS, + FIXED_RATE_MCS4_20M_400NS, + FIXED_RATE_MCS5_20M_400NS, + FIXED_RATE_MCS6_20M_400NS, + FIXED_RATE_MCS7_20M_400NS, + FIXED_RATE_MCS0_40M_800NS, + FIXED_RATE_MCS1_40M_800NS, + FIXED_RATE_MCS2_40M_800NS, + FIXED_RATE_MCS3_40M_800NS, + FIXED_RATE_MCS4_40M_800NS, + FIXED_RATE_MCS5_40M_800NS, + FIXED_RATE_MCS6_40M_800NS, + FIXED_RATE_MCS7_40M_800NS, + FIXED_RATE_MCS32_800NS, + FIXED_RATE_MCS0_40M_400NS, + FIXED_RATE_MCS1_40M_400NS, + FIXED_RATE_MCS2_40M_400NS, + FIXED_RATE_MCS3_40M_400NS, + FIXED_RATE_MCS4_40M_400NS, + FIXED_RATE_MCS5_40M_400NS, + FIXED_RATE_MCS6_40M_400NS, + FIXED_RATE_MCS7_40M_400NS, + FIXED_RATE_MCS32_400NS, + FIXED_RATE_NUM +} ENUM_REGISTRY_FIXED_RATE_T, *P_ENUM_REGISTRY_FIXED_RATE_T; + +typedef enum _ENUM_BT_CMD_T { + BT_CMD_PROFILE = 0, + BT_CMD_UPDATE, + BT_CMD_NUM +} ENUM_BT_CMD_T; + +typedef enum _ENUM_BT_PROFILE_T { + BT_PROFILE_CUSTOM = 0, + BT_PROFILE_SCO, + BT_PROFILE_ACL, + BT_PROFILE_MIXED, + BT_PROFILE_NO_CONNECTION, + BT_PROFILE_NUM +} ENUM_BT_PROFILE_T; + +typedef struct _PTA_PROFILE_T { + ENUM_BT_PROFILE_T eBtProfile; + union { + UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + /* 0: sco reserved slot time, + 1: sco idle slot time, + 2: acl throughput, + 3: bt tx power, + 4: bt rssi + 5: VoIP interval + 6: BIT(0) Use this field, BIT(1) 0 apply single/ 1 dual PTA setting. + */ + UINT_32 au4Btcr[4]; + } u; +} PTA_PROFILE_T, *P_PTA_PROFILE_T; + +typedef struct _PTA_IPC_T { + UINT_8 ucCmd; + UINT_8 ucLen; + union { + PTA_PROFILE_T rProfile; + UINT_8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + } u; +} PARAM_PTA_IPC_T, *P_PARAM_PTA_IPC_T, PTA_IPC_T, *P_PTA_IPC_T; + +/*--------------------------------------------------------------*/ +/*! \brief CFG80211 Scan Request Container */ +/*--------------------------------------------------------------*/ + +typedef struct _PARAM_SCAN_REQUEST_EXT_T { + PARAM_SSID_T rSsid; + UINT_32 u4IELength; + PUINT_8 pucIE; +} PARAM_SCAN_REQUEST_EXT_T, *P_PARAM_SCAN_REQUEST_EXT_T; + +/*--------------------------------------------------------------*/ +/*! \brief CFG80211 Scheduled Scan Request Container */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_SCHED_SCAN_REQUEST_T { + UINT_32 u4SsidNum; + PARAM_SSID_T arSsid[CFG_SCAN_SSID_MATCH_MAX_NUM]; + UINT_32 u4IELength; + PUINT_8 pucIE; + UINT_16 u2ScanInterval; /* in milliseconds */ +} PARAM_SCHED_SCAN_REQUEST, *P_PARAM_SCHED_SCAN_REQUEST; + +#if CFG_SUPPORT_HOTSPOT_2_0 +typedef struct _PARAM_HS20_SET_BSSID_POOL { + BOOLEAN fgIsEnable; + UINT_8 ucNumBssidPool; + PARAM_MAC_ADDRESS arBSSID[8]; +} PARAM_HS20_SET_BSSID_POOL, *P_PARAM_HS20_SET_BSSID_POOL; + +#endif + +typedef struct _PARAM_CUSTOM_WFD_DEBUG_STRUCT_T { + UINT_8 ucWFDDebugMode; /* 0: Disable + 1:Enable but only show inqueue skb ether SN + 2.show skb ether SN and the statistics of skb inqueue time */ + UINT_16 u2SNPeriod; /* The Ether SN Period */ + + UINT_8 reserved; +} PARAM_CUSTOM_WFD_DEBUG_STRUCT_T, *P_PARAM_CUSTOM_WFD_DEBUG_STRUCT_T; + +typedef struct _CMD_GET_PSCAN_CAPABILITY { +/* TBD */ +} CMD_GET_GSCAN_CAPABILITY, *P_CMD_GET_GSCAN_CAPABILITY; + +typedef struct _CMD_SET_PSCAN_ENABLE { + UINT_8 ucPscanAct; + UINT_8 aucReserved[3]; +} CMD_SET_PSCAN_ENABLE, *P_CMD_SET_PSCAN_ENABLE; + +typedef enum _ENUM_PSCAN_ACT_T { + ENABLE, + DISABLE, + SUSPEND, + CLEAR +} ENUM_PSCAN_ACT_T, *P_ENUM_PSCAN_ACT_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*--------------------------------------------------------------*/ +/* Routines to set parameters or query information. */ +/*--------------------------------------------------------------*/ +/***** Routines in wlan_oid.c *****/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetConnect(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +#if 0 +WLAN_STATUS +wlanoidQueryPrivacyFilter(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetPrivacyFilter(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +_wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, IN BOOLEAN fgIsOid, IN UINT_8 ucAlgorithmId, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetChannel(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID prSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuf, IN UINT_32 u4QueryBufLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRfTestRxStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRfTestTxStatus(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); +WLAN_STATUS +wlanoidQueryStatisticsPL(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +#ifdef LINUX + +WLAN_STATUS +wlanoidQueryStatisticsForLinux(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +#endif + +WLAN_STATUS +wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +WLAN_STATUS +wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +/* RF Test related APIs */ +WLAN_STATUS +wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, + OUT PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +#if CFG_SUPPORT_WAPI +WLAN_STATUS +wlanoidSetWapiMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetWapiAssocInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetWapiKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +#if CFG_SUPPORT_WPS2 +WLAN_STATUS +wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 u4QueryInfoLen); + +WLAN_STATUS +wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBSSInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen); + +#if CFG_SLT_SUPPORT + +WLAN_STATUS +wlanoidQuerySLTStatus(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidUpdateSLTMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +#endif + +#if 0 +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBT(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +#if CFG_SUPPORT_BUILD_DATE_CODE +WLAN_STATUS +wlanoidQueryBuildDateCode(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +#endif + +/* +WLAN_STATUS +wlanoidQueryBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); + +WLAN_STATUS +wlanoidSetBtSingleAntenna ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidSetPta ( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +WLAN_STATUS +wlanoidQueryPta ( + IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, + IN UINT_32 u4QueryBufferLen, + OUT PUINT_32 pu4QueryInfoLen + ); +*/ + +#if CFG_ENABLE_WIFI_DIRECT +WLAN_STATUS +wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +#if CFG_SUPPORT_BATCH_SCAN +WLAN_STATUS +wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 +WLAN_STATUS +wlanoidSetHS20Info(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetInterworkingInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRoamingConsortiumIEInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetHS20BssidPool(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetRoamingInfo(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetWfdDebugMode(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetGSCNAction(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetGSCNAParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetGSCNAConfig(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetGSCNResult(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetTxRateInfo( + IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen + ); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +WLAN_STATUS +wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +WLAN_STATUS +wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, + IN UINT_32 u4SetBufferLen, + OUT PUINT_32 pu4SetInfoLen); + +#endif /* _WLAN_OID_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h new file mode 100644 index 0000000000000..0b558d64034d4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/include/wlan_p2p.h @@ -0,0 +1,307 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/include/wlan_p2p.h#3 +*/ + +/*! \file "wlan_p2p.h" + \brief This file contains the declairations of Wi-Fi Direct command + processing routines for MediaTek Inc. 802.11 Wireless LAN Adapters. +*/ + +/* +** Log: wlan_p2p.h + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version + * query & set support for service discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channel Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface + * for supporting Wi-Fi Direct Service Discovery + * ioctl implementations for P2P Service Discovery + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface + * for supporting Wi-Fi Direct Service Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * support wlanoidSetP2pPowerSaveProfile() in P2P + * + * 08 16 2010 george.huang + * NULL + * Support wlanoidSetNetworkAddress() for P2P + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * MT6620 is not supporting NDIS_PACKET_TYPE_PROMISCUOUS. + * + + * +** +*/ + +#ifndef _WLAN_P2P_H +#define _WLAN_P2P_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* Service Discovery */ +typedef struct _PARAM_P2P_SEND_SD_RESPONSE { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucChannelNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_SEND_SD_RESPONSE, *P_PARAM_P2P_SEND_SD_RESPONSE; + +typedef struct _PARAM_P2P_GET_SD_REQUEST { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_REQUEST, *P_PARAM_P2P_GET_SD_REQUEST; + +typedef struct _PARAM_P2P_GET_SD_REQUEST_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 ucChannelNum; /* Channel Number Where SD Request is received. */ + UINT_8 ucSeqNum; /* Get SD Request by sequence number. */ + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_REQUEST_EX, *P_PARAM_P2P_GET_SD_REQUEST_EX; + +typedef struct _PARAM_P2P_SEND_SD_REQUEST { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucVersionNum; /* Indicate the Service Discovery Supplicant Version. */ + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_SEND_SD_REQUEST, *P_PARAM_P2P_SEND_SD_REQUEST; + +/* Service Discovery 1.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_RESPONSE, *P_PARAM_P2P_GET_SD_RESPONSE; + +/* Service Discovery 2.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 ucSeqNum; /* Get SD Response by sequence number. */ + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_RESPONSE_EX, *P_PARAM_P2P_GET_SD_RESPONSE_EX; + +typedef struct _PARAM_P2P_TERMINATE_SD_PHASE { + PARAM_MAC_ADDRESS rPeerAddr; +} PARAM_P2P_TERMINATE_SD_PHASE, *P_PARAM_P2P_TERMINATE_SD_PHASE; + +/*! \brief Key mapping of BSSID */ +typedef struct _P2P_PARAM_KEY_T { + UINT_32 u4Length; /*!< Length of structure */ + UINT_32 u4KeyIndex; /*!< KeyID */ + UINT_32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + UINT_8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} P2P_PARAM_KEY_T, *P_P2P_PARAM_KEY_T; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*--------------------------------------------------------------*/ +/* Routines to handle command */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +/*--------------------------------------------------------------*/ +/* Service Discovery Subroutines */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 puQueryInfoLen); + +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +#if CFG_SUPPORT_ANTI_PIRACY +WLAN_STATUS +wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); +#endif + +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryP2pOpChannel(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); +#endif + +/*--------------------------------------------------------------*/ +/* Callbacks for event indication */ +/*--------------------------------------------------------------*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif +#endif /* _WLAN_P2P_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c new file mode 100644 index 0000000000000..f2324f13280e3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/aaa_fsm.c @@ -0,0 +1,1303 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/aaa_fsm.c#2 +*/ + +/*! \file "aaa_fsm.c" + \brief This file defines the FSM for AAA MODULE. + + This file defines the FSM for AAA MODULE. +*/ + +/* +** Log: aaa_fsm.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 02 22 2012 yuche.tsai + * NULL + * Solve sigma test 5.1.3 issue, assoc response should have P2P IE. + * + * 12 02 2011 yuche.tsai + * NULL + * Resolve inorder issue under AP mode. + * + * data frame may TX before assoc response frame. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 06 17 2011 terry.wu + * NULL + * Add BoW 11N support. + * + * 06 02 2011 eddie.chen + * [WCXRP00000759] [MT6620 Wi-Fi][DRV] Update RCPI in AAA + * Update RCPI when receiving Assoc request. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 09 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * Skip to call p2pRunEventAAAComplete to avoid indicate STA connect twice. + * + * 03 04 2011 terry.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * Remove unused variable. + * + * 02 16 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Add more check after RX assoc frame under Hot-Spot mode. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 15 2011 puff.wen + * NULL + * [On behalf of Frog] Add CFG_ENABLE_WIFI_DIRECT to p2pRunEventAAAComplete + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify AAA flow according to CM's comment. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 29 2010 yuche.tsai + * NULL + * Fix Compile warning, type cast from UINT_32 to UINT_16. + * + * 08 26 2010 yuche.tsai + * NULL + * In P2P AT GO test mode under WinXP, we would not indicate connected event to host. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 17 2010 yuche.tsai + * NULL + * Fix bug while enabling P2P GO. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * modify due to P2P functino call prototype change. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 04 02 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify CFG flags + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * add support of Driver STA_RECORD_T activation + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Event to AIS/BOW/P2P +* +* @param[in] rJoinStatus To indicate JOIN success or failure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prSwRfb Pointer to the SW_RFB_T + +* @return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS aaaFsmSendEventJoinComplete(WLAN_STATUS rJoinStatus, P_STA_RECORD_T prStaRec, P_SW_RFB_T prSwRfb) +{ + P_MSG_SAA_JOIN_COMP_T prJoinCompMsg; + + ASSERT(prStaRec); + + prJoinCompMsg = cnmMemAlloc(RAM_TYPE_TCM, sizeof(MSG_SAA_JOIN_COMP_T)); + if (!prJoinCompMsg) + return WLAN_STATUS_RESOURCES; + + if (IS_STA_IN_AIS(prStaRec)) + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; + else if (IS_STA_IN_P2P(prStaRec)) + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; + else if (IS_STA_IN_BOW(prStaRec)) + prJoinCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; + else + ASSERT(0); + + prJoinCompMsg->rJoinStatus = rJoinStatus; + prJoinCompMsg->prStaRec = prStaRec; + prJoinCompMsg->prSwRfb = prSwRfb; + + mboxSendMsg(MBOX_ID_0, (P_MSG_HDR_T) prJoinCompMsg, MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmSendEventJoinComplete() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Start Event to AAA FSM. +* +* @param[in] prMsgHdr Message of Join Request for a particular STA. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aaaFsmRunEventStart(IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SAA_JOIN_REQ_T prJoinReqMsg; + P_STA_RECORD_T prStaRec; + P_AIS_BSS_INFO_T prAisBssInfo; + + ASSERT(prMsgHdr); + + prJoinReqMsg = (P_MSG_SAA_JOIN_REQ_T) prMsgHdr; + prStaRec = prJoinReqMsg->prStaRec; + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM\n"); + + cnmMemFree(prMsgHdr); + + /* 4 <1> Validation of SAA Start Event */ + if (!IS_AP_STA(prStaRec->eStaType)) { + + DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); + + /* Ignore the return value because don't care the prSwRfb */ + saaFsmSendEventJoinComplete(WLAN_STATUS_FAILURE, prStaRec, NULL); + + return; + } + /* 4 <2> The previous JOIN process is not completed ? */ + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); + prStaRec->eAuthAssocState = AA_STATE_IDLE; + } + /* 4 <3> Reset Status Code and Time */ + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); + + prStaRec->ucTxAuthAssocRetryCount = 0; + + if (prStaRec->prChallengeText) { + cnmMemFree(prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; + } + + cnmTimerStopTimer(&prStaRec->rTxReqDoneOrRxRespTimer); + + prStaRec->ucStaState = STA_STATE_1; + + /* Trigger SAA MODULE */ + saaFsmSteps(prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); + +} /* end of saaFsmRunEventStart() */ +#endif + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Auth Request Frame and then +* trigger AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + UINT_16 u2StatusCode; + BOOLEAN fgReplyAuth = FALSE; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + + ASSERT(prAdapter); + + do { + + /* 4 <1> Check P2P network conditions */ +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prBssInfo->fgIsNetActive) { + + /* 4 <1.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ + if (WLAN_STATUS_SUCCESS == + authProcessRxAuth1Frame(prAdapter, + prSwRfb, + prBssInfo->aucBSSID, + AUTH_ALGORITHM_NUM_OPEN_SYSTEM, + AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + /* 4 <1.2> Validate Auth Frame for Network Specific Conditions */ + fgReplyAuth = p2pFuncValidateAuth(prAdapter, + prSwRfb, &prStaRec, &u2StatusCode); + } else { + fgReplyAuth = TRUE; + } + eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + break; + } + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + /* 4 <2> Check BOW network conditions */ +#if CFG_ENABLE_BT_OVER_WIFI + { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { + + /* 4 <2.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + authProcessRxAuth1Frame(prAdapter, + prSwRfb, + prBssInfo->aucBSSID, + AUTH_ALGORITHM_NUM_OPEN_SYSTEM, + AUTH_TRANSACTION_SEQ_1, &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + + /* 4 <2.2> Validate Auth Frame for Network Specific Conditions */ + fgReplyAuth = + bowValidateAuth(prAdapter, prSwRfb, &prStaRec, &u2StatusCode); + + } else { + + fgReplyAuth = TRUE; + } + eNetTypeIndex = NETWORK_TYPE_BOW_INDEX; + /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ + break; + } + } + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + return; + } while (FALSE); + + if (prStaRec) { + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + } + /* 4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame */ + if (fgReplyAuth) { + + if (prStaRec) { + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(AAA, WARN, "Previous AuthAssocState (%d) != IDLE.\n", + prStaRec->eAuthAssocState); + } + + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + } else { + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else { + /* NOTE(Kevin): We should have STA_RECORD_T if the status code was successful */ + ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL)); + } + + /* NOTE: Ignore the return status for AAA */ + /* 4 <4> Reply Auth */ + authSendAuthFrame(prAdapter, prStaRec, eNetTypeIndex, prSwRfb, AUTH_TRANSACTION_SEQ_2, u2StatusCode); + + } + +} /* end of aaaFsmRunEventRxAuth() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx (Re)Association Request Frame and then +* trigger AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + UINT_16 u2StatusCode = STATUS_CODE_RESERVED; + BOOLEAN fgReplyAssocResp = FALSE; + + ASSERT(prAdapter); + + do { + + /* 4 <1> Check if we have the STA_RECORD_T for incoming Assoc Req */ + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + ASSERT(0); /* Only for debug phase */ + break; + } + + if (!IS_CLIENT_STA(prStaRec)) + break; + + if (prStaRec->ucStaState == STA_STATE_3) { + /* Do Reassocation */ + } else if ((prStaRec->ucStaState == STA_STATE_2) && + (prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2)) { + /* Normal case */ + } else { + DBGLOG(AAA, INFO, "Previous AuthAssocState (%d) != SEND_AUTH2, ucStaState:%d.\n", + prStaRec->eAuthAssocState, + prStaRec->ucStaState); + /* TODO: Why assoc req event is faster than tx done of auth */ + if (prStaRec->eAuthAssocState != AAA_STATE_SEND_AUTH2) + break; + } + + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + + /* 4 <2> Check P2P network conditions */ +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prBssInfo->fgIsNetActive) { + + /* 4 <2.1> Validate Assoc Req Frame and get Status Code */ + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + /* 4 <2.2> Validate Assoc Req Frame for Network Specific Conditions */ + fgReplyAssocResp = p2pFuncValidateAssocReq(prAdapter, + prSwRfb, + (PUINT_16)&u2StatusCode); + } else { + fgReplyAssocResp = TRUE; + } + + break; + } + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + /* 4 <3> Check BOW network conditions */ +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]); + + if ((prBssInfo->fgIsNetActive) && (OP_MODE_BOW == prBssInfo->eCurrentOPMode)) { + + /* 4 <3.1> Validate Auth Frame by Auth Algorithm/Transation Seq */ + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + assocProcessRxAssocReqFrame(prAdapter, prSwRfb, &u2StatusCode)) { + + if (STATUS_CODE_SUCCESSFUL == u2StatusCode) { + + /* 4 <3.2> Validate Auth Frame for Network Specific Conditions */ + fgReplyAssocResp = + bowValidateAssocReq(prAdapter, prSwRfb, &u2StatusCode); + + } else { + + fgReplyAssocResp = TRUE; + } + + /* TODO(Kevin): Allocate a STA_RECORD_T for new client */ + break; + } + } + } +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + return WLAN_STATUS_SUCCESS; /* To release the SW_RFB_T */ + } while (FALSE); + + /* 4 <4> Update STA_RECORD_T and reply Assoc Resp Frame */ + if (fgReplyAssocResp) { + UINT_16 u2IELength; + PUINT_8 pucIE; + + if ((((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_REASSOC_REQ) { + + u2IELength = prSwRfb->u2PacketLen - + (UINT_16) OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; + } else { + u2IELength = prSwRfb->u2PacketLen - (UINT_16) OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; + } + + rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); + + /* 4 <4.1> Assign Association ID */ + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + if (p2pRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + /* prStaRec->eAuthAssocState = AA_STATE_IDLE; */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2;/* NOTE(Kevin): for TX done */ + + /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ + /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ + } else { + /* Client List FULL. */ + u2StatusCode = STATUS_CODE_REQ_DECLINED; + + prStaRec->u2AssocId = 0; /* Invalid Association ID */ + + /* If (Re)association fail, the peer can try Association w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if ((IS_STA_IN_BOW(prStaRec))) { + /* if (bowRunEventAAAComplete(prAdapter, prStaRec) == WLAN_STATUS_SUCCESS) { */ + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + prStaRec->eAuthAssocState = AAA_STATE_SEND_ASSOC2; /* NOTE(Kevin): for TX done */ + + /* NOTE(Kevin): Method A: Change to STATE_3 before handle TX Done */ + /* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ + } +#if 0 + else { + /* Client List FULL. */ + u2StatusCode = STATUS_CODE_REQ_DECLINED; + + prStaRec->u2AssocId = 0; /* Invalid Association ID */ + + /* If (Re)association fail, the peer can try Association w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + } +#endif +#endif + } else { + prStaRec->u2AssocId = 0; /* Invalid Association ID */ + + /* If (Re)association fail, the peer can try Association w/o Auth immediately */ + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + /* NOTE: Ignore the return status for AAA */ + /* 4 <4.2> Reply Assoc Resp */ + assocSendReAssocRespFrame(prAdapter, prStaRec); + +} + +return WLAN_STATUS_SUCCESS; + +} /* end of aaaFsmRunEventRxAssoc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. +* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. +* +* @retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + DBGLOG(AAA, LOUD, "EVENT-TX DONE: Current Time = %lu\n", (unsigned long)kalGetTimeTick()); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + DBGLOG(AAA, INFO, "EVENT-TX DONE: Invalid StaRec"); + return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ + } + + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + DBGLOG(AAA, INFO, "TX DONE status: %d, AuthAssocState: %d, SeqNo: %d\n", + rTxDoneStatus, prStaRec->eAuthAssocState, + prMsduInfo->ucTxSeqNum); + + switch (prStaRec->eAuthAssocState) { + case AAA_STATE_SEND_AUTH2: + { + /* Strictly check the outgoing frame is matched with current AA STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_2) != WLAN_STATUS_SUCCESS) + break; + + if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { + if (TX_RESULT_SUCCESS == rTxDoneStatus) { + + /* NOTE(Kevin): Change to STATE_2 at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } else { + + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) + p2pRunEventAAATxFail(prAdapter, prStaRec); +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) + bowRunEventAAATxFail(prAdapter, prStaRec); +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + } + + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ + + } + break; + + case AAA_STATE_SEND_ASSOC2: + { + /* Strictly check the outgoing frame is matched with current SAA STATE */ + if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) + break; + + if (STATUS_CODE_SUCCESSFUL == prStaRec->u2StatusCode) { + if (TX_RESULT_SUCCESS == rTxDoneStatus) { + + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_3 at TX Done */ +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) + p2pRunEventAAASuccess(prAdapter, prStaRec); +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + + if (IS_STA_IN_BOW(prStaRec)) + bowRunEventAAAComplete(prAdapter, prStaRec); +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + } else { + + prStaRec->eAuthAssocState = AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Change to STATE_2 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) + p2pRunEventAAATxFail(prAdapter, prStaRec); +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_STA_IN_BOW(prStaRec)) + bowRunEventAAATxFail(prAdapter, prStaRec); +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + + } + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with Error Status Code */ + } + break; + + default: + break; /* Ignore other cases */ + } + + return WLAN_STATUS_SUCCESS; + +} /* end of aaaFsmRunEventTxDone() */ +#endif /* CFG_SUPPORT_AAA */ + +#if 0 /* TODO(Kevin): for abort event, just reset the STA_RECORD_T. */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send ABORT Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventAbort(IN P_MSG_HDR_T prMsgHdr) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventAbort"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, "JOIN EVENT: ABORT\n"); + + /* NOTE(Kevin): when reach here, the ARB_STATE should be in ARB_STATE_JOIN. */ + ASSERT(prJoinInfo->prBssDesc); + + /* 4 <1> Update Flags and Elements of JOIN Module. */ + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel all JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); + + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rJoinTimer); + + /* 4 <2> Update the associated STA_RECORD_T during JOIN. */ + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); + if (prStaRec) + prStaRec->ucStaState = STA_STATE_1; /* Update Station Record - Class 1 Flag */ +#if DBG + else + ASSERT(0); /* Shouldn't happened, because we already add this STA_RECORD_T at JOIN_STATE_INIT */ +#endif /* DBG */ + + /* 4 <3> Pull back to IDLE. */ + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + /* 4 <4> If we are in Roaming, recover the settings of previous BSS. */ + /* NOTE: JOIN FAIL - + * Restore original setting from current BSS_INFO_T. + */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) + joinAdoptParametersFromCurrentBss(prAdapter); + +} /* end of joinFsmRunEventAbort() */ +#endif + +/* TODO(Kevin): following code will be modified and move to AIS FSM */ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send Join Timeout Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventJoinTimeOut"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); + + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); + + /* We have renew this Sta Record when in JOIN_STATE_INIT */ + ASSERT(prStaRec); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel other JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); + + /* Restore original setting from current BSS_INFO_T */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) + joinAdoptParametersFromCurrentBss(prAdapter); + + /* Pull back to IDLE */ + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + return WLAN_STATUS_FAILURE; + +} /* end of joinFsmRunEventJoinTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from Peer BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + + DEBUGFUNC("joinAdoptParametersFromPeerBss"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + + /* 4 <1> Adopt Peer BSS' PHY TYPE */ + prAdapter->eCurrentPhyType = prBssDesc->ePhyType; + + DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", + prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); + + /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ + DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); + + nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); + + prJoinInfo->fgIsParameterAdopted = TRUE; + +} /* end of joinAdoptParametersFromPeerBss() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from current associated BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) +{ + /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + prBssInfo = &prAdapter->rBssInfo; + + /* 4 <1> Adopt current BSS' PHY TYPE */ + prAdapter->eCurrentPhyType = prBssInfo->ePhyType; + + /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ + DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); + + nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); + +} /* end of joinAdoptParametersFromCurrentBss() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will update all the SW variables and HW MCR registers after +* the association with target BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinComplete(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + P_PEER_BSS_INFO_T prPeerBssInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_TX_CTRL_T prTxCtrl; +#if CFG_SUPPORT_802_11D + P_IE_COUNTRY_T prIECountry; +#endif + + DEBUGFUNC("joinComplete"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + prPeerBssInfo = &prAdapter->rPeerBssInfo; + prBssInfo = &prAdapter->rBssInfo; + prConnSettings = &prAdapter->rConnSettings; + prTxCtrl = &prAdapter->rTxCtrl; + +/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ + /* Remove previous AP's Connection Flags if have */ + scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); + + prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ + + if (prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't + * broadcast SSID on its Beacon Frame. + */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); + + if (prBssDesc->ucSSIDLen) + prBssDesc->fgIsHiddenSSID = FALSE; +#if DBG + else + ASSERT(0); +#endif /* DBG */ + + DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); + } +/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ + /* 4 <2.A> PHY Type */ + prBssInfo->ePhyType = prBssDesc->ePhyType; + + /* 4 <2.B> BSS Type */ + prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; + + /* 4 <2.C> BSSID */ + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); + + DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); + + /* 4 <2.D> SSID */ + COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + + /* 4 <2.E> Channel / Band information. */ + prBssInfo->eBand = prBssDesc->eBand; + prBssInfo->ucChnl = prBssDesc->ucChannelNum; + + /* 4 <2.F> RSN/WPA information. */ + secFsmRunEventStart(prAdapter); + prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; + prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; + prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; + + if (secRsnKeyHandshakeEnabled()) + prBssInfo->fgIsWPAorWPA2Enabled = TRUE; + else + prBssInfo->fgIsWPAorWPA2Enabled = FALSE; + + /* 4 <2.G> Beacon interval. */ + prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + + /* 4 <2.H> DTIM period. */ + prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; + + /* 4 <2.I> ERP Information */ + if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ + (prBssDesc->fgIsERPPresent)) { + + prBssInfo->fgIsERPPresent = TRUE; + prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ + } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ + prBssInfo->fgIsERPPresent = FALSE; + prBssInfo->ucERP = 0; + } + +#if CFG_SUPPORT_802_11D + /* 4 <2.J> Country inforamtion of the associated AP */ + if (prConnSettings->fgMultiDomainCapabilityEnabled) { + DOMAIN_INFO_ENTRY rDomainInfo; + + if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { + if (prBssDesc->prIECountry) { + prIECountry = prBssDesc->prIECountry; + + domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); + + /* use the domain get from the BSS info */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); + } else { + /* use the domain get from the scan result */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); + } + } + } +#endif + + /* 4 <2.K> Signal Power of the associated AP */ + prBssInfo->rRcpi = prBssDesc->rRcpi; + prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); + GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); + + /* 4 <2.L> Capability Field of the associated AP */ + prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; + + DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", + prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); + +/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ + /* 4 <3.A> Association ID */ + prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; + + /* 4 <3.B> WMM Information */ + if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { + + prBssInfo->fgIsWmmAssoc = TRUE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC3; + + qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); + + if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { + kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } else { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); + } + } else { + prBssInfo->fgIsWmmAssoc = FALSE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC1; + + kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } + + /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ + prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; + prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; + + /* 4 <3.D> Short Preamble */ + if (prBssInfo->fgIsERPPresent) { + + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE FALSE(shouldn't have such case, + * use the AssocResp) + * TRUE FALSE TRUE FALSE + * FALSE FALSE FALSE FALSE(shouldn't have such case, + * use the AssocResp) + * FALSE FALSE TRUE FALSE + * TRUE TRUE FALSE TRUE(follow ERP) + * TRUE TRUE TRUE FALSE(follow ERP) + * FALSE TRUE FALSE FALSE(shouldn't have such case, + * and we should set to FALSE) + * FALSE TRUE TRUE FALSE(we should set to FALSE) + */ + if ((prPeerBssInfo->fgIsShortPreambleAllowed) && + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + + if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) + prBssInfo->fgUseShortPreamble = FALSE; + else + prBssInfo->fgUseShortPreamble = TRUE; + } else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + } else { + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE + * FALSE FALSE FALSE + * TRUE TRUE TRUE + * FALSE TRUE(status success) TRUE + * --> Honor the result of prPeerBssInfo. + */ + + prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = + prPeerBssInfo->fgIsShortPreambleAllowed; + } + + DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", + prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); + + /* 4 <3.E> Short Slot Time */ + prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ + + DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); + + nicSetSlotTime(prAdapter, + prBssInfo->ePhyType, + ((prConnSettings->fgIsShortSlotTimeOptionEnable && + prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); + + /* 4 <3.F> Update Tx Rate for Control Frame */ + bssUpdateTxRateForControlFrame(prAdapter); + + /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ + /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ + { + + if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; + else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; + + prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; + + /* Set the stable time of the associated BSS. We won't do roaming decision + * during the stable time. + */ + SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, + SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); + } + + /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ +#if CFG_TX_FRAGMENT + txFragInfoUpdate(prAdapter); +#endif /* CFG_TX_FRAGMENT */ + +/* 4 <4> Update STA_RECORD_T */ + /* Get a Station Record if possible */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); + + if (prStaRec) { + UINT_16 u2OperationalRateSet, u2DesiredRateSet; + + /* 4 <4.A> Desired Rate Set */ + u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & + prBssInfo->u2OperationalRateSet); + + u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); + if (u2DesiredRateSet) { + prStaRec->u2DesiredRateSet = u2DesiredRateSet; + } else { + /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ + prStaRec->u2DesiredRateSet = u2OperationalRateSet; + } + + /* Try to set the best initial rate for this entry */ + if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, + prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { + + if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) + ASSERT(0); + } + + DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); + + /* 4 <4.B> Preamble Mode */ + prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; + + /* 4 <4.C> QoS Flag */ + prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; + } +#if DBG + else + ASSERT(0); +#endif /* DBG */ + +/* 4 <5> Update NIC */ + /* 4 <5.A> Update BSSID & Operation Mode */ + nicSetupBSS(prAdapter, prBssInfo); + + /* 4 <5.B> Update WLAN Table. */ + if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) + ASSERT(FALSE); + /* 4 <5.C> Update Desired Rate Set for BT. */ +#if CFG_TX_FRAGMENT + if (prConnSettings->fgIsEnableTxAutoFragmentForBT) + txRateSetInitForBT(prAdapter, prStaRec); +#endif /* CFG_TX_FRAGMENT */ + + /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ + if (prBssInfo->fgIsWmmAssoc) { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, FALSE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); + } else { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, TRUE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); + + nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); + } + +#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN + { + prTxCtrl->fgBlockTxDuringJoin = FALSE; + +#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ + nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxRetransmitOfSendWaitQue(prAdapter); + + if (prTxCtrl->fgIsPacketInOsSendQueue) + nicTxRetransmitOfOsSendQue(prAdapter); +#if CFG_SDIO_TX_ENHANCE + halTxLeftClusteredMpdu(prAdapter); +#endif /* CFG_SDIO_TX_ENHANCE */ + + } +#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ + +/* 4 <6> Setup CONNECTION flag. */ + prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; + prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; + + if (prJoinInfo->fgIsReAssoc) + prAdapter->fgBypassPortCtrlForRoaming = TRUE; + else + prAdapter->fgBypassPortCtrlForRoaming = FALSE; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); + +} /* end of joinComplete() */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c new file mode 100644 index 0000000000000..7b5a49a5ba631 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/ais_fsm.c @@ -0,0 +1,5039 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/ais_fsm.c#1 +*/ + +/*! \file "aa_fsm.c" + \brief This file defines the FSM for SAA and AAA MODULE. + + This file defines the FSM for SAA and AAA MODULE. +*/ + +/* +** Log: ais_fsm.c +** +** 09 06 2013 cp.wu +** always paste SSID information to SAA-FSM +** +** 09 06 2013 cp.wu +** add error handling when reassociation request failed to locate bss descriptor +** +** 09 05 2013 cp.wu +** isolate logic regarding roaming & reassociation +** +** 09 04 2013 cp.wu +** fix typo +** +** 09 03 2013 cp.wu +** add path for reassociation + * + * 04 20 2012 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * correct macro + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration with + * corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred band configuration + * corresponding to network type. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous + * to asynchronous approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state + * without join timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED + * cases as an explicit trigger for Android framework + * correct reference to BSSID field in Association-Response frame. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT for REASSOCIATED + * cases as an explicit trigger for Android framework + * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. + * 2. (Android only) when reassociation-and-non-roaming cases happened, indicate an extra DISCONNECT + * indication to Android Wi-Fi framework + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 10 26 2011 tsaiyuan.hsu + * [WCXRP00001064] [MT6620 Wi-Fi][DRV]] add code with roaming awareness when disconnecting AIS network + * be aware roaming when disconnecting AIS network. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * STA_REC shall be NULL for Beacon's MSDU + * + * 10 13 2011 cp.wu + * [MT6620 Wi-Fi][Driver] Reduce join failure count limit to 2 for faster re-join for other BSS + * 1. short join failure count limit to 2 + * 2. treat join timeout as kind of join failure as well + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 30 2011 cm.chang + * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band + * . + * + * 09 20 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * change window registry of driver for roaming. + * + * 09 20 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Handle client mode about preamble type and slot time + * + * 09 08 2011 tsaiyuan.hsu + * [WCXRP00000972] [MT6620 Wi-Fi][DRV]] check if roaming occurs after join failure to avoid state incosistence. + * check if roaming occurs after join failure to avoid deactivation of network. + * + * 08 24 2011 chinghwa.yu + * [WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Update RDD test mode cases. + * + * 08 16 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * EnableRoaming in registry is deprecated. + * + * 08 16 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * use registry to enable or disable roaming. + * + * 07 07 2011 cp.wu + * [WCXRP00000840] [MT6620 Wi-Fi][Driver][AIS] Stop timer for joining when channel is released + * due to join failure count exceeding limit + * stop timer when joining operation is failed due to try count exceeds limitation + * + * 06 28 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work + * around some tricky AP which use space character as hidden SSID + * do not handle SCAN request immediately after connected to increase the probability of receiving 1st beacon frame. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * ensure DEAUTH is always sent before establish a new connection + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * typo fix: a right brace is missed. + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * When RECONNECT request is identified as disconnected, it is necessary to check for pending scan request. + * + * 06 16 2011 cp.wu + * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels + * mark fgIsTransition as TRUE for state rolling. + * + * 06 16 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * always check for pending scan after switched into NORMAL_TR state. + * + * 06 14 2011 cp.wu + * [WCXRP00000782] [MT6620 Wi-Fi][AIS] Treat connection at higher priority over scanning to avoid WZC connection timeout + * always treat connection request at higher priority over scanning request + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 06 02 2011 cp.wu + * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction + * eliminate unused parameters for SAA-FSM + * + * 05 18 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state + * when DEAUTH frame is dropped due to bss disconnection + * change SCAN handling behavior when followed by a CONNECT/DISCONNECT requests by pending instead of dropping. + * + * 05 17 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state + * when DEAUTH frame is dropped due to bss disconnection + * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 13 2011 george.huang + * [WCXRP00000628] [MT6620 Wi-Fi][FW][Driver] Modify U-APSD setting to default OFF + * remove assert + * + * 03 18 2011 cp.wu + * [WCXRP00000575] [MT6620 Wi-Fi][Driver][AIS] reduce memory usage when generating mailbox message for scan request + * when there is no IE needed for probe request, then request a smaller memory for mailbox message + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 03 11 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel + * + * 03 09 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * avoid clearing fgIsScanReqIssued so as to add scan results. + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 04 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * reset retry conter of attemp to connect to ap after completion of join. + * + * 03 04 2011 cp.wu + * [WCXRP00000515] [MT6620 Wi-Fi][Driver] Surpress compiler warning which is identified by GNU compiler collection + * surpress compile warning occurred when compiled by GNU compiler collection. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right + * after connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 02 23 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach to + * improve response time for scanning request + * when handling reconnect request, set fgTryScan as TRUE + * + * 02 22 2011 cp.wu + * [WCXRP00000487] [MT6620 Wi-Fi][Driver][AIS] Serve scan and connect request with a queue-based approach + * to improve response time for scanning request + * handle SCAN and RECONNECT with a FIFO approach. + * + * 02 09 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * Check if prRegInfo is null or not before initializing roaming parameters. + * + * 02 01 2011 cp.wu + * [WCXRP00000416] [MT6620 Wi-Fi][Driver] treat "unable to find BSS" as connection trial + * to prevent infinite reconnection trials + * treat "unable to find BSS" as connection trial to prevent infinite reconnection trials. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 14 2011 cp.wu + * [WCXRP00000359] [MT6620 Wi-Fi][Driver] add an extra state to ensure DEAUTH frame is always sent + * Add an extra state to guarantee DEAUTH frame is sent then connect to new BSS. + * This change is due to WAPI AP needs DEAUTH frame as a necessary step in handshaking protocol. + * + * 01 11 2011 cp.wu + * [WCXRP00000307] [MT6620 Wi-Fi][SQA]WHQL test .2c_wlan_adhoc case fail. + * [IBSS] when merged in, the bss state should be updated to firmware to pass WHQL adhoc failed item + * + * 01 10 2011 cp.wu + * [WCXRP00000351] [MT6620 Wi-Fi][Driver] remove from scanning result in OID handling layer + * when the corresponding BSS is disconnected due to beacon timeout + * remove from scanning result when the BSS is disconnected due to beacon timeout. + * + * 01 03 2011 cp.wu + * [WCXRP00000337] [MT6620 Wi-FI][Driver] AIS-FSM not to invoke cnmStaRecResetStatus + * directly 'cause it frees all belonging STA-RECs + * do not invoke cnmStaRecResetStatus() directly, nicUpdateBss will do the things after bss is disconnected + * + * 12 30 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * do not need to manipulate prStaRec after indicating BSS disconnection to firmware, + * 'cause all STA-RECs belongs to BSS has been freed already + * + * 12 27 2010 cp.wu + * [WCXRP00000269] [MT6620 Wi-Fi][Driver][Firmware] Prepare for v1.1 branch release + * add DEBUGFUNC() macro invoking for more detailed debugging information + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 12 17 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 25 2010 yuche.tsai + * NULL + * Update SLT Function for QoS Support and not be affected by fixed rate function. + * + * 11 25 2010 cp.wu + * [WCXRP00000208] [MT6620 Wi-Fi][Driver] Add scanning with specified SSID to AIS FSM + * add scanning with specified SSID facility to AIS-FSM + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with + * Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] Add implementation for querying current TX rate + * from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] + * Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 14 2010 wh.su + * [WCXRP00000097] [MT6620 Wi-Fi] [Driver] Fixed the P2P not setting the fgIsChannelExt value make scan not abort + * initial the fgIsChannelExt value. + * + * 10 08 2010 cp.wu + * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. + * correct erroneous logic: specifying eBand with incompatible eSco + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T + * and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 23 2010 cp.wu + * [WCXRP00000049] [MT6620 Wi-Fi][Driver] Adhoc cannot be created successfully. + * keep IBSS-ALONE state retrying until further instruction is received + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD + * when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 09 2010 yuche.tsai + * NULL + * Fix NULL IE Beacon issue. Sync Beacon Content to FW before enable beacon. + * Both in IBSS Create & IBSS Merge + * + * 09 09 2010 cp.wu + * NULL + * frequency is in unit of KHz thus no need to divide 1000 once more. + * + * 09 06 2010 cp.wu + * NULL + * 1) initialize for correct parameter even for disassociation. + * 2) AIS-FSM should have a limit on trials to build connection + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 25 2010 cp.wu + * NULL + * add option for enabling AIS 5GHz scan + * + * 08 25 2010 cp.wu + * NULL + * [AIS-FSM] IBSS no longer needs to acquire channel for beaconing, + * RLM/CNM will handle the channel switching when BSS information is updated + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 12 2010 cp.wu + * NULL + * check-in missed files. + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 09 2010 cp.wu + * NULL + * reset fgIsScanReqIssued when abort request is received right after join completion. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 cp.wu + * NULL + * comment out deprecated members in BSS_INFO, which are only used by firmware rather than driver. + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 29 2010 cp.wu + * NULL + * eliminate u4FreqInKHz usage, combined into rConnections.ucAdHoc* + * + * 07 29 2010 cp.wu + * NULL + * allocate on MGMT packet for IBSS beaconing. + * + * 07 29 2010 cp.wu + * NULL + * [AIS-FSM] fix: when join failed, release channel privilege as well + * + * 07 28 2010 cp.wu + * NULL + * reuse join-abort sub-procedure to reduce code size. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 26 2010 cp.wu + * + * AIS-FSM: when scan request is coming in the 1st 5 seconds of channel privilege period, + * just pend it til 5-sec. period finishes + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 26 2010 cp.wu + * + * re-commit code logic being overwriten. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 cp.wu + * + * 1) enable Ad-Hoc + * 2) disable beacon timeout handling temporally due to unexpected beacon timeout event. + * + * 07 23 2010 cp.wu + * + * indicate scan done for linux wireless extension + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 21 2010 cp.wu + * + * separate AIS-FSM states into different cases of channel request. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 20 2010 cp.wu + * + * 1) [AIS] when new scan is issued, clear currently available scanning result except the connected one + * 2) refine disconnection behaviour when issued during BG-SCAN process + * + * 07 20 2010 cp.wu + * + * 1) bugfix: do not stop timer for join after switched into normal_tr state, + * for providing chance for DHCP handshasking + * 2) modify rsnPerformPolicySelection() invoking + * + * 07 19 2010 cp.wu + * + * 1) init AIS_BSS_INFO as channel number = 1 with band = 2.4GHz + * 2) correct typo + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * for AIS scanning, driver specifies no extra IE for probe request + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 yarco.yang + * + * Remove CFG_MQM_MIGRATION + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Refine AIS-FSM by divided into more states + * + * 07 13 2010 cm.chang + * + * Rename MSG_CH_RELEASE_T to MSG_CH_ABORT_T + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, + * other request will be directly dropped by returning BUSY + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * for first connection, if connecting failed do not enter into scan state. + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * once STA-REC is allocated and updated, invoke cnmStaRecChangeState() to sync. with firmware. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * remove unused definitions. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * RSN/PRIVACY compilation flag awareness correction + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change to enqueue TX frame infinitely. + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 01 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add conditionial compiling flag to choose default available bandwidth + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile error if CFG_CMD_EVENT_VER_009 == 0 for prEventConnStatus->ucNetworkType. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 17 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Call pmAbort() and add ucNetworkType field in EVENT_CONNECTION_STATUS + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile warning - define of MQM_WMM_PARSING was removed + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed the use of compiling flag MQM_WMM_PARSING + * + * 04 27 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * + * Fix typo + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the protected bit at cap info for ad-hoc. + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add new HW CH macro support + * + * 04 07 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Add TX Power Control RCPI function. + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * move the wlan table alloc / free to change state function. + * + * 03 25 2010 wh.su + * [BORA00000676][MT6620] Support the frequency setting and query at build connection / connection event + * modify the build connection and status event structure bu CMD_EVENT doc 0.09 draft, default is disable. + * + * 03 24 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * fixed some WHQL testing error. + * + * 03 24 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Set / Unset POWER STATE in AIS Network + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 03 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add PHY_CONFIG to change Phy Type + * + * 03 03 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Use bcmWiFiNotify to replace wifi_send_msg to pass information to BCM module. + * + * 03 03 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Remove wmt_task definition and add PTA function. + * + * 03 02 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Init TXM and MQM testing procedures in aisFsmRunEventJoinComplete() + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Modified aisUpdateBssInfo() to call TXM's functions for setting WTBL TX parameters + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * clear the pmkid cache while indicate media disconnect. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * . + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Enabled MQM parsing WMM IEs for non-AP mode + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Remove CFG_TEST_VIRTUAL_CMD and add support of Driver STA_RECORD_T activation + * + * 02 25 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * use the Rx0 dor event indicate. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Support dynamic channel selection + * + * 02 23 2010 wh.su + * [BORA00000621][MT6620 Wi-Fi] Add the RSSI indicate to avoid XP stalled for query rssi value + * Adding the RSSI event support, + * using the HAL function to get the rcpi value and tranlsate to RSSI and indicate to driver + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Set max AMDPU size supported by the peer to 64 KB, + * removed mqmInit() and mqmTxSendAddBaReq() function calls in aisUpdateBssInfo() + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 20 2010 kevin.huang + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags + * + * 01 15 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Configured the AMPDU factor to 3 for the APu1rwduu`wvpghlqg|q`mpdkb+ilp + * + * 01 14 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Add WiFi BCM module for the 1st time. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Refine JOIN Complete and separate the function of Media State indication + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the sample code to update the wlan table rate, + * + * Dec 10 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Different function prototype of wifi_send_msg() + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call rlm related function to process HT info when join complete + * + * Dec 9 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * default the acquired wlan table entry code off + * + * Dec 9 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to acquired the wlan table entry, and a sample code to update the BA bit at table + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix the problem of prSwRfb overwrited by event packet in aisFsmRunEventJoinComplete() + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to integrate the security related code + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove redundant declaration + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add code for JOIN init and JOIN complete + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename u4RSSI to i4RSSI + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise ENUM_MEDIA_STATE to ENUM_PARAM_MEDIA_STATE + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add fgIsScanReqIssued to CONNECTION_SETTINGS_T + * + * Nov 26 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise Virtual CMD handler due to structure changed + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Virtual CMD & RESP for testing CMD PATH + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmInitializeConnectionSettings() + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add CFG_TEST_MGMT_FSM flag for aisFsmTest() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define AIS_ROAMING_CONNECTION_TRIAL_LIMIT 2 +#define AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME 80 + +#define CTIA_MAGIC_SSID "ctia_test_only_*#*#3646633#*#*" +#define CTIA_MAGIC_SSID_LEN 30 + +#define AIS_JOIN_TIMEOUT 7 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugAisState[AIS_STATE_NUM] = { + (PUINT_8) DISP_STRING("AIS_STATE_IDLE"), + (PUINT_8) DISP_STRING("AIS_STATE_SEARCH"), + (PUINT_8) DISP_STRING("AIS_STATE_SCAN"), + (PUINT_8) DISP_STRING("AIS_STATE_ONLINE_SCAN"), + (PUINT_8) DISP_STRING("AIS_STATE_LOOKING_FOR"), + (PUINT_8) DISP_STRING("AIS_STATE_WAIT_FOR_NEXT_SCAN"), + (PUINT_8) DISP_STRING("AIS_STATE_REQ_CHANNEL_JOIN"), + (PUINT_8) DISP_STRING("AIS_STATE_JOIN"), + (PUINT_8) DISP_STRING("AIS_STATE_IBSS_ALONE"), + (PUINT_8) DISP_STRING("AIS_STATE_IBSS_MERGE"), + (PUINT_8) DISP_STRING("AIS_STATE_NORMAL_TR"), + (PUINT_8) DISP_STRING("AIS_STATE_DISCONNECTING"), + (PUINT_8) DISP_STRING("AIS_STATE_REQ_REMAIN_ON_CHANNEL"), + (PUINT_8) DISP_STRING("AIS_STATE_REMAIN_ON_CHANNEL") +}; + +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to initialize the value of the connection settings for +* AIS network +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucAnyBSSID[] = BC_BSSID; + UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; + int i = 0; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Setup default values for operation */ + COPY_MAC_ADDR(prConnSettings->aucMacAddress, aucZeroMacAddr); + + if (prRegInfo) + prConnSettings->ucDelayTimeOfDisconnectEvent = + (!prAdapter->fgIsHw5GBandDisabled && prRegInfo->ucSupport5GBand) ? + AIS_DELAY_TIME_OF_DISC_SEC_DUALBAND : AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; + else + prConnSettings->ucDelayTimeOfDisconnectEvent = AIS_DELAY_TIME_OF_DISC_SEC_ONLY_2G4; + + COPY_MAC_ADDR(prConnSettings->aucBSSID, aucAnyBSSID); + prConnSettings->fgIsConnByBssidIssued = FALSE; + + prConnSettings->fgIsConnReqIssued = FALSE; + prConnSettings->fgIsDisconnectedByNonRequest = FALSE; + + prConnSettings->ucSSIDLen = 0; + + prConnSettings->eOPMode = NET_TYPE_INFRA; + + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + + if (prRegInfo) { + prConnSettings->ucAdHocChannelNum = (UINT_8) nicFreq2ChannelNum(prRegInfo->u4StartFreq); + prConnSettings->eAdHocBand = prRegInfo->u4StartFreq < 5000000 ? BAND_2G4 : BAND_5G; + prConnSettings->eAdHocMode = (ENUM_PARAM_AD_HOC_MODE_T) (prRegInfo->u4AdhocMode); + } + + prConnSettings->eAuthMode = AUTH_MODE_OPEN; + + prConnSettings->eEncStatus = ENUM_ENCRYPTION_DISABLED; + + prConnSettings->fgIsScanReqIssued = FALSE; + + /* MIB attributes */ + prConnSettings->u2BeaconPeriod = DOT11_BEACON_PERIOD_DEFAULT; + + prConnSettings->u2RTSThreshold = DOT11_RTS_THRESHOLD_DEFAULT; + + prConnSettings->u2DesiredNonHTRateSet = RATE_SET_ALL_ABG; + + /* prConnSettings->u4FreqInKHz; */ /* Center frequency */ + + /* Set U-APSD AC */ + prConnSettings->bmfgApsdEnAc = PM_UAPSD_NONE; + + secInit(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* Features */ + prConnSettings->fgIsEnableRoaming = FALSE; +#if CFG_SUPPORT_ROAMING + if (prRegInfo) + prConnSettings->fgIsEnableRoaming = ((prRegInfo->fgDisRoaming > 0) ? (FALSE) : (TRUE)); +#endif /* CFG_SUPPORT_ROAMING */ + + prConnSettings->fgIsAdHocQoSEnable = FALSE; + + prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGN; + + /* Set default bandwidth modes */ + prConnSettings->uc2G4BandwidthMode = CONFIG_BW_20M; + prConnSettings->uc5GBandwidthMode = CONFIG_BW_20_40M; + + prConnSettings->rRsnInfo.ucElemId = 0x30; + prConnSettings->rRsnInfo.u2Version = 0x0001; + prConnSettings->rRsnInfo.u4GroupKeyCipherSuite = 0; + prConnSettings->rRsnInfo.u4PairwiseKeyCipherSuiteCount = 0; + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prConnSettings->rRsnInfo.au4PairwiseKeyCipherSuite[i] = 0; + prConnSettings->rRsnInfo.u4AuthKeyMgtSuiteCount = 0; + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) + prConnSettings->rRsnInfo.au4AuthKeyMgtSuite[i] = 0; + prConnSettings->rRsnInfo.u2RsnCap = 0; + prConnSettings->rRsnInfo.fgRsnCapPresent = FALSE; + +} /* end of aisFsmInitializeConnectionSettings() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to initialize the value in AIS_FSM_INFO_T for +* AIS FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 ucScanTimeoutTimes = 0; +VOID aisFsmInit(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + + DEBUGFUNC("aisFsmInit()"); + DBGLOG(SW1, TRACE, "->aisFsmInit()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + /* 4 <1> Initiate FSM */ + prAisFsmInfo->ePreviousState = AIS_STATE_IDLE; + prAisFsmInfo->eCurrentState = AIS_STATE_IDLE; + + prAisFsmInfo->ucAvailableAuthTypes = 0; + + prAisFsmInfo->prTargetBssDesc = (P_BSS_DESC_T) NULL; + + prAisFsmInfo->ucSeqNumOfReqMsg = 0; + prAisFsmInfo->ucSeqNumOfChReq = 0; + prAisFsmInfo->ucSeqNumOfScanReq = 0; + + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = FALSE; +#endif /* CFG_SUPPORT_ROAMING */ + prAisFsmInfo->fgIsChannelRequested = FALSE; + prAisFsmInfo->fgIsChannelGranted = FALSE; + + /* 4 <1.1> Initiate FSM - Timer INIT */ + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rBGScanTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventBGSleepTimeOut, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rIbssAloneTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventIbssAloneTimeOut, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisPostponedEventOfDisconnTimeout, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rJoinTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventJoinTimeout, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rScanDoneTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventScanDoneTimeOut, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rChannelTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventChannelTimeout, (ULONG) NULL); + + cnmTimerInitTimer(prAdapter, + &prAisFsmInfo->rDeauthDoneTimer, + (PFN_MGMT_TIMEOUT_FUNC) aisFsmRunEventDeauthTimeout, (ULONG) NULL); + + /* 4 <1.2> Initiate PWR STATE */ + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BSS_INFO_INIT(prAdapter, NETWORK_TYPE_AIS_INDEX); + COPY_MAC_ADDR(prAisBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); + + /* 4 <3> Initiate BSS_INFO_T - private part */ + /* TODO */ + prAisBssInfo->eBand = BAND_2G4; + prAisBssInfo->ucPrimaryChannel = 1; + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + + /* 4 <4> Allocate MSDU_INFO_T for Beacon */ + prAisBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prAisBssInfo->prBeacon) { + prAisBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prAisBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ + } else { + ASSERT(0); + } + +#if 0 + prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; +#else + if (prAdapter->u4UapsdAcBmp == 0) { + prAdapter->u4UapsdAcBmp = CFG_INIT_UAPSD_AC_BMP; + /* ASSERT(prAdapter->u4UapsdAcBmp); */ + } + prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; +#endif + + /* request list initialization */ + LINK_INITIALIZE(&prAisFsmInfo->rPendingReqList); + + /* DBGPRINTF("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", */ + /* prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, */ + /* prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, */ + /* prAisBssInfo->rPmProfSetupInfo.ucUapsdSp); */ + + /*reset ucScanTimeoutTimes value*/ + ucScanTimeoutTimes = 0; + +} /* end of aisFsmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief the function is used to uninitialize the value in AIS_FSM_INFO_T for +* AIS FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + + DEBUGFUNC("aisFsmUninit()"); + DBGLOG(SW1, INFO, "->aisFsmUninit()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + /* 4 <1> Stop all timers */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); /* Add by Enlai */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + + /* 4 <2> flush pending request */ + aisFsmFlushRequest(prAdapter); + + /* 4 <3> Reset driver-domain BSS-INFO */ + if (prAisBssInfo->prBeacon) { + cnmMgtPktFree(prAdapter, prAisBssInfo->prBeacon); + prAisBssInfo->prBeacon = NULL; + } +#if CFG_SUPPORT_802_11W + rsnStopSaQuery(prAdapter); +#endif + +} /* end of aisFsmUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialization of JOIN STATE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try to join with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_JOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + ASSERT(prBssDesc); + + /* 4 <1> We are going to connect to this BSS. */ + prBssDesc->fgIsConnecting = TRUE; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_LEGACY_AP, NETWORK_TYPE_AIS_INDEX, prBssDesc); + if (prStaRec == NULL) { + DBGLOG(AIS, WARN, "Create station record fail\n"); + return; + } + + prAisFsmInfo->prTargetStaRec = prStaRec; + + /* 4 <2.1> sync. to firmware domain */ + if (prStaRec->ucStaState == STA_STATE_1) + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + + prStaRec->fgIsReAssoc = FALSE; + + switch (prConnSettings->eAuthMode) { + case AUTH_MODE_OPEN: /* Note: Omit break here. */ + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; + break; + + case AUTH_MODE_SHARED: + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(AIS, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); + prAisFsmInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | AUTH_TYPE_SHARED_KEY); + break; + + default: + ASSERT(!(prConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); + DBGLOG(AIS, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", + prConnSettings->eAuthMode); + /* TODO(Kevin): error handling ? */ + return; + } + + /* TODO(tyhsu): Assume that Roaming Auth Type is equal to ConnSettings eAuthMode */ + prAisSpecificBssInfo->ucRoamingAuthTypes = prAisFsmInfo->ucAvailableAuthTypes; + + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + + } else { + ASSERT(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE); + ASSERT(!prBssDesc->fgIsConnected); + + DBGLOG(AIS, LOUD, "JOIN INIT: AUTH TYPE = %d for Roaming\n", + prAisSpecificBssInfo->ucRoamingAuthTypes); + + prStaRec->fgIsReAssoc = TRUE; /* We do roaming while the medium is connected */ + + /* TODO(Kevin): We may call a sub function to acquire the Roaming Auth Type */ + prAisFsmInfo->ucAvailableAuthTypes = prAisSpecificBssInfo->ucRoamingAuthTypes; + + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING; + } + + /* 4 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes */ + if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); + prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { + + DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; + } else if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { + + DBGLOG(AIS, LOUD, "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; + } else { + ASSERT(0); + } + + /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ + if (prBssDesc->ucSSIDLen) + COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); /* Can't trigger SAA FSM */ + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + if (1) { + int j; + P_FRAG_INFO_T prFragInfo; + + for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { + prFragInfo = &prStaRec->rFragInfo[j]; + + if (prFragInfo->pr1stFrag) { + /* nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); */ + prFragInfo->pr1stFrag = (P_SW_RFB_T) NULL; + } + } + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); + +} /* end of aisFsmInit_JOIN() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval TRUE We will retry JOIN +* @retval FALSE We will not retry JOIN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_RetryJOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* Retry other AuthType if possible */ + if (!prAisFsmInfo->ucAvailableAuthTypes) + return FALSE; + + if (prAisFsmInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { + + DBGLOG(AIS, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; + } else { + DBGLOG(AIS, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); + ASSERT(0); + } + + prAisFsmInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + + ASSERT(0); /* Can't trigger SAA FSM */ + return FALSE; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); + + return TRUE; + +} /* end of aisFsmRetryJOIN() */ + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief State Initialization of AIS_STATE_IBSS_ALONE +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* 4 <1> Check if IBSS was created before ? */ + if (prAisBssInfo->fgIsBeaconActivated) { + + /* 4 <2> Start IBSS Alone Timer for periodic SCAN and then SEARCH */ +#if !CFG_SLT_SUPPORT + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); +#endif + } + + aisFsmCreateIBSS(prAdapter); + +} /* end of aisFsmStateInit_IBSS_ALONE() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief State Initialization of AIS_STATE_IBSS_MERGE +* +* @param[in] prBssDesc The pointer of BSS_DESC_T which is the IBSS we will try to merge with. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + ASSERT(prBssDesc); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* 4 <1> We will merge with to this BSS immediately. */ + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); + if (prStaRec == NULL) { + DBGLOG(AIS, WARN, "Create station record fail\n"); + return; + } + + prStaRec->fgIsMerging = TRUE; + + prAisFsmInfo->prTargetStaRec = prStaRec; + + /* 4 <2.1> sync. to firmware domain */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* 4 <3> IBSS-Merge */ + aisFsmMergeIBSS(prAdapter, prStaRec); + +} /* end of aisFsmStateInit_IBSS_MERGE() */ + +#endif /* CFG_SUPPORT_ADHOC */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of JOIN Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_ABORT_T prJoinAbortMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* 1. Abort JOIN process */ + prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + + ASSERT(0); /* Can't abort SAA FSM */ + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prAisFsmInfo->prTargetStaRec; + + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); + + /* 2. Return channel privilege */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + +} /* end of aisFsmAbortJOIN() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of SCAN Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* Abort JOIN process. */ + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + + ASSERT(0); /* Can't abort SCN FSM */ + return; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_CANCEL; + prScanCancelMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfScanReq; + prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + prScanCancelMsg->fgIsChannelExt = FALSE; +#endif + + /* unbuffered message to guarantee scan is cancelled in sequence */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_UNBUF); + +} /* end of aisFsmAbortSCAN() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of NORMAL_TR Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + DBGLOG(AIS, TRACE, "aisFsmStateAbort_NORMAL_TR\n"); + + /* TODO(Kevin): Do abort other MGMT func */ + + /* 1. Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* 2.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 2.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + +} /* end of aisFsmAbortNORMAL_TR() */ + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of NORMAL_TR Abort +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_DESC_T prBssDesc; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* reset BSS-DESC */ + if (prAisFsmInfo->prTargetStaRec) { + prBssDesc = scanSearchBssDescByTA(prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); + + if (prBssDesc) { + prBssDesc->fgIsConnected = FALSE; + prBssDesc->fgIsConnecting = FALSE; + } + } + /* release channel privilege */ + aisFsmReleaseCh(prAdapter); + +} +#endif /* CFG_SUPPORT_ADHOC */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of AIS(Ad-hoc, Infra STA) +* +* @param[in] eNextState Enum value of next AIS STATE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + P_MSG_CH_REQ_T prMsgChReq; + P_MSG_SCN_SCAN_REQ prScanReqMsg; + P_AIS_REQ_HDR_T prAisReq; + ENUM_BAND_T eBand; + UINT_8 ucChannel; + UINT_16 u2ScanIELen; + ENUM_AIS_STATE_T eOriPreState; + + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + DEBUGFUNC("aisFsmSteps()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + eOriPreState = prAisFsmInfo->ePreviousState; + + do { + + /* Do entering Next State */ + prAisFsmInfo->ePreviousState = prAisFsmInfo->eCurrentState; + +#if DBG + DBGLOG(AIS, STATE, "TRANSITION: [%s] -> [%s]\n", + apucDebugAisState[prAisFsmInfo->eCurrentState], apucDebugAisState[eNextState]); +#else + DBGLOG(AIS, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", + DBG_AIS_IDX, prAisFsmInfo->eCurrentState, eNextState); +#endif + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + prAisFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN) FALSE; + + /* Do tasks of the State that we just entered */ + switch (prAisFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of following + * switch case. Instead I would like to use a common lookup table of array + * of function pointer to speed up state search. + */ + case AIS_STATE_IDLE: + + prAisReq = aisFsmGetNextRequest(prAdapter); + + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + + if (prAisReq == NULL || prAisReq->eReqType == AIS_REQUEST_RECONNECT) { + if (prConnSettings->fgIsConnReqIssued == TRUE && + prConnSettings->fgIsDisconnectedByNonRequest == FALSE) { + + prAisFsmInfo->fgTryScan = TRUE; + + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* sync with firmware */ + nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* reset trial count */ + prAisFsmInfo->ucConnTrialCount = 0; + + eNextState = AIS_STATE_SEARCH; + fgIsTransition = TRUE; + } else { + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* sync with firmware */ + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* check for other pending request */ + if (prAisReq && + (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE)) { + + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_SCAN; + + fgIsTransition = TRUE; + } + } + + if (prAisReq) { + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + } else if (prAisReq->eReqType == AIS_REQUEST_SCAN) { +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = FALSE; +#endif /* CFG_SUPPORT_ROAMING */ + wlanClearScanningResult(prAdapter); + + eNextState = AIS_STATE_SCAN; + fgIsTransition = TRUE; + + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } else if (prAisReq->eReqType == AIS_REQUEST_ROAMING_CONNECT + || prAisReq->eReqType == AIS_REQUEST_ROAMING_SEARCH) { + /* ignore */ + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } else if (prAisReq->eReqType == AIS_REQUEST_REMAIN_ON_CHANNEL) { + eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; + fgIsTransition = TRUE; + + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + + prAisFsmInfo->u4SleepInterval = AIS_BG_SCAN_INTERVAL_MIN_SEC; + + break; + + case AIS_STATE_SEARCH: + /* 4 <1> Search for a matched candidate and save it to prTargetBssDesc. */ +#if CFG_SLT_SUPPORT + prBssDesc = prAdapter->rWifiVar.rSltInfo.prPseudoBssDesc; +#else + prBssDesc = scanSearchBssDescByPolicy(prAdapter, NETWORK_TYPE_AIS_INDEX); +#endif + /* every time BSS join failure count is integral multiples of SCN_BSS_JOIN_FAIL_THRESOLD, + we need to scan again to find if a new BSS is here in the ESS, + this can also avoid too frequency to retry the rejected AP */ + if (prAisFsmInfo->ePreviousState == AIS_STATE_LOOKING_FOR || + ((eOriPreState == AIS_STATE_ONLINE_SCAN || + eOriPreState == AIS_STATE_SCAN) && prAisFsmInfo->ePreviousState != eOriPreState)) { + /* if previous state is scan/online scan/looking for, don't try to scan again */ + } else if (prBssDesc && prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD && + ((prBssDesc->ucJoinFailureCount - SCN_BSS_JOIN_FAIL_THRESOLD) % + SCN_BSS_JOIN_FAIL_THRESOLD) == 0) + prBssDesc = NULL; + + /* we are under Roaming Condition. */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if (prAisFsmInfo->ucConnTrialCount > AIS_ROAMING_CONNECTION_TRIAL_LIMIT) { +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_CONNLIMIT); +#endif /* CFG_SUPPORT_ROAMING */ + /* reset retry count */ + prAisFsmInfo->ucConnTrialCount = 0; + + /* abort connection trial */ + prConnSettings->fgIsConnReqIssued = FALSE; + + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = TRUE; + + break; + } + } + /* 4 <2> We are not under Roaming Condition. */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + + /* 4 <2.a> If we have the matched one */ + if (prBssDesc) { + + /* 4 Stored the Selected BSS security cipher. + For later asoc req compose IE */ + prAisBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; + prAisBssInfo->u4RsnSelectedPairwiseCipher = + prBssDesc->u4RsnSelectedPairwiseCipher; + prAisBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; + + /* 4 Do STATE transition and update current Operation Mode. */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* Record the target BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = TRUE; + + /* increase connection trial count */ + prAisFsmInfo->ucConnTrialCount++; + } +#if CFG_SUPPORT_ADHOC + else if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* Record the target BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + eNextState = AIS_STATE_IBSS_MERGE; + fgIsTransition = TRUE; + } +#endif /* CFG_SUPPORT_ADHOC */ + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = TRUE; + } + } + /* 4 <2.b> If we don't have the matched one */ + else { + + /* increase connection trial count for infrastructure connection */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) + prAisFsmInfo->ucConnTrialCount++; + /* 4 Try to SCAN */ + if (prAisFsmInfo->fgTryScan) { + eNextState = AIS_STATE_LOOKING_FOR; + + fgIsTransition = TRUE; + break; + } + /* 4 We've do SCAN already, now wait in some STATE. */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + + /* issue reconnect request, + * and retreat to idle state for scheduling */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eNextState = AIS_STATE_IDLE; + fgIsTransition = TRUE; + } +#if CFG_SUPPORT_ADHOC + else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) + || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) + || (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + prAisFsmInfo->prTargetBssDesc = NULL; + + eNextState = AIS_STATE_IBSS_ALONE; + fgIsTransition = TRUE; + } +#endif /* CFG_SUPPORT_ADHOC */ + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = TRUE; + } + } + } + /* 4 <3> We are under Roaming Condition. */ + else { /* prAdapter->eConnectionState == MEDIA_STATE_CONNECTED. */ + + /* 4 <3.a> This BSS_DESC_T is our AP. */ + /* NOTE(Kevin 2008/05/16): Following cases will go back to NORMAL_TR. + * CASE I: During Roaming, APP(WZC/NDISTEST) change the connection + * settings. That make we can NOT match the original AP, so the + * prBssDesc is NULL. + * CASE II: The same reason as CASE I. Because APP change the + * eOPMode to other network type in connection setting + * (e.g. NET_TYPE_IBSS), so the BssDesc become the IBSS node. + * (For CASE I/II, before WZC/NDISTEST set the OID_SSID, it will change + * other parameters in connection setting first. So if we do roaming + * at the same time, it will hit these cases.) + * + * CASE III: Normal case, we can't find other candidate to roam + * out, so only the current AP will be matched. + * + * CASE IV: Timestamp of the current AP might be reset + */ + if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION && + ((!prBssDesc) || /* CASE I */ + (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) || /* CASE II */ + (prBssDesc->fgIsConnected) || /* CASE III */ + (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID))) /* CASE IV */) { +#if DBG + if ((prBssDesc) && (prBssDesc->fgIsConnected)) + ASSERT(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); +#endif /* DBG */ + /* We already associated with it, go back to NORMAL_TR */ + /* TODO(Kevin): Roaming Fail */ +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); +#endif /* CFG_SUPPORT_ROAMING */ + + /* Retreat to NORMAL_TR state */ + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = TRUE; + break; + } + + /* 4 <3.b> Try to roam out for JOIN this BSS_DESC_T. */ + if (prBssDesc == NULL) { + /* increase connection trial count for infrastructure connection */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) + prAisFsmInfo->ucConnTrialCount++; + /* 4 Try to SCAN */ + if (prAisFsmInfo->fgTryScan) { + eNextState = AIS_STATE_LOOKING_FOR; + + fgIsTransition = TRUE; + break; + } + + /* 4 We've do SCAN already, now wait in some STATE. */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + + /* issue reconnect request, and retreat to idle state + * for scheduling */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eNextState = AIS_STATE_IDLE; + fgIsTransition = TRUE; + } +#if CFG_SUPPORT_ADHOC + else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) + || (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) + || (prConnSettings->eOPMode == + NET_TYPE_DEDICATED_IBSS)) { + + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + prAisFsmInfo->prTargetBssDesc = NULL; + + eNextState = AIS_STATE_IBSS_ALONE; + fgIsTransition = TRUE; + } +#endif /* CFG_SUPPORT_ADHOC */ + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = TRUE; + } + } else { +#if DBG + if (prAisBssInfo->ucReasonOfDisconnect != + DISCONNECT_REASON_CODE_REASSOCIATION) { + ASSERT(UNEQUAL_MAC_ADDR + (prBssDesc->aucBSSID, prAisBssInfo->aucBSSID)); + } +#endif /* DBG */ + + /* 4 Record the target BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* tyhsu: increase connection trial count */ + prAisFsmInfo->ucConnTrialCount++; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = TRUE; + } + } + + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + + DBGLOG(AIS, LOUD, "SCAN: Idle Begin - Current Time = %u\n", kalGetTimeTick()); + + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rBGScanTimer, SEC_TO_MSEC(prAisFsmInfo->u4SleepInterval)); + + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + if (prAisFsmInfo->u4SleepInterval < AIS_BG_SCAN_INTERVAL_MAX_SEC) + prAisFsmInfo->u4SleepInterval <<= 1; + break; + + case AIS_STATE_SCAN: + case AIS_STATE_ONLINE_SCAN: + case AIS_STATE_LOOKING_FOR: + + if (!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) { + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* sync with firmware */ + nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + } + + /* IE length decision */ + if (prAisFsmInfo->u4ScanIELength > 0) { + u2ScanIELen = (UINT_16) prAisFsmInfo->u4ScanIELength; + } else { +#if CFG_SUPPORT_WPS2 + u2ScanIELen = prAdapter->prGlueInfo->u2WSCIELen; +#else + u2ScanIELen = 0; +#endif + } + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + OFFSET_OF(MSG_SCN_SCAN_REQ, + aucIE) + u2ScanIELen); + if (!prScanReqMsg) { + ASSERT(0); /* Can't trigger SCAN FSM */ + return; + } + + prScanReqMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfScanReq; + prScanReqMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; + +#if CFG_SUPPORT_RDD_TEST_MODE + prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; +#else + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; +#endif + +#if CFG_SUPPORT_ROAMING_ENC + if (prAdapter->fgIsRoamingEncEnabled == TRUE) { + if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR && + prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + prScanReqMsg->u2ChannelDwellTime = AIS_ROAMING_SCAN_CHANNEL_DWELL_TIME; + } + } +#endif /* CFG_SUPPORT_ROAMING_ENC */ + + if (prAisFsmInfo->eCurrentState == AIS_STATE_SCAN + || prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + if (prAisFsmInfo->ucScanSSIDLen == 0) { + /* Scan for all available SSID */ + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + } else { + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + COPY_SSID(prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength, + prAisFsmInfo->aucScanSSID, prAisFsmInfo->ucScanSSIDLen); + } + } else { + /* Scan for determined SSID */ + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + COPY_SSID(prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + } + + /* check if tethering is running and need to fix on specific channel */ + if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->ucChannelListNum = 1; + prScanReqMsg->arChnlInfoList[0].eBand = eBand; + prScanReqMsg->arChnlInfoList[0].ucChannelNum = ucChannel; + } else { +#if 0 + aisFsmSetChannelInfo(prAdapter, prScanReqMsg, prAisFsmInfo->eCurrentState); +#endif + if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_NULL) { + if (prAdapter->fgEnable5GBand == TRUE) + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + else + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_2G4) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_5G) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + } else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + ASSERT(0); + } + + } + + if (prAisFsmInfo->u4ScanIELength > 0) { + kalMemCopy(prScanReqMsg->aucIE, prAisFsmInfo->aucScanIEBuf, + prAisFsmInfo->u4ScanIELength); + } else { +#if CFG_SUPPORT_WPS2 + if (prAdapter->prGlueInfo->u2WSCIELen > 0) { + kalMemCopy(prScanReqMsg->aucIE, &prAdapter->prGlueInfo->aucWSCIE, + prAdapter->prGlueInfo->u2WSCIELen); + } + } +#endif + + prScanReqMsg->u2IELen = u2ScanIELen; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); + DBGLOG(AIS, TRACE, "SendSR%d\n", prScanReqMsg->ucSeqNum); + prAisFsmInfo->fgTryScan = FALSE; /* Will enable background sleep for infrastructure */ + + prAdapter->ucScanTime++; + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel acquiring */ + return; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + prMsgChReq->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + + if (prAisFsmInfo->prTargetBssDesc != NULL) { + prMsgChReq->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prMsgChReq->eRfSco = prAisFsmInfo->prTargetBssDesc->eSco; + prMsgChReq->eRfBand = prAisFsmInfo->prTargetBssDesc->eBand; + COPY_MAC_ADDR(prMsgChReq->aucBSSID, prAisFsmInfo->prTargetBssDesc->aucBSSID); + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgIsChannelRequested = TRUE; + break; + + case AIS_STATE_JOIN: + aisFsmStateInit_JOIN(prAdapter, prAisFsmInfo->prTargetBssDesc); + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + aisFsmStateInit_IBSS_ALONE(prAdapter); + break; + + case AIS_STATE_IBSS_MERGE: + aisFsmStateInit_IBSS_MERGE(prAdapter, prAisFsmInfo->prTargetBssDesc); + break; +#endif /* CFG_SUPPORT_ADHOC */ + + case AIS_STATE_NORMAL_TR: + if (prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { + /* Don't do anything when rJoinTimeoutTimer is still ticking */ + } else { + /* 1. Process for pending scan */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + fgIsTransition = TRUE; + } + /* 2. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE) == TRUE) { + eNextState = AIS_STATE_LOOKING_FOR; + fgIsTransition = TRUE; + } + /* 3. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE) == TRUE) { + eNextState = AIS_STATE_SEARCH; + fgIsTransition = TRUE; + } else if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE) == + TRUE) { + eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; + fgIsTransition = TRUE; + } + } + + break; + + case AIS_STATE_DISCONNECTING: + /* send for deauth frame for disconnection */ + authSendDeauthFrame(prAdapter, + prAisBssInfo->prStaRecOfAP, + (P_SW_RFB_T) NULL, REASON_CODE_DEAUTH_LEAVING_BSS, aisDeauthXmitComplete); + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer, 100); + break; + + case AIS_STATE_REQ_REMAIN_ON_CHANNEL: + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel acquiring */ + return; + } + + /* zero-ize */ + kalMemZero(prMsgChReq, sizeof(MSG_CH_REQ_T)); + + /* filling */ + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + prMsgChReq->u4MaxInterval = prAisFsmInfo->rChReqInfo.u4DurationMs; + prMsgChReq->ucPrimaryChannel = prAisFsmInfo->rChReqInfo.ucChannelNum; + prMsgChReq->eRfSco = prAisFsmInfo->rChReqInfo.eSco; + prMsgChReq->eRfBand = prAisFsmInfo->rChReqInfo.eBand; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgIsChannelRequested = TRUE; + + break; + + case AIS_STATE_REMAIN_ON_CHANNEL: + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + /* sync with firmware */ + nicActivateNetwork(prAdapter, NETWORK_TYPE_AIS_INDEX); + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + break; + + } + } while (fgIsTransition); + + return; + +} /* end of aisFsmSteps() */ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmSetChannelInfo(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ ScanReqMsg, IN ENUM_AIS_STATE_T CurrentState) +{ + /*get scan channel infro from prAdapter->prGlueInfo->prScanRequest*/ + struct cfg80211_scan_request *scan_req_t = NULL; + struct ieee80211_channel *channel_tmp = NULL; + int i = 0; + int j = 0; + UINT_8 channel_num = 0; + UINT_8 channel_counts = 0; + + if ((prAdapter == NULL) || (ScanReqMsg == NULL)) + return; + if ((CurrentState == AIS_STATE_SCAN) || (CurrentState == AIS_STATE_ONLINE_SCAN)) { + if (prAdapter->prGlueInfo->prScanRequest != NULL) { + scan_req_t = prAdapter->prGlueInfo->prScanRequest; + if ((scan_req_t != NULL) && (scan_req_t->n_channels != 0) && + (scan_req_t->channels != NULL)) { + channel_counts = scan_req_t->n_channels; + DBGLOG(AIS, TRACE, "channel_counts=%d\n", channel_counts); + + while (j < channel_counts) { + channel_tmp = scan_req_t->channels[j]; + if (channel_tmp == NULL) + break; + + DBGLOG(AIS, TRACE, "set channel band=%d\n", channel_tmp->band); + if (channel_tmp->band >= IEEE80211_BAND_60GHZ) { + j++; + continue; + } + if (i >= MAXIMUM_OPERATION_CHANNEL_LIST) + break; + if (channel_tmp->band == IEEE80211_BAND_2GHZ) + ScanReqMsg->arChnlInfoList[i].eBand = BAND_2G4; + else if (channel_tmp->band == IEEE80211_BAND_5GHZ) + ScanReqMsg->arChnlInfoList[i].eBand = BAND_5G; + + DBGLOG(AIS, TRACE, "set channel channel_rer =%d\n", + channel_tmp->center_freq); + + channel_num = (UINT_8)nicFreq2ChannelNum( + channel_tmp->center_freq * 1000); + + DBGLOG(AIS, TRACE, "set channel channel_num=%d\n", + channel_num); + ScanReqMsg->arChnlInfoList[i].ucChannelNum = channel_num; + + j++; + i++; + } + } + } + } + + DBGLOG(AIS, INFO, "set channel i=%d\n", i); + if (i > 0) { + ScanReqMsg->ucChannelListNum = i; + ScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + + return; + } + + if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_NULL) { + if (prAdapter->fgEnable5GBand == TRUE) + ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + else + ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_2G4) { + ScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } else if (prAdapter->aePreferBand[NETWORK_TYPE_AIS_INDEX] + == BAND_5G) { + ScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + } else { + ScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + ASSERT(0); + } + + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +VOID aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + UINT_8 ucSeqNumOfCompMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventScanDone()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + ucScanTimeoutTimes = 0; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + ASSERT(prScanDoneMsg->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX); + + ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; + cnmMemFree(prAdapter, prMsgHdr); + + eNextState = prAisFsmInfo->eCurrentState; + + if (ucSeqNumOfCompMsg != prAisFsmInfo->ucSeqNumOfScanReq) { + DBGLOG(AIS, WARN, "SEQ NO of AIS SCN DONE MSG is not matched %d %d.\n", + ucSeqNumOfCompMsg, prAisFsmInfo->ucSeqNumOfScanReq); + } else { + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_SCAN: + prConnSettings->fgIsScanReqIssued = FALSE; + + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); + eNextState = AIS_STATE_IDLE; +#if CFG_SUPPORT_AGPS_ASSIST + scanReportScanResultToAgps(prAdapter); +#endif + break; + + case AIS_STATE_ONLINE_SCAN: + prConnSettings->fgIsScanReqIssued = FALSE; + + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_NORMAL_TR; +#endif /* CFG_SUPPORT_ROAMING */ +#if CFG_SUPPORT_AGPS_ASSIST + scanReportScanResultToAgps(prAdapter); +#endif + break; + + case AIS_STATE_LOOKING_FOR: + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + scanReportBss2Cfg80211(prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_SEARCH; +#endif /* CFG_SUPPORT_ROAMING */ + break; + + default: + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + break; + + } + } + + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisFsmRunEventScanDone() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + UINT_8 ucReasonOfDisconnect; + BOOLEAN fgDelayIndication; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventAbort()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> Extract information of Abort Message and then free memory. */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T) prMsgHdr; + ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; + fgDelayIndication = prAisAbortMsg->fgDelayIndication; + + cnmMemFree(prAdapter, prMsgHdr); + +#if DBG + DBGLOG(AIS, STATE, "EVENT-ABORT: Current State %s %d\n", + apucDebugAisState[prAisFsmInfo->eCurrentState], ucReasonOfDisconnect); +#else + DBGLOG(AIS, STATE, "[%d] EVENT-ABORT: Current State [%d %d]\n", + DBG_AIS_IDX, prAisFsmInfo->eCurrentState, ucReasonOfDisconnect); +#endif + + GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); + + /* 4 <2> clear previous pending connection request and insert new one */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DEAUTHENTICATED + || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DISASSOCIATED) { + prConnSettings->fgIsDisconnectedByNonRequest = TRUE; + } else { + prConnSettings->fgIsDisconnectedByNonRequest = FALSE; + } + /* to support user space triggered roaming */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_ROAMING && + prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && + prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_ROAMING_CONNECT); + } + return; + } + + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + if (prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + /* 4 <3> invoke abort handler */ + aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, fgDelayIndication); + } + +} /* end of aisFsmRunEventAbort() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function handles AIS-FSM abort event/command +* +* \param[in] prAdapter Pointer of ADAPTER_T +* ucReasonOfDisconnect Reason for disonnection +* fgDelayIndication Option to delay disconnection indication +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmStateAbort(IN P_ADAPTER_T prAdapter, UINT_8 ucReasonOfDisconnect, BOOLEAN fgDelayIndication) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + BOOLEAN fgIsCheckConnected; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + fgIsCheckConnected = FALSE; + + /* 4 <1> Save information of Abort Message and then free memory. */ + prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; + + /* 4 <2> Abort current job. */ + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IDLE: + case AIS_STATE_SEARCH: + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + /* Do cancel timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + + break; + + case AIS_STATE_LOOKING_FOR: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_JOIN: + /* Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = TRUE; + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + case AIS_STATE_IBSS_MERGE: + aisFsmStateAbort_IBSS(prAdapter); + break; +#endif /* CFG_SUPPORT_ADHOC */ + + case AIS_STATE_ONLINE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, FALSE) == FALSE) + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_NORMAL_TR: + fgIsCheckConnected = TRUE; + break; + + case AIS_STATE_DISCONNECTING: + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + + break; + + case AIS_STATE_REQ_REMAIN_ON_CHANNEL: + /* release channel */ + aisFsmReleaseCh(prAdapter); + break; + + case AIS_STATE_REMAIN_ON_CHANNEL: + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2. stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + + break; + + default: + break; + } + + if (fgIsCheckConnected && (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState)) { + + /* switch into DISCONNECTING state for sending DEAUTH if necessary */ + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_NEW_CONNECTION && + prAisBssInfo->prStaRecOfAP && prAisBssInfo->prStaRecOfAP->fgIsInUse) { + aisFsmSteps(prAdapter, AIS_STATE_DISCONNECTING); + + return; + } + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + + } + + aisFsmDisconnect(prAdapter, fgDelayIndication); + + +} /* end of aisFsmStateAbort() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Join Complete Event from SAA FSM for AIS FSM +* +* @param[in] prMsgHdr Message of Join Complete of SAA FSM. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_JOIN_COMP_T prJoinCompMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prAssocRspSwRfb; + P_BSS_INFO_T prAisBssInfo; + UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; + OS_SYSTIME rCurrentTime; + + DEBUGFUNC("aisFsmRunEventJoinComplete()"); + + ASSERT(prMsgHdr); + + GET_CURRENT_SYSTIME(&rCurrentTime); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + + eNextState = prAisFsmInfo->eCurrentState; + + DBGLOG(AIS, TRACE, "AISOK\n"); + + /* Check State and SEQ NUM */ + do { + if (prAisFsmInfo->eCurrentState != AIS_STATE_JOIN) + break; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prAisFsmInfo->ucSeqNumOfReqMsg) { + + /* 4 <1> JOIN was successful */ + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + + /* 1. Reset retry count */ + prAisFsmInfo->ucConnTrialCount = 0; + + /* Completion of roaming */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + +#if CFG_SUPPORT_ROAMING + /* 2. Deactivate previous BSS */ + aisFsmRoamingDisconnectPrevAP(prAdapter, prStaRec); + + /* 3. Update bss based on roaming staRec */ + aisUpdateBssInfoForRoamingAP(prAdapter, prStaRec, prAssocRspSwRfb); +#endif /* CFG_SUPPORT_ROAMING */ + } else { + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && + (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, + STA_STATE_1); + } + /* 4 <1.3> Update BSS_INFO_T */ + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + /* 4 <1.5> Update RSSI if necessary */ + nicUpdateRSSI(prAdapter, NETWORK_TYPE_AIS_INDEX, + (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); + + /* 4 <1.6> Indicate Connected Event to Host immediately. */ + /* Require BSSID, Association ID, Beacon Interval.. */ + /* from AIS_BSS_INFO_T */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, + FALSE); + + /* add for ctia mode */ + if (EQUAL_SSID + (aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen)) { + nicEnterCtiaMode(prAdapter, TRUE, FALSE); + } + } + +#if CFG_SUPPORT_ROAMING + /* if bssid is given, it means we no need fw roaming */ + if (prAdapter->rWifiVar.rConnSettings.eConnectionPolicy != CONNECT_BY_BSSID) + roamingFsmRunEventStart(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + /* 4 <1.7> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + } + /* 4 <2> JOIN was not successful */ + else { + /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ + if (aisFsmStateInit_RetryJOIN(prAdapter, prStaRec) == FALSE) { + P_BSS_DESC_T prBssDesc; + + /* 1. Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* 2. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + prBssDesc = scanSearchBssDescByBssid(prAdapter, prStaRec->aucMacAddr); + + if (prBssDesc == NULL) { + /* it maybe NULL when wlanRemove */ + /* + (1) UI does wifi off during SAA does auth/assoc procedure. + (2) We will do LINK_INITIALIZE(&prScanInfo->rBSSDescList); + in nicUninitMGMT(). + (3) We will handle prMsduInfo->pfTxDoneHandler + in nicTxRelease(). + (4) prMsduInfo->pfTxDoneHandler will point to + saaFsmRunEventTxDone(). + (5) Then jump to saaFsmSteps() -> saaFsmSendEventJoinComplete() + (6) Finally mboxSendMsg() -> aisFsmRunEventJoinComplete(). + (7) In aisFsmRunEventJoinComplete(), we will check + "prBssDesc = scanSearchBssDescByBssid(prAdapter, + prStaRec->aucMacAddr);" + (8) And prBssDesc will be NULL and hangs in + "ASSERT(prBssDesc->fgIsConnecting);" when DBG=0. + ASSERT(prBssDesc); + ASSERT(prBssDesc->fgIsConnecting); + */ + break; + } + /* ASSERT(prBssDesc); */ + /* ASSERT(prBssDesc->fgIsConnecting); */ + prBssDesc->ucJoinFailureCount++; + if (prBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { + GET_CURRENT_SYSTIME(&prBssDesc->rJoinFailTime); + DBGLOG(AIS, INFO, + "Bss %pM join fail %d times,temp disable it at time:%u\n", + prBssDesc->aucBSSID, + SCN_BSS_JOIN_FAIL_THRESOLD, prBssDesc->rJoinFailTime); + } + + if (prBssDesc) + prBssDesc->fgIsConnecting = FALSE; + + /* 3.3 Free STA-REC */ + if (prStaRec != prAisBssInfo->prStaRecOfAP) + cnmStaRecFree(prAdapter, prStaRec, FALSE); + + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { +#if CFG_SUPPORT_ROAMING + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; +#endif /* CFG_SUPPORT_ROAMING */ + } else if (CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, + SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { + /* abort connection trial */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = FALSE; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_CONNECT_INDICATION, NULL, 0); + + eNextState = AIS_STATE_IDLE; + } else { + /* 4.b send reconnect request */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eNextState = AIS_STATE_IDLE; + } + } + } + } +#if DBG + else + DBGLOG(AIS, WARN, "SEQ NO of AIS JOIN COMP MSG is not matched.\n"); +#endif /* DBG */ + + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + } while (FALSE); + + if (prAssocRspSwRfb) + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + + cnmMemFree(prAdapter, prMsgHdr); + +} /* end of aisFsmRunEventJoinComplete() */ + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Grant Msg of IBSS Create which was sent by +* CNM to indicate that channel was changed for creating IBSS. +* +* @param[in] prAdapter Pointer of ADAPTER_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + do { + /* Check State */ + if (prAisFsmInfo->eCurrentState == AIS_STATE_IBSS_ALONE) + aisUpdateBssInfoForCreateIBSS(prAdapter); + } while (FALSE); + +} /* end of aisFsmCreateIBSS() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Grant Msg of IBSS Merge which was sent by +* CNM to indicate that channel was changed for merging IBSS. +* +* @param[in] prAdapter Pointer of ADAPTER_T +* @param[in] prStaRec Pointer of STA_RECORD_T for merge +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + do { + + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_MERGE: + { + P_BSS_DESC_T prBssDesc; + + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous Peers' STA_RECORD_T in Driver if have. */ + bssClearClientList(prAdapter, prAisBssInfo); + + /* 4 <1.3> Unmark connection flag of previous BSS_DESC_T. */ + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + if (prBssDesc != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = FALSE; + } + /* 4 <1.4> Update BSS_INFO_T */ + aisUpdateBssInfoForMergeIBSS(prAdapter, prStaRec); + + /* 4 <1.5> Add Peers' STA_RECORD_T to Client List */ + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + + /* 4 <1.6> Activate current Peer's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + /* 4 <1.7> Enable other features */ + + /* 4 <1.8> Indicate Connected Event to Host immediately. */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + + /* 4 <1.9> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + + /* 4 <1.10> Release channel privilege */ + aisFsmReleaseCh(prAdapter); + +#if CFG_SLT_SUPPORT + prAdapter->rWifiVar.rSltInfo.prPseudoStaRec = prStaRec; +#endif + } + break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + + } while (FALSE); + +} /* end of aisFsmMergeIBSS() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Notification of existing IBSS was found +* from SCN. +* +* @param[in] prMsgHdr Message of Notification of an IBSS was present. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + BOOLEAN fgIsMergeIn; + + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) prMsgHdr; + + ASSERT(prAisIbssPeerFoundMsg->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX); + + prStaRec = prAisIbssPeerFoundMsg->prStaRec; + ASSERT(prStaRec); + + fgIsMergeIn = prAisIbssPeerFoundMsg->fgIsMergeIn; + + cnmMemFree(prAdapter, prMsgHdr); + + eNextState = prAisFsmInfo->eCurrentState; + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: + { + /* 4 <1> An IBSS Peer 'merged in'. */ + if (fgIsMergeIn) { + + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Add Peers' STA_RECORD_T to Client List */ + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + +#if CFG_SLT_SUPPORT + /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + if (prBssDesc != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + } else { + ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ + } + + /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ + prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ +#else + /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + if (prBssDesc != NULL) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + } else { + ASSERT(0); /* Should be able to find a BSS_DESC_T here. */ + } + + /* 4 <1.4> Activate current Peer's STA_RECORD_T in Driver. */ + prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ + +#endif + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + /* 4 <1.6> sync. to firmware */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <1.7> Indicate Connected Event to Host immediately. */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + + /* 4 <1.8> indicate PM for connected */ + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <1.9> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + + /* 4 <1.10> Release channel privilege */ + aisFsmReleaseCh(prAdapter); + } + /* 4 <2> We need 'merge out' to this IBSS */ + else { + + /* 4 <2.1> Get corresponding BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* 4 <2.2> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_IBSS_MERGE; + } + } + break; + + case AIS_STATE_NORMAL_TR: + { + + /* 4 <3> An IBSS Peer 'merged in'. */ + if (fgIsMergeIn) { + + /* 4 <3.1> Add Peers' STA_RECORD_T to Client List */ + bssAddStaRecToClientList(prAdapter, prAisBssInfo, prStaRec); + +#if CFG_SLT_SUPPORT + /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ + prStaRec->fgIsQoS = TRUE; /* TODO(Kevin): TBD */ +#else + /* 4 <3.2> Activate current Peer's STA_RECORD_T in Driver. */ + prStaRec->fgIsQoS = FALSE; /* TODO(Kevin): TBD */ +#endif + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = FALSE; + + } + /* 4 <4> We need 'merge out' to this IBSS */ + else { + + /* 4 <4.1> Get corresponding BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* 4 <4.2> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_IBSS_MERGE; + + } + } + break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisFsmRunEventFoundIBSSPeer() */ +#endif /* CFG_SUPPORT_ADHOC */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Media State to HOST +* +* @param[in] eConnectionState Current Media State +* @param[in] fgDelayIndication Set TRUE for postponing the Disconnect Indication. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, BOOLEAN fgDelayIndication) +{ + EVENT_CONNECTION_STATUS rEventConnStatus; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisIndicationOfMediaStateToHost()"); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* NOTE(Kevin): Move following line to aisChangeMediaState() macro per CM's request. */ + /* prAisBssInfo->eConnectionState = eConnectionState; */ + + /* For indicating the Disconnect Event only if current media state is + * disconnected and we didn't do indication yet. + */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + if (prAisBssInfo->eConnectionStateIndicated == eConnectionState) + return; + } + + if (!fgDelayIndication) { + /* 4 <0> Cancel Delay Timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); + + /* 4 <1> Fill EVENT_CONNECTION_STATUS */ + rEventConnStatus.ucMediaStatus = (UINT_8) eConnectionState; + + if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + rEventConnStatus.ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_INFRA; + rEventConnStatus.u2AID = prAisBssInfo->u2AssocId; + rEventConnStatus.u2ATIMWindow = 0; + } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + rEventConnStatus.ucInfraMode = (UINT_8) NET_TYPE_IBSS; + rEventConnStatus.u2AID = 0; + rEventConnStatus.u2ATIMWindow = prAisBssInfo->u2ATIMWindow; + } else { + ASSERT(0); + } + + COPY_SSID(rEventConnStatus.aucSsid, + rEventConnStatus.ucSsidLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + COPY_MAC_ADDR(rEventConnStatus.aucBssid, prAisBssInfo->aucBSSID); + + rEventConnStatus.u2BeaconPeriod = prAisBssInfo->u2BeaconInterval; + rEventConnStatus.u4FreqInKHz = nicChannelNum2Freq(prAisBssInfo->ucPrimaryChannel); + + switch (prAisBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_HR_DSSS_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + + case PHY_TYPE_ERP_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM24; + break; + + case PHY_TYPE_OFDM_INDEX: + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_OFDM5; + break; + + default: + ASSERT(0); + rEventConnStatus.ucNetworkType = (UINT_8) PARAM_NETWORK_TYPE_DS; + break; + } + } else { + /* Deactivate previous Peers' STA_RECORD_T in Driver if have. */ + bssClearClientList(prAdapter, prAisBssInfo); + +#if CFG_PRIVACY_MIGRATION + /* Clear the pmkid cache while media disconnect */ + secClearPmkid(prAdapter); +#endif + + rEventConnStatus.ucReasonOfDisconnect = prAisBssInfo->ucReasonOfDisconnect; + } + + /* 4 <2> Indication */ + nicMediaStateChange(prAdapter, NETWORK_TYPE_AIS_INDEX, &rEventConnStatus); + prAisBssInfo->eConnectionStateIndicated = eConnectionState; + } else { + /* NOTE: Only delay the Indication of Disconnect Event */ + ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); + + DBGLOG(AIS, INFO, "Postpone the indication of Disconnect for %d seconds\n", + prConnSettings->ucDelayTimeOfDisconnectEvent); + + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer, + SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); + } + +} /* end of aisIndicationOfMediaStateToHost() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Media Disconnect" to HOST +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if (prAisBssInfo->prStaRecOfAP) { + /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ + + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + } + /* 4 <2> Remove pending connection request */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + prConnSettings->fgIsDisconnectedByNonRequest = TRUE; + prAisBssInfo->u2DeauthReason = REASON_CODE_BEACON_TIMEOUT; + /* 4 <3> Indicate Disconnected Event to Host immediately. */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, FALSE); + +} /* end of aisPostponedEventOfDisconnTimeout() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the association was completed. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, P_SW_RFB_T prAssocRspSwRfb) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_BSS_DESC_T prBssDesc; + UINT_16 u2IELength; + PUINT_8 pucIE; + + DEBUGFUNC("aisUpdateBssInfoForJOIN()"); + + ASSERT(prStaRec); + ASSERT(prAssocRspSwRfb); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + + DBGLOG(AIS, TRACE, "Update AIS_BSS_INFO_T and apply settings to MAC\n"); + + /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Setup Channel, Band */ + prAisBssInfo->ucPrimaryChannel = prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prAisBssInfo->eBand = prAisFsmInfo->prTargetBssDesc->eBand; + + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = prStaRec; + prAisBssInfo->u2AssocId = prStaRec->u2AssocId; + + /* 4 <2.2> Setup Capability */ + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) + prAisBssInfo->fgIsShortPreambleAllowed = TRUE; + else + prAisBssInfo->fgIsShortPreambleAllowed = FALSE; + +#if (CFG_SUPPORT_TDLS == 1) + /* init the TDLS flags */ + prAisBssInfo->fgTdlsIsProhibited = prStaRec->fgTdlsIsProhibited; + prAisBssInfo->fgTdlsIsChSwProhibited = prStaRec->fgTdlsIsChSwProhibited; +#endif /* CFG_SUPPORT_TDLS */ + + /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ + /* 4 <3.1> Setup BSSID */ + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + /* 4 <3.2> Parse WMM and setup QBSS flag */ + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prAisBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAssocRspFrame->aucBSSID); + if (prBssDesc) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + prBssDesc->ucJoinFailureCount = 0; + + /* 4 <4.1> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + } else { + /* should never happen */ + ASSERT(0); + } + + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; + + /* 4 <4.2> Update HT information and set channel */ + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + /* 4 <4.3> Sync with firmware for BSS-INFO */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ + /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ + +} /* end of aisUpdateBssInfoForJOIN() */ + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will create an Ad-Hoc network and start sending Beacon Frames. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prAisBssInfo->fgIsBeaconActivated) + return; + /* 3 <1> Update BSS_INFO_T per Network Basis */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + prAisBssInfo->u2AssocId = 0; + + /* 4 <1.4> Setup Channel, Band and Phy Attributes */ + prAisBssInfo->ucPrimaryChannel = prConnSettings->ucAdHocChannelNum; + prAisBssInfo->eBand = prConnSettings->eAdHocBand; + + if (prAisBssInfo->eBand == BAND_2G4) { + /* Depend on eBand */ + prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_MIXED_11BG; + } else { + /* Depend on eBand */ + prAisBssInfo->ucPhyTypeSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_11A; + } + + /* 4 <1.5> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prConnSettings->u2BeaconPeriod; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = prConnSettings->u2AtimWindow; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + +#if CFG_PRIVACY_MIGRATION + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION2_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION3_ENABLED) { + prAisBssInfo->fgIsProtection = TRUE; + } else { + prAisBssInfo->fgIsProtection = FALSE; + } +#else + prAisBssInfo->fgIsProtection = FALSE; +#endif + + /* 3 <2> Update BSS_INFO_T common part */ + ibssInitForAdHoc(prAdapter, prAisBssInfo); + + /* 3 <3> Set MAC HW */ + /* 4 <3.1> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + /* 4 <3.2> use command packets to inform firmware */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <3.3> enable beaconing */ + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <3.4> Update AdHoc PM parameter */ + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 3 <4> Set ACTIVE flag. */ + prAisBssInfo->fgIsBeaconActivated = TRUE; + prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; + + /* 3 <5> Start IBSS Alone Timer */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); + + return; + +} /* end of aisCreateIBSS() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the existing IBSS was found. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + /* UINT_16 u2IELength; */ + /* PUINT_8 pucIE; */ + + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + + if (!prAisBssInfo->fgIsBeaconActivated) { + + /* 3 <1> Update BSS_INFO_T per Network Basis */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + prAisBssInfo->u2AssocId = 0; + } + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Setup Capability */ + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use Peer's Cap Info as IBSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prAisBssInfo->fgIsShortPreambleAllowed = TRUE; + prAisBssInfo->fgUseShortPreamble = TRUE; + } else { + prAisBssInfo->fgIsShortPreambleAllowed = FALSE; + prAisBssInfo->fgUseShortPreamble = FALSE; + } + + /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ + prAisBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ + prAisBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + + if (prAisBssInfo->u2CapInfo & CAP_INFO_PRIVACY) + prAisBssInfo->fgIsProtection = TRUE; + else + prAisBssInfo->fgIsProtection = FALSE; + + /* 4 <2.2> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + rateGetDataRatesFromRateSet(prAisBssInfo->u2OperationalRateSet, + prAisBssInfo->u2BSSBasicRateSet, + prAisBssInfo->aucAllSupportedRates, &prAisBssInfo->ucAllSupportedRatesLen); + + /* 3 <3> X Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + if (prBssDesc) { + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + /* 4 <4.1> Setup BSSID */ + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prBssDesc->aucBSSID); + + /* 4 <4.2> Setup Channel, Band */ + prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prAisBssInfo->eBand = prBssDesc->eBand; + + /* 4 <4.3> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; /* TBD(Kevin) */ + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + } else { + /* should never happen */ + ASSERT(0); + } + + /* 3 <5> Set MAC HW */ + /* 4 <5.1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + { + UINT_8 ucLowestBasicRateIndex; + + if (!rateGetLowestRateIndexFromRateSet(prAisBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex)) { + + if (prAisBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_OFDM) + ucLowestBasicRateIndex = RATE_6M_INDEX; + else + ucLowestBasicRateIndex = RATE_1M_INDEX; + } + + prAisBssInfo->ucHwDefaultFixedRateCode = + aucRateIndex2RateCode[prAisBssInfo->fgUseShortPreamble][ucLowestBasicRateIndex]; + } + + /* 4 <5.2> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + /* 4 <5.3> use command packets to inform firmware */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <5.4> enable beaconing */ + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 4 <5.5> Update AdHoc PM parameter */ + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* 3 <6> Set ACTIVE flag. */ + prAisBssInfo->fgIsBeaconActivated = TRUE; + prAisBssInfo->fgHoldSameBssidForIBSS = TRUE; + +} /* end of aisUpdateBssInfoForMergeIBSS() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + BOOLEAN fgReplyProbeResp = FALSE; + + ASSERT(prSwRfb); + ASSERT(pu4ControlFlags); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, ...) */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8) prSwRfb->pvHeader + prSwRfb->u2HeaderLen; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_SSID == IE_ID(pucIE)) { + if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) + prIeSsid = (P_IE_SSID_T) pucIE; + break; + } + } /* end of IE_FOR_EACH */ + + /* 4 <2> Check network conditions */ + + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + + if ((prIeSsid) && ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, /* CURRENT SSID */ + prIeSsid->aucSSID, prIeSsid->ucLength))) { + fgReplyProbeResp = TRUE; + } + } + + return fgReplyProbeResp; + +} /* end of aisValidateProbeReq() */ + +#endif /* CFG_SUPPORT_ADHOC */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will modify and update necessary information to firmware +* for disconnection handling +* +* @param[in] prAdapter Pointer to the Adapter structure. +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgDelayIndication) +{ + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); + +#if CFG_SUPPORT_ADHOC + if (prAisBssInfo->fgIsBeaconActivated) { + nicUpdateBeaconIETemplate(prAdapter, IE_UPD_METHOD_DELETE_ALL, NETWORK_TYPE_AIS_INDEX, 0, NULL, 0); + + prAisBssInfo->fgIsBeaconActivated = FALSE; + } +#endif + + rlmBssAborted(prAdapter, prAisBssInfo); + + /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { + /* add for ctia mode */ + { + UINT_8 aucP2pSsid[] = CTIA_MAGIC_SSID; + + if (EQUAL_SSID(aucP2pSsid, CTIA_MAGIC_SSID_LEN, prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) + nicEnterCtiaMode(prAdapter, FALSE, FALSE); + } + + if (prAisBssInfo->ucReasonOfDisconnect == DISCONNECT_REASON_CODE_RADIO_LOST) { + scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + + /* remove from scanning results as well */ + wlanClearBssInScanningResult(prAdapter, prAisBssInfo->aucBSSID); + + /* trials for re-association */ + if (fgDelayIndication) { + DBGLOG(AIS, INFO, "try to do re-association due to radio lost!\n"); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, TRUE); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + } + } else { + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + } + + if (fgDelayIndication) { + if (OP_MODE_IBSS != prAisBssInfo->eCurrentOPMode) + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } else { + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } + } else { + prAisBssInfo->fgHoldSameBssidForIBSS = FALSE; + } + + /* 4 <4> Change Media State immediately. */ + if (prAisBssInfo->ucReasonOfDisconnect != DISCONNECT_REASON_CODE_REASSOCIATION) { + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + /* 4 <4.1> sync. with firmware */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + } + + if (!fgDelayIndication) { + /* 4 <5> Deactivate previous AP's STA_RECORD_T or all Clients in Driver if have. */ + if (prAisBssInfo->prStaRecOfAP) { + /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ + + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + } + } +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventAbort(prAdapter); + + /* clear pending roaming connection request */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); +#endif /* CFG_SUPPORT_ROAMING */ + + /* 4 <6> Indicate Disconnected Event to Host */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, fgDelayIndication); + + /* 4 <7> Trigger AIS FSM */ + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + +} /* end of aisFsmDisconnect() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of Scan done Time-Out to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 IsrCnt = 0, IsrPassCnt = 0, TaskIsrCnt = 0; +VOID aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ +#define SCAN_DONE_TIMEOUT_TIMES_LIMIT 20 + + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_CONNECTION_SETTINGS_T prConnSettings; + GL_HIF_INFO_T *HifInfo; + UINT_32 u4FwCnt; + P_GLUE_INFO_T prGlueInfo; + + DEBUGFUNC("aisFsmRunEventScanDoneTimeOut()"); + + prGlueInfo = prAdapter->prGlueInfo; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + HifInfo = &prAdapter->prGlueInfo->rHifInfo; + + DBGLOG(AIS, WARN, "aisFsmRunEventScanDoneTimeOut Current[%d], ucScanTimeoutTimes=%d\n", + prAisFsmInfo->eCurrentState, ucScanTimeoutTimes); + DBGLOG(AIS, WARN, "Isr/task %u %u %u (0x%x)\n", prGlueInfo->IsrCnt, prGlueInfo->IsrPassCnt, + prGlueInfo->TaskIsrCnt, prAdapter->fgIsIntEnable); + + /* dump firmware program counter */ + DBGLOG(AIS, WARN, "CONNSYS FW CPUINFO:\n"); + for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) + DBGLOG(AIS, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); + + ucScanTimeoutTimes++; + if (ucScanTimeoutTimes > SCAN_DONE_TIMEOUT_TIMES_LIMIT) { + kalSendAeeWarning("[Scan done timeout more than 20 times!]", __func__); + glDoChipReset(); + } +#if 0 /* ALPS02018734: remove trigger assert */ + if (prAdapter->fgTestMode == FALSE) { + /* Titus - xxx */ + /* assert if and only if in normal mode */ + mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 40); + } +#endif + /* report all scanned frames to upper layer to avoid scanned frame is timeout */ + /* must be put before kalScanDone */ +/* scanReportBss2Cfg80211(prAdapter,BSS_TYPE_INFRASTRUCTURE,NULL); */ + + prConnSettings->fgIsScanReqIssued = FALSE; + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, WLAN_STATUS_SUCCESS); + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_SCAN: + prAisFsmInfo->u4ScanIELength = 0; + eNextState = AIS_STATE_IDLE; + break; + case AIS_STATE_ONLINE_SCAN: + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_NORMAL_TR; +#endif /* CFG_SUPPORT_ROAMING */ + break; + default: + break; + } + + /* try to stop scan in CONNSYS */ + aisFsmStateAbort_SCAN(prAdapter); + + /* wlanQueryDebugCode(prAdapter); */ /* display current SCAN FSM in FW, debug use */ + + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisFsmBGSleepTimeout() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Background Scan Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventBGSleepTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + DBGLOG(AIS, LOUD, "EVENT - SCAN TIMER: Idle End - Current Time = %u\n", kalGetTimeTick()); + + eNextState = AIS_STATE_LOOKING_FOR; + + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX); + + break; + + default: + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisFsmBGSleepTimeout() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "IBSS ALONE Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventIbssAloneTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: + + /* There is no one participate in our AdHoc during this TIMEOUT Interval + * so go back to search for a valid IBSS again. + */ + + DBGLOG(AIS, LOUD, "EVENT-IBSS ALONE TIMER: Start pairing\n"); + + prAisFsmInfo->fgTryScan = TRUE; + + /* abort timer */ + aisFsmReleaseCh(prAdapter); + + /* Pull back to SEARCH to find candidate again */ + eNextState = AIS_STATE_SEARCH; + + break; + + default: + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisIbssAloneTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Join Time-Out" to AIS FSM. +* +* @param[in] u4Param Unused timer parameter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + OS_SYSTIME rCurrentTime; + + DEBUGFUNC("aisFsmRunEventJoinTimeout()"); + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + eNextState = prAisFsmInfo->eCurrentState; + + GET_CURRENT_SYSTIME(&rCurrentTime); + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_JOIN: + DBGLOG(AIS, LOUD, "EVENT- JOIN TIMEOUT\n"); + + /* 1. Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* 2. Increase Join Failure Count */ + prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount++; +/* For JB nl802.11 */ + if (prAisFsmInfo->prTargetBssDesc->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) { + /* 3.1 Retreat to AIS_STATE_SEARCH state for next try */ + eNextState = AIS_STATE_SEARCH; + } else if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* 3.2 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } else if (!CHECK_FOR_TIMEOUT(rCurrentTime, prAisFsmInfo->rJoinReqTime, + SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { + /* 3.3 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for next try */ + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } else { + /* 3.4 Retreat to AIS_STATE_JOIN_FAILURE to terminate join operation */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_CONNECT_INDICATION, NULL, 0); + eNextState = AIS_STATE_IDLE; + } + break; + + case AIS_STATE_NORMAL_TR: + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + prAisFsmInfo->fgIsInfraChannelFinished = TRUE; + + /* 2. process if there is pending scan */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, TRUE) == TRUE) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + } + + break; + + default: + /* release channel */ + aisFsmReleaseCh(prAdapter); + break; + + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) + aisFsmSteps(prAdapter, eNextState); + +} /* end of aisFsmRunEventJoinTimeout() */ + +VOID aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + aisDeauthXmitComplete(prAdapter, NULL, TX_RESULT_LIFE_TIMEOUT); +} + +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisTest(VOID) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucSSID[] = "pci-11n"; + UINT_8 ucSSIDLen = 7; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Set Connection Request Issued Flag */ + prConnSettings->fgIsConnReqIssued = TRUE; + prConnSettings->ucSSIDLen = ucSSIDLen; + kalMemCopy(prConnSettings->aucSSID, aucSSID, ucSSIDLen); + + prAisAbortMsg = (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + + ASSERT(0); /* Can't trigger SCAN FSM */ + return; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_HEM_AIS_FSM_ABORT; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + + wifi_send_msg(INDX_WIFI, MSG_ID_WIFI_IST, 0); + +} +#endif /* CFG_TEST_MGMT_FSM */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] prSsid Pointer of SSID_T if specified +* \param[in] pucIe Pointer to buffer of extra information elements to be attached +* \param[in] u4IeLength Length of information elements +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisFsmScanRequest()"); + + ASSERT(prAdapter); + ASSERT(u4IeLength <= MAX_IE_LENGTH); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (!prConnSettings->fgIsScanReqIssued) { + prConnSettings->fgIsScanReqIssued = TRUE; + + if (prSsid == NULL) { + prAisFsmInfo->ucScanSSIDLen = 0; + } else { + COPY_SSID(prAisFsmInfo->aucScanSSID, + prAisFsmInfo->ucScanSSIDLen, prSsid->aucSsid, (UINT_8) prSsid->u4SsidLen); + } + + if (u4IeLength > 0 && u4IeLength <= MAX_IE_LENGTH) { + prAisFsmInfo->u4ScanIELength = u4IeLength; + kalMemCopy(prAisFsmInfo->aucScanIEBuf, pucIe, u4IeLength); + } else { + prAisFsmInfo->u4ScanIELength = 0; + } + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE + && prAisFsmInfo->fgIsInfraChannelFinished == FALSE) { + /* 802.1x might not finished yet, pend it for later handling .. */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } else { + if (prAisFsmInfo->fgIsChannelGranted == TRUE) { + DBGLOG(AIS, WARN, + "Scan Request with channel granted for join operation: %d, %d", + prAisFsmInfo->fgIsChannelGranted, prAisFsmInfo->fgIsChannelRequested); + } + + /* start online scan */ + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); + } + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_SCAN); + } else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + } else { + DBGLOG(AIS, WARN, "Scan Request dropped. (state: %d)\n", prAisFsmInfo->eCurrentState); + } + +} /* end of aisFsmScanRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is invoked when CNM granted channel privilege +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_GRANT_T prMsgChGrant; + UINT_8 ucTokenID; + UINT_32 u4GrantInterval; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; + + ucTokenID = prMsgChGrant->ucTokenID; + u4GrantInterval = prMsgChGrant->u4GrantInterval; + + /* 1. free message */ + cnmMemFree(prAdapter, prMsgHdr); + + if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN && prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { + /* 2. channel privilege has been approved */ + prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; + + /* 3. state transition to join/ibss-alone/ibss-merge */ + /* 3.1 set timeout timer in cases join could not be completed */ + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rJoinTimeoutTimer, + prAisFsmInfo->u4ChGrantedInterval - AIS_JOIN_CH_GRANT_THRESHOLD); + /* 3.2 set local variable to indicate join timer is ticking */ + prAisFsmInfo->fgIsInfraChannelFinished = FALSE; + + /* 3.3 switch to join state */ + aisFsmSteps(prAdapter, AIS_STATE_JOIN); + + prAisFsmInfo->fgIsChannelGranted = TRUE; + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL && + prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { + /* 2. channel privilege has been approved */ + prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; + + /* 3.1 set timeout timer in cases upper layer cancel_remain_on_channel never comes */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer, prAisFsmInfo->u4ChGrantedInterval); + + /* 3.2 switch to remain_on_channel state */ + aisFsmSteps(prAdapter, AIS_STATE_REMAIN_ON_CHANNEL); + + /* 3.3. indicate upper layer for channel ready */ + kalReadyOnChannel(prAdapter->prGlueInfo, + prAisFsmInfo->rChReqInfo.u8Cookie, + prAisFsmInfo->rChReqInfo.eBand, + prAisFsmInfo->rChReqInfo.eSco, + prAisFsmInfo->rChReqInfo.ucChannelNum, prAisFsmInfo->rChReqInfo.u4DurationMs); + + prAisFsmInfo->fgIsChannelGranted = TRUE; + } else { /* mismatched grant */ + /* 2. return channel privilege to CNM immediately */ + aisFsmReleaseCh(prAdapter); + } + +} /* end of aisFsmRunEventChGrant() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM that channel privilege +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmReleaseCh(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_ABORT_T prMsgChAbort; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (prAisFsmInfo->fgIsChannelGranted == TRUE || prAisFsmInfo->fgIsChannelRequested == TRUE) { + + prAisFsmInfo->fgIsChannelRequested = FALSE; + prAisFsmInfo->fgIsChannelGranted = FALSE; + + /* 1. return channel privilege to CNM immediately */ + prMsgChAbort = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChAbort) { + ASSERT(0); /* Can't release Channel to CNM */ + return; + } + + prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChAbort->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prMsgChAbort->ucTokenID = prAisFsmInfo->ucSeqNumOfChReq; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChAbort, MSG_SEND_METHOD_BUF); + } + +} /* end of aisFsmReleaseCh() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform AIS that corresponding beacon has not +* been received for a while and probing is not successful +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prAisBssInfo; + BOOLEAN fgDoAbortIndication = FALSE; + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* 4 <1> Diagnose Connection for Beacon Timeout Event */ + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) { + if (OP_MODE_INFRASTRUCTURE == prAisBssInfo->eCurrentOPMode) { + P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; + + if (prStaRec) + fgDoAbortIndication = TRUE; + } else if (OP_MODE_IBSS == prAisBssInfo->eCurrentOPMode) { + fgDoAbortIndication = TRUE; + } + } + /* 4 <2> invoke abort handler */ + if (fgDoAbortIndication) { +#if 0 + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prConnSettings->fgIsDisconnectedByNonRequest = TRUE; +#endif + + DBGLOG(AIS, INFO, "Beacon Timeout, Remove BSS [%pM]\n", prAisBssInfo->aucBSSID); + scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + + /* + Note: Cannot change TRUE to FALSE; or you will suffer the problem in + ALPS01270257/ ALPS01804173 + */ + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, TRUE); + } + +} /* end of aisBssBeaconTimeout() */ + +VOID aisBssSecurityChanged(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + prAdapter->rWifiVar.rConnSettings.fgIsDisconnectedByNonRequest = TRUE; + prAisBssInfo->u2DeauthReason = REASON_CODE_BSS_SECURITY_CHANGE; + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_DEAUTHENTICATED, FALSE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform AIS that DEAUTH frame has been +* sent and thus state machine could go ahead +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] prMsduInfo Pointer of MSDU_INFO_T for DEAUTH frame +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (rTxDoneStatus == TX_RESULT_SUCCESS) + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer); + + if (prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { + if (rTxDoneStatus != TX_RESULT_DROPPED_IN_DRIVER) + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_NEW_CONNECTION, FALSE); + } else { + DBGLOG(AIS, WARN, "DEAUTH frame transmitted without further handling"); + } + + return WLAN_STATUS_SUCCESS; + +} /* end of aisDeauthXmitComplete() */ + +#if CFG_SUPPORT_ROAMING +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate an Event of "Looking for a candidate due to weak signal" to AIS FSM. +* +* @param[in] u4ReqScan Requesting Scan or not +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, UINT_32 u4ReqScan) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + ENUM_AIS_REQUEST_TYPE_T eAisRequest; + + DBGLOG(AIS, LOUD, "aisFsmRunEventRoamingDiscovery()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* search candidates by best rssi */ + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + +#if CFG_SUPPORT_WFD +#if CFG_ENABLE_WIFI_DIRECT + { + /* Check WFD is running */ + P_BSS_INFO_T prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + if (prAdapter->fgIsP2PRegistered && + IS_BSS_ACTIVE(prP2pBssInfo) && + (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || + prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)) { + DBGLOG(ROAMING, INFO, "Handle roaming when P2P is GC or GO.\n"); + if (prAdapter->rWifiVar.prP2pFsmInfo) { + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + if ((prWfdCfgSettings->ucWfdEnable == 1) && + ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { + DBGLOG(ROAMING, INFO, "WFD is running. Stop roaming.\n"); + roamingFsmRunEventRoam(prAdapter); + roamingFsmRunEventFail(prAdapter, ROAMING_FAIL_REASON_NOCANDIDATE); + return; + } + } else { + ASSERT(0); + } + } /* fgIsP2PRegistered */ + } +#endif +#endif + + /* results are still new */ + if (!u4ReqScan) { + roamingFsmRunEventRoam(prAdapter); + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } else { + if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN + || prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } else { + eAisRequest = AIS_REQUEST_ROAMING_SEARCH; + } + } + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && prAisFsmInfo->fgIsInfraChannelFinished == TRUE) { + if (eAisRequest == AIS_REQUEST_ROAMING_SEARCH) + aisFsmSteps(prAdapter, AIS_STATE_LOOKING_FOR); + else + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, TRUE); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, TRUE); + + aisFsmInsertRequest(prAdapter, eAisRequest); + } + +} /* end of aisFsmRunEventRoamingDiscovery() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the time of ScanDone for roaming and transit to Roam state. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DBGLOG(AIS, LOUD, "->aisFsmRoamingScanResultsUpdate()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + roamingFsmScanResultsUpdate(prAdapter); + + eNextState = prAisFsmInfo->eCurrentState; + if (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) { + roamingFsmRunEventRoam(prAdapter); + eNextState = AIS_STATE_SEARCH; + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eNextState = AIS_STATE_SEARCH; + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + eNextState = AIS_STATE_NORMAL_TR; + } + + return eNextState; +} /* end of aisFsmRoamingScanResultsUpdate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will modify and update necessary information to firmware +* for disconnection of last AP before switching to roaming bss. +* +* @param IN prAdapter Pointer to the Adapter structure. +* prTargetStaRec Target of StaRec of roaming +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prTargetStaRec) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, LOUD, "aisFsmRoamingDisconnectPrevAP()"); + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_AIS_INDEX); + + /* Not invoke rlmBssAborted() here to avoid prAisBssInfo->fg40mBwAllowed + * to be reset. RLM related parameters will be reset again when handling + * association response in rlmProcessAssocRsp(). 20110413 + */ + /* rlmBssAborted(prAdapter, prAisBssInfo); */ + + /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if needed. */ + if (PARAM_MEDIA_STATE_CONNECTED == prAisBssInfo->eConnectionState) + scanRemoveConnFlagOfBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + /* 4 <4> Change Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + /* 4 <4.1> sync. with firmware */ + prTargetStaRec->ucNetTypeIndex = 0xff; /* Virtial NetType */ + nicUpdateBss(prAdapter, NETWORK_TYPE_AIS_INDEX); + prTargetStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; /* Virtial NetType */ + +#if (CFG_SUPPORT_TDLS == 1) + TdlsexLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, prAisBssInfo->aucBSSID, + TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING); +#endif /* CFG_SUPPORT_TDLS */ + +} /* end of aisFsmRoamingDisconnectPrevAP() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the roaming was completed. +* +* @param IN prAdapter Pointer to the Adapter structure. +* prStaRec StaRec of roaming AP +* prAssocRspSwRfb +* +* @retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, LOUD, "aisUpdateBssInfoForRoamingAP()"); + + ASSERT(prAdapter); + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, STA_STATE_1); + } + /* 4 <1.3> Update BSS_INFO_T */ + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + /* 4 <1.6> Indicate Connected Event to Host immediately. */ + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, FALSE); + +} /* end of aisFsmRoamingUpdateBss() */ + +#endif /* CFG_SUPPORT_ROAMING */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Check if there is any pending request and remove it (optional) +* +* @param prAdapter +* eReqType +* bRemove +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType, IN BOOLEAN bRemove) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr, prPendingReqHdrNext; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* traverse through pending request list */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingReqHdr, + prPendingReqHdrNext, &(prAisFsmInfo->rPendingReqList), rLinkEntry, AIS_REQ_HDR_T) { + /* check for specified type */ + if (prPendingReqHdr->eReqType == eReqType) { + /* check if need to remove */ + if (bRemove == TRUE) { + LINK_REMOVE_KNOWN_ENTRY(&(prAisFsmInfo->rPendingReqList), + &(prPendingReqHdr->rLinkEntry)); + + cnmMemFree(prAdapter, prPendingReqHdr); + } + + return TRUE; + } + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Get next pending request +* +* @param prAdapter +* +* @return P_AIS_REQ_HDR_T +*/ +/*----------------------------------------------------------------------------*/ +P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + LINK_REMOVE_HEAD(&(prAisFsmInfo->rPendingReqList), prPendingReqHdr, P_AIS_REQ_HDR_T); + + return prPendingReqHdr; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Insert a new request +* +* @param prAdapter +* eReqType +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, IN ENUM_AIS_REQUEST_TYPE_T eReqType) +{ + P_AIS_REQ_HDR_T prAisReq; + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + prAisReq = (P_AIS_REQ_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(AIS_REQ_HDR_T)); + + if (!prAisReq) { + ASSERT(0); /* Can't generate new message */ + return FALSE; + } + + prAisReq->eReqType = eReqType; + + /* attach request into pending request list */ + LINK_INSERT_TAIL(&prAisFsmInfo->rPendingReqList, &prAisReq->rLinkEntry); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Flush all pending requests +* +* @param prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFsmFlushRequest(IN P_ADAPTER_T prAdapter) +{ + P_AIS_REQ_HDR_T prAisReq; + + ASSERT(prAdapter); + + while ((prAisReq = aisFsmGetNextRequest(prAdapter)) != NULL) + cnmMemFree(prAdapter, prAisReq); + +} + +VOID aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_REMAIN_ON_CHANNEL_T prRemainOnChannel; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prRemainOnChannel = (P_MSG_REMAIN_ON_CHANNEL_T) prMsgHdr; + + /* record parameters */ + prAisFsmInfo->rChReqInfo.eBand = prRemainOnChannel->eBand; + prAisFsmInfo->rChReqInfo.eSco = prRemainOnChannel->eSco; + prAisFsmInfo->rChReqInfo.ucChannelNum = prRemainOnChannel->ucChannelNum; + prAisFsmInfo->rChReqInfo.u4DurationMs = prRemainOnChannel->u4DurationMs; + prAisFsmInfo->rChReqInfo.u8Cookie = prRemainOnChannel->u8Cookie; + + if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE || prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + /* transit to next state */ + aisFsmSteps(prAdapter, AIS_STATE_REQ_REMAIN_ON_CHANNEL); + } else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL); + } + + /* free messages */ + cnmMemFree(prAdapter, prMsgHdr); + +} + +VOID aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prCancelRemainOnChannel; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + prCancelRemainOnChannel = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) prMsgHdr; + + /* 1. Check the cookie first */ + if (prCancelRemainOnChannel->u8Cookie == prAisFsmInfo->rChReqInfo.u8Cookie) { + + /* 2. release channel privilege/request */ + if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_REMAIN_ON_CHANNEL) { + /* 2.1 elease channel */ + aisFsmReleaseCh(prAdapter); + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { + /* 2.1 release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2.2 stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + } + + /* 3. clear pending request of remain_on_channel */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, TRUE); + + /* 4. decide which state to retreat */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) + aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); + else + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + } + + /* 5. free message */ + cnmMemFree(prAdapter, prMsgHdr); + +} + +VOID aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + /* prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); */ + + if (prAisFsmInfo == NULL) + break; + prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T) prMsgHdr; + + aisFuncTxMgmtFrame(prAdapter, + &prAisFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* aisFsmRunEventMgmtFrameTx */ + +VOID aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2. stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + + /* 3. expiration indication to upper layer */ + kalRemainOnChannelExpired(prAdapter->prGlueInfo, + prAisFsmInfo->rChReqInfo.u8Cookie, + prAisFsmInfo->rChReqInfo.eBand, + prAisFsmInfo->rChReqInfo.eSco, prAisFsmInfo->rChReqInfo.ucChannelNum); + + /* 4. decide which state to retreat */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) + aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); + else + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + } else { + DBGLOG(AIS, WARN, "Unexpected remain_on_channel timeout event\n"); +#if DBG + DBGLOG(AIS, STATE, "CURRENT State: [%s]\n", apucDebugAisState[prAisFsmInfo->eCurrentState]); +#else + DBGLOG(AIS, STATE, "[%d] CURRENT State: [%d]\n", DBG_AIS_IDX, prAisFsmInfo->eCurrentState); +#endif + } + +} + +WLAN_STATUS +aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_AIS_MGMT_TX_REQ_INFO_T) NULL; + BOOLEAN fgIsSuccess = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prMgmtTxReqInfo = &(prAisFsmInfo->rMgmtTxInfo); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(AIS, ERROR, "Mgmt Frame TX Fail, Status:%d.\n", rTxDoneStatus); + } else { + fgIsSuccess = TRUE; + /* printk("Mgmt Frame TX Done.\n"); */ + } + + if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { + kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + fgIsSuccess, prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); + + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; + +} /* aisFsmRunEventMgmtFrameTxDone */ + +WLAN_STATUS +aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); + + if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { + + /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ + /* Packet on driver, not done yet, drop it. */ + prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; + if (prTxMsduInfo != NULL) { + + kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + FALSE, + prTxMsduInfo->prPacket, (UINT_32) prTxMsduInfo->u2FrameLength); + + /* Leave it to TX Done handler. */ + /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ + /* Packet transmitted, wait tx done. (cookie issue) */ + } + + ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); + + prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanHdr->aucAddr1); + prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_AIS_INDEX; + + prMgmtTxReqInfo->u8Cookie = u8Cookie; + prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; + prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; + + prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; + prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); + if (prStaRec != NULL) { + /* Do nothing */ + /* printk("Mgmt with station record: %pM .\n", prStaRec->aucMacAddr); */ + } + + prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ + prMgmtTxMsdu->fgIs802_1x = FALSE; + prMgmtTxMsdu->fgIs802_11 = TRUE; + prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMgmtTxMsdu->pfTxDoneHandler = aisFsmRunEventMgmtFrameTxDone; + prMgmtTxMsdu->fgIsBasicRate = TRUE; + DBGLOG(AIS, TRACE, "Mgmt seq NO. %d .\n", prMgmtTxMsdu->ucTxSeqNum); + + nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); + + } while (FALSE); + + return rWlanStatus; +} /* aisFuncTxMgmtFrame */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Action Frame and indicate to uppoer layer +* if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; + + DEBUGFUNC("aisFuncValidateRxActionFrame"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (1 /* prAisFsmInfo->u4AisPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME */) { + /* Leave the action frame to wpa_supplicant. */ + kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + } while (FALSE); + + return; + +} /* aisFuncValidateRxActionFrame */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c new file mode 100644 index 0000000000000..f02d7c3bb5b27 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/assoc.c @@ -0,0 +1,1932 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/assoc.c#3 +*/ + +/*! \file "assoc.c" + \brief This file includes the association-related functions. + + This file includes the association-related functions. +*/ + +/*\ +** Log: assoc.c +** +** 07 27 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Fix wifi direct connection issue. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 06 08 2012 cp.wu + * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development + * add a pair of brace for compilation success. + * + * 06 04 2012 cp.wu + * [WCXRP00001245] [MT6620 Wi-Fi][Driver][Firmware] NPS Software Development + * discussed with WH, privacy bit in associate response is not necessary to be checked, + * and identified as association failure when mismatching with beacon/probe response + * + * 03 14 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Add code from 2.2 + * + * 03 09 2012 terry.wu + * NULL + * Fix build error. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 16 2012 yuche.tsai + * NULL + * Update Driver for wifi driect gc join IE update issue. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * Fix PhyTypeSet in STA_REC in AP mode + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 19 2011 yuche.tsai + * NULL + * Fix KE when enable hot-spot & any one client connect to this hot-spot. + * + * 09 14 2011 yuche.tsai + * NULL + * Add P2P IE in assoc response. + * + * 07 15 2011 terry.wu + * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment + * Update workaround for Kingnet AP. + * + * 07 15 2011 terry.wu + * [WCXRP00000855] [MT6620 Wi-Fi] [Driver] Workaround for Kingnet 710 AP wrong AID assignment + * Workaround for Kingnet 710 AP wrong AID assignment. + * + * 05 02 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning[WCXRP00000672] [MT6620 Wi-Fi][FW] + * Fix the PS event allocation + * Check STA when rx assoc. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Make assoc req to append P2P IE if wifi direct is enabled. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 03 14 2011 wh.su + * [WCXRP00000545] [MT6620 Wi-Fi] [Driver] Fixed the p2p not enable, received a assoc rsp + * cause the rx assoc execute a null function + * Modify file for avoid assert at BOW receive a assoc response frame but no p2p function. + * + * 03 08 2011 terry.wu + * [WCXRP00000524] [MT6620 Wi-Fi][Driver] Fix p2p assoc request containing wrong IE format + * Fix p2p assoc request containing wrong IE format. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix RX disassoc issue under Hot-spot mode. + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Update Phy Type Set. When legacy client is connected, it can use 11b rate, + * but if the P2P device is connected, 11b rate is not allowed. + * + * 01 11 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Update Desired Non-HT Rate Set. + * + * 12 30 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Recover the code that was coverwritted.. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 yuche.tsai + * NULL + * Add SSID IE in assoc req frame which is sent by P2P GC. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RSN IE generation by CFG_RSN_MIGRATION compilation flag. + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * revised. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update assocProcessRxAssocReqFrame() to avoid redundant SSID IE {0,0} for IOT. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix compile warning - macro > 10 line, initial value of an array + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * * * * * * and will send Null frame to diagnose connection + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * adding the wpa-none for ibss beacon. + * + * 03 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 28 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * fixed the compiling warning.u1rwduu`wvpghlqg|rm+vp + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update Assoc ID for PS + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Use new constant definition ELEM_MAX_LEN_EXT_CAP + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Modify assoc req IE talbe for HT cap IE + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * update the assocComposeReAssocReqFrameHeader() and fix the u2EstimatedFrameLen in assocSendReAssocReqFrame() + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * remove some space line + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the sending disassoc frame function + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the txassocReq IE table, adding for WPA/RSN + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix eNetType not init in send AssocReq function + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Integrate the send Assoc with TXM + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code to indicate the assoc request and assoc response (now disable) + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove unused variables + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +APPEND_VAR_IE_ENTRY_T txAssocReqIETable[] = { + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmReqGenerateHtCapIE} + , /* 45 */ +#if CFG_SUPPORT_WPS2 + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WSC), NULL, rsnGenerateWSCIE} + , /* 221 */ +#endif +#if CFG_RSN_MIGRATION + {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} + , /* 48 */ +#endif +#if CFG_SUPPORT_WAPI + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WAPI), NULL, wapiGenerateWAPIIE} + , /* 68 */ +#endif +#if CFG_SUPPORT_HOTSPOT_2_0 + {(ELEM_HDR_LEN + ELEM_MAX_LEN_INTERWORKING), NULL, hs20GenerateInterworkingIE} + , /* 107 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_ROAMING_CONSORTIUM), NULL, hs20GenerateRoamingConsortiumIE} + , /* 111 */ +#endif + {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmReqGenerateExtCapIE} + , /* 127 */ +#if CFG_SUPPORT_HOTSPOT_2_0 + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HS20_INDICATION), NULL, hs20GenerateHS20IE} + , /* 221 */ +#endif + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO), NULL, mqmGenerateWmmInfoIE} + , /* 221 */ +#if CFG_RSN_MIGRATION + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE} + , /* 221 */ +#endif +}; + +#if CFG_SUPPORT_AAA +VERIFY_IE_ENTRY_T rxAssocReqIETable[] = { + {ELEM_ID_RESERVED, NULL} /* 255 */ +}; + +APPEND_VAR_IE_ENTRY_T txAssocRespIETable[] = { + {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} + , /* 42 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} + , /* 45 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} + , /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} + , /* 74 */ + {(0), p2pFuncCalculateP2p_IELenForAssocRsp, p2pFuncGenerateP2p_IEForAssocRsp} + , /* 221 */ +#if CFG_SUPPORT_WFD + {(0), wfdFuncCalculateWfdIELenForAssocRsp, wfdFuncGenerateWfdIEForAssocRsp} + , /* 221 */ +#endif +#endif + {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} + , /* 127 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} + , /* 221 */ + + {(0), p2pFuncCalculateWSC_IELenForAssocRsp, p2pFuncGenerateWSC_IEForAssocRsp} /* 221 */ + +}; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose the Capability Info Field. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval Capability Info Field +*/ +/*----------------------------------------------------------------------------*/ +UINT_16 +assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + UINT_32 u4NonHTPhyType; + UINT_16 u2CapInfo; + + /* Set up our requested capabilities. */ + u2CapInfo = CAP_INFO_ESS; + u2CapInfo |= CAP_CF_STA_NOT_POLLABLE; + + if (prStaRec == NULL) + u2CapInfo |= CAP_INFO_PRIVACY; + else { + if (prStaRec->u2CapInfo & CAP_INFO_PRIVACY) + u2CapInfo |= CAP_INFO_PRIVACY; + } + + /* 7.3.1.4 */ + if (prStaRec == NULL) { + if ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) ||/* ShortPreambleOptionEnable is TRUE */ + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO)) + u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + if (prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) + u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } else if (prStaRec->fgHasBasicPhyType) { + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + if ((rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortPreambleOptionImplemented) && + /* Short Preamble Option Enable is TRUE */ + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO) && + (prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + + /* Case I: Implemented == TRUE and Short Preamble Option Enable == TRUE. + * Case II: Implemented == TRUE and Short Preamble == AUTO (depends on + * BSS_DESC_T's capability) + */ + u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } +#if CFG_SUPPORT_SPEC_MGMT /*Add by Enlai */ + /* Support 802.11h */ + if (prStaRec->u2CapInfo & CAP_INFO_SPEC_MGT) { + /* + 1. The Power Capability element shall be present if + dot11SpectrumManagementRequired is true. + + 2. A STA shall set dot11SpectrumManagementRequired to TRUE before + associating with a BSS or IBSS in which the Spectrum Management + bit is set to 1 in the Capability Information field in Beacon frames + and Probe Response frames received from the BSS or IBSS. + */ + if (prAdapter->fgEnable5GBand == TRUE) + u2CapInfo |= CAP_INFO_SPEC_MGT; + } +#endif + + if (rNonHTPhyAttributes[u4NonHTPhyType].fgIsShortSlotTimeOptionImplemented && + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) { + u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + } + + if (prStaRec) { + DBGLOG(SAA, LOUD, "ASSOC REQ: Compose Capability = 0x%04x for Target BSS [%pM].\n", + u2CapInfo, prStaRec->aucMacAddr); + } + + return u2CapInfo; + +} /* end of assocBuildCapabilityInfo() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Association +* Request Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID assocBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + PUINT_8 pucBuffer; + UINT_16 u2SupportedRateSet; + UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; + UINT_8 ucAllSupportedRatesLen; + UINT_8 ucSupRatesLen; + UINT_8 ucExtSupRatesLen; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) + return; + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (IS_STA_IN_AIS(prStaRec)) { + + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) + pucBuffer = p2pBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo, pucBuffer); +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) { + + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } +#endif + else { + /* Do nothing */ + /* TODO(Kevin): For other network */ + } + + /* NOTE(Kevin 2008/12/19): 16.3.6.3 MLME-ASSOCIATE.indication - + * SupportedRates - The set of data rates that are supported by the STA + * that is requesting association. + * Original(Portable Driver): Only send the Rates that we'll support. + * New: Send the Phy Rates if the result of following & operation == NULL. + */ + /* rateGetDataRatesFromRateSet((prBssDesc->u2OperationalRateSet & */ + /* rPhyAttributes[prBssDesc->ePhyType].u2SupportedRateSet), */ + + if (prStaRec->fgHasBasicPhyType) { + UINT_32 u4NonHTPhyType; + + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + u2SupportedRateSet = (prStaRec->u2OperationalRateSet & + rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet); + + ASSERT(u2SupportedRateSet); + + if (!u2SupportedRateSet) + u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + + /* TODO(Kevin): For P2P, we shouldn't send support rate set which contains 11b rate */ + + rateGetDataRatesFromRateSet(u2SupportedRateSet, 0, aucAllSupportedRates, &ucAllSupportedRatesLen); + + ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? + ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); + + ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* 7.3.2.19 Supported Channels element */ +#if CFG_SUPPORT_DFS /* Add by Enlai */ + if (prAdapter->fgEnable5GBand == TRUE) { + SUPPORTED_CHANNELS_IE(pucBuffer)->ucId = ELEM_ID_SUP_CHS; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucLength = 8; + + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[0] = 36; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[1] = 4; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[2] = 52; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[3] = 4; +/* Not China --- Start */ + /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 100; */ + /* SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 11; */ +/* Not China --- End */ + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[4] = 149; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[5] = 4; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[6] = 165; + SUPPORTED_CHANNELS_IE(pucBuffer)->ucChannelNum[7] = 1; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } +#endif + } + +} /* end of assocBuildReAssocReqFrameCommonIEs() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the (Re)Association Request frame header and +* its fixed fields +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in out] pu2PayloadLen Return the length of the composed fixed fields +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +assocComposeReAssocReqFrameHeaderAndFF(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN OUT PUINT_16 pu2PayloadLen) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + BOOLEAN fgIsReAssoc; + + UINT_16 u2FrameCtrl; + UINT_16 u2CapInfo; + UINT_16 u2ListenInterval; + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + ASSERT(pu2PayloadLen); + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ + /* Fill the Frame Control field. */ + if (fgIsReAssoc) + u2FrameCtrl = MAC_FRAME_REASSOC_REQ; + else + u2FrameCtrl = MAC_FRAME_ASSOC_REQ; + WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prAssocFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + + /* Fill the Capability Information field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); + + /* Calculate the listen interval for the maximum power mode. Currently, we + set it to the value 2 times DTIM period. */ + if (prStaRec->ucDTIMPeriod) { + u2ListenInterval = prStaRec->ucDTIMPeriod * DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD; + } else { + DBGLOG(SAA, TRACE, "Use default listen interval\n"); + u2ListenInterval = DEFAULT_LISTEN_INTERVAL; + } + prStaRec->u2ListenInterval = u2ListenInterval; + + /* Fill the Listen Interval field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2ListenInterval, u2ListenInterval); + + /* 4 <3> Compose the Current AP Address field for ReAssociation Request frame. */ + /* Fill the Current AP Address field. */ + if (prStaRec->fgIsReAssoc) { + if (IS_STA_IN_AIS(prStaRec)) { + + P_AIS_BSS_INFO_T prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + P_WLAN_REASSOC_REQ_FRAME_T prReAssocFrame = (P_WLAN_REASSOC_REQ_FRAME_T) prAssocFrame; + + COPY_MAC_ADDR(prReAssocFrame->aucCurrentAPAddr, prAisBssInfo->aucBSSID); + } else { + ASSERT(0); /* We don't support ReAssociation for other network */ + } + + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + CURR_AP_ADDR_FIELD_LEN); + } else { + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN); + } + +} /* end of assocComposeReAssocReqFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the (Re)Association Request frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + BOOLEAN fgIsReAssoc; + UINT_32 i; + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ + if (fgIsReAssoc) { + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + CAP_INFO_FIELD_LEN + + LISTEN_INTERVAL_FIELD_LEN + + CURR_AP_ADDR_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + } else { + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + CAP_INFO_FIELD_LEN + + LISTEN_INTERVAL_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + } + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + if ((prAdapter->fgIsP2PRegistered)) { + u2EstimatedExtraIELen = p2pCalculate_IEForAssocReq(prAdapter, + prStaRec->ucNetTypeIndex, prStaRec); + } else { + DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); + ASSERT(FALSE); + } + } else { + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; + } else { + u2EstimatedExtraIELen += + (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + } + } +#else + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; + } else { + u2EstimatedExtraIELen += (UINT_16) txAssocReqIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + } +#endif + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Request.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Compose Header and Fixed Field */ + assocComposeReAssocReqFrameHeaderAndFF(prAdapter, + prStaRec, + (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucOwnMacAddr, &u2PayloadLen); + + /* 4 <3> Update information of MSDU_INFO_T */ + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ + assocBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + if ((prAdapter->fgIsP2PRegistered)) { + p2pGenerate_IEForAssocReq(prAdapter, prMsduInfo); + } else { + DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); + ASSERT(FALSE); + } + } else { + /* Append IE */ + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].pfnAppendIE) + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } +#else + /* Append IE */ + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocReqIETable[i].pfnAppendIE) + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } +#endif + + /* 4 <6> Update the (Re)association request information */ + if (IS_STA_IN_AIS(prStaRec)) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + +#if CFG_RSN_MIGRATION + kalUpdateReAssocReqInfo(prAdapter->prGlueInfo, + (PUINT_8) &prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), + fgIsReAssoc); +#endif + } +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, + (PUINT_8) &prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength - offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), + fgIsReAssoc); + } +#endif + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ + DBGLOG(SAA, INFO, "Sending (Re)Assoc Request, network: %d seqNo: %d\n", + prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of assocSendReAssocReqFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX (Re)Association Request frame for +* SAA event handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) (prMsduInfo->prPacket); + ASSERT(prAssocReqFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_REQ) + return WLAN_STATUS_FAILURE; + } else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_REQ) + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckTxReAssocReqFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX (Re)Association Response frame for +* AAA event handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) (prMsduInfo->prPacket); + ASSERT(prAssocRspFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + /* WLAN_GET_FIELD_16(&prAssocFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_RSP) + return WLAN_STATUS_FAILURE; + } else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_RSP) + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckTxReAssocRespFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the incoming (Re)Association Frame and take out +* the status code. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + UINT_16 u2RxFrameCtrl; + UINT_16 u2RxCapInfo; + UINT_16 u2RxStatusCode; + UINT_16 u2RxAssocId; + + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(SAA, LOUD, "prSwRfb->u2PayloadLength = %d\n", prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + /* 4 <1> locate the (Re)Association Resp Frame. */ + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of (Re)Association Resp Frame. */ + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2FrameCtrl, &u2RxFrameCtrl); */ + u2RxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2RxFrameCtrl != MAC_FRAME_REASSOC_RSP) + return WLAN_STATUS_FAILURE; + } else { + if (u2RxFrameCtrl != MAC_FRAME_ASSOC_RSP) + return WLAN_STATUS_FAILURE; + } + + /* 4 <3> Parse the Fixed Fields of (Re)Association Resp Frame Body. */ + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2CapInfo, &u2RxCapInfo); */ + u2RxCapInfo = prAssocRspFrame->u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ + + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2StatusCode, &u2RxStatusCode); */ + u2RxStatusCode = prAssocRspFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ + + /* 4 <4> Check CAP_INFO */ + /* NOTE(Kevin): CM suggest to add MGMT workaround for those APs didn't check + * the CAP Privacy Bit to overcome a corner case that the Privacy Bit + * of our SCAN result didn't consist with AP's Association Resp. + */ + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { + /* WAPI AP allow the customer use WZC to join mode, the privacy bit is 0 */ + /* even at WAI & WAPI_PSK mode, but the assoc respose set the privacy bit set 1 */ + DBGLOG(SEC, TRACE, "Workaround the WAPI AP allow the customer to use WZC to join\n"); + } else +#endif +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && 1) { + /* Todo:: Fixed this */ + } else +#endif + { + } + +#if CFG_STRICT_CHECK_CAPINFO_PRIVACY + if ((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ^ (u2RxCapInfo & CAP_INFO_PRIVACY)) + u2RxStatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; +#endif + } + + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_RSN_MIGRATION + /* Update the information in the structure used to query and set + OID_802_11_ASSOCIATION_INFORMATION. */ + kalUpdateReAssocRspInfo(prAdapter->prGlueInfo, + (PUINT_8) &prAssocRspFrame->u2CapInfo, (UINT_32) (prSwRfb->u2PacketLen)); +#endif + } + /* 4 <5> Update CAP_INFO and ASSOC_ID */ + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { + prStaRec->u2CapInfo = u2RxCapInfo; + + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2AssocId, &u2RxAssocId); */ + u2RxAssocId = prAssocRspFrame->u2AssocId; /* NOTE(Kevin): Optimized for ARM */ + + /* 20110715 Workaround for Kingnet 710 AP (Realtek 8186) + * This AP raises the bit 6&7 not bit 14&15 in AID field. + * It cause wrong AID assignment. + * For AID = 2 + * Normal case: 0xC002(1100 0000 0000 0010) => 2 + * Kingnet 710: 0x00C2(0000 0000 1100 0010) => 194 + * workaround: mask bit 6&7 for this AP + */ + if ((u2RxAssocId & BIT(6)) && (u2RxAssocId & BIT(7)) && !(u2RxAssocId & BITS(8, 15))) { + prStaRec->u2AssocId = u2RxAssocId & ~BITS(6, 7); + } else { + prStaRec->u2AssocId = u2RxAssocId & ~AID_MSB; +#if CFG_SUPPORT_802_11W + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prBssSpecInfo->ucSaQueryTimedOut = 0; + } +#endif + } + } +#if CFG_SUPPORT_802_11W + if (u2RxStatusCode == STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED) { + DBGLOG(SAA, INFO, "AP rejected due the authentication algorithm not support\n"); + } else if (u2RxStatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { + PUINT_8 pucIE, pucTime; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8) ((ULONG) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_TIMEOUT_INTERVAL == IE_ID(pucIE) && IE_LEN(pucIE) == 5) { + pucTime = ((P_IE_HDR_T) pucIE)->aucInfo; + if (pucTime[0] == ACTION_SA_TIMEOUT_ASSOC_COMEBACK) { + UINT_32 tu; + + WLAN_GET_FIELD_32(pucTime + 1, &tu); + DBGLOG(SAA, INFO, + "AP rejected association temporarily;comeback duration %u TU (%u ms)\n", + tu, TU_TO_MSEC(tu)); + if (tu > TX_ASSOCIATION_RETRY_TIMEOUT_TU) { + DBGLOG(SAA, INFO, "Update timer based on comeback duration\n"); + /* ieee80211_reschedule_timer(wpa_s, ms); */ + } + } + break; + } + } /* end of IE_FOR_EACH */ + } +#endif + *pu2StatusCode = u2RxStatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocCheckRxReAssocRspFrameStatus() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will compose the Disassociation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2ReasonCode The reason code of disassociation +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +assocComposeDisassocFrame(IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, IN UINT_8 aucMACAddress[], IN UINT_16 u2ReasonCode) +{ + P_WLAN_DISASSOC_FRAME_T prDisAssocFrame; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + + prDisAssocFrame = (P_WLAN_DISASSOC_FRAME_T) pucBuffer; + + /* 4 <1> Compose the frame header of the DisAssociation frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DISASSOC; + + WLAN_SET_FIELD_16(&prDisAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDisAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prDisAssocFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Disassociation frame. */ + /* Fill the Reason Code field. */ + WLAN_SET_FIELD_16(&prDisAssocFrame->u2ReasonCode, u2ReasonCode); + +} /* end of assocComposeDisassocFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Disassociation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2ReasonCode The reason code of disassociation +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2ReasonCode) +{ + PUINT_8 pucMacAddress; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + /* UINT_32 u4Status = WLAN_STATUS_SUCCESS; */ + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Disassociation Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending DisAssoc.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Disassociation frame header and fixed fields in MSDU_INfO_T. */ + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + pucMacAddress = prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].aucOwnMacAddr; + + /* Compose Header and Fixed Field */ + assocComposeDisassocFrame(prStaRec, + (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucMacAddress, u2ReasonCode); + +#if CFG_SUPPORT_802_11W + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + + prDisassocFrame = + (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + DBGLOG(TX, WARN, "assocSendDisAssocFrame with protection\n"); + } +#endif + + u2PayloadLen = REASON_CODE_FIELD_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Enqueue the frame to send this (Re)Association request frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of assocSendDisAssocFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Disassociation frame +* if the given BSSID is matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucBSSID Given BSSID +* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) +{ + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + UINT_16 u2RxReasonCode; + + ASSERT(prSwRfb); + ASSERT(aucBSSID); + ASSERT(pu2ReasonCode); + + /* 4 <1> locate the Disassociation Frame. */ + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Disassociation Frame. */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDisassocFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, "Ignore Disassoc Frame from other BSS [ %pM ]\n", + prDisassocFrame->aucSrcAddr); + return WLAN_STATUS_FAILURE; + } + /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ + WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocProcessRxDisassocFrame() */ + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Association Req frame +* and return a Status Code. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode Pointer to store the Status Code for carried in Association Response. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; + P_RSN_INFO_ELEM_T prIeRsn = (P_RSN_INFO_ELEM_T) NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; + PUINT_8 pucIE, pucIEStart; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + UINT_16 u2StatusCode = STATUS_CODE_SUCCESSFUL; + UINT_16 u2RxFrameCtrl; + UINT_16 u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) + return WLAN_STATUS_FAILURE; + /* 4 <1> locate the Association Req Frame. */ + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Association Req Frame. */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prAssocReqFrame->aucBSSID, prBssInfo->aucBSSID)) + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2RxFrameCtrl); */ + u2RxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (MAC_FRAME_REASSOC_REQ == u2RxFrameCtrl) { + prStaRec->fgIsReAssoc = TRUE; + + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16) (OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); + + pucIEStart = pucIE = ((P_WLAN_REASSOC_REQ_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem; + } else { + prStaRec->fgIsReAssoc = FALSE; + + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16) (OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN); + + pucIEStart = pucIE = prAssocReqFrame->aucInfoElem; + } + + /* 4 <3> Parse the Fixed Fields of Assoc Req Frame Body. */ + prStaRec->u2CapInfo = prAssocReqFrame->u2CapInfo; + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + if (((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) && !kalP2PGetCipher(prAdapter->prGlueInfo))) { + u2StatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; + DBGLOG(RSN, TRACE, "STA Assoc req privacy bit check fail\n"); + return WLAN_STATUS_SUCCESS; + } + } +#endif + + prStaRec->u2ListenInterval = prAssocReqFrame->u2ListenInterval; + prStaRec->ucPhyTypeSet = 0; + + /* Might be legacy client or p2p gc. */ + prStaRec->eStaType = STA_TYPE_LEGACY_CLIENT; + + /* 4 <4> Parse the IE of Assoc Req Frame Body. */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): Get SSID once */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T) pucIE; + } + break; + + case ELEM_ID_SUP_RATES: + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) + prIeSupportedRate = SUP_RATES_IE(pucIE); + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + break; + case ELEM_ID_HT_CAP: + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + kalMemCopy(&prStaRec->u2HtCapInfo, &(HT_CAP_IE(pucIE)->u2HtCapInfo), 2); + break; + case ELEM_ID_RSN: +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + prIeRsn = RSN_IE(pucIE); + rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, &u2StatusCode); + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } +#endif + break; + case ELEM_ID_VENDOR: +#if CFG_ENABLE_WIFI_DIRECT + { + if ((prAdapter->fgIsP2PRegistered)) { + UINT_8 ucOuiType = 0; + + p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType); + + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + DBGLOG(P2P, TRACE, "Target Client is a P2P group client\n"); + prStaRec->eStaType = STA_TYPE_P2P_GC; + } + } + } +#endif + break; + default: + for (i = 0; i < (sizeof(rxAssocReqIETable) / sizeof(VERIFY_IE_ENTRY_T)); i++) { + + if ((IE_ID(pucIE)) == rxAssocReqIETable[i].ucElemID) { + rxAssocReqIETable[i].pfnVarifyIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIE, + &u2StatusCode); + + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } + } + + break; + } + } /* end of IE_FOR_EACH */ + + /* parsing for WMM related information (2010/12/21) */ + mqmProcessAssocReq(prAdapter, prSwRfb, pucIEStart, u2IELength); + + do { + if (prIeSsid) { + if (UNEQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } + } else { + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } + + prStaRec->u2OperationalRateSet = 0; + prStaRec->u2BSSBasicRateSet = 0; + + if (prIeSupportedRate || prIeExtSupportedRate) { + rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, &prStaRec->u2OperationalRateSet, + &u2BSSBasicRateSet, /* Ignore any Basic Bit */ + &fgIsUnknownBssBasicRate); + + if ((prBssInfo->u2BSSBasicRateSet & prStaRec->u2OperationalRateSet) != + prBssInfo->u2BSSBasicRateSet) { + + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + + /* Accpet the Sta, update BSSBasicRateSet from Bss */ + + prStaRec->u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = (prStaRec->u2OperationalRateSet & RATE_SET_ALL_ABG); + + if (BAND_2G4 == HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr)) { +#if 0 /* Marked by CMC 20111024 */ + /* check if support 11n */ + if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + + if ((!(u2BSSBasicRateSet & RATE_SET_OFDM)) && + (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS)) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + + } + + } +#else + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; +#endif + } else { /* (BAND_5G == prBssDesc->eBande) */ +#if 0 /* Marked by CMC 20111024 */ + if (!(u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + ASSERT((prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) == 0); +#else + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; +#endif + } + + } else { + ASSERT(0); + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + if (prIeRsn) { + if (!kalP2PGetCipher(prAdapter->prGlueInfo)) { + u2StatusCode = STATUS_CODE_CIPHER_SUITE_REJECTED; + break; + } + } else { + prStaRec->rSecInfo.fgAllowOnly1x = FALSE; + if (kalP2PGetCipher(prAdapter->prGlueInfo)) { + /* Only Allow 1x */ + prStaRec->rSecInfo.fgAllowOnly1x = TRUE; + break; + } + } + } +#endif + + } while (FALSE); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { +#if 1 /* ICS */ + { + PUINT_8 cp = (PUINT_8) &prAssocReqFrame->u2CapInfo; + P_UINT_8 prNewAssocReqIe = NULL; + + if (u2IELength) { + prNewAssocReqIe = kalMemAlloc(u2IELength, VIR_MEM_TYPE); + if (NULL == prNewAssocReqIe) { + DBGLOG(AIS, WARN, "allocate memory for (Re)assocReqIe fail!\n"); + u2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; + return WLAN_STATUS_FAILURE; + } + } + + if (prStaRec->fgIsReAssoc) + cp += 10; + else + cp += 4; + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + } + prStaRec->u2AssocReqIeLen = u2IELength; + if (u2IELength) { + prStaRec->pucAssocReqIe = prNewAssocReqIe; /* kalMemAlloc(u2IELength, VIR_MEM_TYPE); */ + kalMemCopy(prStaRec->pucAssocReqIe, cp, u2IELength); + } + } +#endif + kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, (PUINT_8) &prAssocReqFrame->u2CapInfo, + u2IELength + (prStaRec->fgIsReAssoc ? 10 : 4), prStaRec->fgIsReAssoc); + } +#endif + + *pu2StatusCode = u2StatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of assocProcessRxAssocReqFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Association +* Response Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +assocBuildReAssocRespFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo) +{ + PUINT_8 pucBuffer; + P_STA_RECORD_T prStaRec; + UINT_8 ucSupRatesLen; + UINT_8 ucExtSupRatesLen; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; + } else { + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + ucExtSupRatesLen = 0; + } + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* end of assocBuildReAssocRespFrameCommonIEs() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the (Re)Association Response frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucBssid Given BSSID. +* @param[in] u2CapInfo Capability Field of current BSS. +* @param[in out] pu2PayloadLen Return the length of the composed fixed fields +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +assocComposeReAssocRespFrameHeaderAndFF(IN P_STA_RECORD_T prStaRec, + IN PUINT_8 pucBuffer, + IN UINT_8 aucBSSID[], IN UINT_16 u2CapInfo, IN OUT PUINT_16 pu2PayloadLen) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + BOOLEAN fgIsReAssoc; + + UINT_16 u2FrameCtrl; + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucBSSID); + ASSERT(pu2PayloadLen); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* 4 <1> Compose the frame header of the (Re)Association Request frame. */ + /* Fill the Frame Control field. */ + if (fgIsReAssoc) + u2FrameCtrl = MAC_FRAME_REASSOC_RSP; + else + u2FrameCtrl = MAC_FRAME_ASSOC_RSP; + /* WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); */ + prAssocRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the DA field with Target MAC Address. */ + COPY_MAC_ADDR(prAssocRspFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucSrcAddr, aucBSSID); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucBSSID, aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prAssocRspFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the (Re)Association Request frame. */ + /* Fill the Capability Information field. */ + /* WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); */ + prAssocRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ + + /* WLAN_SET_FIELD_16(&prAssocFrame->u2StatusCode, prStaRec->u2StatusCode); */ + prAssocRspFrame->u2StatusCode = prStaRec->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ + + /* WLAN_SET_FIELD_16(&prAssocFrame->u2AssocId, ((prStaRec->u2AssocId & AID_MASK) | AID_MSB)); */ + prAssocRspFrame->u2AssocId = ((prStaRec->u2AssocId & AID_MASK) | AID_MSB); /* NOTE(Kevin): Optimized for ARM */ + + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); + +} /* end of assocComposeReAssocRespFrameHeaderAndFF() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the (Re)Association Resp frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + + UINT_16 u2PayloadLen; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + BOOLEAN fgIsReAssoc; + UINT_32 i; + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + + AID_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocRespIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocRespIETable[i].u2EstimatedFixedIELen; + } else if (txAssocRespIETable[i].pfnCalculateVariableIELen != NULL) { + u2EstimatedExtraIELen += (UINT_16) txAssocRespIETable[i].pfnCalculateVariableIELen(prAdapter, + prStaRec->ucNetTypeIndex, + prStaRec); + } + + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(AAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Response.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose (Re)Association Request frame header and fixed fields in MSDU_INfO_T. */ + ASSERT(prStaRec->ucNetTypeIndex != NETWORK_TYPE_AIS_INDEX); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Compose Header and Fixed Field */ + assocComposeReAssocRespFrameHeaderAndFF(prStaRec, + (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucBSSID, prBssInfo->u2CapInfo, &u2PayloadLen); + + /* 4 <3> Update information of MSDU_INFO_T */ + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = aaaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Compose the frame body's IEs of the (Re)Association Request frame. */ + assocBuildReAssocRespFrameCommonIEs(prAdapter, prMsduInfo, prBssInfo); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ + + /* Append IE */ + for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txAssocRespIETable[i].pfnAppendIE) + txAssocRespIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* 4 <6> Enqueue the frame to send this (Re)Association request frame. */ + DBGLOG(SAA, INFO, "Sending (Re)Assoc Response, network: %d seqNo: %d\n", + prMsduInfo->ucNetworkType, prMsduInfo->ucTxSeqNum); + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of assocSendReAssocRespFrame() */ +#endif /* CFG_SUPPORT_AAA */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c new file mode 100644 index 0000000000000..43b91d72bd431 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/auth.c @@ -0,0 +1,1211 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/auth.c#1 +*/ + +/*! \file "auth.c" + \brief This file includes the authentication-related functions. + + This file includes the authentication-related functions. +*/ + +/* +** Log: auth.c + * + * 02 13 2012 cp.wu + * NULL + * show error message only instead of raise assertion when + * received authentication frame is carrying illegal parameters. + * + * 11 09 2011 yuche.tsai + * NULL + * Fix a network index & station record index issue when TX deauth frame. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 06 22 2011 yuche.tsai + * NULL + * Fix coding error. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000796] [Volunteer Patch][MT6620][Driver] Add BC deauth frame TX feature. + * BC deauth support. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * 1. Fix Service Disocvery Logical issue. + * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 21 2011 terry.wu + * [WCXRP00000381] [MT6620 Wi-Fi][Driver] Kernel panic when replying unaccept Auth in AP mode + * In AP mode, use STA_REC_INDEX_NOT_FOUND(0xFE) instead of StaRec index when replying an unaccept Auth frame. + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update authSendDeauthFrame() for correct the value of eNetTypeIndex in MSDU_INFO_T + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Check Net is active before sending Deauth frame. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Fix compile warning + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add debug message for abnormal authentication frame from AP + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * Fix the Debug Label + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update the authComposeAuthFrameHeader() + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the send deauth frame function + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Integrate send Auth with TXM + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +APPEND_IE_ENTRY_T txAuthIETable[] = { + {(ELEM_HDR_LEN + ELEM_MAX_LEN_CHALLENGE_TEXT), authAddIEChallengeText} +}; + +HANDLE_IE_ENTRY_T rxAuthIETable[] = { + {ELEM_ID_CHALLENGE_TEXT, authHandleIEChallengeText} +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Authentication frame header and fixed fields. +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucPeerMACAddress Given Peer MAC Address. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2AuthAlgNum Authentication Algorithm Number +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* @param[in] u2StatusCode Status Code +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +authComposeAuthFrameHeaderAndFF(IN PUINT_8 pucBuffer, + IN UINT_8 aucPeerMACAddress[], + IN UINT_8 aucMACAddress[], + IN UINT_16 u2AuthAlgNum, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T) pucBuffer; + + /* 4 <1> Compose the frame header of the Authentication frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_AUTH; + + /* If this frame is the third frame in the shared key authentication + * sequence, it shall be encrypted. + */ + if ((u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) + u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; /* HW will also detect this bit for applying encryption */ + /* WLAN_SET_FIELD_16(&prAuthFrame->u2FrameCtrl, u2FrameCtrl); */ + prAuthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAuthFrame->aucSrcAddr, aucMACAddress); + + switch (u2TransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucPeerMACAddress); + break; + + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + + /* Fill the BSSID field with Current BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); + break; + + default: + ASSERT(0); + } + + /* Clear the SEQ/FRAG_NO field. */ + prAuthFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ + /* Fill the Authentication Algorithm Number field. */ + /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthAlgNum, u2AuthAlgNum); */ + prAuthFrame->u2AuthAlgNum = u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the Authentication Transaction Sequence Number field. */ + /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, u2TransactionSeqNum); */ + prAuthFrame->u2AuthTransSeqNo = u2TransactionSeqNum; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the Status Code field. */ + /* WLAN_SET_FIELD_16(&prAuthFrame->u2StatusCode, u2StatusCode); */ + prAuthFrame->u2StatusCode = u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ + +} /* end of authComposeAuthFrameHeaderAndFF() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will append Challenge Text IE to the Authentication frame +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID authAddIEChallengeText(IN P_ADAPTER_T prAdapter, IN OUT P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TransactionSeqNum; + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) + return; + + ASSERT(prStaRec); + + /* For Management, frame header and payload are in a continuous buffer */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prMsduInfo->prPacket; + + WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) + + /* Only consider SEQ_3 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && (prStaRec->prChallengeText != NULL)) { + + COPY_IE(((ULONG) (prMsduInfo->prPacket) + prMsduInfo->u2FrameLength), (prStaRec->prChallengeText)); + + prMsduInfo->u2FrameLength += IE_SIZE(prStaRec->prChallengeText); + } + + return; + +} /* end of authAddIEChallengeText() */ + +#if !CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Authenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN UINT_16 u2TransactionSeqNum) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + UINT_16 u2PayloadLen; + UINT_32 i; + + DBGLOG(SAA, LOUD, "Send Auth Frame\n"); + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec->aucMacAddr, + prBssInfo->aucOwnMacAddr, + prStaRec->ucAuthAlgNum, u2TransactionSeqNum, STATUS_CODE_RESERVED); + + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); + + /* 4 <3> Update information of MSDU_INFO_T */ + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = saaFsmRunEventTxDone; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Compose IEs in MSDU_INFO_T */ + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { + if (txAuthIETable[i].pfnAppendIE) + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* 4 <6> Inform TXM to send this Authentication frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendAuthFrame() */ + +#else + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Authenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_SW_RFB_T prFalseAuthSwRfb, IN UINT_16 u2TransactionSeqNum, IN UINT_16 u2StatusCode) +{ + PUINT_8 pucReceiveAddr; + PUINT_8 pucTransmitAddr; + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + /*get from input parameter */ + /* ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; */ + PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedExtraIELen; + UINT_16 u2PayloadLen; + UINT_16 ucAuthAlgNum; + UINT_32 i; + + DBGLOG(SAA, LOUD, "Send Auth Frame %d, Status Code = %d\n", u2TransactionSeqNum, u2StatusCode); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Authentication Request frame header and fixed fields in MSDU_INfO_T. */ + if (prStaRec) { + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucReceiveAddr = prStaRec->aucMacAddr; + + ucAuthAlgNum = prStaRec->ucAuthAlgNum; + + switch (u2TransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + pfTxDoneHandler = saaFsmRunEventTxDone; + break; + + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + pfTxDoneHandler = aaaFsmRunEventTxDone; + break; + } + + } else { /* For Error Status Code */ + P_WLAN_AUTH_FRAME_T prFalseAuthFrame; + + ASSERT(prFalseAuthSwRfb); + prFalseAuthFrame = (P_WLAN_AUTH_FRAME_T) prFalseAuthSwRfb->pvHeader; + + ASSERT(u2StatusCode != STATUS_CODE_SUCCESSFUL); + + pucTransmitAddr = prFalseAuthFrame->aucDestAddr; + + pucReceiveAddr = prFalseAuthFrame->aucSrcAddr; + + ucAuthAlgNum = prFalseAuthFrame->u2AuthAlgNum; + + u2TransactionSeqNum = (prFalseAuthFrame->u2AuthTransSeqNo + 1); + } + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, + pucTransmitAddr, ucAuthAlgNum, u2TransactionSeqNum, u2StatusCode); + + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); + + /* 4 <3> Update information of MSDU_INFO_T */ + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + if (prStaRec) + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + else + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; /* false Auth frame */ + prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Compose IEs in MSDU_INFO_T */ + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) { + if (txAuthIETable[i].pfnAppendIE) + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* 4 <6> Inform TXM to send this Authentication frame. */ + DBGLOG(SAA, INFO, "network: %d Send Auth Frame %d, Status Code = %d seq num %d\n", + eNetTypeIndex, u2TransactionSeqNum, u2StatusCode, prMsduInfo->ucTxSeqNum); + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendAuthFrame() */ + +#endif /* CFG_SUPPORT_AAA */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will strictly check the TX Authentication frame for SAA/AAA event +* handling. +* +* @param[in] prMsduInfo Pointer of MSDU_INFO_T +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN UINT_16 u2TransactionSeqNum) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TxFrameCtrl; + UINT_16 u2TxAuthAlgNum; + UINT_16 u2TxTransactionSeqNum; + + ASSERT(prMsduInfo); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T) (prMsduInfo->prPacket); + ASSERT(prAuthFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + /* WLAN_GET_FIELD_16(&prAuthFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAuthFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (u2TxFrameCtrl != MAC_FRAME_AUTH) + return WLAN_STATUS_FAILURE; + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2TxAuthAlgNum) */ + u2TxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ + if (u2TxAuthAlgNum != (UINT_16) (prStaRec->ucAuthAlgNum)) + return WLAN_STATUS_FAILURE; + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TxTransactionSeqNum) */ + u2TxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ + if (u2TxTransactionSeqNum != u2TransactionSeqNum) + return WLAN_STATUS_FAILURE; + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckTxAuthFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Auth Frame's Transaction Sequence +* Number before delivering it to the corresponding SAA or AAA Module. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain authentication frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2RxTransactionSeqNum; + + ASSERT(prSwRfb); + + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Authentication Frame. */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN)) { + ASSERT(0); + return WLAN_STATUS_SUCCESS; + } + /* 4 <3> Parse the Fixed Fields of Authentication Frame Body. */ + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ + u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ + + switch (u2RxTransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + saaFsmRunEventRxAuth(prAdapter, prSwRfb); + break; + + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAuth(prAdapter, prSwRfb); +#endif /* CFG_SUPPORT_AAA */ + break; + + default: + DBGLOG(SAA, WARN, "Strange Authentication Packet: Auth Trans Seq No = %d, Error Status Code = %d\n", + u2RxTransactionSeqNum, prAuthFrame->u2StatusCode); + break; + } + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckRxAuthFrameTransSeq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the incoming Authentication Frame and take +* the status code out. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] u2TransactionSeqNum Transaction Sequence Number +* @param[out] pu2StatusCode Pointer to store the Status Code from Authentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN UINT_16 u2TransactionSeqNum, OUT PUINT_16 pu2StatusCode) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2RxAuthAlgNum; + UINT_16 u2RxTransactionSeqNum; + /* UINT_16 u2RxStatusCode; // NOTE(Kevin): Optimized for ARM */ + + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Fixed Fields of Authentication Frame Body. */ + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2RxAuthAlgNum); */ + u2RxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized for ARM */ + if (u2RxAuthAlgNum != (UINT_16) prStaRec->ucAuthAlgNum) { + DBGLOG(SAA, WARN, "Discard Auth frame with auth type = %d, current = %d\n", + u2RxAuthAlgNum, prStaRec->ucAuthAlgNum); + *pu2StatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; + return WLAN_STATUS_SUCCESS; + } + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2RxTransactionSeqNum); */ + u2RxTransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ + if (u2RxTransactionSeqNum != u2TransactionSeqNum) { + DBGLOG(SAA, WARN, "Discard Auth frame with Transaction Seq No = %d\n", u2RxTransactionSeqNum); + *pu2StatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; + return WLAN_STATUS_SUCCESS; + } + /* 4 <3> Get the Status code */ + /* WLAN_GET_FIELD_16(&prAuthFrame->u2StatusCode, &u2RxStatusCode); */ + /* *pu2StatusCode = u2RxStatusCode; */ + *pu2StatusCode = prAuthFrame->u2StatusCode; /* NOTE(Kevin): Optimized for ARM */ + + return WLAN_STATUS_SUCCESS; + +} /* end of authCheckRxAuthFrameStatus() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Challenge Text IE from the Authentication frame +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] prIEHdr Pointer to start address of IE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, P_IE_HDR_T prIEHdr) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + UINT_16 u2TransactionSeqNum; + + ASSERT(prSwRfb); + ASSERT(prIEHdr); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (!prStaRec) + return; + + /* For Management, frame header and payload are in a continuous buffer */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthTransSeqNo, &u2TransactionSeqNum) */ + u2TransactionSeqNum = prAuthFrame->u2AuthTransSeqNo; /* NOTE(Kevin): Optimized for ARM */ + + /* Only consider SEQ_2 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_2) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY)) { + + /* Free previous allocated TCM memory */ + if (prStaRec->prChallengeText) { + ASSERT(0); + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; + } + + prStaRec->prChallengeText = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, IE_SIZE(prIEHdr)); + if (prStaRec->prChallengeText == NULL) + return; + + /* Save the Challenge Text from Auth Seq 2 Frame, before sending Auth Seq 3 Frame */ + COPY_IE(prStaRec->prChallengeText, prIEHdr); + } + + return; + +} /* end of authAddIEChallengeText() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Authentication frame. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + PUINT_8 pucIEsBuffer; + UINT_16 u2IEsLen; + UINT_16 u2Offset; + UINT_8 ucIEID; + UINT_32 i; + + ASSERT(prSwRfb); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + pucIEsBuffer = &prAuthFrame->aucInfoElem[0]; + u2IEsLen = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (AUTH_ALGORITHM_NUM_FIELD_LEN + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + STATUS_CODE_FIELD_LEN); + + IE_FOR_EACH(pucIEsBuffer, u2IEsLen, u2Offset) { + ucIEID = IE_ID(pucIEsBuffer); + + for (i = 0; i < (sizeof(rxAuthIETable) / sizeof(HANDLE_IE_ENTRY_T)); i++) { + + if (ucIEID == rxAuthIETable[i].ucElemID) + rxAuthIETable[i].pfnHandleIE(prAdapter, prSwRfb, (P_IE_HDR_T) pucIEsBuffer); + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxAuth2_Auth4Frame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Deauthentication frame +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] aucPeerMACAddress Given Peer MAC Address. +* @param[in] aucMACAddress Given Our MAC Address. +* @param[in] u2StatusCode Status Code +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID +authComposeDeauthFrameHeaderAndFF(IN PUINT_8 pucBuffer, + IN UINT_8 aucPeerMACAddress[], + IN UINT_8 aucMACAddress[], IN UINT_8 aucBssid[], IN UINT_16 u2ReasonCode) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + ASSERT(aucBssid); + + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) pucBuffer; + + /* 4 <1> Compose the frame header of the Deauthentication frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DEAUTH; + + /* WLAN_SET_FIELD_16(&prDeauthFrame->u2FrameCtrl, u2FrameCtrl); */ + prDeauthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDeauthFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucBSSID, aucBssid); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prDeauthFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Authentication frame. */ + /* Fill the Status Code field. */ + /* WLAN_SET_FIELD_16(&prDeauthFrame->u2ReasonCode, u2ReasonCode); */ + prDeauthFrame->u2ReasonCode = u2ReasonCode; /* NOTE(Kevin): Optimized for ARM */ + +} /* end of authComposeDeauthFrameHeaderAndFF() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send the Deauthenticiation frame +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prClassErrSwRfb Pointer to the SW_RFB_T which is Class Error. +* @param[in] u2ReasonCode A reason code to indicate why to leave BSS. +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCES No available resource for frame composing. +* @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module +* @retval WLAN_STATUS_FAILURE Didn't send Deauth frame for various reasons. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendDeauthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, IN UINT_16 u2ReasonCode, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_WLAN_MAC_HEADER_A4_T prWlanMacHeader = NULL; + PUINT_8 pucReceiveAddr; + PUINT_8 pucTransmitAddr; + PUINT_8 pucBssid = NULL; + + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2RxFrameCtrl; + P_BSS_INFO_T prBssInfo; + + P_DEAUTH_INFO_T prDeauthInfo; + OS_SYSTIME rCurrentTime; + INT_32 i4NewEntryIndex, i; + UINT_8 ucStaRecIdx = STA_REC_INDEX_NOT_FOUND; + +#if CFG_ENABLE_WIFI_DIRECT + UINT_8 aucBMC[] = BC_MAC_ADDR; +#endif + + /* NOTE(Kevin): The best way to reply the Deauth is according to the incoming data + * frame + */ + /* 4 <1> Find the Receiver Address first. */ + if (prClassErrSwRfb) { + BOOLEAN fgIsAbleToSendDeauth = FALSE; + + prWlanMacHeader = (P_WLAN_MAC_HEADER_A4_T) prClassErrSwRfb->pvHeader; + + /* WLAN_GET_FIELD_16(&prWlanMacHeader->u2FrameCtrl, &u2RxFrameCtrl); */ + u2RxFrameCtrl = prWlanMacHeader->u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* TODO(Kevin): Currently we won't send Deauth for IBSS node. How about DLS ? */ + if ((prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) == 0) + return WLAN_STATUS_FAILURE; + + /* Check if corresponding BSS is able to send Deauth */ + for (i = NETWORK_TYPE_AIS_INDEX; i < NETWORK_TYPE_INDEX_NUM; i++) { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[i]); + + if (IS_NET_ACTIVE(prAdapter, i) && + (EQUAL_MAC_ADDR(prWlanMacHeader->aucAddr1, prBssInfo->aucOwnMacAddr))) { + { + fgIsAbleToSendDeauth = TRUE; + eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) i; + break; + } + } + } + + if (!fgIsAbleToSendDeauth) + return WLAN_STATUS_FAILURE; + + pucReceiveAddr = prWlanMacHeader->aucAddr2; + + } else if (prStaRec) { + + pucReceiveAddr = prStaRec->aucMacAddr; + } else { +#if CFG_ENABLE_WIFI_DIRECT + pucReceiveAddr = aucBMC; +#else + return WLAN_STATUS_FAILURE; +#endif + } + + /* 4 <2> Check if already send a Deauth frame in MIN_DEAUTH_INTERVAL_MSEC */ + GET_CURRENT_SYSTIME(&rCurrentTime); + + i4NewEntryIndex = -1; + for (i = 0; i < MAX_DEAUTH_INFO_COUNT; i++) { + prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i]); + + /* For continuously sending Deauth frame, the minimum interval is + * MIN_DEAUTH_INTERVAL_MSEC. + */ + if (CHECK_FOR_TIMEOUT(rCurrentTime, + prDeauthInfo->rLastSendTime, MSEC_TO_SYSTIME(MIN_DEAUTH_INTERVAL_MSEC))) { + + i4NewEntryIndex = i; + } else if (EQUAL_MAC_ADDR(pucReceiveAddr, prDeauthInfo->aucRxAddr) && (!pfTxDoneHandler)) { + + return WLAN_STATUS_FAILURE; + } + } + + /* 4 <3> Update information. */ + if (i4NewEntryIndex > 0) { + + prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i4NewEntryIndex]); + + COPY_MAC_ADDR(prDeauthInfo->aucRxAddr, pucReceiveAddr); + prDeauthInfo->rLastSendTime = rCurrentTime; + } else { + /* NOTE(Kevin): for the case of AP mode, we may encounter this case + * if deauth all the associated clients. + */ + DBGLOG(SAA, WARN, "No unused DEAUTH_INFO_T !\n"); + } + + /* 4 <4> Allocate a PKT_INFO_T for Deauthentication Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN); + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Deauth Request.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <5> Find the Transmitter Address and BSSID. */ + if (prClassErrSwRfb) { + + /* The TA of Deauth is the A1 of RX frame */ + pucTransmitAddr = prWlanMacHeader->aucAddr1; + + switch (prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) { + + case MASK_FC_FROM_DS: + /* The BSSID of Deauth is the A2 of RX frame */ + pucBssid = prWlanMacHeader->aucAddr2; + break; + + case MASK_FC_TO_DS: + /* The BSSID of Deauth is the A1 of RX frame */ + pucBssid = prWlanMacHeader->aucAddr1; + break; + + case MASK_TO_DS_FROM_DS: + /* TODO(Kevin): Consider BOW, now we set the BSSID of Deauth + * to the A2 of RX frame for temporary solution. + */ + pucBssid = prWlanMacHeader->aucAddr2; + break; + + /* No Default */ + } + + } else if (prStaRec) { + eNetTypeIndex = prStaRec->ucNetTypeIndex; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucBssid = prBssInfo->aucBSSID; + } +#if CFG_ENABLE_WIFI_DIRECT + else { + if (prAdapter->fgIsP2PRegistered) { + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + ucStaRecIdx = STA_REC_INDEX_BMCAST; + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucBssid = prBssInfo->aucBSSID; + + eNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + } else { + /* 20130122: free packet by samplin */ + cnmMgtPktFree(prAdapter, prMsduInfo); + return WLAN_STATUS_FAILURE; + } + } + +#endif + + /* 4 <6> compose Deauthentication frame header and some fixed fields */ + authComposeDeauthFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, pucTransmitAddr, pucBssid, u2ReasonCode); + +#if CFG_SUPPORT_802_11W + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + + prDeauthFrame = + (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + DBGLOG(TX, WARN, "authSendDeauthFrame with protection\n"); + } +#endif + + /* 4 <7> Update information of MSDU_INFO_T */ + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = ((prStaRec == NULL) ? ucStaRecIdx : prStaRec->ucIndex); + prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + DBGLOG(SAA, INFO, "Sending Deauth, network: %d, seqNo %d\n", + eNetTypeIndex, prMsduInfo->ucTxSeqNum); + + /* 4 <8> Inform TXM to send this Deauthentication frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} /* end of authSendDeauthFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Deauthentication frame +* if the given BSSID is matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucBSSID Given BSSID +* @param[out] pu2ReasonCode Pointer to store the Reason Code from Deauthentication. +* +* @retval WLAN_STATUS_FAILURE This is not the frame we should handle at current state. +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, IN UINT_8 aucBSSID[], OUT PUINT_16 pu2ReasonCode) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + UINT_16 u2RxReasonCode; + + ASSERT(prSwRfb); + ASSERT(aucBSSID); + ASSERT(pu2ReasonCode); + + /* 4 <1> locate the Deauthentication Frame. */ + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Deauthentication Frame. */ +#if 0 /* Kevin: Seems redundant */ + WLAN_GET_FIELD_16(&prDeauthFrame->u2FrameCtrl, &u2RxFrameCtrl) + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (u2RxFrameCtrl != MAC_FRAME_DEAUTH) + return WLAN_STATUS_FAILURE; +#endif + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Deauth Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDeauthFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, "Ignore Deauth Frame from other BSS [ %pM ]\n", + prDeauthFrame->aucSrcAddr); + return WLAN_STATUS_FAILURE; + } + /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ + WLAN_GET_FIELD_16(&prDeauthFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxDeauthFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will parse and process the incoming Authentication frame. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] aucExpectedBSSID Given Expected BSSID. +* @param[in] u2ExpectedAuthAlgNum Given Expected Authentication Algorithm Number +* @param[in] u2ExpectedTransSeqNum Given Expected Transaction Sequence Number. +* @param[out] pu2ReturnStatusCode Return Status Code. +* +* @retval WLAN_STATUS_SUCCESS This is the frame we should handle. +* @retval WLAN_STATUS_FAILURE The frame we will ignore. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN UINT_8 aucExpectedBSSID[], + IN UINT_16 u2ExpectedAuthAlgNum, + IN UINT_16 u2ExpectedTransSeqNum, OUT PUINT_16 pu2ReturnStatusCode) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + UINT_16 u2ReturnStatusCode = STATUS_CODE_SUCCESSFUL; + + ASSERT(prSwRfb); + ASSERT(aucExpectedBSSID); + ASSERT(pu2ReturnStatusCode); + + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + /* 4 <2> Check the BSSID */ + if (UNEQUAL_MAC_ADDR(prAuthFrame->aucBSSID, aucExpectedBSSID)) + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + /* 4 <3> Check the SA, which should not be MC/BC */ + if (prAuthFrame->aucSrcAddr[0] & BIT(0)) { + DBGLOG(P2P, WARN, "Invalid STA MAC with MC/BC bit set: %pM\n", + prAuthFrame->aucSrcAddr); + return WLAN_STATUS_FAILURE; + } + /* 4 <4> Parse the Fixed Fields of Authentication Frame Body. */ + if (prAuthFrame->u2AuthAlgNum != u2ExpectedAuthAlgNum) + u2ReturnStatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; + + if (prAuthFrame->u2AuthTransSeqNo != u2ExpectedTransSeqNum) + u2ReturnStatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; + + *pu2ReturnStatusCode = u2ReturnStatusCode; + + return WLAN_STATUS_SUCCESS; + +} /* end of authProcessRxAuth1Frame() */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c new file mode 100644 index 0000000000000..160779583655f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/bss.c @@ -0,0 +1,2521 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/bss.c#3 +*/ + +/*! \file "bss.c" + \brief This file contains the functions for creating BSS(AP)/IBSS(AdHoc). + + This file contains the functions for BSS(AP)/IBSS(AdHoc). We may create a BSS/IBSS + network, or merge with exist IBSS network and sending Beacon Frame or reply + the Probe Response Frame for received Probe Request Frame. +*/ + +/* +** Log: bss.c +** +** 09 03 2013 cp.wu +** add path for reassociation +** +** 08 30 2012 chinglan.wang +** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only +** . +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 14 2012 chinglan.wang + * NULL + * Fix the losing of the HT IE in assoc request.. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 03 08 2012 yuche.tsai + * NULL + * Fix FW assert when start Hot-Spot. + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 01 20 2012 chinglan.wang + * 03 02 2012 terry.wu + * NULL + * Fix the WPA-PSK TKIP and WPA2-PSK AES security mode bug. + * + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 15 2012 yuche.tsai + * NULL + * Fix wrong basic rate issue. + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 03 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Always set short slot time to TRUE initially in AP mode + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 09 14 2011 yuche.tsai + * NULL + * Add P2P IE in assoc response. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 03 29 2011 eddie.chen + * [WCXRP00000608] [MT6620 Wi-Fi][DRV] Change wmm parameters in beacon + * Change wmm parameters in beacon. + * + * 03 29 2011 yuche.tsai + * [WCXRP00000607] [Volunteer Patch][MT6620][Driver] Coding Style Fix for klocwork scan. + * Fix klocwork issue. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Make assoc req to append P2P IE if wifi direct is enabled. + * + * 03 11 2011 chinglan.wang + * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. + * . + * + * 03 03 2011 george.huang + * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated + * . + * + * 03 03 2011 george.huang + * [WCXRP00000508] [MT6620 Wi-Fi][Driver] aware of beacon MSDU will be free, after BSS deactivated + * modify to handle if beacon MSDU been released when BSS deactivated + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 03 02 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * Add code to send beacon and probe response WSC IE at Auto GO. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Change GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 12 2011 yuche.tsai + * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. + * bss should create station record type according to callers input. + * + * 02 11 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * In p2p link function, check networktype before calling p2p function. + * + * 02 11 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Modify p2p link function to avoid assert. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 25 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Fix the compile error in windows. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 24 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * .Fix typo and missing entry + * + * 12 30 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Fix prBssInfo->aucCWminLog to prBssInfo->aucCWminLogForBcast + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, + +Add per station flow control when STA is in PS + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC + * for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 29 2010 yuche.tsai + * NULL + * Finish SLT TX/RX & Rate Changing Support. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 16 2010 yuche.tsai + * NULL + * Before composing Beacon IE, assign network type index for msdu info, + * this information is needed by RLM module while composing some RLM related IE field. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Fix undefined pucDestAddr in bssUpdateBeaconContent() + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 08 02 2010 george.huang + * NULL + * add WMM-PS test related OID/ CMD handlers + * + * 07 26 2010 yuche.tsai + * + * Add support to RX probe response for P2P. + * + * 07 20 2010 cp.wu + * + * 1) bugfix: do not stop timer for join after switched into normal_tr state, for providing chance for DHCP handshasking + * 2) modify rsnPerformPolicySelection() invoking + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * when IBSS is being merged-in, send command packet to PM for connected indication + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error while enable WIFI_DIRECT support. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct when ADHOC support is turned on. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * auth.c is migrated. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fix compilation error when WIFI_DIRECT is turned on + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add bss.c. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add ClientList handling API - bssClearClientList, bssAddStaRecToClientList + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update bssProcessProbeRequest() to avoid redundant SSID IE {0,0} for IOT. + * + * 05 21 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine txmInitWtblTxRateTable() - set TX initial rate according to AP's operation rate set + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Use TX MGMT Frame API for sending PS NULL frame to avoid the TX Burst Mechanism in TX FW Frame API + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Separate Beacon and ProbeResp IE array + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed the use of compiling flag MQM_WMM_PARSING + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 20 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Fix restart Beacon Timeout Func after connection diagnosis + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * adding the wpa-none for ibss beacon. + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the protected bit at cap info for ad-hoc. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename the CFG flags + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Update outgoing beacon's TX data rate + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add DTIM count update while TX Beacon + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify code due to define - BAND_24G and specific BSS_INFO_T was changed + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +APPEND_VAR_IE_ENTRY_T txBcnIETable[] = { + {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ +#endif + {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE}, /* 221 */ +#if CFG_ENABLE_WIFI_DIRECT + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE}, /* 221 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ +#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ + {0, p2pFuncCalculateExtra_IELenForBeacon, p2pFuncGenerateExtra_IEForBeacon}, /* 221 */ +#else + {0, p2pFuncCalculateP2p_IELenForBeacon, p2pFuncGenerateP2p_IEForBeacon}, /* 221 */ + {0, p2pFuncCalculateWSC_IELenForBeacon, p2pFuncGenerateWSC_IEForBeacon}, /* 221 */ + {0, p2pFuncCalculateP2P_IE_NoA, p2pFuncGenerateP2P_IE_NoA}, /* 221 */ +#endif +#endif /* CFG_ENABLE_WIFI_DIRECT */ +}; + +APPEND_VAR_IE_ENTRY_T txProbRspIETable[] = { + {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE}, /* 50 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE}, /* 42 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE}, /* 45 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE}, /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE}, /* 48 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE}, /* 74 */ +#endif + {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE}, /* 127 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE}, /* 221 */ + {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ +}; + +#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will create or reset a STA_RECORD_T by given BSS_DESC_T for +* Infrastructure or AdHoc Mode. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eStaType Assign STA Type for this STA_RECORD_T +* @param[in] eNetTypeIndex Assign Net Type Index for this STA_RECORD_T +* @param[in] prBssDesc Received Beacon/ProbeResp from this STA +* +* @retval Pointer to STA_RECORD_T +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_BSS_DESC_T prBssDesc) +{ + P_STA_RECORD_T prStaRec; + UINT_8 ucNonHTPhyTypeSet; + + ASSERT(prBssDesc); + + /* 4 <1> Get a valid STA_RECORD_T */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); + if (!prStaRec) { + + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) eNetTypeIndex); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + + if (!prStaRec) { + ASSERT(FALSE); + return NULL; + } + + ASSERT(prStaRec); + + prStaRec->ucStaState = STA_STATE_1; + prStaRec->ucJoinFailureCount = 0; + /* TODO(Kevin): If this is an old entry, we may also reset the ucJoinFailureCount to 0. + */ + + COPY_MAC_ADDR(prStaRec->aucMacAddr, prBssDesc->aucSrcAddr); + } + /* 4 <2> Setup STA TYPE and NETWORK */ + prStaRec->eStaType = eStaType; + + prStaRec->ucNetTypeIndex = eNetTypeIndex; + + /* 4 <3> Update information from BSS_DESC_T to current P_STA_RECORD_T */ + prStaRec->u2CapInfo = prBssDesc->u2CapInfo; + + prStaRec->u2OperationalRateSet = prBssDesc->u2OperationalRateSet; + prStaRec->u2BSSBasicRateSet = prBssDesc->u2BSSBasicRateSet; + + prStaRec->ucPhyTypeSet = prBssDesc->ucPhyTypeSet; + if (IS_STA_IN_AIS(prStaRec)) { + if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_KEY_ABSENT) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION_DISABLED) || + (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) || (prAdapter->prGlueInfo->u2WapiAssocInfoIESz))) { + DBGLOG(BSS, TRACE, "Ignore the HT Bit for TKIP as pairwise cipher configured!\n"); + prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; + } + } else { + DBGLOG(BSS, TRACE, "P2P skip TKIP limitation for HT Hit!\n"); + } + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prAdapter->rWifiVar.ucAvailablePhyTypeSet; + + ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; + + /* Check for Target BSS's non HT Phy Types */ + if (ucNonHTPhyTypeSet) { + + if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ + + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = TRUE; + } else { + /* Use mandatory for 11N only BSS */ + ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); + + { + /* TODO(Kevin): which value should we set for 11n ? ERP ? */ + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = FALSE; + } + + /* Update non HT Desired Rate Set */ + { + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prStaRec->u2DesiredNonHTRateSet = + (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); + } + + /* 4 <4> Update information from BSS_DESC_T to current P_STA_RECORD_T */ + if (IS_AP_STA(prStaRec)) { + /* do not need to parse IE for DTIM, + * which have been parsed before inserting into BSS_DESC_T + */ + if (prBssDesc->ucDTIMPeriod) + prStaRec->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + else + prStaRec->ucDTIMPeriod = 0; /* Means that TIM was not parsed. */ + } + /* 4 <5> Update default value */ + prStaRec->fgDiagnoseConnection = FALSE; + + /* 4 <6> Update default value for other Modules */ + /* Determine fgIsWmmSupported and fgIsUapsdSupported in STA_REC */ + mqmProcessScanResult(prAdapter, prBssDesc, prStaRec); + + return prStaRec; + +} /* end of bssCreateStaRecFromBssDesc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Null Data frame. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] prStaRec Pointer to the STA_RECORD_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec) +{ + P_WLAN_MAC_HEADER_T prNullFrame; + P_BSS_INFO_T prBssInfo; + UINT_16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(prStaRec); + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo); + + prNullFrame = (P_WLAN_MAC_HEADER_T) pucBuffer; + + /* 4 <1> Decide the Frame Control Field */ + u2FrameCtrl = MAC_FRAME_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) + u2FrameCtrl |= MASK_FC_PWR_MGT; + } else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } else { + /* NOTE(Kevin): We won't send Null frame for IBSS */ + ASSERT(0); + return; + } + + /* 4 <2> Compose the Null frame */ + /* Fill the Frame Control field. */ + /* WLAN_SET_FIELD_16(&prNullFrame->u2FrameCtrl, u2FrameCtrl); */ + prNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prNullFrame->u2SeqCtrl = 0; + + return; + +} /* end of bssComposeNullFrameHeader() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the QoS Null Data frame. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] prStaRec Pointer to the STA_RECORD_T. +* @param[in] ucUP User Priority. +* @param[in] fgSetEOSP Set the EOSP bit. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuffer, IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN BOOLEAN fgSetEOSP) +{ + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + P_BSS_INFO_T prBssInfo; + UINT_16 u2FrameCtrl; + UINT_16 u2QosControl; + + ASSERT(pucBuffer); + ASSERT(prStaRec); + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo); + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) pucBuffer; + + /* 4 <1> Decide the Frame Control Field */ + u2FrameCtrl = MAC_FRAME_QOS_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) + u2FrameCtrl |= MASK_FC_PWR_MGT; + } else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } else { + /* NOTE(Kevin): We won't send QoS Null frame for IBSS */ + ASSERT(0); + return; + } + + /* 4 <2> Compose the QoS Null frame */ + /* Fill the Frame Control field. */ + /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2FrameCtrl, u2FrameCtrl); */ + prQoSNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prQoSNullFrame->u2SeqCtrl = 0; + + u2QosControl = (UINT_16) (ucUP & WMM_QC_UP_MASK); + + if (fgSetEOSP) + u2QosControl |= WMM_QC_EOSP; + /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2QosCtrl, u2QosControl); */ + prQoSNullFrame->u2QosCtrl = u2QosControl; /* NOTE(Kevin): Optimized for ARM */ + + return; + +} /* end of bssComposeQoSNullFrameHeader() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the Null Frame +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Succe]ss. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeNullFrame(prAdapter, (PUINT_8) ((ULONG) prMsduInfo->prPacket + MAC_TX_RESERVED_FIELD), prStaRec); +#if 0 + /* 4 <3> Update information of MSDU_INFO_T */ + TXM_SET_DATA_PACKET( + /* STA_REC ptr */ prStaRec, + /* MSDU_INFO ptr */ prMsduInfo, + /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), + /* MAC HDR length */ WLAN_MAC_HEADER_LEN, + /* PAYLOAD ptr */ + (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN), + /* PAYLOAD length */ 0, + /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, + /* TID */ 0 /* BE: AC1 */ , + /* Flag 802.11 */ TRUE, + /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , + /* Resource TC */ 0 /* Irrelevant */ , + /* Flag 802.1x */ FALSE, + /* TX-done callback */ pfTxDoneHandler, + /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, + /* PS Session ID */ 0 /* Irrelevant */ , + /* Flag fixed rate */ TRUE, + /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, + /* Fixed-rate retry */ BSS_DEFAULT_CONN_TEST_NULL_FRAME_RETRY_LIMIT, + /* PAL LLH */ 0 /* Irrelevant */ , + /* ACL SN */ 0 /* Irrelevant */ , + /* Flag No Ack */ FALSE + ); + + /* Terminate with a NULL pointer */ + NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* Indicate the packet to TXM */ + /* 4 <4> Inform TXM to send this Null frame. */ + txmSendFwDataPackets(prMsduInfo); +#endif + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = FALSE; + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendNullFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the QoS Null Frame +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] pfTxDoneHandler TX Done call back function +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeQoSNullFrame(prAdapter, + (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec, ucUP, FALSE); +#if 0 + /* 4 <3> Update information of MSDU_INFO_T */ + TXM_SET_DATA_PACKET( + /* STA_REC ptr */ prStaRec, + /* MSDU_INFO ptr */ prMsduInfo, + /* MAC HDR ptr */ (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD), + /* MAC HDR length */ WLAN_MAC_HEADER_QOS_LEN, + /* PAYLOAD ptr */ + (prMsduInfo->pucBuffer + MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN), + /* PAYLOAD length */ 0, + /* Network Type Index */ (UINT_8) prStaRec->ucNetTypeIndex, + /* TID */ 0 /* BE: AC1 */ , + /* Flag 802.11 */ TRUE, + /* Pkt arrival time */ 0 /* TODO: Obtain the system time */ , + /* Resource TC */ 0 /* Irrelevant */ , + /* Flag 802.1x */ FALSE, + /* TX-done callback */ pfTxDoneHandler, + /* PS forwarding type */ PS_FORWARDING_TYPE_NON_PS, + /* PS Session ID */ 0 /* Irrelevant */ , + /* Flag fixed rate */ TRUE, + /* Fixed tx rate */ g_aprBssInfo[prStaRec->ucNetTypeIndex]->ucHwDefaultFixedRateCode, + /* Fixed-rate retry */ TXM_DEFAULT_DATA_FRAME_RETRY_LIMIT, + /* PAL LLH */ 0 /* Irrelevant */ , + /* ACL SN */ 0 /* Irrelevant */ , + /* Flag No Ack */ FALSE + ); + + /* Terminate with a NULL pointer */ + NIC_HIF_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* Indicate the packet to TXM */ + /* 4 <4> Inform TXM to send this Null frame. */ + txmSendFwDataPackets(prMsduInfo); +#endif + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendQoSNullFrame() */ + +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate Information Elements of Extended +* Support Rate +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + PUINT_8 pucBuffer; + UINT_8 ucExtSupRatesLen; + + ASSERT(prMsduInfo); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); + ASSERT(prBssInfo); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) + ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; + else + ucExtSupRatesLen = 0; + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ELEM_MAX_LEN_SUP_RATES], ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* end of bssGenerateExtSuppRate_IE() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for Beacon +* or Probe Response Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, IN P_BSS_INFO_T prBssInfo, IN PUINT_8 pucDestAddr) +{ + PUINT_8 pucBuffer; + UINT_8 ucSupRatesLen; + + ASSERT(prMsduInfo); + ASSERT(prBssInfo); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + /* Compose the frame body of the Probe Response frame. */ + /* 4 <1> Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + if (prBssInfo->eHiddenSsidType == ENUM_HIDDEN_SSID_LEN) { + if ((!pucDestAddr) && /* For Beacon only */ + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + SSID_IE(pucBuffer)->ucLength = 0; + } else { /* Probe response */ + SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; + if (prBssInfo->ucSSIDLen) + kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + } + } else { + SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; + if (prBssInfo->ucSSIDLen) + kalMemCopy(SSID_IE(pucBuffer)->aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + } + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + /* 4 <2> Fill the Supported Rates element. */ + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + else + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, prBssInfo->aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + /* 4 <3> Fill the DS Parameter Set element. */ + if (prBssInfo->eBand == BAND_2G4) { + DS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_DS_PARAM_SET; + DS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_DS_PARAMETER_SET; + DS_PARAM_IE(pucBuffer)->ucCurrChnl = prBssInfo->ucPrimaryChannel; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + /* 4 <4> IBSS Parameter Set element, ID: 6 */ + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + IBSS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_IBSS_PARAM_SET; + IBSS_PARAM_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_IBSS_PARAMETER_SET; + WLAN_SET_FIELD_16(&(IBSS_PARAM_IE(pucBuffer)->u2ATIMWindow), prBssInfo->u2ATIMWindow); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + /* 4 <5> TIM element, ID: 5 */ + if ((!pucDestAddr) && /* For Beacon only. */ + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + +#if CFG_ENABLE_WIFI_DIRECT + /*no fgIsP2PRegistered protect */ + if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { +#if 0 + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + UINT_8 ucBitmapControl = 0; + UINT_32 u4N1, u4N2; + + prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); + + /* Clear existing value. */ + prP2pSpecificBssInfo->ucBitmapCtrl = 0; + kalMemZero(prP2pSpecificBssInfo->aucPartialVirtualBitmap, + sizeof(prP2pSpecificBssInfo->aucPartialVirtualBitmap)); + + /* IEEE 802.11 2007 - 7.3.2.6 */ + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucDTIMCount = prBssInfo->ucDTIMCount; + TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; + + /* Setup DTIM Count for next TBTT. */ + if (prBssInfo->ucDTIMCount == 0) { + /*Do nothing*/ + /* 3 *** pmQueryBufferedBCAST(); */ + } + /* 3 *** pmQueryBufferedPSNode(); */ + /* TODO(Kevin): Call PM Module here to loop all STA_RECORD_Ts and it + * will call bssSetTIMBitmap to toggle the Bitmap. + */ + + /* Set Virtual Bitmap for UCAST */ + u4N1 = (prP2pSpecificBssInfo->u2SmallestAID >> 4) << 1; /* Find the largest even number. */ + u4N2 = prP2pSpecificBssInfo->u2LargestAID >> 3; /* Find the smallest number. */ + + ASSERT(u4N2 >= u4N1); + + kalMemCopy(TIM_IE(pucBuffer)->aucPartialVirtualMap, + &prP2pSpecificBssInfo->aucPartialVirtualBitmap[u4N1], ((u4N2 - u4N1) + 1)); + + /* Set Virtual Bitmap for BMCAST */ + /* BMC bit only indicated when DTIM count == 0. */ + if (prBssInfo->ucDTIMCount == 0) + ucBitmapControl = prP2pSpecificBssInfo->ucBitmapCtrl; + TIM_IE(pucBuffer)->ucBitmapControl = ucBitmapControl | (UINT_8) u4N1; + + TIM_IE(pucBuffer)->ucLength = ((u4N2 - u4N1) + 4); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); +#else + + /* IEEE 802.11 2007 - 7.3.2.6 */ + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ + TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP); /*((u4N2 - u4N1) + 4) */ + /* will be overwrite by FW */ + TIM_IE(pucBuffer)->ucDTIMCount = 0; /*prBssInfo->ucDTIMCount */ + TIM_IE(pucBuffer)->ucDTIMPeriod = prBssInfo->ucDTIMPeriod; + /* will be overwrite by FW */ + TIM_IE(pucBuffer)->ucBitmapControl = 0; /*ucBitmapControl | (UINT_8)u4N1 */ + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + +#endif + + } else +#endif /* CFG_ENABLE_WIFI_DIRECT */ + { + /* NOTE(Kevin): 1. AIS - Didn't Support AP Mode. + * 2. BOW - Didn't Support BCAST and PS. + */ + } + + } + +} /* end of bssBuildBeaconProbeRespFrameCommonIEs() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Beacon/Probe Response frame header and +* its fixed fields. +* +* @param[in] pucBuffer Pointer to the frame buffer. +* @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means Beacon. +* @param[in] pucOwnMACAddress Given Our MAC Address. +* @param[in] pucBSSID Given BSSID of the BSS. +* @param[in] u2BeaconInterval Given Beacon Interval. +* @param[in] u2CapInfo Given Capability Info. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +bssComposeBeaconProbeRespFrameHeaderAndFF(IN PUINT_8 pucBuffer, + IN PUINT_8 pucDestAddr, + IN PUINT_8 pucOwnMACAddress, + IN PUINT_8 pucBSSID, IN UINT_16 u2BeaconInterval, IN UINT_16 u2CapInfo) +{ + P_WLAN_BEACON_FRAME_T prBcnProbRspFrame; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + UINT_16 u2FrameCtrl; + + DEBUGFUNC("bssComposeBeaconProbeRespFrameHeaderAndFF"); + /* DBGLOG(INIT, LOUD, ("\n")); */ + + ASSERT(pucBuffer); + ASSERT(pucOwnMACAddress); + ASSERT(pucBSSID); + + prBcnProbRspFrame = (P_WLAN_BEACON_FRAME_T) pucBuffer; + + /* 4 <1> Compose the frame header of the Beacon /ProbeResp frame. */ + /* Fill the Frame Control field. */ + if (pucDestAddr) { + u2FrameCtrl = MAC_FRAME_PROBE_RSP; + } else { + u2FrameCtrl = MAC_FRAME_BEACON; + pucDestAddr = aucBCAddr; + } + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2FrameCtrl, u2FrameCtrl); */ + prBcnProbRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the DA field with BCAST MAC ADDR or TA of ProbeReq. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucDestAddr, pucDestAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucSrcAddr, pucOwnMACAddress); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucBSSID, pucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need to clear it). */ + prBcnProbRspFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the Beacon /ProbeResp frame. */ + /* MAC will update TimeStamp field */ + + /* Fill the Beacon Interval field. */ + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2BeaconInterval, u2BeaconInterval); */ + prBcnProbRspFrame->u2BeaconInterval = u2BeaconInterval; /* NOTE(Kevin): Optimized for ARM */ + + /* Fill the Capability Information field. */ + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2CapInfo, u2CapInfo); */ + prBcnProbRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for ARM */ + +} /* end of bssComposeBeaconProbeRespFrameHeaderAndFF() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the Beacon Frame Template to FW for AIS AdHoc and P2P GO. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eNetTypeIndex Specify which network reply the Probe Response. +* +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_WLAN_BEACON_FRAME_T prBcnFrame; + UINT_32 i; + + DEBUGFUNC("bssUpdateBeaconContent"); + DBGLOG(BSS, LOUD, "\n"); + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + /* 4 <1> Allocate a PKT_INFO_T for Beacon Frame */ + /* Allocate a MSDU_INFO_T */ + /* For Beacon */ + prMsduInfo = prBssInfo->prBeacon; + + /* beacon prMsduInfo will be NULLify once BSS deactivated, so skip if it is */ + if (prMsduInfo == NULL) + return WLAN_STATUS_SUCCESS; + /* 4 <2> Compose header */ + bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + NULL, + prBssInfo->aucOwnMacAddr, + prBssInfo->aucBSSID, + prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); + + prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); + + prMsduInfo->ucNetworkType = eNetTypeIndex; + + /* 4 <3> Compose the frame body's Common IEs of the Beacon frame. */ + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, NULL); + + /* 4 <4> Compose IEs in MSDU_INFO_T */ + + /* Append IE for Beacon */ + for (i = 0; i < sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); i++) { + if (txBcnIETable[i].pfnAppendIE) + txBcnIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; + + return nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + eNetTypeIndex, + prBssInfo->u2CapInfo, + (PUINT_8) prBcnFrame->aucInfoElem, + prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); + +} /* end of bssUpdateBeaconContent() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send the Beacon Frame(for BOW) or Probe Response Frame according to the given +* Destination Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eNetTypeIndex Specify which network reply the Probe Response. +* @param[in] pucDestAddr Pointer to the Destination Address to reply +* @param[in] u4ControlFlags Control flags for information on Probe Response. +* +* @retval WLAN_STATUS_RESOURCE No available resources to send frame. +* @retval WLAN_STATUS_SUCCESS Success. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN PUINT_8 pucDestAddr, IN UINT_32 u4ControlFlags) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + UINT_16 u2EstimatedFixedIELen; + UINT_16 u2EstimatedExtraIELen; + P_APPEND_VAR_IE_ENTRY_T prIeArray = NULL; + UINT_32 u4IeArraySize = 0; + UINT_32 i; + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if (!pucDestAddr) { /* For Beacon */ + prIeArray = &txBcnIETable[0]; + u4IeArraySize = sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + } else { + prIeArray = &txProbRspIETable[0]; + u4IeArraySize = sizeof(txProbRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + } + + /* 4 <1> Allocate a PKT_INFO_T for Beacon /Probe Response Frame */ + /* Allocate a MSDU_INFO_T */ + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE Fields */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + WLAN_MAC_MGMT_HEADER_LEN + + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + + CAP_INFO_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_IBSS_PARAMETER_SET) + (ELEM_HDR_LEN + (3 + MAX_LEN_TIM_PARTIAL_BMP)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < u4IeArraySize; i++) { + u2EstimatedFixedIELen = prIeArray[i].u2EstimatedFixedIELen; + + if (u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += u2EstimatedFixedIELen; + } else { + ASSERT(prIeArray[i].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += (UINT_16) + prIeArray[i].pfnCalculateVariableIELen(prAdapter, eNetTypeIndex, NULL); + } + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending %s.\n", ((!pucDestAddr) ? "Beacon" : "Probe Response")); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Beacon/Probe Response frame header and fixed fields in MSDU_INfO_T. */ + /* Compose Header and Fixed Field */ +#if CFG_ENABLE_WIFI_DIRECT + if (u4ControlFlags & BSS_PROBE_RESP_USE_P2P_DEV_ADDR) { + if (prAdapter->fgIsP2PRegistered) { + bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) + ((ULONG) (prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), pucDestAddr, + prAdapter->rWifiVar.aucDeviceAddress, + prAdapter->rWifiVar.aucDeviceAddress, + DOT11_BEACON_PERIOD_DEFAULT, + (prBssInfo->u2CapInfo & + ~(CAP_INFO_ESS | CAP_INFO_IBSS))); + } + } else +#endif /* CFG_ENABLE_WIFI_DIRECT */ + { + bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) + ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucDestAddr, prBssInfo->aucOwnMacAddr, prBssInfo->aucBSSID, + prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); + } + + /* 4 <3> Update information of MSDU_INFO_T */ + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = 0xFF; + prMsduInfo->ucNetworkType = (UINT_8) eNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = (WLAN_MAC_MGMT_HEADER_LEN + + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + + /* 4 <4> Compose the frame body's Common IEs of the Beacon/ProbeResp frame. */ + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, pucDestAddr); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ + + /* Append IE */ + for (i = 0; i < u4IeArraySize; i++) { + if (prIeArray[i].pfnAppendIE) + prIeArray[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU */ + + /* 4 <6> Inform TXM to send this Beacon /Probe Response frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + +} /* end of bssSendBeaconProbeResponse() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Probe Request Frame and then send +* back the corresponding Probe Response Frame if the specified conditions +* were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + UINT_8 aucBCBSSID[] = BC_BSSID; + BOOLEAN fgIsBcBssid; + BOOLEAN fgReplyProbeResp; + UINT_32 u4CtrlFlagsForProbeResp = 0; + ENUM_BAND_T eBand; + UINT_8 ucHwChannelNum; + + ASSERT(prSwRfb); + + /* 4 <1> Parse Probe Req and Get BSSID */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; + + if (EQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID)) + fgIsBcBssid = TRUE; + else + fgIsBcBssid = FALSE; + + /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ + for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { + + if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) + continue; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if ((!fgIsBcBssid) && UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) + continue; + + eBand = HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr); + ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); + + if (prBssInfo->eBand != eBand) + continue; + + if (prBssInfo->ucPrimaryChannel != ucHwChannelNum) + continue; + + fgReplyProbeResp = FALSE; + + if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { + +#if CFG_SUPPORT_ADHOC + fgReplyProbeResp = aisValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); +#endif + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex)) { + if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { + /* Resource margin is enough */ + fgReplyProbeResp = + p2pFuncValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); + } + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) + fgReplyProbeResp = bowValidateProbeReq(prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); +#endif + + if (fgReplyProbeResp) { + if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { + /* Resource margin is enough */ + bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr, + u4CtrlFlagsForProbeResp); + } + } + } + + return WLAN_STATUS_SUCCESS; + +} /* end of bssProcessProbeRequest() */ + +#if 0 /* NOTE(Kevin): condition check should move to P2P_FSM.c */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Probe Request Frame and then send +* back the corresponding Probe Response Frame if the specified conditions +* were matched. +* +* @param[in] prSwRfb Pointer to SW RFB data structure. +* +* @retval WLAN_STATUS_SUCCESS Always return success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + UINT_8 aucBCBSSID[] = BC_BSSID; + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + BOOLEAN fgReplyProbeResp; +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgP2PTargetDeviceFound; + UINT_8 aucP2PWildcardSSID[] = P2P_WILDCARD_SSID; +#endif + + ASSERT(prSwRfb); + + /* 4 <1> Parse Probe Req and Get SSID IE ptr */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (PUINT_8) ((UINT_32) prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + prIeSsid = (P_IE_SSID_T) NULL; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) + prIeSsid = (P_IE_SSID_T) pucIE; + break; + + case ELEM_ID_SUP_RATES: + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + /* if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SUP_RATES) { */ + if (IE_LEN(pucIE) <= RATE_NUM) + prIeSupportedRate = SUP_RATES_IE(pucIE); + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + break; + +#if CFG_ENABLE_WIFI_DIRECT + /* TODO: P2P IE & WCS IE parsing for P2P. */ + case ELEM_ID_P2P: + + break; +#endif + + /* no default */ + } + } /* end of IE_FOR_EACH */ + + /* 4 <2> Check network conditions before reply Probe Response Frame (Consider Concurrent) */ + for (eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; eNetTypeIndex < NETWORK_TYPE_INDEX_NUM; eNetTypeIndex++) { + + if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) + continue; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if (UNEQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID) && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { + /* BSSID not Wildcard BSSID. */ + continue; + } + + fgReplyProbeResp = FALSE; + + if (NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) { + + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + + /* TODO(Kevin): Check if we are IBSS Master. */ + if (TRUE && prIeSsid) { + if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + fgReplyProbeResp = TRUE; + } + } + } + } +#if CFG_ENABLE_WIFI_DIRECT + else if (NETWORK_TYPE_P2P_INDEX == eNetTypeIndex) { + + /* TODO(Kevin): Move following lines to p2p_fsm.c */ + + if ((prIeSsid) && + ((prIeSsid->ucLength == BC_SSID_LEN) || + (EQUAL_SSID(aucP2PWildcardSSID, + P2P_WILDCARD_SSID_LEN, prIeSsid->aucSSID, prIeSsid->ucLength)))) { + /* if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prMgtHdr->aucSrcAddr, + pucIE, u2IELength)) { */ + if (p2pFsmRunEventRxProbeRequestFrame(prAdapter, prSwRfb)) { + /* Extand channel request time & cancel scan request. */ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + /* TODO: RX probe request may not caused by LISTEN state. */ + /* TODO: It can be GO. */ + /* Generally speaking, cancel a non-exist scan request is fine. + * We can check P2P FSM here for only LISTEN state. + */ + + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + /* Abort JOIN process. */ + prScanCancelMsg = + (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + ASSERT(0); /* Can't abort SCN FSM */ + continue; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; + prScanCancelMsg->ucSeqNum = prP2pFsmInfo->ucSeqNumOfScnMsg; + prScanCancelMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; + prScanCancelMsg->fgIsChannelExt = TRUE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); + } + } else { + /* 1. Probe Request without SSID. + * 2. Probe Request with SSID not Wildcard SSID & not P2P Wildcard SSID. + */ + continue; + } + +#if 0 /* Frog */ + if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_LISTEN) { + /* P2P 2.4.1 - P2P Devices shall not respond to Probe Request frames + which only contain 11b rates only. */ + if (prIeSupportedRate || prIeExtSupportedRate) { + UINT_16 u2OperationalRateSet, u2BSSBasicRateSet; + BOOLEAN fgIsUnknownBssBasicRate; + + rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, + &u2OperationalRateSet, + &u2BSSBasicRateSet, /* Ignore any Basic Bit */ + &fgIsUnknownBssBasicRate); + + if (u2OperationalRateSet & ~RATE_SET_HR_DSSS) + continue; + } + } + /* TODO: Check channel time before first check point to: */ + /* If Target device is selected: + * 1. Send XXXX request frame. + * else + * 1. Send Probe Response frame. + */ + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* TODO(Kevin): During PROVISION state, can we reply Probe Response ? */ + + /* TODO(Kevin): + * If we are GO, accept legacy client --> accept Wildcard SSID + * If we are in Listen State, accept only P2P Device --> check P2P IE and WPS IE + */ + if (TRUE /* We are GO */ && prIeSsid) { + UINT_8 aucSSID[] = P2P_WILDCARD_SSID; + + if ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength) || + EQUAL_SSID(aucSSID, P2P_WILDCARD_SSID_LEN, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + fgReplyProbeResp = TRUE; + } + } +/* else if (FALSE) { */ /* We are in Listen State */ +/* } */ + + /* TODO(Kevin): Check P2P IE and WPS IE */ + } +#endif + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (NETWORK_TYPE_BOW_INDEX == eNetTypeIndex) { + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* Do nothing */ + /* TODO(Kevin): TBD */ + } + } +#endif + else + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + if (fgReplyProbeResp) + bssSendBeaconProbeResponse(prAdapter, eNetTypeIndex, prMgtHdr->aucSrcAddr); + + } + + return WLAN_STATUS_SUCCESS; + +} /* end of bssProcessProbeRequest() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to clear the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Given related BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssClearClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + P_LINK_T prStaRecOfClientList; + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prPeerStaRec; + + LINK_FOR_EACH_ENTRY(prPeerStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + cnmStaRecChangeState(prAdapter, prPeerStaRec, STA_STATE_1); + } + + LINK_INITIALIZE(prStaRecOfClientList); + } + +} /* end of bssClearClientList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to Add a STA_RECORD_T to the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Given related BSS_INFO_T. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssAddStaRecToClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) +{ + P_LINK_T prStaRecOfClientList; + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + + if (prCurrStaRec == prStaRec) { + DBGLOG(BSS, WARN, + "Current Client List already contains that STA_RECORD_T[%pM]\n", + prStaRec->aucMacAddr); + return; + } + } + } + + LINK_INSERT_TAIL(prStaRecOfClientList, &prStaRec->rLinkEntry); + +} /* end of bssAddStaRecToClientList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to Remove a STA_RECORD_T from the client list for AdHoc or AP Mode +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssRemoveStaRecFromClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec) +{ + P_LINK_T prStaRecOfClientList; + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + +#if 0 + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + + if (prCurrStaRec == prStaRec) { + + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); + + return; + } + } + } +#endif + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + if ((ULONG) prStaRec == (ULONG) prLinkEntry) { + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prStaRec->rLinkEntry); + return; + } + } + } + + DBGLOG(BSS, INFO, "Current Client List didn't contain that STA_RECORD_T[%pM] before removing.\n", + prStaRec->aucMacAddr); + +} /* end of bssRemoveStaRecFromClientList() */ +#endif /* CFG_SUPPORT_ADHOC || CFG_SUPPORT_AAA */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Get station record by Address for AP mode +* +* @param[in] prBssInfo Pointer to BSS_INFO_T. +* @param[in] pucMacAddr Pointer to target mac address +* +* @return pointer of STA_RECORD_T if found, otherwise, return NULL +*/ +/*----------------------------------------------------------------------------*/ + +P_STA_RECORD_T bssGetClientByAddress(IN P_BSS_INFO_T prBssInfo, PUINT_8 pucMacAddr) +{ + P_LINK_T prStaRecOfClientList; + + ASSERT(prBssInfo); + ASSERT(pucMacAddr); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prStaRecOfClientList, rLinkEntry, STA_RECORD_T) { + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, pucMacAddr)) + return prCurrStaRec; + } + } + return NULL; +} + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to process Beacons from current Ad-Hoc network peers. +* We also process Beacons from other Ad-Hoc network during SCAN. If it has +* the same SSID and we'll decide to merge into it if it has a larger TSF. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] prBSSDesc Pointer to the BSS Descriptor. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, IN P_BSS_DESC_T prBssDesc, IN UINT_8 ucRCPI) +{ + P_STA_RECORD_T prStaRec = NULL; + + BOOLEAN fgIsCheckCapability = FALSE; + BOOLEAN fgIsCheckTSF = FALSE; + BOOLEAN fgIsGoingMerging = FALSE; + BOOLEAN fgIsSameBSSID; + + ASSERT(prBssInfo); + ASSERT(prBssDesc); + + /* 4 <1> Process IBSS Beacon only after we create or merge with other IBSS. */ + if (!prBssInfo->fgIsBeaconActivated) + return; + /* 4 <2> Get the STA_RECORD_T of TA. */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prBssDesc->aucSrcAddr); + + fgIsSameBSSID = UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID) ? FALSE : TRUE; + + /* 4 <3> IBSS Merge Decision Flow for Processing Beacon. */ + if (fgIsSameBSSID) { + + /* Same BSSID: + * Case I. This is a new TA and it has decide to merged with us. + * a) If fgIsMerging == FALSE - we will send msg to notify AIS. + * b) If fgIsMerging == TRUE - already notify AIS. + * Case II. This is an old TA and we've already merged together. + */ + if (!prStaRec) { + + /* For Case I - Check this IBSS's capability first before adding this Sta Record. */ + fgIsCheckCapability = TRUE; + + /* If check is passed, then we perform merging with this new IBSS */ + fgIsGoingMerging = TRUE; + + } else { + + ASSERT((prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) && IS_ADHOC_STA(prStaRec)); + + if (prStaRec->ucStaState != STA_STATE_3) { + + if (!prStaRec->fgIsMerging) { + + /* For Case I - Check this IBSS's capability first + * before adding this Sta Record. */ + fgIsCheckCapability = TRUE; + + /* If check is passed, then we perform merging with this new IBSS */ + fgIsGoingMerging = TRUE; + } else { + /* For Case II - Update rExpirationTime of Sta Record */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + } + } else { + /* For Case II - Update rExpirationTime of Sta Record */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + } + + } + } else { + + /* Unequal BSSID: + * Case III. This is a new TA and we need to compare the TSF and get the winner. + * Case IV. This is an old TA and it merge into a new IBSS before we do the same thing. + * We need to compare the TSF to get the winner. + * Case V. This is an old TA and it restart a new IBSS. We also need to + * compare the TSF to get the winner. + */ + + /* For Case III, IV & V - We'll always check this new IBSS's capability first + * before merging into new IBSS. + */ + fgIsCheckCapability = TRUE; + + /* If check is passed, we need to perform TSF check to decide the major BSSID */ + fgIsCheckTSF = TRUE; + + /* For Case IV & V - We won't update rExpirationTime of Sta Record */ + } + + /* 4 <7> Check this BSS_DESC_T's capability. */ + if (fgIsCheckCapability) { + BOOLEAN fgIsCapabilityMatched = FALSE; + + do { + if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: %pM - Unsupported Phy.\n", + prBssDesc->aucSrcAddr); + + break; + } + + if (prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: %pM - Unknown Basic Rate.\n", + prBssDesc->aucSrcAddr); + + break; + } + + if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", + prBssDesc->aucSrcAddr); + + break; + } + + fgIsCapabilityMatched = TRUE; + } while (FALSE); + + if (!fgIsCapabilityMatched) { + + if (prStaRec) { + /* For Case II - We merge this STA_RECORD in RX Path. + * Case IV & V - They change their BSSID after we merge with them. + */ + + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: %pM - Capability is not matched.\n", + prBssDesc->aucSrcAddr); + } + + return; + } + + DBGLOG(BSS, LOUD, + "IBSS MERGE: Peer MAC: %pM - Check capability was passed.\n", + prBssDesc->aucSrcAddr); + } + + if (fgIsCheckTSF) { +#if CFG_SLT_SUPPORT + fgIsGoingMerging = TRUE; +#else + if (prBssDesc->fgIsLargerTSF) + fgIsGoingMerging = TRUE; + else + return; +#endif + } + + if (fgIsGoingMerging) { + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + + /* 4 <1> We will merge with to this BSS immediately. */ + prBssDesc->fgIsConnecting = TRUE; + prBssDesc->fgIsConnected = FALSE; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + STA_TYPE_ADHOC_PEER, NETWORK_TYPE_AIS_INDEX, prBssDesc); + + if (!prStaRec) { + /* no memory ? */ + return; + } + + prStaRec->fgIsMerging = TRUE; + + /* update RCPI */ + prStaRec->ucRCPI = ucRCPI; + + /* 4 <3> Send Merge Msg to CNM to obtain the channel privilege. */ + prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_IBSS_PEER_FOUND_T)); + + if (!prAisIbssPeerFoundMsg) { + + ASSERT(0); /* Can't send Merge Msg */ + return; + } + + prAisIbssPeerFoundMsg->rMsgHdr.eMsgId = MID_SCN_AIS_FOUND_IBSS; + prAisIbssPeerFoundMsg->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_AIS_INDEX; + prAisIbssPeerFoundMsg->prStaRec = prStaRec; + + /* Inform AIS to do STATE TRANSITION + * For Case I - If AIS in IBSS_ALONE, let it jump to NORMAL_TR after we know the new member. + * For Case III, IV - Now this new BSSID wins the TSF, follow it. + */ + if (fgIsSameBSSID) { + prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; + } else { +#if CFG_SLT_SUPPORT + prAisIbssPeerFoundMsg->fgIsMergeIn = TRUE; +#else + prAisIbssPeerFoundMsg->fgIsMergeIn = (prBssDesc->fgIsLargerTSF) ? FALSE : TRUE; +#endif + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisIbssPeerFoundMsg, MSG_SEND_METHOD_BUF); + + } + +} /* end of ibssProcessMatchedBeacon() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the Capability for Ad-Hoc to decide if we are +* able to merge with(same capability). +* +* @param[in] prBSSDesc Pointer to the BSS Descriptor. +* +* @retval WLAN_STATUS_FAILURE Can't pass the check of Capability. +* @retval WLAN_STATUS_SUCCESS Pass the check of Capability. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + + ASSERT(prBssDesc); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + do { + /* 4 <1> Check the BSS Basic Rate Set for current AdHoc Mode */ + if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11B) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_HR_DSSS)) { + break; + } else if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11A) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_OFDM)) { + break; + } + /* 4 <2> Check the Short Slot Time. */ +#if 0 /* Do not check ShortSlotTime until Wi-Fi define such policy */ + if (prConnSettings->eAdHocMode == AD_HOC_MODE_11G) { + if (((prConnSettings->fgIsShortSlotTimeOptionEnable) && + !(prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) || + (!(prConnSettings->fgIsShortSlotTimeOptionEnable) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))) { + break; + } + } +#endif + + /* 4 <3> Check the ATIM window setting. */ + if (prBssDesc->u2ATIMWindow) { + DBGLOG(BSS, INFO, "AdHoc PS was not supported(ATIM Window: %d)\n", prBssDesc->u2ATIMWindow); + break; + } +#if CFG_RSN_MIGRATION + /* 4 <4> Check the Security setting. */ + if (!rsnPerformPolicySelection(prAdapter, prBssDesc)) + break; +#endif + + rStatus = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rStatus; + +} /* end of ibssCheckCapabilityForAdHocMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial the BSS_INFO_T for IBSS Mode. +* +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + UINT_8 ucLowestBasicRateIndex; + UINT_8 aucBSSID[MAC_ADDR_LEN]; + PUINT_16 pu2BSSID = (PUINT_16) &aucBSSID[0]; + UINT_32 i; + + ASSERT(prBssInfo); + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_IBSS); + + /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); + + /* 4 <2> Setup BSSID */ + if (!prBssInfo->fgHoldSameBssidForIBSS) { + + for (i = 0; i < sizeof(aucBSSID) / sizeof(UINT_16); i++) + pu2BSSID[i] = (UINT_16) (kalRandomNumber() & 0xFFFF); + + aucBSSID[0] &= ~0x01; /* 7.1.3.3.3 - The individual/group bit of the address is set to 0. */ + aucBSSID[0] |= 0x02; /* 7.1.3.3.3 - The universal/local bit of the address is set to 1. */ + + COPY_MAC_ADDR(prBssInfo->aucBSSID, aucBSSID); + } + /* 4 <3> Setup Capability - Short Preamble */ + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { + prBssInfo->fgIsShortPreambleAllowed = TRUE; + prBssInfo->fgUseShortPreamble = TRUE; + } else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + + /* 4 <4> Setup Capability - Short Slot Time */ + /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ + prBssInfo->fgUseShortSlotTime = FALSE; /* Set to FALSE for AdHoc */ + + /* 4 <5> Compoase Capability */ + prBssInfo->u2CapInfo = CAP_INFO_IBSS; + + if (prBssInfo->fgIsProtection) + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + + if (prBssInfo->fgIsShortPreambleAllowed) + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + + if (prBssInfo->fgUseShortSlotTime) + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); + + prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; + +} /* end of ibssInitForAdHoc() */ + +#endif /* CFG_SUPPORT_ADHOC */ + +#if CFG_SUPPORT_AAA + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial the BSS_INFO_T for AP Mode. +* +* @param[in] prBssInfo Given related BSS_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN BOOLEAN fgIsRateUpdate) +{ + UINT_8 ucLowestBasicRateIndex; + + P_AC_QUE_PARMS_T prACQueParms; + + ENUM_WMM_ACI_T eAci; + + UINT_8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; + UINT_8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3 }; + UINT_8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; + UINT_8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ + + UINT_8 auCWminLog2[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, 2 /*VI*/ }; + UINT_8 auCWmaxLog2[WMM_AC_INDEX_NUM] = { 7, 10, 4, 3 }; + UINT_8 auAifs[WMM_AC_INDEX_NUM] = { 3, 7, 1, 1 }; + UINT_8 auTxop[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ + + DEBUGFUNC("bssInitForAP"); + DBGLOG(BSS, LOUD, "\n"); + + ASSERT(prBssInfo); + ASSERT((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || (prBssInfo->eCurrentOPMode == OP_MODE_BOW)); + +#if 0 + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = CONFIG_BW_20M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = CONFIG_BW_20M; +#endif + + /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prBssInfo->u2OperationalRateSet = rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + if (fgIsRateUpdate) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, &prBssInfo->ucAllSupportedRatesLen); + } + /* 4 <2> Setup BSSID */ + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssInfo->aucOwnMacAddr); + + /* 4 <3> Setup Capability - Short Preamble */ + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].fgIsShortPreambleOptionImplemented && + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || /* Short Preamble Option Enable is TRUE */ + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { + prBssInfo->fgIsShortPreambleAllowed = TRUE; + prBssInfo->fgUseShortPreamble = TRUE; + } else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + + /* 4 <4> Setup Capability - Short Slot Time */ + prBssInfo->fgUseShortSlotTime = TRUE; + + /* 4 <5> Compoase Capability */ + prBssInfo->u2CapInfo = CAP_INFO_ESS; + + if (prBssInfo->fgIsProtection) + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + + if (prBssInfo->fgIsShortPreambleAllowed) + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + + if (prBssInfo->fgUseShortSlotTime) + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex); + + prBssInfo->ucHwDefaultFixedRateCode = aucRateIndex2RateCode[PREAMBLE_DEFAULT_LONG_NONE][ucLowestBasicRateIndex]; + + /* 4 <7> Fill the EDCA */ + + prACQueParms = prBssInfo->arACQueParmsForBcast; + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + prACQueParms[eAci].fgIsACMSet = FALSE; + prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; + + prBssInfo->aucCWminLog2ForBcast[eAci] = auCWminLog2ForBcast[eAci]; /* used to send WMM IE */ + prBssInfo->aucCWmaxLog2ForBcast[eAci] = auCWmaxLog2ForBcast[eAci]; + + DBGLOG(BSS, INFO, "Bcast: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, prACQueParms[eAci].fgIsACMSet, + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); + + } + + prACQueParms = prBssInfo->arACQueParms; + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + prACQueParms[eAci].fgIsACMSet = FALSE; + prACQueParms[eAci].u2Aifsn = auAifs[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2[eAci]) - 1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2[eAci]) - 1; + prACQueParms[eAci].u2TxopLimit = auTxop[eAci]; + + DBGLOG(BSS, INFO, "eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, prACQueParms[eAci].fgIsACMSet, + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, prACQueParms[eAci].u2TxopLimit); + } + + /* Note: Caller should update the EDCA setting to HW by nicQmUpdateWmmParms() it there is no AIS network */ + /* Note: In E2, only 4 HW queues. The the Edca parameters should be folow by AIS network */ + /* Note: In E3, 8 HW queues. the Wmm parameters should be updated to right queues according to BSS */ + +} /* end of bssInitForAP() */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update DTIM Count +* +* @param[in] eNetTypeIndex Specify which network to update +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(eNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + + /* Setup DTIM Count for next TBTT. */ + if (prBssInfo->ucDTIMCount > 0) { + prBssInfo->ucDTIMCount--; + } else { + + ASSERT(prBssInfo->ucDTIMPeriod > 0); + + prBssInfo->ucDTIMCount = prBssInfo->ucDTIMPeriod - 1; + } + } + +} /* end of bssUpdateDTIMIE() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to set the Virtual Bitmap in TIM Information Elements +* +* @param[in] prBssInfo Pointer to the BSS_INFO_T. +* @param[in] u2AssocId The association id to set in Virtual Bitmap. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN UINT_16 u2AssocId) +{ + + ASSERT(prBssInfo); + + if (prBssInfo->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + prP2pSpecificBssInfo = &(prAdapter->rWifiVar.rP2pSpecificBssInfo); + + /* Use Association ID == 0 for BMCAST indication */ + if (u2AssocId == 0) { + + prP2pSpecificBssInfo->ucBitmapCtrl |= (UINT_8) BIT(0); + } else { + PUINT_8 pucPartialVirtualBitmap; + UINT_8 ucBitmapToSet; + + /* (u2AssocId / 8) */ + pucPartialVirtualBitmap = &prP2pSpecificBssInfo->aucPartialVirtualBitmap[(u2AssocId >> 3)]; + ucBitmapToSet = (UINT_8) BIT((u2AssocId % 8)); + + if (*pucPartialVirtualBitmap & ucBitmapToSet) { + /* The virtual bitmap has been set */ + return; + } + + *pucPartialVirtualBitmap |= ucBitmapToSet; + + /* Update u2SmallestAID and u2LargestAID */ + if ((u2AssocId < prP2pSpecificBssInfo->u2SmallestAID) || + (prP2pSpecificBssInfo->u2SmallestAID == 0)) { + prP2pSpecificBssInfo->u2SmallestAID = u2AssocId; + } + + if ((u2AssocId > prP2pSpecificBssInfo->u2LargestAID) || + (prP2pSpecificBssInfo->u2LargestAID == 0)) { + prP2pSpecificBssInfo->u2LargestAID = u2AssocId; + } + } + } + +} /* end of bssSetTIMBitmap() */ +#endif + +#endif /* CFG_SUPPORT_AAA */ + +VOID bssCreateStaRecFromAuth(IN P_ADAPTER_T prAdapter) +{ + +} + +VOID bssUpdateStaRecFromAssocReq(IN P_ADAPTER_T prAdapter) +{ + +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c new file mode 100644 index 0000000000000..39af02df2af29 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm.c @@ -0,0 +1,738 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm.c#2 +*/ + +/*! \file "cnm.c" + \brief Module of Concurrent Network Management + + Module of Concurrent Network Management +*/ + +/* +** Log: cnm.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 11 15 2011 cm.chang + * NULL + * Fix possible wrong message when P2P is unregistered + * + * 11 14 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Fix large network type index assert in FW issue. + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 01 2011 cm.chang + * [WCXRP00001077] [All Wi-Fi][Driver] Fix wrong preferred channel for AP and BOW + * Only check AIS channel for P2P and BOW + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * Extension channel of some 5G AP will not follow regulation requirement + * + * 09 30 2011 cm.chang + * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band + * . + * + * 09 01 2011 cm.chang + * [WCXRP00000937] [MT6620 Wi-Fi][Driver][FW] cnm.c line #848 assert when doing monkey test + * Print message only in Linux platform for monkey testing + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Limit AIS to fixed channel same with BOW + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Check if P2P network index is Tethering AP + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 02 17 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * When P2P registried, invoke BOW deactivate function + * + * 01 12 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Provide function to decide if BSS can be activated or not + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 10 13 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when cmd buffer is not available + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Fix wrong message ID for channel grant to requester + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set 20/40M bandwidth of AP HT OP before association process + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 21 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support TCP/UDP/IP Checksum offload feature + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add a new function to send abort message + * + * 04 27 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * BMC mac address shall be ignored in basic config command + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support change of MAC address by host command + * + * 04 16 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * adding the wpa-none for ibss beacon. + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix bug for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 25 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * use the Rx0 dor event indicate. + * + * 02 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support partial part about cmd basic configuration + * + * Dec 10 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove conditional compiling FPGA_V5 + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add function cnmFsmEventInit() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in CNM_INFO_T. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmInit(P_ADAPTER_T prAdapter) +{ + +} /* end of cnmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in CNM_INFO_T. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmUninit(P_ADAPTER_T prAdapter) +{ + +} /* end of cnmUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Before handle the message from other module, it need to obtain +* the Channel privilege from Channel Manager +* +* @param[in] prMsgHdr The message need to be handled. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_CH_REQ_T prMsgChReq; + P_CMD_CH_PRIVILEGE_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChReq = (P_MSG_CH_REQ_T) prMsgHdr; + + prCmdBody = (P_CMD_CH_PRIVILEGE_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, "ChReq: fail to get buf (net=%d, token=%d)\n", + prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(CNM, INFO, "ChReq net=%d token=%d b=%d c=%d s=%d\n", + prMsgChReq->ucNetTypeIndex, prMsgChReq->ucTokenID, + prMsgChReq->eRfBand, prMsgChReq->ucPrimaryChannel, prMsgChReq->eRfSco); + + prCmdBody->ucNetTypeIndex = prMsgChReq->ucNetTypeIndex; + prCmdBody->ucTokenID = prMsgChReq->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_REQ; /* Request */ + prCmdBody->ucPrimaryChannel = prMsgChReq->ucPrimaryChannel; + prCmdBody->ucRfSco = (UINT_8) prMsgChReq->eRfSco; + prCmdBody->ucRfBand = (UINT_8) prMsgChReq->eRfBand; + prCmdBody->ucReqType = (UINT_8) prMsgChReq->eReqType; + prCmdBody->ucReserved = 0; + prCmdBody->u4MaxInterval = prMsgChReq->u4MaxInterval; + COPY_MAC_ADDR(prCmdBody->aucBSSID, prMsgChReq->aucBSSID); + + ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) + DBGLOG(CNM, ERROR, "CNM: ChReq with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); + +} /* end of cnmChMngrRequestPrivilege() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Before deliver the message to other module, it need to release +* the Channel privilege to Channel Manager. +* +* @param[in] prMsgHdr The message need to be delivered +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_CH_ABORT_T prMsgChAbort; + P_CMD_CH_PRIVILEGE_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChAbort = (P_MSG_CH_ABORT_T) prMsgHdr; + + prCmdBody = (P_CMD_CH_PRIVILEGE_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, "ChAbort: fail to get buf (net=%d, token=%d)\n", + prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(CNM, INFO, "ChAbort net=%d token=%d\n", prMsgChAbort->ucNetTypeIndex, prMsgChAbort->ucTokenID); + + prCmdBody->ucNetTypeIndex = prMsgChAbort->ucNetTypeIndex; + prCmdBody->ucTokenID = prMsgChAbort->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_ABORT; /* Abort */ + + ASSERT(prCmdBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) + DBGLOG(CNM, ERROR, "CNM: ChAbort with wrong netIdx=%d\n\n", prCmdBody->ucNetTypeIndex); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); + +} /* end of cnmChMngrAbortPrivilege() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent) +{ + P_EVENT_CH_PRIVILEGE_T prEventBody; + P_MSG_CH_GRANT_T prChResp; + + ASSERT(prAdapter); + ASSERT(prEvent); + + prEventBody = (P_EVENT_CH_PRIVILEGE_T) (prEvent->aucBuffer); + prChResp = (P_MSG_CH_GRANT_T) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_GRANT_T)); + ASSERT(prChResp); + + /* To do: exception handle */ + if (!prChResp) { + DBGLOG(CNM, ERROR, "ChGrant: fail to get buf (net=%d, token=%d)\n", + prEventBody->ucNetTypeIndex, prEventBody->ucTokenID); + + return; + } + + DBGLOG(CNM, INFO, "ChGrant net=%d token=%d ch=%d sco=%d\n", + prEventBody->ucNetTypeIndex, prEventBody->ucTokenID, + prEventBody->ucPrimaryChannel, prEventBody->ucRfSco); + + ASSERT(prEventBody->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + ASSERT(prEventBody->ucStatus == EVENT_CH_STATUS_GRANT); + + /* Decide message ID based on network and response status */ + if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) + prChResp->rMsgHdr.eMsgId = MID_CNM_AIS_CH_GRANT; +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && (prEventBody->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) + prChResp->rMsgHdr.eMsgId = MID_CNM_P2P_CH_GRANT; +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (prEventBody->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) + prChResp->rMsgHdr.eMsgId = MID_CNM_BOW_CH_GRANT; +#endif + else { + cnmMemFree(prAdapter, prChResp); + return; + } + + prChResp->ucNetTypeIndex = prEventBody->ucNetTypeIndex; + prChResp->ucTokenID = prEventBody->ucTokenID; + prChResp->ucPrimaryChannel = prEventBody->ucPrimaryChannel; + prChResp->eRfSco = (ENUM_CHNL_EXT_T) prEventBody->ucRfSco; + prChResp->eRfBand = (ENUM_BAND_T) prEventBody->ucRfBand; + prChResp->eReqType = (ENUM_CH_REQ_TYPE_T) prEventBody->ucReqType; + prChResp->u4GrantInterval = prEventBody->u4GrantInterval; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prChResp, MSG_SEND_METHOD_BUF); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked for P2P or BOW networks +* +* @param (none) +* +* @return TRUE: suggest to adopt the returned preferred channel +* FALSE: No suggestion. Caller should adopt its preference +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prBand); + ASSERT(pucPrimaryChannel); + ASSERT(prBssSCO); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (RLM_NET_PARAM_VALID(prBssInfo)) { + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + *prBssSCO = prBssInfo->eBssSCO; + + return TRUE; + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: available channel is limited to return value +* FALSE: no limited +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) +{ +#if CFG_ENABLE_WIFI_DIRECT || (CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL) + P_BSS_INFO_T prBssInfo; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { + + ASSERT(prAdapter->fgIsP2PRegistered); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + + return TRUE; + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_LIMIT_AIS_CHNL + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + + return TRUE; + } +#endif + + return FALSE; +} + +#if CFG_P2P_LEGACY_COEX_REVISE +BOOLEAN cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + P_BSS_INFO_T prP2PBssInfo = &prWifiVar->arBssInfo[NETWORK_TYPE_P2P_INDEX]; +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX) && + (prP2PBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || + (prP2PBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && prP2PBssInfo->eIntendOPMode == OP_MODE_NUM))) { + *prBand = prP2PBssInfo->eBand; + *pucPrimaryChannel = prP2PBssInfo->ucPrimaryChannel; +#if CFG_SUPPORT_MCC + if (nicFreq2ChannelNum(prWifiVar->rConnSettings.u4FreqInKHz * 1000) != *pucPrimaryChannel) { + DBGLOG(CNM, INFO, "p2p is running on Channel %d, but supplicant try to run as MCC\n", + *pucPrimaryChannel); + return FALSE; + } +#endif + DBGLOG(CNM, INFO, "p2p is running on Channel %d, supplicant try to run as SCC\n", + *pucPrimaryChannel); + return TRUE; + } +#endif + return FALSE; +} +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmAisInfraConnectNotify(P_ADAPTER_T prAdapter) +{ +#if CFG_ENABLE_BT_OVER_WIFI + P_BSS_INFO_T prAisBssInfo, prBowBssInfo; + + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prBowBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + if (RLM_NET_PARAM_VALID(prAisBssInfo) && RLM_NET_PARAM_VALID(prBowBssInfo)) { + if (prAisBssInfo->eBand != prBowBssInfo->eBand || + prAisBssInfo->ucPrimaryChannel != prBowBssInfo->ucPrimaryChannel) { + + /* Notify BOW to do deactivation */ + bowNotifyAllLinkDisconnected(prAdapter); + } + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) + return FALSE; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) + return FALSE; +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN cnmP2PIsPermitted(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) + return FALSE; +#if CFG_ENABLE_BT_OVER_WIFI + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_BOW_INDEX)) { + /* Notify BOW to do deactivation */ + bowNotifyAllLinkDisconnected(prAdapter); + } +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN cnmBowIsPermitted(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + if (IS_BSS_ACTIVE(prBssInfo) && prBssInfo->eCurrentOPMode == OP_MODE_IBSS) + return FALSE; +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) + return FALSE; +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param (none) +* +* @return TRUE: permitted +* FALSE: Not permitted +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 i; + P_BSS_DESC_T prBssDesc = NULL; + + /* Note: To support real-time decision instead of current activated-time, + * the STA roaming case shall be considered about synchronization + * problem. Another variable fgAssoc40mBwAllowed is added to + * represent HT capability when association + */ + for (i = 0; i < NETWORK_TYPE_INDEX_NUM; i++) { + if (i != (UINT_8) eNetTypeIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[i]; + + if (IS_BSS_ACTIVE(prBssInfo) && (prBssInfo->fg40mBwAllowed || prBssInfo->fgAssoc40mBwAllowed)) + return FALSE; + } + } + + if (eNetTypeIdx == NETWORK_TYPE_AIS_INDEX) + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + else if ((eNetTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->rWifiVar.prP2pFsmInfo)) + prBssDesc = prAdapter->rWifiVar.prP2pFsmInfo->prTargetBss; + if (prBssDesc) { +#if (CFG_FORCE_USE_20BW == 1) + if (prBssDesc->eBand == BAND_2G4) + return FALSE; +#endif + if (prBssDesc->eSco == CHNL_EXT_SCN) + return FALSE; + } + + return TRUE; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c new file mode 100644 index 0000000000000..05bd0ff35f7ac --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_mem.c @@ -0,0 +1,1236 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_mem.c#2 +*/ + +/*! \file "cnm_mem.c" + \brief This file contain the management function of packet buffers and + generic memory alloc/free functioin for mailbox message. + + A data packet has a fixed size of buffer, but a management + packet can be equipped with a variable size of buffer. +*/ + +/* +** Log: cnm_mem.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 03 14 2012 wh.su + * [WCXRP00001173] [MT6620 Wi-Fi][Driver] Adding the ICS Tethering WPA2-PSK supporting + * Add code from 2.2 + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * initialize fgNeedResp. + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 11 29 2010 cm.chang + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC + * for initial TX rate selection of auto-rate algorithm + * Sync RCPI of STA_REC to FW as reference of initial TX rate + * + * 11 25 2010 yuche.tsai + * NULL + * Update SLT Function for QoS Support and not be affected by fixed rate function. + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete + * and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 10 13 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when cmd buffer is not available + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD + * when entering RF test with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 07 07 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support state of STA record change from 1 to 1 + * + * 07 05 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Fix correct structure size in cnmStaSendDeactivateCmd() + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * spin lock target revised + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change inner loop index from i to k. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 05 31 2010 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add RX TSF Log Feature and ADDBA Rsp with DECLINE handling + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support checking of duplicated buffer free + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 28 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Move define of STA_REC_NUM to config.h and rename to CFG_STA_REC_NUM + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 28 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Modified some MQM-related data structures (SN counter, TX/RX BA table) + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Added new TX/RX BA tables in STA_REC + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Notify MQM, TXM, and RXM upon disconnection . + * + * 04 26 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Call mqm, txm, rxm functions upon disconnection + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support + * * * * * * * * * * and will send Null frame to diagnose connection + * + * 04 09 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * [BORA00000644] WiFi phase 4 integration + * * Added per-TID SN cache in STA_REC + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * move the wlan table alloc / free to change state function. + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support power control + * + * 03 03 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Initialize StaRec->arStaWaitQueue + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add debug message when no available pkt buffer + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Fixed STA_REC initialization bug: prStaRec->au2CachedSeqCtrl[k] + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsWmmSupported in STA_RECORD_T. + * + * 02 26 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added fgIsUapsdSupported in STA_RECORD_T + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * add support of Driver STA_RECORD_T activation + * + * 02 13 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added arTspecTable in STA_REC for TSPEC management + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable mgmt buffer debug by default + * + * 02 12 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Added BUFFER_SOURCE_BCN + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 cp.wu + * [BORA00000368]Integrate HIF part into BORA + * 1) separate wifi_var_emu.c/.h from wifi_var.c/.h + * * * * * * * * * 2) eliminate HIF_EMULATION code sections appeared in wifi_var/cnm_mem + * * * * * * * * * 3) use cnmMemAlloc() instead to allocate SRAM buffer + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * * * * * * MQM: BA handling + * * * * * * * TXM: Macros updates + * * * * * * * RXM: Macros/Duplicate Removal updates + * + * 12 24 2009 yarco.yang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * 12 21 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support several data buffer banks. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * .For new FPGA memory size + * + * Dec 9 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed DBGPRINT + * + * Dec 9 2009 mtk02752 + * [BORA00000368] Integrate HIF part into BORA + * add cnmDataPktFree() for emulation loopback purpose + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix warning of null pointer + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add cnmGetStaRecByAddress() and add fgIsInUse flag in STA_RECORD_T + * + * Nov 23 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Assign ucBufferSource in function cnmMgtPktAlloc() + * + * Nov 23 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added packet redispatch function calls + * + * Nov 13 2009 mtk01084 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * enable packet re-usable in current emulation driver + * + * Nov 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * 1. Add new function cnmGetStaRecByIndex() + * 2. Rename STA_REC_T to STA_RECORD_T + * + * Nov 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call cnmDataPktDispatch() in cnmPktFree() + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove definition of pragma section code + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Oct 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * + * Oct 8 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf); + +static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp); + +static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T cnmMgtPktAlloc(P_ADAPTER_T prAdapter, UINT_32 u4Length) +{ + P_MSDU_INFO_T prMsduInfo; + P_QUE_T prQueList; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + /* Get a free MSDU_INFO_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(prQueList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if (prMsduInfo) { + prMsduInfo->prPacket = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + prMsduInfo->eSrc = TX_PACKET_MGMT; + + if (prMsduInfo->prPacket == NULL) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = NULL; + } + if (prMsduInfo) { + prMsduInfo->eCmdType = COMMAND_TYPE_NUM; + prMsduInfo->ucCID = 0xff; + prMsduInfo->u4InqueTime = 0; + prMsduInfo->ucPacketType = TX_PACKET_NUM; + } + } else { + P_QUE_T prTxingQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; + P_TX_TCQ_STATUS_T pTc = (P_TX_TCQ_STATUS_T) NULL; + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + pTc = &(prAdapter->rTxCtrl.rTc); + + DBGLOG(MEM, LOUD, "++dump TxPendingMsdu=%u, Tc0=%d Tc1=%d Tc2=%d Tc3=%d, Tc4=%d Tc5=%d\n", + prTxingQue->u4NumElem, pTc->aucFreeBufferCount[TC0_INDEX], + pTc->aucFreeBufferCount[TC1_INDEX], pTc->aucFreeBufferCount[TC2_INDEX], + pTc->aucFreeBufferCount[TC3_INDEX], pTc->aucFreeBufferCount[TC4_INDEX], + pTc->aucFreeBufferCount[TC5_INDEX]); + + prQueueEntry = QUEUE_GET_HEAD(prTxingQue); + + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; + + DBGLOG(MEM, LOUD, + "msdu type=%u, ucid=%u, type=%d, time=%u, seq=%u, sta=%u\n", + prMsduInfo->ucPacketType, + prMsduInfo->ucCID, + prMsduInfo->eCmdType, + prMsduInfo->u4InqueTime, prMsduInfo->ucTxSeqNum, prMsduInfo->ucStaRecIndex); + prQueueEntry = QUEUE_GET_NEXT_ENTRY(prQueueEntry); + } + DBGLOG(MEM, LOUD, "--end dump\n"); + } + +#if DBG + if (prMsduInfo == NULL) { + DBGLOG(MEM, WARN, "MgtDesc#=%u\n", prQueList->u4NumElem); + +#if CFG_DBG_MGT_BUF + DBGLOG(MEM, WARN, "rMgtBufInfo: alloc#=%u, free#=%u, null#=%u\n", + prAdapter->rMgtBufInfo.u4AllocCount, + prAdapter->rMgtBufInfo.u4FreeCount, prAdapter->rMgtBufInfo.u4AllocNullCount); +#endif + + DBGLOG(MEM, WARN, "\n"); + } +#endif + + return prMsduInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmMgtPktFree(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_QUE_T prQueList; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + ASSERT(prMsduInfo->prPacket); + if (prMsduInfo->prPacket) { + cnmMemFree(prAdapter, prMsduInfo->prPacket); + prMsduInfo->prPacket = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo->fgIsBasicRate = FALSE; + QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry) + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to initial the MGMT/MSG memory pool. +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmMemInit(P_ADAPTER_T prAdapter) +{ + P_BUF_INFO_T prBufInfo; + + /* Initialize Management buffer pool */ + prBufInfo = &prAdapter->rMgtBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMgtBufInfo)); + prBufInfo->pucBuf = prAdapter->pucMgtBufCached; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + /* Initialize Message buffer pool */ + prBufInfo = &prAdapter->rMsgBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMsgBufInfo)); + prBufInfo->pucBuf = &prAdapter->aucMsgBuf[0]; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = (BUF_BITMAP) BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + return; + +} /* end of cnmMemInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate MGMT/MSG memory pool. +* +* \param[in] eRamType Target RAM type. +* TCM blk_sz= 16bytes, BUF blk_sz= 256bytes +* \param[in] u4Length Length of the buffer to allocate. +* +* \retval !NULL Pointer to the start address of allocated memory. +* \retval NULL Fail to allocat memory +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 u4MemAllocCnt = 0, u4MemFreeCnt = 0; +PVOID cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, IN UINT_32 u4Length) +{ + P_BUF_INFO_T prBufInfo; + BUF_BITMAP rRequiredBitmap; + UINT_32 u4BlockNum; + UINT_32 i, u4BlkSzInPower; + PVOID pvMemory; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(u4Length); + + u4MemAllocCnt++; + + if (eRamType == RAM_TYPE_MSG && u4Length <= 256) { + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlkSzInPower = MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4Length += (MSG_BUF_BLOCK_SIZE - 1); + u4BlockNum = u4Length >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } else { + eRamType = RAM_TYPE_BUF; + + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlkSzInPower = MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4Length += (MGT_BUF_BLOCK_SIZE - 1); + u4BlockNum = u4Length >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocCount++; +#endif + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + if ((u4BlockNum > 0) && (u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS)) { + + /* Convert number of block into bit cluster */ + rRequiredBitmap = BITS(0, u4BlockNum - 1); + + for (i = 0; i <= (MAX_NUM_OF_BUF_BLOCKS - u4BlockNum); i++) { + + /* Have available memory blocks */ + if ((prBufInfo->rFreeBlocksBitmap & rRequiredBitmap) + == rRequiredBitmap) { + + /* Clear corresponding bits of allocated memory blocks */ + prBufInfo->rFreeBlocksBitmap &= ~rRequiredBitmap; + + /* Store how many blocks be allocated */ + prBufInfo->aucAllocatedBlockNum[i] = (UINT_8) u4BlockNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, + eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + /* Return the start address of allocated memory */ + return (PVOID) (prBufInfo->pucBuf + (i << u4BlkSzInPower)); + + } + + rRequiredBitmap <<= 1; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + /* cannot move the allocation between spin_lock_irqsave and spin_unlock_irqrestore */ +#ifdef LINUX + pvMemory = (PVOID) kalMemAlloc(u4Length, VIR_MEM_TYPE); + if (pvMemory) + kalMemZero(pvMemory, u4Length); +#else + pvMemory = (PVOID) NULL; +#endif + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocNullCount++; + + if (pvMemory) + prAdapter->u4MemAllocDynamicCount++; +#endif + + KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + return pvMemory; + +} /* end of cnmMemAlloc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release memory to MGT/MSG memory pool. +* +* \param pucMemory Start address of previous allocated memory +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmMemFree(IN P_ADAPTER_T prAdapter, IN PVOID pvMemory) +{ + P_BUF_INFO_T prBufInfo; + UINT_32 u4BlockIndex; + BUF_BITMAP rAllocatedBlocksBitmap; + ENUM_RAM_TYPE_T eRamType; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(pvMemory); + if (!pvMemory) + return; + + u4MemFreeCnt++; + + /* Judge it belongs to which RAM type */ + if (((ULONG) pvMemory >= (ULONG)&prAdapter->aucMsgBuf[0]) && + ((ULONG) pvMemory <= (ULONG)&prAdapter->aucMsgBuf[MSG_BUFFER_SIZE - 1])) { + + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) + >> MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_MSG; + } else if (((ULONG) pvMemory >= (ULONG) prAdapter->pucMgtBufCached) && + ((ULONG) pvMemory <= ((ULONG) prAdapter->pucMgtBufCached + MGT_BUFFER_SIZE - 1))) { + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlockIndex = ((ULONG) pvMemory - (ULONG) prBufInfo->pucBuf) + >> MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_BUF; + } else { +#ifdef LINUX + /* For Linux, it is supported because size is not needed */ + kalMemFree(pvMemory, VIR_MEM_TYPE, 0); +#else + /* For Windows, it is not supported because of no size argument */ + ASSERT(0); +#endif + +#if CFG_DBG_MGT_BUF + prAdapter->u4MemFreeDynamicCount++; +#endif + return; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + +#if CFG_DBG_MGT_BUF + prBufInfo->u4FreeCount++; +#endif + + /* Convert number of block into bit cluster */ + ASSERT(prBufInfo->aucAllocatedBlockNum[u4BlockIndex] > 0); + + rAllocatedBlocksBitmap = BITS(0, prBufInfo->aucAllocatedBlockNum[u4BlockIndex] - 1); + rAllocatedBlocksBitmap <<= u4BlockIndex; + + /* Clear saved block count for this memory segment */ + prBufInfo->aucAllocatedBlockNum[u4BlockIndex] = 0; + + /* Set corresponding bit of released memory block */ + prBufInfo->rFreeBlocksBitmap |= rAllocatedBlocksBitmap; + + KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? SPIN_LOCK_MSG_BUF : SPIN_LOCK_MGT_BUF); + + return; + +} /* end of cnmMemFree() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaRecInit(P_ADAPTER_T prAdapter) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + prStaRec->ucIndex = (UINT_8) i; + prStaRec->fgIsInUse = FALSE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaRecUninit(IN P_ADAPTER_T prAdapter) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse) + cnmStaRecFree(prAdapter, prStaRec, FALSE); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmStaRecAlloc(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i, k; + + ASSERT(prAdapter); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (!prStaRec->fgIsInUse) { + /*---- Initialize STA_REC_T here ----*/ + kalMemZero(prStaRec, sizeof(STA_RECORD_T)); + prStaRec->ucIndex = (UINT_8) i; + prStaRec->ucNetTypeIndex = ucNetTypeIndex; + prStaRec->fgIsInUse = TRUE; + + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + prStaRec->u2AssocReqIeLen = 0; + } + + /* Initialize the SN caches for duplicate detection */ + for (k = 0; k < TID_NUM + 1; k++) + prStaRec->au2CachedSeqCtrl[k] = 0xFFFF; + + /* Initialize SW TX queues in STA_REC */ + for (k = 0; k < STA_WAIT_QUEUE_NUM; k++) + LINK_INITIALIZE(&prStaRec->arStaWaitQueue[k]); + + /* Default enable TX/RX AMPDU */ + prStaRec->fgTxAmpduEn = TRUE; + prStaRec->fgRxAmpduEn = TRUE; + +#if CFG_ENABLE_PER_STA_STATISTICS && CFG_ENABLE_PKT_LIFETIME_PROFILE + prStaRec->u4TotalTxPktsNumber = 0; + prStaRec->u4TotalTxPktsTime = 0; + prStaRec->u4MaxTxPktsTime = 0; +#endif + + for (k = 0; k < NUM_OF_PER_STA_TX_QUEUES; k++) + QUEUE_INITIALIZE(&prStaRec->arTxQueue[k]); + + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaRecFree(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgSyncToChip) +{ + ASSERT(prAdapter); + ASSERT(prStaRec); + + /* To do: free related resources, e.g. timers, buffers, etc */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + prStaRec->fgTransmitKeyExist = FALSE; + prStaRec->fgSetPwrMgtBit = FALSE; + + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + prStaRec->u2AssocReqIeLen = 0; + } + + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); + + if (fgSyncToChip) + cnmStaSendRemoveCmd(prAdapter, prStaRec); + + prStaRec->fgIsInUse = FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaFreeAllStaByNetType(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, BOOLEAN fgSyncToChip) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex) + cnmStaRecFree(prAdapter, prStaRec, fgSyncToChip); + } /* end of for loop */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetStaRecByIndex(P_ADAPTER_T prAdapter, UINT_8 ucIndex) +{ + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + + prStaRec = (ucIndex < CFG_STA_REC_NUM) ? &prAdapter->arStaRec[ucIndex] : NULL; + + if (prStaRec && prStaRec->fgIsInUse == FALSE) + prStaRec = NULL; + + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). +* +* @param[in] pucPeerMacAddr Given Peer MAC Address. +* +* @retval Pointer to STA_RECORD_T, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetStaRecByAddress(P_ADAPTER_T prAdapter, UINT_8 ucNetTypeIndex, PUINT_8 pucPeerMacAddr) +{ + P_STA_RECORD_T prStaRec; + UINT_16 i; + + ASSERT(prAdapter); + ASSERT(pucPeerMacAddr); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && + prStaRec->ucNetTypeIndex == ucNetTypeIndex && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Reset the Status and Reason Code Field to 0 of all Station Records for +* the specified Network Type +* +* @param[in] eNetType Specify Network Type +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaRecResetStatus(P_ADAPTER_T prAdapter, ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + cnmStaFreeAllStaByNetType(prAdapter, eNetTypeIndex, FALSE); + +#if 0 + P_STA_RECORD_T prStaRec; + UINT_16 i; + + ASSERT(prAdapter); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse) { + if ((NETWORK_TYPE_AIS_INDEX == eNetTypeIndex) && IS_STA_IN_AIS(prStaRec->eStaType)) { + + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->u2ReasonCode = REASON_CODE_RESERVED; + prStaRec->ucJoinFailureCount = 0; + prStaRec->fgTransmitKeyExist = FALSE; + + prStaRec->fgSetPwrMgtBit = FALSE; + } + + /* TODO(Kevin): For P2P and BOW */ + } + } + + return; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will change the ucStaState of STA_RECORD_T and also do +* event indication to HOST to sync the STA_RECORD_T in driver. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] u4NewState New STATE to change. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmStaRecChangeState(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, UINT_8 ucNewState) +{ + BOOLEAN fgNeedResp; + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prStaRec->fgIsInUse); + + /* Do nothing when following state transitions happen, + * other 6 conditions should be sync to FW, including 1-->1, 3-->3 + */ + if ((ucNewState == STA_STATE_2 && prStaRec->ucStaState != STA_STATE_3) || + (ucNewState == STA_STATE_1 && prStaRec->ucStaState == STA_STATE_2)) { + prStaRec->ucStaState = ucNewState; + return; + } + + fgNeedResp = FALSE; + if (ucNewState == STA_STATE_3) { + secFsmEventStart(prAdapter, prStaRec); + if (ucNewState != prStaRec->ucStaState) + fgNeedResp = TRUE; + } else { + if (ucNewState != prStaRec->ucStaState && prStaRec->ucStaState == STA_STATE_3) + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); + fgNeedResp = FALSE; + } + prStaRec->ucStaState = ucNewState; + + cnmStaSendUpdateCmd(prAdapter, prStaRec, fgNeedResp); + +#if CFG_ENABLE_WIFI_DIRECT + /* To do: Confirm if it is invoked here or other location, but it should + * be invoked after state sync of STA_REC + * Update system operation parameters for AP mode + */ + if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { + P_BSS_INFO_T prBssInfo; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) + rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); + } +#endif +} + +P_STA_RECORD_T +cnmStaTheTypeGet(P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, ENUM_STA_TYPE_T eStaType, UINT32 *pu4StartIdx) +{ + P_STA_RECORD_T prStaRec = NULL; + UINT_16 i; + + for (i = *pu4StartIdx; i < CFG_STA_REC_NUM; i++) { + prStaRec = (P_STA_RECORD_T) &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && + prStaRec->ucNetTypeIndex == (UINT_8) eNetTypeIndex && prStaRec->eStaType == eStaType) { + i++; + break; + } + + prStaRec = NULL; /* reset */ + } /* end of for loop */ + + *pu4StartIdx = i; + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, P_CMD_INFO_T prCmdInfo, PUINT_8 pucEventBuf) +{ + P_EVENT_ACTIVATE_STA_REC_T prEventContent; + P_STA_RECORD_T prStaRec; + + prEventContent = (P_EVENT_ACTIVATE_STA_REC_T) pucEventBuf; + prStaRec = cnmGetStaRecByIndex(prAdapter, prEventContent->ucStaRecIdx); + + if (prStaRec && prStaRec->ucStaState == STA_STATE_3 && + !kalMemCmp(&prStaRec->aucMacAddr[0], &prEventContent->aucMacAddr[0], MAC_ADDR_LEN)) { + + qmActivateStaRec(prAdapter, prStaRec); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, BOOLEAN fgNeedResp) +{ + P_CMD_UPDATE_STA_RECORD_T prCmdContent; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prStaRec->fgIsInUse); + + /* To do: come out a mechanism to limit one STA_REC sync once for AP mode + * to avoid buffer empty case when many STAs are associated + * simultaneously. + */ + + /* To do: how to avoid 2 times of allocated memory. Use Stack? + * One is here, the other is in wlanSendQueryCmd() + */ + prCmdContent = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_UPDATE_STA_RECORD_T)); + ASSERT(prCmdContent); + + /* To do: exception handle */ + if (!prCmdContent) + return; + + prCmdContent->ucIndex = prStaRec->ucIndex; + prCmdContent->ucStaType = (UINT_8) prStaRec->eStaType; + kalMemCopy(&prCmdContent->aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); + prCmdContent->u2AssocId = prStaRec->u2AssocId; + prCmdContent->u2ListenInterval = prStaRec->u2ListenInterval; + prCmdContent->ucNetTypeIndex = prStaRec->ucNetTypeIndex; + + prCmdContent->ucDesiredPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + prCmdContent->u2DesiredNonHTRateSet = prStaRec->u2DesiredNonHTRateSet; + prCmdContent->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + prCmdContent->ucMcsSet = prStaRec->ucMcsSet; + prCmdContent->ucSupMcs32 = (UINT_8) prStaRec->fgSupMcs32; + prCmdContent->u2HtCapInfo = prStaRec->u2HtCapInfo; + prCmdContent->ucNeedResp = (UINT_8) fgNeedResp; + +#if !CFG_SLT_SUPPORT + if (prAdapter->rWifiVar.eRateSetting != FIXED_RATE_NONE) { + /* override rate configuration */ + nicUpdateRateParams(prAdapter, + prAdapter->rWifiVar.eRateSetting, + &(prCmdContent->ucDesiredPhyTypeSet), + &(prCmdContent->u2DesiredNonHTRateSet), + &(prCmdContent->u2BSSBasicRateSet), + &(prCmdContent->ucMcsSet), + &(prCmdContent->ucSupMcs32), &(prCmdContent->u2HtCapInfo)); + } +#endif + + prCmdContent->ucIsQoS = prStaRec->fgIsQoS; + prCmdContent->ucIsUapsdSupported = prStaRec->fgIsUapsdSupported; + prCmdContent->ucStaState = prStaRec->ucStaState; + + prCmdContent->ucAmpduParam = prStaRec->ucAmpduParam; + prCmdContent->u2HtExtendedCap = prStaRec->u2HtExtendedCap; + prCmdContent->u4TxBeamformingCap = prStaRec->u4TxBeamformingCap; + prCmdContent->ucAselCap = prStaRec->ucAselCap; + prCmdContent->ucRCPI = prStaRec->ucRCPI; + + prCmdContent->ucUapsdAc = prStaRec->ucBmpTriggerAC | (prStaRec->ucBmpDeliveryAC << 4); + prCmdContent->ucUapsdSp = prStaRec->ucUapsdSp; + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_UPDATE_STA_RECORD, /* ucCID */ + TRUE, /* fgSetQuery */ + fgNeedResp, /* fgNeedResp */ + FALSE, /* fgIsOid */ + fgNeedResp ? cnmStaRecHandleEventPkt : NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_UPDATE_STA_RECORD_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdContent); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + CMD_REMOVE_STA_RECORD_T rCmdContent; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + rCmdContent.ucIndex = prStaRec->ucIndex; + kalMemCopy(&rCmdContent.aucMacAddr[0], &prStaRec->aucMacAddr[0], MAC_ADDR_LEN); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_REMOVE_STA_RECORD, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_REMOVE_STA_RECORD_T), /* u4SetQueryInfoLen */ + (PUINT_8) &rCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c new file mode 100644 index 0000000000000..8cc9ef9078fe4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/cnm_timer.c @@ -0,0 +1,482 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/cnm_timer.c#1 +*/ + +/*! \file "cnm_timer.c" + \brief + +*/ + +/* +** Log: cnm_timer.c + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation + * because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support sleep notification to host + * + * 05 19 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some checking assertions + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Return timer token back to COS when entering wait off state + * + * 01 11 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Remove compiling warning + * + * 01 08 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support longer timeout interval to 45 days from 65secu1rwduu`wvpghlqg|fh+fmdkb + * + * 01 06 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix system time is 32KHz instead of 1ms + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Place rRootTimer.rNextExpiredSysTime = rExpiredSysTime; before set timer + * + * Oct 30 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * In cnmTimerInitialize(), just stop timer if it was already created. + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Move the external reference for Lint to precomp.h + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the time to do the time out check. +* +* \param[in] rTimeout Time out interval from current time. +* +* \retval TRUE Success. +* +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN cnmTimerSetTimer(IN P_ADAPTER_T prAdapter, IN OS_SYSTIME rTimeout) +{ + P_ROOT_TIMER prRootTimer; + BOOLEAN fgNeedWakeLock; + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + kalSetTimer(prAdapter->prGlueInfo, rTimeout); + + if (rTimeout <= SEC_TO_SYSTIME(WAKE_LOCK_MAX_TIME)) { + fgNeedWakeLock = TRUE; + + if (!prRootTimer->fgWakeLocked) { + KAL_WAKE_LOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = TRUE; + } + } else { + fgNeedWakeLock = FALSE; + } + + return fgNeedWakeLock; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to initialize a root timer. +* +* \param[in] prAdapter +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerInitialize(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + /* Note: glue layer have configured timer */ + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + KAL_WAKE_LOCK_INIT(prAdapter, &prRootTimer->rWakeLock, "WLAN Timer"); + prRootTimer->fgWakeLocked = FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to destroy a root timer. +* When WIFI is off, the token shall be returned back to system. +* +* \param[in] +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerDestroy(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + if (prRootTimer->fgWakeLocked) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + KAL_WAKE_LOCK_DESTROY(prAdapter, &prRootTimer->rWakeLock); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + /* Note: glue layer will be responsible for timer destruction */ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to initialize a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* \param[in] pfnFunc Pointer to the call back function. +* \param[in] u4Data Parameter for call back function. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN PFN_MGMT_TIMEOUT_FUNC pfFunc, IN ULONG ulData) +{ + ASSERT(prAdapter); + + ASSERT(prTimer); + +#if DBG + /* Note: NULL function pointer is permitted for HEM POWER */ + if (pfFunc == NULL) + DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n"); +#endif + +#if DBG + ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); + { + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prPendingTimer; + + prTimerList = &(prAdapter->rRootTimer.rLinkHead); + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prPendingTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prPendingTimer); + ASSERT(prPendingTimer != prTimer); + } + } +#endif + + LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); + + prTimer->pfMgmtTimeOutFunc = pfFunc; + prTimer->ulData = ulData; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to stop a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN BOOLEAN fgAcquireSpinlock) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + prRootTimer = &prAdapter->rRootTimer; + + if (fgAcquireSpinlock) + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + if (timerPendingTimer(prTimer)) { + LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, &prTimer->rLinkEntry); + + /* Reduce dummy timeout for power saving, especially HIF activity. + * If two or more timers exist and being removed timer is smallest, + * this dummy timeout will still happen, but it is OK. + */ + if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { + kalCancelTimer(prAdapter->prGlueInfo); + + if (fgAcquireSpinlock && prRootTimer->fgWakeLocked) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + } + } + + if (fgAcquireSpinlock) + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to stop a timer. +* +* \param[in] prTimer Pointer to a timer structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer) +{ + ASSERT(prAdapter); + ASSERT(prTimer); + + cnmTimerStopTimer_impl(prAdapter, prTimer, TRUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to start a timer with wake_lock. +* +* \param[in] prTimer Pointer to a timer structure. +* \param[in] u4TimeoutMs Timeout to issue the timer and call back function +* (unit: ms). +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, IN UINT_32 u4TimeoutMs) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + OS_SYSTIME rExpiredSysTime, rTimeoutSystime; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList = &prRootTimer->rLinkHead; + + /* If timeout interval is larger than 1 minute, the mod value is set + * to the timeout value first, then per minutue. + */ + if (u4TimeoutMs > MSEC_PER_MIN) { + ASSERT(u4TimeoutMs <= ((UINT_32) 0xFFFF * MSEC_PER_MIN)); + + prTimer->u2Minutes = (UINT_16) (u4TimeoutMs / MSEC_PER_MIN); + u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN); + if (u4TimeoutMs == 0) { + u4TimeoutMs = MSEC_PER_MIN; + prTimer->u2Minutes--; + } + } else { + prTimer->u2Minutes = 0; + } + + /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */ + ASSERT(u4TimeoutMs < (((UINT_32) 0x80000000 - MSEC_PER_SEC) / KAL_HZ)); + rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs); + rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime; + + /* If no timer pending or the fast time interval is used. */ + if (LINK_IS_EMPTY(prTimerList) || TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { + + prRootTimer->rNextExpiredSysTime = rExpiredSysTime; + cnmTimerSetTimer(prAdapter, rTimeoutSystime); + } + + /* Add this timer to checking list */ + prTimer->rExpiredSysTime = rExpiredSysTime; + + if (!timerPendingTimer(prTimer)) + LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routines is called to check the timer list. +* +* \param[in] +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prTimer; + OS_SYSTIME rCurSysTime; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; + ULONG ulTimeoutData; + BOOLEAN fgNeedWakeLock; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + /* acquire spin lock */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList = &prRootTimer->rLinkHead; + + rCurSysTime = kalGetTimeTick(); + + /* Set the permitted max timeout value for new one */ + prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prTimer); + + /* Check if this entry is timeout. */ + if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { + cnmTimerStopTimer_impl(prAdapter, prTimer, FALSE); + + pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; + ulTimeoutData = prTimer->ulData; + + if (prTimer->u2Minutes > 0) { + prTimer->u2Minutes--; + prTimer->rExpiredSysTime = rCurSysTime + MSEC_TO_SYSTIME(MSEC_PER_MIN); + LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); + } else if (pfMgmtTimeOutFunc) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + (pfMgmtTimeOutFunc) (prAdapter, ulTimeoutData); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } + + /* Search entire list again because of nest del and add timers + * and current MGMT_TIMER could be volatile after stopped + */ + prLinkEntry = (P_LINK_ENTRY_T) prTimerList; + + prRootTimer->rNextExpiredSysTime = rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + } else if (TIME_BEFORE(prTimer->rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { + prRootTimer->rNextExpiredSysTime = prTimer->rExpiredSysTime; + } + } /* end of for loop */ + + /* Setup the prNext timeout event. It is possible the timer was already + * set in the above timeout callback function. + */ + fgNeedWakeLock = FALSE; + if (!LINK_IS_EMPTY(prTimerList)) { + ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, rCurSysTime)); + + fgNeedWakeLock = cnmTimerSetTimer(prAdapter, (OS_SYSTIME) + ((INT_32) prRootTimer->rNextExpiredSysTime - (INT_32) rCurSysTime)); + } + + if (prRootTimer->fgWakeLocked && !fgNeedWakeLock) { + KAL_WAKE_UNLOCK(prAdapter, &prRootTimer->rWakeLock); + prRootTimer->fgWakeLocked = FALSE; + } + + /* release spin lock */ + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c new file mode 100644 index 0000000000000..c7a23eb018b63 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hem_mbox.c @@ -0,0 +1,816 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/hem_mbox.c#3 +*/ + +/*! \file "hem_mbox.c" + \brief + +*/ + +/* +** Log: hem_mbox.c +** +** 08 31 2012 yuche.tsai +** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device +** have connected to AP previously,one device reboots automatically with KE +** Fix possible KE when concurrent & disconnect. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 05 03 2012 cp.wu + * [WCXRP00001231] [MT6620 Wi-Fi][MT5931][Driver] Correct SCAN_V2 related debugging facilities within hem_mbox.c + * correct for debug message string table by adding missed scan_v2 related definitions. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 17 2012 yuche.tsai + * NULL + * Update mgmt frame filter setting. + * Please also update FW 2.1 + * + * 01 13 2012 yuche.tsai + * NULL + * WiFi Hot Spot Tethering for ICS ALPHA testing version. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 15 2011 cm.chang + * NULL + * Add exception handle for NULL function pointer of mailbox message + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search + * for more than one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support + * as well as uProbeDelay in NDIS 6.x driver model + * + * 06 07 2011 yuche.tsai + * [WCXRP00000696] [Volunteer Patch][MT6620][Driver] Infinite loop issue when RX invitation response. + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Add invitation support. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation + * because NdisMSleep() won't sleep long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update bowString and channel grant. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 12 08 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support concurrent networks. + * + * 11 08 2010 cm.chang + * [WCXRP00000169] [MT6620 Wi-Fi][Driver][FW] Remove unused CNM recover message ID + * Remove CNM channel reover message ID + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 16 2010 cm.chang + * NULL + * Remove unused message ID + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 26 2010 yuche.tsai + * NULL + * Add P2P Connection Abort Event Message handler. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 yarco.yang + * NULL + * Fixed Driver ASSERT at mboxInitMsgMap() + * + * 08 24 2010 chinghwa.yu + * NULL + * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. + * Update saa_fsm for BOW. + * + * 08 23 2010 chinghwa.yu + * NULL + * Add CFG_ENABLE_BT_OVER_WIFI. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 16 2010 yuche.tsai + * NULL + * Add debug message for newly add P2P message. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some function entry for P2P FSM under provisioning phase.. + * + * 08 11 2010 yuche.tsai + * NULL + * Add some events to P2P Module. + * + * 08 05 2010 yuche.tsai + * NULL + * Add message box event for P2P device switch on & device discovery. + * + * 08 04 2010 cp.wu + * NULL + * remove unused mailbox message definitions. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * message table should not be commented out by compilation option without modifying header file + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 yuche.tsai + * + * Add wifi direct scan done callback. + * + * 07 09 2010 cp.wu + * + * change handler of MID_MNY_CNM_CONNECTION_ABORT from NULL to mboxDummy. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Rename MID_MNY_CNM_CH_RELEASE to MID_MNY_CNM_CH_ABORT + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Modify CNM message handler for new flow + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable currently migrated message call-backs. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * restore utility function invoking via hem_mbox to direct calls + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add buildable & linkable ais_fsm.c + * + * related reference are still waiting to be resolved + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * hem_mbox is migrated. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add hem_mbox.c and cnm_mem.h (but disabled some feature) for further migration + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Fix file merge error + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_QOS_ACTION_FRAME + * + * 04 29 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * Removed MID_RXM_MQM_BA_ACTION_FRAME + * + * 04 27 2010 tehuang.liu + * [BORA00000605][WIFISYS] Phase3 Integration + * MID_RXM_MQM_BA_ACTION_FRAME + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Develop partial DPD code + * + * 02 11 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Updated arMsgMapTable for MID_RXM_MQM_QOS_ACTION_FRAME + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * Dec 9 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add hemRunEventScanDone() to arMsgMapTable[] + * + * Dec 4 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix mboxDummy() didn't free prMsgHdr + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add saaAisJoinComplete event handler + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Fixed the handler function name in arMsgMapTable for MID_RXM_MQM_BA_ACTION_FRAME + * + * Dec 2 2009 MTK02468 + * [BORA00000337] To check in codes for FPGA emulation + * Added MID_RXM_MQM_BA_ACTION_FRAME to MsgMapTable + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MSG Handler (remove dummy and add for SAA) + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add aisFsmRunEventAbort() event handler + * + * Nov 11 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Nov 10 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add more MSG_HNDL_ENTRY_T to avoid ASSERT() in mboxInitMsgMap() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add SCN message and function entry to arMsgMapTable[] + * + * Nov 2 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix sorting algorithm in mboxInitMsgMap() + * + * Oct 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugMsg[] = { + (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_REQ"), + (PUINT_8) DISP_STRING("MID_MNY_CNM_CH_ABORT"), + (PUINT_8) DISP_STRING("MID_CNM_AIS_CH_GRANT"), + (PUINT_8) DISP_STRING("MID_CNM_P2P_CH_GRANT"), + (PUINT_8) DISP_STRING("MID_CNM_BOW_CH_GRANT"), + + (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ"), + (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_REQ_V2"), + (PUINT_8) DISP_STRING("MID_AIS_SCN_SCAN_CANCEL"), + (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ"), + (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_REQ_V2"), + (PUINT_8) DISP_STRING("MID_P2P_SCN_SCAN_CANCEL"), + (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ"), + (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_REQ_V2"), + (PUINT_8) DISP_STRING("MID_BOW_SCN_SCAN_CANCEL"), + (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ"), + (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_REQ_V2"), + (PUINT_8) DISP_STRING("MID_RLM_SCN_SCAN_CANCEL"), + (PUINT_8) DISP_STRING("MID_SCN_AIS_SCAN_DONE"), + (PUINT_8) DISP_STRING("MID_SCN_P2P_SCAN_DONE"), + (PUINT_8) DISP_STRING("MID_SCN_BOW_SCAN_DONE"), + (PUINT_8) DISP_STRING("MID_SCN_RLM_SCAN_DONE"), + + (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_JOIN_REQ"), + (PUINT_8) DISP_STRING("MID_OID_AIS_FSM_ABORT"), + (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_START"), + (PUINT_8) DISP_STRING("MID_AIS_SAA_FSM_ABORT"), + (PUINT_8) DISP_STRING("MID_SAA_AIS_JOIN_COMPLETE"), + +#if CFG_ENABLE_BT_OVER_WIFI + (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_START"), + (PUINT_8) DISP_STRING("MID_BOW_SAA_FSM_ABORT"), + (PUINT_8) DISP_STRING("MID_SAA_BOW_JOIN_COMPLETE"), +#endif + +#if CFG_ENABLE_WIFI_DIRECT + (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_START"), + (PUINT_8) DISP_STRING("MID_P2P_SAA_FSM_ABORT"), + (PUINT_8) DISP_STRING("MID_SAA_P2P_JOIN_COMPLETE"), + + (PUINT_8) DISP_STRING("MID_MNY_P2P_FUN_SWITCH"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_DEVICE_DISCOVERY"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_REQ"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_CONNECTION_ABORT"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_BEACON_UPDATE"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_STOP_AP"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_REQ"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_CHNL_ABORT"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_TX"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_GROUP_DISSOLVE"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_MGMT_FRAME_REGISTER"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_NET_DEV_REGISTER"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_START_AP"), + (PUINT_8) DISP_STRING("MID_MNY_P2P_UPDATE_IE_BUF"), +#endif + +#if CFG_SUPPORT_ADHOC + /* (PUINT_8)DISP_STRING("MID_AIS_CNM_CREATE_IBSS_REQ"), */ + /* (PUINT_8)DISP_STRING("MID_CNM_AIS_CREATE_IBSS_GRANT"), */ + /* (PUINT_8)DISP_STRING("MID_AIS_CNM_MERGE_IBSS_REQ"), */ + /* (PUINT_8)DISP_STRING("MID_CNM_AIS_MERGE_IBSS_GRANT"), */ + (PUINT_8) DISP_STRING("MID_SCN_AIS_FOUND_IBSS"), +#endif /* CFG_SUPPORT_ADHOC */ + + (PUINT_8) DISP_STRING("MID_SAA_AIS_FSM_ABORT"), + (PUINT_8) DISP_STRING("MID_MNY_AIS_REMAIN_ON_CHANNEL"), + (PUINT_8) DISP_STRING("MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL"), + (PUINT_8) DISP_STRING("MID_MNY_AIS_MGMT_TX") +}; + +/*lint -restore */ +#endif /* DBG */ + +/* This message entry will be re-ordered based on the message ID order + * by invoking mboxInitMsgMap() + */ +static MSG_HNDL_ENTRY_T arMsgMapTable[] = { + {MID_MNY_CNM_CH_REQ, cnmChMngrRequestPrivilege}, + {MID_MNY_CNM_CH_ABORT, cnmChMngrAbortPrivilege}, + {MID_CNM_AIS_CH_GRANT, aisFsmRunEventChGrant}, +#if CFG_ENABLE_WIFI_DIRECT + {MID_CNM_P2P_CH_GRANT, p2pFsmRunEventChGrant}, /*set in gl_p2p_init.c */ +#else + {MID_CNM_P2P_CH_GRANT, mboxDummy}, +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + {MID_CNM_BOW_CH_GRANT, bowRunEventChGrant}, +#else + {MID_CNM_BOW_CH_GRANT, mboxDummy}, +#endif + + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + {MID_AIS_SCN_SCAN_REQ, scnFsmMsgStart}, + {MID_AIS_SCN_SCAN_REQ_V2, scnFsmMsgStart}, + {MID_AIS_SCN_SCAN_CANCEL, scnFsmMsgAbort}, + {MID_P2P_SCN_SCAN_REQ, scnFsmMsgStart}, + {MID_P2P_SCN_SCAN_REQ_V2, scnFsmMsgStart}, + {MID_P2P_SCN_SCAN_CANCEL, scnFsmMsgAbort}, + {MID_BOW_SCN_SCAN_REQ, scnFsmMsgStart}, + {MID_BOW_SCN_SCAN_REQ_V2, scnFsmMsgStart}, + {MID_BOW_SCN_SCAN_CANCEL, scnFsmMsgAbort}, + {MID_RLM_SCN_SCAN_REQ, scnFsmMsgStart}, + {MID_RLM_SCN_SCAN_REQ_V2, scnFsmMsgStart}, + {MID_RLM_SCN_SCAN_CANCEL, scnFsmMsgAbort}, + {MID_SCN_AIS_SCAN_DONE, aisFsmRunEventScanDone}, +#if CFG_ENABLE_WIFI_DIRECT + {MID_SCN_P2P_SCAN_DONE, p2pFsmRunEventScanDone}, /*set in gl_p2p_init.c */ +#else + {MID_SCN_P2P_SCAN_DONE, mboxDummy}, +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + {MID_SCN_BOW_SCAN_DONE, bowResponderScanDone}, +#else + {MID_SCN_BOW_SCAN_DONE, mboxDummy}, +#endif + {MID_SCN_RLM_SCAN_DONE, rlmObssScanDone}, + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + {MID_OID_AIS_FSM_JOIN_REQ, aisFsmRunEventAbort}, + {MID_OID_AIS_FSM_ABORT, aisFsmRunEventAbort}, + {MID_AIS_SAA_FSM_START, saaFsmRunEventStart}, + {MID_AIS_SAA_FSM_ABORT, saaFsmRunEventAbort}, + {MID_SAA_AIS_JOIN_COMPLETE, aisFsmRunEventJoinComplete}, + +#if CFG_ENABLE_BT_OVER_WIFI + /*--------------------------------------------------*/ + /* BOW Module Mailbox Messages */ + /*--------------------------------------------------*/ + {MID_BOW_SAA_FSM_START, saaFsmRunEventStart}, + {MID_BOW_SAA_FSM_ABORT, saaFsmRunEventAbort}, + {MID_SAA_BOW_JOIN_COMPLETE, bowFsmRunEventJoinComplete}, +#endif + +#if CFG_ENABLE_WIFI_DIRECT /*set in gl_p2p_init.c */ + {MID_P2P_SAA_FSM_START, saaFsmRunEventStart}, + {MID_P2P_SAA_FSM_ABORT, saaFsmRunEventAbort}, + {MID_SAA_P2P_JOIN_COMPLETE, p2pFsmRunEventJoinComplete}, /* TODO: p2pFsmRunEventJoinComplete */ + + {MID_MNY_P2P_FUN_SWITCH, p2pFsmRunEventSwitchOPMode}, + {MID_MNY_P2P_DEVICE_DISCOVERY, p2pFsmRunEventScanRequest}, + {MID_MNY_P2P_CONNECTION_REQ, p2pFsmRunEventConnectionRequest}, + {MID_MNY_P2P_CONNECTION_ABORT, p2pFsmRunEventConnectionAbort}, + {MID_MNY_P2P_BEACON_UPDATE, p2pFsmRunEventBeaconUpdate}, + {MID_MNY_P2P_STOP_AP, p2pFsmRunEventStopAP}, + {MID_MNY_P2P_CHNL_REQ, p2pFsmRunEventChannelRequest}, + {MID_MNY_P2P_CHNL_ABORT, p2pFsmRunEventChannelAbort}, + {MID_MNY_P2P_MGMT_TX, p2pFsmRunEventMgmtFrameTx}, + {MID_MNY_P2P_GROUP_DISSOLVE, p2pFsmRunEventDissolve}, + {MID_MNY_P2P_MGMT_FRAME_REGISTER, p2pFsmRunEventMgmtFrameRegister}, + {MID_MNY_P2P_NET_DEV_REGISTER, p2pFsmRunEventNetDeviceRegister}, + {MID_MNY_P2P_START_AP, p2pFsmRunEventStartAP}, + {MID_MNY_P2P_MGMT_FRAME_UPDATE, p2pFsmRunEventUpdateMgmtFrame}, + {MID_MNY_P2P_EXTEND_LISTEN_INTERVAL, p2pFsmRunEventExtendListen}, +#if CFG_SUPPORT_WFD + {MID_MNY_P2P_WFD_CFG_UPDATE, p2pFsmRunEventWfdSettingUpdate}, +#endif + +#endif + +#if CFG_SUPPORT_ADHOC + {MID_SCN_AIS_FOUND_IBSS, aisFsmRunEventFoundIBSSPeer}, +#endif /* CFG_SUPPORT_ADHOC */ + + {MID_SAA_AIS_FSM_ABORT, aisFsmRunEventAbort}, + {MID_MNY_AIS_REMAIN_ON_CHANNEL, aisFsmRunEventRemainOnChannel}, + {MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, aisFsmRunEventCancelRemainOnChannel}, + {MID_MNY_AIS_MGMT_TX, aisFsmRunEventMgmtFrameTx} +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if DBG +#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, "DO MSG [%d: %s]\n", prMsg->eMsgId, apucDebugMsg[prMsg->eMsgId]); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ + } \ + else { \ + DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ + cnmMemFree(prAdapter, prMsg); \ + } \ +} while (0) +#else +#define MBOX_HNDL_MSG(prAdapter, prMsg) do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, "DO MSG [%d]\n", prMsg->eMsgId); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, prMsg); \ + } \ + else { \ + DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", prMsg->eMsgId); \ + cnmMemFree(prAdapter, prMsg); \ + } \ +} while (0) +#endif +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxInitMsgMap(VOID) +{ + UINT_32 i, idx; + MSG_HNDL_ENTRY_T rTempEntry; + + ASSERT((sizeof(arMsgMapTable) / sizeof(MSG_HNDL_ENTRY_T)) == MID_TOTAL_NUM); + + for (i = 0; i < MID_TOTAL_NUM; i++) { + if (arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i) + continue; + for (idx = i + 1; idx < MID_TOTAL_NUM; idx++) { + if (arMsgMapTable[idx].eMsgId == (ENUM_MSG_ID_T) i) + break; + } + ASSERT(idx < MID_TOTAL_NUM); + if (idx >= MID_TOTAL_NUM) + continue; + + /* Swap target entry and current entry */ + rTempEntry.eMsgId = arMsgMapTable[idx].eMsgId; + rTempEntry.pfMsgHndl = arMsgMapTable[idx].pfMsgHndl; + + arMsgMapTable[idx].eMsgId = arMsgMapTable[i].eMsgId; + arMsgMapTable[idx].pfMsgHndl = arMsgMapTable[i].pfMsgHndl; + + arMsgMapTable[i].eMsgId = rTempEntry.eMsgId; + arMsgMapTable[i].pfMsgHndl = rTempEntry.pfMsgHndl; + } + + /* Verify the correctness of final message map */ + for (i = 0; i < MID_TOTAL_NUM; i++) { + ASSERT(arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T) i); + while (arMsgMapTable[i].eMsgId != (ENUM_MSG_ID_T) i) + ; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId) +{ + P_MBOX_T prMbox; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INITIALIZE(&prMbox->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mboxSendMsg(IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId, IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod) +{ + P_MBOX_T prMbox; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prMsg); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + switch (eMethod) { + case MSG_SEND_METHOD_BUF: + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INSERT_TAIL(&prMbox->rLinkHead, &prMsg->rLinkEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + /* to wake up main service thread */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + break; + + case MSG_SEND_METHOD_UNBUF: + MBOX_HNDL_MSG(prAdapter, prMsg); + break; + + default: + ASSERT(0); + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, ENUM_MBOX_ID_T eMboxId) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + MBOX_HNDL_MSG(prAdapter, prMsg); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxInitialize(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i; + + ASSERT(prAdapter); + + /* Initialize Mailbox */ + mboxInitMsgMap(); + + /* Setup/initialize each mailbox */ + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) + mboxSetup(prAdapter, i); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxDestroy(IN P_ADAPTER_T prAdapter) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + UINT_8 i; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { + prMbox = &(prAdapter->arMbox[i]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + cnmMemFree(prAdapter, prMsg); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This is dummy function to prevent empty arMsgMapTable[] for compiling. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mboxDummy(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + ASSERT(prAdapter); + + cnmMemFree(prAdapter, prMsgHdr); + +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c new file mode 100644 index 0000000000000..7fb71a199ccf4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/hs20.c @@ -0,0 +1,498 @@ +/* +** Id: //Department/DaVinci/BRANCHES/HS2_DEV_SW/MT6620_WIFI_DRIVER_V2_1_HS_2_0/mgmt/hs20.c#2 +*/ + +/*! \file "hs20.c" + \brief This file including the hotspot 2.0 related function. + + This file provided the macros and functions library support for the + protocol layer hotspot 2.0 related function. + +*/ + +/* +** Log: hs20.c + * + */ + + /******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_HOTSPOT_2_0 + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to generate Interworking IE for Probe Rsp, Bcn, Assoc Req/Rsp. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[out] prMsduInfo Pointer of the Msdu Info +* +* \return VOID +*/ +/*----------------------------------------------------------------------------*/ +VOID hs20GenerateInterworkingIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) +{ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to generate Roaming Consortium IE for Probe Rsp, Bcn, Assoc Req/Rsp. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[out] prMsduInfo Pointer of the Msdu Info +* +* \return VOID +*/ +/*----------------------------------------------------------------------------*/ +VOID hs20GenerateRoamingConsortiumIE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) +{ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to generate HS2.0 IE for Probe Rsp, Bcn, Assoc Req/Rsp. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[out] prMsduInfo Pointer of the Msdu Info +* +* \return VOID +*/ +/*----------------------------------------------------------------------------*/ +VOID hs20GenerateHS20IE(IN P_ADAPTER_T prAdapter, OUT P_MSDU_INFO_T prMsduInfo) +{ + PUINT_8 pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 221 :0xDD */ + if (prAdapter->prGlueInfo->u2HS20AssocInfoIELen) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucHS20AssocInfoIE, + prAdapter->prGlueInfo->u2HS20AssocInfoIELen); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2HS20AssocInfoIELen; + } + +} + +VOID hs20FillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) +{ + P_HS20_EXT_CAP_T prExtCap; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + /* Add Extended Capabilities IE */ + prExtCap = (P_HS20_EXT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + prExtCap->ucId = ELEM_ID_EXTENDED_CAP; + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) + prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; + else + prExtCap->ucLength = 3 - ELEM_HDR_LEN; + + kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); + + prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; + + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); + + /* For R2 WNM-Notification */ + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); + } + kalPrint("IE_SIZE(prExtCap) = %d, %d %d\n", IE_SIZE(prExtCap), ELEM_HDR_LEN, ELEM_MAX_LEN_EXT_CAP); + ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to fill up the content of Ext Cap IE bit 31. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[out] pucIE Pointer of the IE buffer +* +* \return VOID +*/ +/*----------------------------------------------------------------------------*/ +VOID hs20FillProreqExtCapIE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) +{ + P_HS20_EXT_CAP_T prExtCap; + + ASSERT(prAdapter); + + /* Add Extended Capabilities IE */ + prExtCap = (P_HS20_EXT_CAP_T) pucIE; + + prExtCap->ucId = ELEM_ID_EXTENDED_CAP; + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) + prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; + else + prExtCap->ucLength = 3 - ELEM_HDR_LEN; + + kalMemZero(prExtCap->aucCapabilities, prExtCap->ucLength); + + prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_BSS_TRANSITION_BIT); + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT); + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); + + /* For R2 WNM-Notification */ + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to fill up the content of HS2.0 IE. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[out] pucIE Pointer of the IE buffer +* +* \return VOID +*/ +/*----------------------------------------------------------------------------*/ +VOID hs20FillHS20IE(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucIE) +{ + P_IE_HS20_INDICATION_T prHS20IndicationIe; + /* P_HS20_INFO_T prHS20Info; */ + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + + /* prHS20Info = &(prAdapter->rWifiVar.rHS20Info); */ + + prHS20IndicationIe = (P_IE_HS20_INDICATION_T) pucIE; + + prHS20IndicationIe->ucId = ELEM_ID_VENDOR; + prHS20IndicationIe->ucLength = sizeof(IE_HS20_INDICATION_T) - ELEM_HDR_LEN; + prHS20IndicationIe->aucOui[0] = aucWfaOui[0]; + prHS20IndicationIe->aucOui[1] = aucWfaOui[1]; + prHS20IndicationIe->aucOui[2] = aucWfaOui[2]; + prHS20IndicationIe->ucType = VENDOR_OUI_TYPE_HS20; + prHS20IndicationIe->ucHotspotConfig = 0x00; /* prHS20Info->ucHotspotConfig; */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called while calculating length of hotspot 2.0 indication IE for Probe Request. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] pucTargetBSSID Pointer of target HESSID +* +* \return the length of composed HS20 IE +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 hs20CalculateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID) +{ + UINT_32 u4IeLength; + + if (0) /* Todo:: Not HS20 STA */ + return 0; + + u4IeLength = + sizeof(IE_HS20_INDICATION_T) + /* sizeof(IE_INTERWORKING_T) */ + (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP); + + if (!pucTargetBSSID) { + /* Do nothing */ + /* u4IeLength -= MAC_ADDR_LEN; */ + } + + return u4IeLength; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called while composing hotspot 2.0 indication IE for Probe Request. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* \param[in] pucTargetBSSID Pointer of target HESSID +* \param[out] prIE Pointer of the IE buffer +* +* \return the wlan status +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS hs20GenerateHS20RelatedIEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTargetBSSID, OUT PUINT_8 prIE) +{ + if (0) /* Todo:: Not HS20 STA */ + return 0; +#if 0 + P_HS20_INFO_T prHS20Info; + + prHS20Info = &(prAdapter->rWifiVar.rHS20Info); + + /* + * Generate 802.11u Interworking IE (107) + */ + hs20FillInterworkingIE(prAdapter, + prHS20Info->ucAccessNetworkOptions, + prHS20Info->ucVenueGroup, prHS20Info->ucVenueType, pucTargetBSSID, prIE); + prIE += IE_SIZE(prIE); +#endif + /* + * Generate Ext Cap IE (127) + */ + hs20FillProreqExtCapIE(prAdapter, prIE); + prIE += IE_SIZE(prIE); + + /* + * Generate HS2.0 Indication IE (221) + */ + hs20FillHS20IE(prAdapter, prIE); + prIE += IE_SIZE(prIE); + + return WLAN_STATUS_SUCCESS; +} + +BOOLEAN hs20IsGratuitousArp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) +{ + PUINT_8 pucSenderIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SENDER_IP_OFFSET; + PUINT_8 pucTargetIP = prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_IP_OFFSET; + PUINT_8 pucSenderMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_SNEDER_MAC_OFFSET); +#if CFG_HS20_DEBUG && 0 +/* UINT_8 aucIpAllZero[4] = {0,0,0,0}; */ +/* UINT_8 aucMACAllZero[MAC_ADDR_LEN] = {0,0,0,0,0,0}; */ + PUINT_8 pucTargetMac = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_TARGET_MAC_OFFSET); +#endif + +#if CFG_HS20_DEBUG && 0 + PUINT_16 pu2ArpOper = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + ARP_OPERATION_OFFSET); + + kalPrint("Recv ARP 0x%04X\n", htons(*pu2ArpOper)); + kalPrint("SENDER[ %pM ] [%pI4]\n", pucSenderMac, pucSenderIP); + kalPrint("TARGET[ %pM ] [%pI4]\n", pucTargetMac, pucTargetIP); +#endif + + /* IsGratuitousArp */ + if (!kalMemCmp(pucSenderIP, pucTargetIP, 4)) { + kalPrint("Drop Gratuitous ARP from [ %pM ] [%pI4]\n", pucSenderMac, pucTargetIP); + return TRUE; + } + return FALSE; +} + +BOOLEAN hs20IsUnsolicitedNeighborAdv(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prCurrSwRfb) +{ + PUINT_8 pucIpv6Protocol = ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_PROTOCOL_OFFSET); + + /* kalPrint("pucIpv6Protocol [%02X:%02X]\n", *pucIpv6Protocol, IPV6_PROTOCOL_ICMPV6); */ + if (*pucIpv6Protocol == IPV6_PROTOCOL_ICMPV6) { + PUINT_8 pucICMPv6Type = + ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_TYPE_OFFSET); + /* kalPrint("pucICMPv6Type [%02X:%02X]\n", *pucICMPv6Type, ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT); */ + if (*pucICMPv6Type == ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT) { + PUINT_8 pucICMPv6Flag = + ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_LEN + ICMPV6_FLAG_OFFSET); + PUINT_8 pucSrcMAC = ((PUINT_8) prCurrSwRfb->pvHeader + MAC_ADDR_LEN); + +#if CFG_HS20_DEBUG + kalPrint("NAdv Flag [%02X] [R(%d)\\S(%d)\\O(%d)]\n", + *pucICMPv6Flag, + (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_ROUTER_BIT) >> 7, + (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT) >> 6, + (UINT_8) (*pucICMPv6Flag & ICMPV6_FLAG_OVERWRITE_BIT) >> 5); +#endif + if (!(*pucICMPv6Flag & ICMPV6_FLAG_SOLICITED_BIT)) { + kalPrint("Drop Unsolicited Neighbor Advertisement from [%pM]\n", pucSrcMAC); + return TRUE; + } + } + } + + return FALSE; +} + +#if CFG_ENABLE_GTK_FRAME_FILTER +BOOLEAN hs20IsForgedGTKFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) +{ + /* + P_CONNECTION_SETTINGS_T prConnSettings = &prAdapter->rWifiVar.rConnSettings; + PUINT_8 pucEthDestAddr = prCurrSwRfb->pvHeader; + */ + /* 3 TODO: Need to verify this function before enable it */ + return FALSE; + /* + if ((prConnSettings->eEncStatus != ENUM_ENCRYPTION_DISABLED) && IS_BMCAST_MAC_ADDR(pucEthDestAddr)) { + UINT_8 ucIdx = 0; + PUINT_32 prIpAddr, prPacketDA; + PUINT_16 pu2PktIpVer = + (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); + + if (*pu2PktIpVer == htons(ETH_P_IPV4)) { + if (!prBssInfo->prIpV4NetAddrList) + return FALSE; + for (ucIdx = 0; ucIdx < prBssInfo->prIpV4NetAddrList->ucAddrCount; ucIdx++) { + prIpAddr = (PUINT_32) &prBssInfo->prIpV4NetAddrList->arNetAddr[ucIdx].aucIpAddr[0]; + prPacketDA = + (PUINT_32) ((PUINT_8) prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + + IPV4_HDR_IP_DST_ADDR_OFFSET); + + if (kalMemCmp(prIpAddr, prPacketDA, 4) == 0) { + kalPrint("Drop FORGED IPv4 packet\n"); + return TRUE; + } + } + } +#ifdef CONFIG_IPV6 + else if (*pu2PktIpVer == htons(ETH_P_IPV6)) { + UINT_8 aucIPv6Mac[MAC_ADDR_LEN]; + PUINT_8 pucIdx = + prCurrSwRfb->pvHeader + ETHER_HEADER_LEN + IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET; + + kalMemCopy(&aucIPv6Mac[0], pucIdx, 3); + pucIdx += 5; + kalMemCopy(&aucIPv6Mac[3], pucIdx, 3); + kalPrint("Get IPv6 frame Dst IP MAC part %pM\n", aucIPv6Mac); + if (EQUAL_MAC_ADDR(aucIPv6Mac, prBssInfo->aucOwnMacAddr)) { + kalPrint("Drop FORGED IPv6 packet\n"); + return TRUE; + } + } +#endif + } + + return FALSE; + */ +} +#endif + +BOOLEAN hs20IsUnsecuredFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_SW_RFB_T prCurrSwRfb) +{ + PUINT_16 pu2PktIpVer = (PUINT_16) ((PUINT_8) prCurrSwRfb->pvHeader + (ETHER_HEADER_LEN - ETHER_TYPE_LEN)); + + /* kalPrint("IPVER 0x%4X\n", htons(*pu2PktIpVer)); */ +#if CFG_HS20_DEBUG & 0 + UINT_8 i = 0; + + kalPrint("==============================================="); + for (i = 0; i < 96; i++) { + if (!(i % 16)) + kalPrint("\n"); + kalPrint("%02X ", *((PUINT_8) prCurrSwRfb->pvHeader + i)); + } + kalPrint("\n"); +#endif + +#if CFG_ENABLE_GTK_FRAME_FILTER + if (hs20IsForgedGTKFrame(prAdapter, prBssInfo, prCurrSwRfb)) + return TRUE; + +#endif + if (*pu2PktIpVer == htons(ETH_P_ARP)) + return hs20IsGratuitousArp(prAdapter, prCurrSwRfb); + else if (*pu2PktIpVer == htons(ETH_P_IPV6)) + return hs20IsUnsolicitedNeighborAdv(prAdapter, prCurrSwRfb); + + return FALSE; +} + +BOOLEAN hs20IsFrameFilterEnabled(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ +#if 1 + if (prAdapter->prGlueInfo->fgConnectHS20AP) + return TRUE; +#else + PARAM_SSID_T rParamSsid; + P_BSS_DESC_T prBssDesc; + + rParamSsid.u4SsidLen = prBssInfo->ucSSIDLen; + COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + + prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, prBssInfo->aucBSSID, TRUE, &rParamSsid); + if (!prBssDesc) + return FALSE; + + if (prBssDesc->fgIsSupportHS20) { + if (!(prBssDesc->ucHotspotConfig & ELEM_HS_CONFIG_DGAF_DISABLED_MASK)) + return TRUE; + + /* Disable frame filter only if DGAF == 1 */ + return FALSE; + + } +#endif + + /* For Now, always return true to run hs20 check even for legacy AP */ + return TRUE; +} + +WLAN_STATUS hs20SetBssidPool(IN P_ADAPTER_T prAdapter, IN PVOID pvBuffer, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx) +{ + P_PARAM_HS20_SET_BSSID_POOL prParamBssidPool = (P_PARAM_HS20_SET_BSSID_POOL) pvBuffer; + P_HS20_INFO_T prHS20Info; + UINT_8 ucIdx; + + prHS20Info = &(prAdapter->rWifiVar.rHS20Info); + kalPrint("[%s]Set Bssid Pool! enable[%d] num[%d]\n", __func__, prParamBssidPool->fgIsEnable, + prParamBssidPool->ucNumBssidPool); + for (ucIdx = 0; ucIdx < prParamBssidPool->ucNumBssidPool; ucIdx++) { + COPY_MAC_ADDR(prHS20Info->arBssidPool[ucIdx].aucBSSID, &prParamBssidPool->arBSSID[ucIdx]); + kalPrint("[%s][%d][ %pM ]\n", __func__, ucIdx, (prHS20Info->arBssidPool[ucIdx].aucBSSID)); + } + prHS20Info->fgIsHS2SigmaMode = prParamBssidPool->fgIsEnable; + prHS20Info->ucNumBssidPoolEntry = prParamBssidPool->ucNumBssidPool; + +#if 0 + wlanClearScanningResult(prAdapter); +#endif + + return WLAN_STATUS_SUCCESS; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c new file mode 100644 index 0000000000000..469a48ebe9c10 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/mib.c @@ -0,0 +1,111 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/mib.c#1 +*/ + +/*! \file "mib.c" + \brief This file includes the mib default vale and functions. +*/ + +/* +** Log: mib.c + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add mib.c. + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[] = { + {RATE_SET_HR_DSSS, TRUE, FALSE} + , /* For PHY_TYPE_HR_DSSS_INDEX(0) */ + {RATE_SET_ERP, TRUE, TRUE} + , /* For PHY_TYPE_ERP_INDEX(1) */ + {RATE_SET_ERP_P2P, TRUE, TRUE} + , /* For PHY_TYPE_ERP_P2P_INDEX(2) */ + {RATE_SET_OFDM, FALSE, FALSE} + , /* For PHY_TYPE_OFDM_INDEX(3) */ +}; + +NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[AD_HOC_MODE_NUM] = { + {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} + , /* For AD_HOC_MODE_11B(0) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} + , /* For AD_HOC_MODE_MIXED_11BG(1) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} + , /* For AD_HOC_MODE_11G(2) */ + {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} + , /* For AD_HOC_MODE_11A(3) */ +}; + +NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[AP_MODE_NUM] = { + {PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS} + , /* For AP_MODE_11B(0) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP} + , /* For AP_MODE_MIXED_11BG(1) */ + {PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP} + , /* For AP_MODE_11G(2) */ + {PHY_TYPE_ERP_P2P_INDEX, BASIC_RATE_SET_ERP_P2P} + , /* For AP_MODE_11G_P2P(3) */ + {PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM} + , /* For AP_MODE_11A(4) */ +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c new file mode 100644 index 0000000000000..cb5fbebedd495 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_assoc.c @@ -0,0 +1,87 @@ +/* +** Id: @(#) p2p_assoc.c@@ +*/ + +/*! \file "p2p_assoc.c" + \brief This file includes the Wi-Fi Direct association-related functions. + + This file includes the association-related functions. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to compose Common Information Elements for P2P Association +* Request Frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +PUINT_8 p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN PUINT_8 pucBuffer) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case of + * Passive Scan and the target BSS didn't broadcast SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, + SSID_IE(pucBuffer)->ucLength, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + return pucBuffer; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c new file mode 100644 index 0000000000000..72a20a322cee6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_bss.c @@ -0,0 +1,58 @@ +/* +** Id: @(#) p2p_bss.c@@ +*/ + +/*! \file "p2p_bss.c" + \brief This file contains the functions for creating p2p BSS(AP). + + This file contains the functions for BSS(AP). We may create a BSS + network, or merge with exist IBSS network and sending Beacon Frame or reply + the Probe Response Frame for received Probe Request Frame. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c new file mode 100644 index 0000000000000..f8c09e2aa9ded --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_fsm.c @@ -0,0 +1,3139 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/mgmt/p2p_fsm.c#61 +*/ + +/*! \file "p2p_fsm.c" + \brief This file defines the FSM for P2P Module. + + This file defines the FSM for P2P Module. +*/ + +/* +** Log: p2p_fsm.c +** +** 12 20 2012 yuche.tsai +** [ALPS00410124] [Rose][Free Test][KE][rlmUpdateParamsForAP]The device reboot automatically +** and then "Fatal/Kernel" pops up during use data service.(Once) +** Fix possible NULL station record cause KE under AP mode. +** May due to variable uninitial. +** Review: http://mtksap20:8080/go?page=NewReview&reviewid=49970 +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 31 2012 yuche.tsai +** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected +**to AP previously,one device reboots automatically with KE +** Fix possible KE when concurrent & disconnect. +** +** 08 21 2012 yuche.tsai +** NULL +** fix disconnect indication. +** +** 08 16 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 14 2012 yuche.tsai +** NULL +** Fix p2p bug find on ALPS.JB trunk. +** +** 07 27 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update for driver unload KE issue. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Fix the compile flag of enhancement. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000808] [Volunteer Patch][MT6620][Driver/FW] Device discoverability issue fix + * Change device discoverability methodology. From driver SCAN to FW lock channel. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Add wifi direct connection enhancement method I, II & VI. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000833] [Volunteer Patch][WiFi Direct][Driver] Service Discovery Frame RX Indicate Issue + * Fix Service Discovery Race Condition Issue. + * + * 06 23 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * change parameter name from PeerAddr to BSSID + * + * 06 21 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix an issue of accepting connection of GO. + * + * 06 21 2011 yuche.tsai + * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability + * Drop GAS frame when SD is not enabled. + * + * 06 20 2011 yuche.tsai + * NULL + * Fix compile error. + * + * 06 20 2011 yuche.tsai + * [WCXRP00000799] [Volunteer Patch][MT6620][Driver] Connection Indication Twice Issue. + * Fix connection indication twice issue. + * + * 06 20 2011 cp.wu + * [WCXRP00000798] [MT6620 Wi-Fi][Firmware] Follow-ups for WAPI frequency offset workaround in firmware SCN module + * 1. specify target's BSSID when requesting channel privilege. + * 2. pass BSSID information to firmware domain + * + * 06 20 2011 yuche.tsai + * [WCXRP00000795] [Volunteer Patch][MT6620][Driver] GO can not connect second device issue + * Solve P2P GO can not formation with second device issue. + * + * 06 14 2011 yuche.tsai + * NULL + * Change disconnect feature. + * + * 06 10 2011 yuche.tsai + * [WCXRP00000775] [Volunteer Patch][MT6620][Driver] Dynamic enable SD capability[WCXRP00000776] + * [Need Patch][MT6620][Driver] MT6620 response probe request of P2P device with P2P IE under Hot Spot mode. + * 1. Dynamic enable SD capability after P2P supplicant ready. + * 2. Avoid response probe respone with p2p IE when under hot spot mode. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Fix RX SD request under AP mode issue. + * + * 06 02 2011 cp.wu + * [WCXRP00000681] [MT5931][Firmware] HIF code size reduction + * eliminate unused parameters for SAA-FSM + * + * 05 26 2011 yuche.tsai + * [WCXRP00000745] Support accepting connection after one Group Connection Lost. + +After Group Formation & lost connection, if MT6620 behave as: + +1. GO: It would keep under GO state until been dissolved by supplicant. + + At this time, other P2P device can use join method to join this group. + +2. GC: It would keep on searching target GO or target device until been dissolved by supplicant. + +At this time, it would ignore other P2P device formation request. + +-- + +Modification: Make driver to accept GO NEGO REQ at this time, to let user decide to accept new connection or not. + + * [Volunteer Patch][MT6620][Driver] + * Driver would indicate connection request, if password ID is not ready but connection request is issued. + * + * 05 18 2011 yuche.tsai + * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. + * A solution for both connection request & IO control. + * + * 05 16 2011 yuche.tsai + * [WCXRP00000728] [Volunteer Patch][MT6620][Driver] Service Discovery Request TX issue. + * Fix SD request can not send out issue. + * + * 05 09 2011 terry.wu + * [WCXRP00000711] [MT6620 Wi-Fi][Driver] Set Initial value of StaType in StaRec for Hotspot Client + * Set initial value of StaType in StaRec for hotspot client. + * + * 05 04 2011 yuche.tsai + * [WCXRP00000697] [Volunteer Patch][MT6620][Driver] + * Bug fix for p2p descriptor is NULL if BSS descriptor is found first. + * + * 05 04 2011 yuche.tsai + * NULL + * Support partial persistent group function. + * + * 05 02 2011 yuche.tsai + * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. + * Clear formation flag after formation timeout. + * + * 04 20 2011 yuche.tsai + * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition + * when add scan & query scan result at the same time. + * Fix side effect while starting ATGO. + * + * 04 20 2011 yuche.tsai + * NULL + * Fix ASSERT issue in FW, side effect of last change. + * + * 04 19 2011 yuche.tsai + * [WCXRP00000668] [Volunteer Patch][MT6620][Driver] Possible race condition + * when add scan & query scan result at the same time. + * Workaround for multiple device connection, before invitation ready. + * + * 04 19 2011 yuche.tsai + * [WCXRP00000665] [Wifi Direct][MT6620 E4] When use Ralink's dongle to establish wifi direct connection with PBC. + * But 6573 always not pop accept option to establish connection. + * Support connection indication when GO NEGO REQ doesn't have configure method, instead it has PasswordID. + * + * 04 18 2011 yuche.tsai + * NULL + * Fix error. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Fix a connection issue. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Fix the channel issue of AP mode. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Connection flow refine for Sigma test. + * + * 04 09 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Fix Device discoverability related issue. + * + * 04 09 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Fix bug for Device Discoverability. + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Fix compile error. + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. + * + * 03 28 2011 yuche.tsai + * NULL + * Fix a possible issue for retry join when media status connected. + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 24 2011 yuche.tsai + * NULL + * Assign AID before change STA_REC state to state 3. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix Response Rate Issue when TX Auth Rsp Frame under P2P Mode. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix issue of connection to one GC. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix ASSERT issue when starting Hot-spot. + * + * 03 22 2011 yuche.tsai + * NULL + * When Target Information is not available, change to passive mode. + * + * 03 22 2011 yuche.tsai + * NULL + * Fix one connection issue while using Keypad to connect a GO. + * + * 03 22 2011 yuche.tsai + * NULL + * 1. Fix two issues that may cause kernel panic. + * + * 03 22 2011 yuche.tsai + * NULL + * Fix GC connect to other device issue. + * + * 03 22 2011 yuche.tsai + * NULL + * 1.Shorten the LISTEN interval. + * 2. Fix IF address issue when we are GO + * 3. Fix LISTEN channel issue. + * + * 03 22 2011 yuche.tsai + * NULL + * Modify formation policy setting. + * + * 03 21 2011 yuche.tsai + * NULL + * Solve Listen State doesn't response probe response issue. + * + * 03 21 2011 yuche.tsai + * NULL + * Change P2P Connection Request Flow. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue + * Indicate the correct Group SSID when join on Group. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000583] [Volunteer Patch][MT6620][Driver] P2P connection of the third peer issue + * Support the third P2P device to join GO/GC group. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000581] [Volunteer Patch][MT6620][Driver] P2P IE in Assoc Req Issue + * Append P2P IE in Assoc Req, so that GC can be discovered in probe response of GO. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000578] [Volunteer Patch][MT6620][Driver] Separate Connection Request from general IOCTL + * Separate connection request from general IOCTL. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 17 2011 yuche.tsai + * NULL + * When AIS is connect to an AP, Hot Spot would be enabled under fixed same channel. + * + * 03 17 2011 yuche.tsai + * NULL + * Solve the Group Info IE in Probe Response incorrect issue. + * + * 03 17 2011 yuche.tsai + * NULL + * Release Channel after Join Complete. + * + * 03 16 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the protected while at P2P start GO, and skip some security check . + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix local configure method issue. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 14 2011 yuche.tsai + * NULL + * . + * + * 03 14 2011 yuche.tsai + * NULL + * Fix password ID issue. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 08 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue[WCXRP00000509] + * [Volunteer Patch][MT6620][Driver] Kernal panic when remove p2p module. + * . + * + * 03 07 2011 yuche.tsai + * [WCXRP00000502] [Volunteer Patch][MT6620][Driver] Fix group ID issue when doing Group Formation. + * . + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 04 2011 wh.su + * [WCXRP00000510] [MT6620 Wi-Fi] [Driver] Fixed the CTIA enter test mode issue + * fixed the p2p action frame type check for device request indication. + * + * 03 02 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Service Discovery RX packet buffer pointer. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Update Service Discovery Related wlanoid function. + * + * 02 21 2011 yuche.tsai + * [WCXRP00000481] [Volunteer Patch][MT6620][FW] Scan hang under concurrent case. + * Fix all BE issue of WSC or P2P IE. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the wsc config method mapping to driver used config method issue. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000479] [Volunteer Patch][MT6620][Driver] Probe Response of P2P using 11b rate. + * Update basic rate to FW, after P2P is initialed. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame during search + * phase do not contain P2P wildcard SSID. + * Use P2P Wildcard SSID when scan type of P2P_WILDCARD_SSID is set. + * + * 02 18 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC IE BE format issue. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 16 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * fixed the probe request send out without WSC IE issue (at P2P). + * + * 02 16 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * If two station connected to the Hot-Spot and one disconnect, FW would get into an infinite loop + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix re-connection issue after RX deauthentication. + * + * 02 15 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Fix conneciton issue after disconnect with AP. + * + * 02 12 2011 yuche.tsai + * [WCXRP00000441] [Volunteer Patch][MT6620][Driver] BoW can not create desired station type when Hot Spot is enabled. + * P2P Create Station Type according to Target BSS capability. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Support Disassoc & Deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Indication Related code. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000429] [Volunteer Patch][MT6620][Driver] Hot Spot Client Limit Issue + * Fix Client Limit Issue. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect + * to target station for AAA module. + * Disconnect every station client when disolve on P2P group. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * 1. Fix Service Disocvery Logical issue. + * 2. Fix a NULL pointer access violation issue when sending deauthentication packet to a class error station. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect + * to target station for AAA module. + * Workaround of disable P2P network. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue + * 1. Fixed SSID wrong length issue. + * 2. Under Hot Spot configuration, there won't be any P2P IE. + * 3. Under Hot Spot configuration, P2P FSM won't get into LISTEN state first. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Modify Start GO flow. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix desire phy type set issue. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Add desire phy type set phase I. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix P2P Disconnect Issue. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Add Service Discovery Function. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix compile error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type Definition. + * + * 01 19 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Add P2P QoS Support. + * + * 01 19 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Null NOA attribute setting when no related parameters. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify AAA flow according to CM's comment. + * + * 01 13 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Resolve Channel ZERO issue. (Uninitialized default channel) + * + * 01 13 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Update P2P State Debug Message. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Fix bug when allocating message buffer. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000353] [Volunteer Patch][MT6620][Driver] Desired Non-HT Rate Set update + * when STA record is created under AP Mode. + * Update Phy Type Set. When legacy client is connected, it can use 11b rate, + * but if the P2P device is connected, 11b rate is not allowed. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. + * 2. Call cnmP2pIsPermit() before active P2P network. + * 3. Add channel selection support for AP mode. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix Bug of reference to NULL pointer. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Modify some behavior of AP mode. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix bug of wrong pointer check. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix Compile Error. + * + * 01 11 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Add station record into client list before change it state from STATE_2 to STATE_3. + * + * 01 05 2011 yuche.tsai + * [WCXRP00000345] [MT6620][Volunteer Patch] P2P may issue a SSID specified scan request, + * but the SSID length is still invalid. + * Specify SSID Type when issue a scan request. + * + * 01 05 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations + * to ease physically continuous memory demands + * correct typo + * + * 01 05 2011 george.huang + * [WCXRP00000343] [MT6620 Wi-Fi] Add TSF reset path for concurrent operation + * modify NOA update path for preventing assertion false alarm. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations + * to ease physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 01 03 2011 wh.su + * [WCXRP00000326] [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * let the p2p ap mode acept a legacy device join. + * + * 12 22 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Fix Compile Error. + * + * 12 15 2010 yuche.tsai + * [WCXRP00000245] 1. Invitation Request/Response. +2. Provision Discovery Request/Response + + * Refine Connection Flow. + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add + * + * 12 08 2010 yuche.tsai + * [WCXRP00000244] [MT6620][Driver] Add station record type for each client when in AP mode. + * Change STA Type under AP mode. We would tell if client is a P2P device or a legacy client + * by checking the P2P IE in assoc req frame. + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * The order of invoking nicUpdateBss() and rlm functions + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation. + * + * 12 02 2010 yuche.tsai + * NULL + * Update P2P Connection Policy for Invitation & Provision Discovery. + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 30 2010 yuche.tsai + * NULL + * Update Configure Method indication & selection for Provision Discovery & GO_NEGO_REQ + * + * 11 30 2010 yuche.tsai + * NULL + * Update RCIP value when RX assoc request frame. + * + * 11 29 2010 yuche.tsai + * NULL + * Update P2P related function for INVITATION & PROVISION DISCOVERY. + * + * 11 26 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Update P2P PS for NOA function. + * + * 11 25 2010 yuche.tsai + * NULL + * Update Code for Invitation Related Function. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] + * Set the Tx lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 05 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * fixed the p2p role code error. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * fixed the ASSERT check error + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 19 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state + * machine[WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * fixed the compiling error. + * + * 10 14 2010 wh.su + * [WCXRP00000102] [MT6620 Wi-Fi] [FW] Add a compiling flag and code for support Direct GO at Android + * adding a code to support Direct GO with a compiling flag . + * + * 10 08 2010 cp.wu + * [WCXRP00000087] [MT6620 Wi-Fi][Driver] Cannot connect to 5GHz AP, driver will cause FW assert. + * correct erroneous logic: specifying eBand with incompatible eSco + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * fixed the compiling error. + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at WinXP. + * + * 09 07 2010 yuche.tsai + * NULL + * Reset Common IE Buffer of P2P INFO when scan request is issued. + * If an action frame other than public action frame is received, return direcly. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 26 2010 yuche.tsai + * NULL + * Add P2P Connection Abort Event Message handler. + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 yuche.tsai + * NULL + * 1. Fix Interface Address from GO Nego Req/Rsp is not correct. + * 2. Fix GO mode does not change media state after station connected. + * 3. Fix STA don't response probe request when there is a connection request. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 20 2010 kevin.huang + * NULL + * Modify AAA Module for changing STA STATE 3 at p2p/bowRunEventAAAComplete() + * + * 08 20 2010 yuche.tsai + * NULL + * Add Glue Layer indication. + * + * 08 17 2010 yuche.tsai + * NULL + * Fix compile warning under Linux. + * + * 08 17 2010 yuche.tsai + * NULL + * Fix some P2P FSM bug. + * + * 08 16 2010 yuche.tsai + * NULL + * Add random Interface Address Generation support. + * + * 08 16 2010 yuche.tsai + * NULL + * Fix some P2P FSM bug. + * + * 08 16 2010 yuche.tsai + * NULL + * Update P2P FSM code for GO Nego. + * + * 08 16 2010 kevin.huang + * NULL + * Refine AAA functions + * + * 08 12 2010 kevin.huang + * NULL + * Refine bssProcessProbeRequest() and bssSendBeaconProbeResponse() + * + * 08 12 2010 yuche.tsai + * NULL + * Join complete indication. + * + * 08 11 2010 yuche.tsai + * NULL + * Add two boolean in connection request. + * Based on these two boolean value, P2P FSM should + * decide to do invitation or group formation or start a GO directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Update P2P FSM, currently P2P Device Discovery is verified. + * + * 08 05 2010 yuche.tsai + * NULL + * Update P2P FSM for group formation. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 03 2010 cp.wu + * NULL + * limit build always needs spin-lock declaration. + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Add P2P FSM code check in. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 yuche.tsai + * + * Update P2P FSM. + * + * 07 09 2010 george.huang + * + * [WPD00001556] Migrate PM variables from FW to driver: for composing QoS Info + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error while enable WIFI_DIRECT support. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Update P2P Function call. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * First draft for migration P2P FSM from FW to Driver. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Rename CFG flag for P2P + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add code to test P2P GO + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add Wi-Fi Direct SSID and P2P GO Test Mode + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Modify code due to BAND_24G define was changed + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Revise data structure to share the same BSS_INFO_T for avoiding coding error + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugP2pState[P2P_STATE_NUM] = { + (PUINT_8) DISP_STRING("P2P_STATE_IDLE"), + (PUINT_8) DISP_STRING("P2P_STATE_SCAN"), + (PUINT_8) DISP_STRING("P2P_STATE_AP_CHANNEL_DETECT"), + (PUINT_8) DISP_STRING("P2P_STATE_REQING_CHANNEL"), + (PUINT_8) DISP_STRING("P2P_STATE_CHNL_ON_HAND"), + (PUINT_8) DISP_STRING("P2P_STATE_GC_JOIN") +}; + +/*lint -restore */ +#else +static UINT_8 apucDebugP2pState[P2P_STATE_NUM] = { + P2P_STATE_IDLE, + P2P_STATE_SCAN, + P2P_STATE_AP_CHANNEL_DETECT, + P2P_STATE_REQING_CHANNEL, + P2P_STATE_CHNL_ON_HAND, + P2P_STATE_GC_JOIN +}; + +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/* p2pStateXXX : Processing P2P FSM related action. + * p2pFSMXXX : Control P2P FSM flow. + * p2pFuncXXX : Function for doing one thing. + */ +VOID p2pFsmInit(IN P_ADAPTER_T prAdapter) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + ASSERT_BREAK(prP2pFsmInfo != NULL); + + LINK_INITIALIZE(&(prP2pFsmInfo->rMsgEventQueue)); + LINK_INITIALIZE(&(prP2pBssInfo->rStaRecOfClientList)); + + prP2pFsmInfo->eCurrentState = prP2pFsmInfo->ePreviousState = P2P_STATE_IDLE; + prP2pFsmInfo->prTargetBss = NULL; + prP2pFsmInfo->fgIsWPSMode = 0; + + cnmTimerInitTimer(prAdapter, + &(prAdapter->rP2pFsmTimeoutTimer), + (PFN_MGMT_TIMEOUT_FUNC) p2pFsmRunEventFsmTimeout, (ULONG) prP2pFsmInfo); + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BSS_INFO_INIT(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* 4 <2.1> Initiate BSS_INFO_T - Setup HW ID */ + prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + prP2pBssInfo->ucHwDefaultFixedRateCode = RATE_OFDM_6M; + + prP2pBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prP2pBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + + prP2pBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prP2pBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prP2pBssInfo->u2OperationalRateSet, + prP2pBssInfo->u2BSSBasicRateSet, + prP2pBssInfo->aucAllSupportedRates, &prP2pBssInfo->ucAllSupportedRatesLen); + + prP2pBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prP2pBssInfo->prBeacon) { + prP2pBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prP2pBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ + prP2pBssInfo->prBeacon->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + } else { + /* Out of memory. */ + ASSERT(FALSE); + } + + prP2pBssInfo->eCurrentOPMode = OP_MODE_NUM; + + prP2pBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; + prP2pBssInfo->ucPrimaryChannel = P2P_DEFAULT_LISTEN_CHANNEL; + prP2pBssInfo->eBand = BAND_2G4; + prP2pBssInfo->eBssSCO = CHNL_EXT_SCN; + + if (prAdapter->rWifiVar.fgSupportQoS) + prP2pBssInfo->fgIsQBSS = TRUE; + else + prP2pBssInfo->fgIsQBSS = FALSE; + + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + + } while (FALSE); + +} /* p2pFsmInit */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function is used to uninitialize the value in P2P_FSM_INFO_T for +* P2P FSM operation +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DEBUGFUNC("p2pFsmUninit()"); + DBGLOG(P2P, INFO, "->p2pFsmUninit()\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, OP_MODE_P2P_DEVICE, TRUE); + + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, P2P_STATE_NUM); + + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + wlanAcquirePowerControl(prAdapter); + + /* Release all pending CMD queue. */ + DBGLOG(P2P, TRACE, "p2pFsmUninit: wlanProcessCommandQueue, num of element:%d\n", + (UINT_32) prAdapter->prGlueInfo->rCmdQueue.u4NumElem); + wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); + + wlanReleasePowerControl(prAdapter); + + /* Release pending mgmt frame, + * mgmt frame may be pending by CMD without resource. + */ + kalClearMgmtFramesByNetType(prAdapter->prGlueInfo, NETWORK_TYPE_P2P_INDEX); + + /* Clear PendingCmdQue */ + wlanReleasePendingCMDbyNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + if (prP2pBssInfo->prBeacon) { + cnmMgtPktFree(prAdapter, prP2pBssInfo->prBeacon); + prP2pBssInfo->prBeacon = NULL; + } + + } while (FALSE); + + return; + +} /* end of p2pFsmUninit() */ + +VOID p2pFsmStateTransition(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) +{ + BOOLEAN fgIsTransOut = (BOOLEAN) FALSE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (!IS_BSS_ACTIVE(prP2pBssInfo)) { + if (!cnmP2PIsPermitted(prAdapter)) + return; + + SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + fgIsTransOut = fgIsTransOut ? FALSE : TRUE; + + if (!fgIsTransOut) { +#if DBG + DBGLOG(P2P, STATE, "TRANSITION: [%s] -> [%s]\n", + apucDebugP2pState[prP2pFsmInfo->eCurrentState], + apucDebugP2pState[eNextState]); +#else + DBGLOG(P2P, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", + DBG_P2P_IDX, apucDebugP2pState[prP2pFsmInfo->eCurrentState], + apucDebugP2pState[eNextState]); +#endif + + /* Transition into current state. */ + prP2pFsmInfo->ePreviousState = prP2pFsmInfo->eCurrentState; + prP2pFsmInfo->eCurrentState = eNextState; + } + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_IDLE: + if (fgIsTransOut) + p2pStateAbort_IDLE(prAdapter, prP2pFsmInfo, eNextState); + else + fgIsTransOut = p2pStateInit_IDLE(prAdapter, prP2pFsmInfo, prP2pBssInfo, &eNextState); + break; + case P2P_STATE_SCAN: + if (fgIsTransOut) { + /* Scan done / scan canceled. */ + p2pStateAbort_SCAN(prAdapter, prP2pFsmInfo, eNextState); + } else { + /* Initial scan request. */ + p2pStateInit_SCAN(prAdapter, prP2pFsmInfo); + } + + break; + case P2P_STATE_AP_CHANNEL_DETECT: + if (fgIsTransOut) { + /* Scan done */ + /* Get sparse channel result. */ + p2pStateAbort_AP_CHANNEL_DETECT(prAdapter, + prP2pFsmInfo, prP2pSpecificBssInfo, eNextState); + } + + else { + /* Initial passive scan request. */ + p2pStateInit_AP_CHANNEL_DETECT(prAdapter, prP2pFsmInfo); + } + + break; + case P2P_STATE_REQING_CHANNEL: + if (fgIsTransOut) { + /* Channel on hand / Channel canceled. */ + p2pStateAbort_REQING_CHANNEL(prAdapter, prP2pFsmInfo, eNextState); + } else { + /* Initial channel request. */ + p2pFuncAcquireCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + break; + case P2P_STATE_CHNL_ON_HAND: + if (fgIsTransOut) { + p2pStateAbort_CHNL_ON_HAND(prAdapter, prP2pFsmInfo, prP2pBssInfo, eNextState); + } else { + /* Initial channel ready. */ + /* Send channel ready event. */ + /* Start a FSM timer. */ + p2pStateInit_CHNL_ON_HAND(prAdapter, prP2pBssInfo, prP2pFsmInfo); + } + + break; + case P2P_STATE_GC_JOIN: + if (fgIsTransOut) { + /* Join complete / join canceled. */ + p2pStateAbort_GC_JOIN(prAdapter, prP2pFsmInfo, &(prP2pFsmInfo->rJoinInfo), eNextState); + } else { + if (prP2pFsmInfo->prTargetBss == NULL) { + ASSERT(FALSE); + } else { + /* Send request to SAA module. */ + p2pStateInit_GC_JOIN(prAdapter, + prP2pFsmInfo, + prP2pBssInfo, + &(prP2pFsmInfo->rJoinInfo), prP2pFsmInfo->prTargetBss); + } + } + + break; + default: + break; + } + + } while (fgIsTransOut); + +} /* p2pFsmStateTransition */ + +VOID p2pFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchOpMode = (P_MSG_P2P_SWITCH_OP_MODE_T) prMsgHdr; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwitchOpMode != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventSwitchOPMode\n"); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prSwitchOpMode->eOpMode >= OP_MODE_NUM) { + ASSERT(FALSE); + break; + } + + /* P2P Device / GC. */ + p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, prSwitchOpMode->eOpMode, TRUE); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventSwitchOPMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle scan done event during Device Discovery. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; + P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) NULL; + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + /* This scan done event is either for "SCAN" phase or "SEARCH" state or "LISTEN" state. + * The scan done for SCAN phase & SEARCH state doesn't imply Device + * Discovery over. + */ + DBGLOG(P2P, TRACE, "P2P Scan Done Event\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + + if (prScanDoneMsg->ucSeqNum != prScanReqInfo->ucSeqNumOfScnMsg) { + /* Scan Done message sequence number mismatch. + * Ignore this event. (P2P FSM issue two scan events.) + */ + /* The scan request has been cancelled. + * Ignore this message. It is possible. + */ + DBGLOG(P2P, TRACE, "P2P Scan Don SeqNum:%d <-> P2P Fsm SCAN Msg:%d\n", + prScanDoneMsg->ucSeqNum, prScanReqInfo->ucSeqNumOfScnMsg); + + break; + } + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_SCAN: + { + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + prScanReqInfo->fgIsAbort = FALSE; + + if (prConnReqInfo->fgIsConnRequest) { + prP2pFsmInfo->prTargetBss = p2pFuncKeepOnConnection(prAdapter, + &prP2pFsmInfo->rConnReqInfo, + &prP2pFsmInfo->rChnlReqInfo, + &prP2pFsmInfo->rScanReqInfo); + if (prP2pFsmInfo->prTargetBss == NULL) + eNextState = P2P_STATE_SCAN; + else + eNextState = P2P_STATE_REQING_CHANNEL; + } else { + eNextState = P2P_STATE_IDLE; + } + + } + break; + case P2P_STATE_AP_CHANNEL_DETECT: + eNextState = P2P_STATE_REQING_CHANNEL; + break; + default: + /* Unexpected channel scan done event without being chanceled. */ + ASSERT(FALSE); + break; + } + + prScanReqInfo->fgIsScanRequest = FALSE; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventScanDone */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when channel is granted by CNM module from FW. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T) NULL; + UINT_8 ucTokenID = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "P2P Run Event Channel Grant\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr; + ucTokenID = prMsgChGrant->ucTokenID; + prP2pFsmInfo->u4GrantInterval = prMsgChGrant->u4GrantInterval; + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + if (ucTokenID == prChnlReqInfo->ucSeqNumOfChReq) { + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_REQING_CHANNEL: + switch (prChnlReqInfo->eChannelReqType) { + case CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL: + eNextState = P2P_STATE_CHNL_ON_HAND; + break; + case CHANNEL_REQ_TYPE_GC_JOIN_REQ: + eNextState = P2P_STATE_GC_JOIN; + break; + case CHANNEL_REQ_TYPE_GO_START_BSS: + eNextState = P2P_STATE_IDLE; + break; + default: + break; + } + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); + break; + default: + /* Channel is granted under unexpected state. + * Driver should cancel channel privileagea before leaving the states. + */ + ASSERT(FALSE); + break; + } + + } else { + /* Channel requsted, but released. */ + /* ASSERT(!prChnlReqInfo->fgIsChannelRequested); */ + DBGLOG(P2P, TRACE, "Channel requsted, but released\n"); + } + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + + return; + +} /* p2pFsmRunEventChGrant */ + +VOID p2pFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + P_MSG_P2P_CHNL_REQUEST_T prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + ENUM_P2P_STATE_T eNextState = P2P_STATE_NUM; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pChnlReqMsg = (P_MSG_P2P_CHNL_REQUEST_T) prMsgHdr; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelRequest\n"); + + /* Special case of time renewing for same frequency. */ + if ((prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) && + (prChnlReqInfo->ucReqChnlNum == prP2pChnlReqMsg->rChannelInfo.ucChannelNum) && + (prChnlReqInfo->eBand == prP2pChnlReqMsg->rChannelInfo.eBand) && + (prChnlReqInfo->eChnlSco == prP2pChnlReqMsg->eChnlSco)) { + + ASSERT(prChnlReqInfo->fgIsChannelRequested == TRUE); + ASSERT(prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL); + + prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; + prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; + + /* Re-enter the state. */ + eNextState = P2P_STATE_CHNL_ON_HAND; + } else { + + /* Make sure the state is in IDLE state. */ + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + /* Cookie can only be assign after abort.(for indication) */ + prChnlReqInfo->u8Cookie = prP2pChnlReqMsg->u8Cookie; + prChnlReqInfo->ucReqChnlNum = prP2pChnlReqMsg->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prP2pChnlReqMsg->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prP2pChnlReqMsg->eChnlSco; + prChnlReqInfo->u4MaxInterval = prP2pChnlReqMsg->u4Duration; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_REMAIN_ON_CHANNEL; + + eNextState = P2P_STATE_REQING_CHANNEL; + } + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, eNextState); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventChannelRequest */ + +VOID p2pFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_MSG_P2P_CHNL_ABORT_T prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T) prMsgHdr; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + DBGLOG(P2P, TRACE, "p2pFsmRunEventChannelAbort\n"); + + if ((prChnlAbortMsg->u8Cookie == prChnlReqInfo->u8Cookie) && (prChnlReqInfo->fgIsChannelRequested)) { + + ASSERT((prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL || + (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND))); + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventChannelAbort */ + +VOID p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; + UINT_32 u4ChnlListSize = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T) prMsgHdr; + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventScanRequest\n"); + + /* Make sure the state is in IDLE state. */ + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + ASSERT(prScanReqInfo->fgIsScanRequest == FALSE); + + prScanReqInfo->fgIsAbort = TRUE; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + + /* Channel List */ + prScanReqInfo->ucNumChannelList = prP2pScanReqMsg->u4NumChannel; + DBGLOG(P2P, TRACE, "Scan Request Channel List Number: %d\n", prScanReqInfo->ucNumChannelList); + if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { + DBGLOG(P2P, TRACE, "Channel List Number Overloaded: %d, change to: %d\n", + prScanReqInfo->ucNumChannelList, MAXIMUM_OPERATION_CHANNEL_LIST); + prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + u4ChnlListSize = sizeof(RF_CHANNEL_INFO_T) * prScanReqInfo->ucNumChannelList; + kalMemCopy(prScanReqInfo->arScanChannelList, prP2pScanReqMsg->arChannelListInfo, u4ChnlListSize); + + /* TODO: I only take the first SSID. Multiple SSID may be needed in the future. */ + /* SSID */ + if (prP2pScanReqMsg->i4SsidNum >= 1) + kalMemCopy(&(prScanReqInfo->rSsidStruct), prP2pScanReqMsg->prSSID, sizeof(P2P_SSID_STRUCT_T)); + else + prScanReqInfo->rSsidStruct.ucSsidLen = 0; + + /* IE Buffer */ + kalMemCopy(prScanReqInfo->aucIEBuf, prP2pScanReqMsg->pucIEBuf, prP2pScanReqMsg->u4IELen); + + prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventScanRequest */ + +VOID p2pFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventScanAbort\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = TRUE; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventScanAbort */ + +VOID p2pFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventAbort\n"); + + if (prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_SCAN) { + + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = TRUE; + } else if (prP2pFsmInfo->eCurrentState == P2P_STATE_REQING_CHANNEL) { + /* 2012/08/06: frog + * Prevent Start GO. + */ + prP2pBssInfo->eIntendOPMode = OP_MODE_NUM; + } + /* For other state, is there any special action that should be take before leaving? */ + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } else { + /* P2P State IDLE. */ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + if (prChnlReqInfo->fgIsChannelRequested) + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + + cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); + } + + } while (FALSE); + +} /* p2pFsmRunEventAbort */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle FSM Timeout. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventFsmTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParam) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) ulParam; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + DBGLOG(P2P, TRACE, "P2P FSM Timeout Event\n"); + + switch (prP2pFsmInfo->eCurrentState) { + case P2P_STATE_IDLE: + { + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + if (prChnlReqInfo->fgIsChannelRequested) { + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + } else if (IS_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } + break; + +/* case P2P_STATE_SCAN: */ +/* break; */ +/* case P2P_STATE_AP_CHANNEL_DETECT: */ +/* break; */ +/* case P2P_STATE_REQING_CHANNEL: */ +/* break; */ + case P2P_STATE_CHNL_ON_HAND: + switch (prP2pFsmInfo->eListenExted) { + case P2P_DEV_NOT_EXT_LISTEN: + case P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT: + DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", + prP2pFsmInfo->eListenExted); + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; + break; + case P2P_DEV_EXT_LISTEN_ING: + DBGLOG(P2P, INFO, "p2p timeout, state==P2P_STATE_CHNL_ON_HAND, eListenExted: %d\n", + prP2pFsmInfo->eListenExted); + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_CHNL_ON_HAND); + prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_WAITFOR_TIMEOUT; + break; + default: + ASSERT(FALSE); + DBGLOG(P2P, ERROR, + "Current P2P State %d is unexpected for FSM timeout event.\n", + prP2pFsmInfo->eCurrentState); + } + break; +/* case P2P_STATE_GC_JOIN: */ +/* break; */ + default: + break; + } + + } while (FALSE); + +} /* p2pFsmRunEventFsmTimeout */ + +VOID p2pFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventMgmtFrameTx\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T) prMsgHdr; + + p2pFuncTxMgmtFrame(prAdapter, + &prP2pFsmInfo->rMgmtTxInfo, prMgmtTxMsg->prMgmtMsduInfo, prMgmtTxMsg->u8Cookie); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + + return; + +} /* p2pFsmRunEventMgmtTx */ + +VOID p2pFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventStartAP\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) prMsgHdr; + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (prP2pStartAPMsg->u4BcnInterval) { + DBGLOG(P2P, TRACE, "Beacon interval updated to :%u\n", prP2pStartAPMsg->u4BcnInterval); + prP2pBssInfo->u2BeaconInterval = (UINT_16) prP2pStartAPMsg->u4BcnInterval; + } else if (prP2pBssInfo->u2BeaconInterval == 0) { + prP2pBssInfo->u2BeaconInterval = DOT11_BEACON_PERIOD_DEFAULT; + } + + if (prP2pStartAPMsg->u4DtimPeriod) { + DBGLOG(P2P, TRACE, "DTIM interval updated to :%u\n", prP2pStartAPMsg->u4DtimPeriod); + prP2pBssInfo->ucDTIMPeriod = (UINT_8) prP2pStartAPMsg->u4DtimPeriod; + } else if (prP2pBssInfo->ucDTIMPeriod == 0) { + prP2pBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + } + + if (prP2pStartAPMsg->u2SsidLen != 0) { + kalMemCopy(prP2pBssInfo->aucSSID, prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen); + kalMemCopy(prP2pSpecificBssInfo->aucGroupSsid, prP2pStartAPMsg->aucSsid, + prP2pStartAPMsg->u2SsidLen); + prP2pBssInfo->ucSSIDLen = prP2pSpecificBssInfo->u2GroupSsidLen = prP2pStartAPMsg->u2SsidLen; + } + + prP2pBssInfo->eHiddenSsidType = prP2pStartAPMsg->ucHiddenSsidType; + + /* TODO: JB */ + /* Privacy & inactive timeout. */ + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { + UINT_8 ucPreferedChnl = 0; + ENUM_BAND_T eBand = BAND_NULL; + ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; + ENUM_P2P_STATE_T eNextState = P2P_STATE_SCAN; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prP2pFsmInfo->eCurrentState != P2P_STATE_SCAN && + prP2pFsmInfo->eCurrentState != P2P_STATE_IDLE) { + /* Make sure the state is in IDLE state. */ + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + } + prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; + DBGLOG(P2P, INFO, + "NFC:p2pFsmRunEventStartAP,fgIsGOInitialDone[%d]\n", + prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); + + /* 20120118: Moved to p2pFuncSwitchOPMode(). */ + /* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + /* Leave IDLE state. */ + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* sync with firmware */ + /* DBGLOG(P2P, INFO, ("Activate P2P Network.\n")); */ + /* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + /* Key to trigger P2P FSM to allocate channel for AP mode. */ + prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; + + /* Sparse Channel to decide which channel to use. */ + if ((cnmPreferredChannel(prAdapter, + &eBand, + &ucPreferedChnl, + &eSco) == FALSE) && (prP2pConnSettings->ucOperatingChnl == 0)) { + /* Sparse Channel Detection using passive mode. */ + eNextState = P2P_STATE_AP_CHANNEL_DETECT; + } else { + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + +#if 1 + /* 2012-01-27: frog - Channel set from upper layer is the first priority. */ + /* Because the channel & beacon is decided by p2p_supplicant. */ + if (prP2pConnSettings->ucOperatingChnl != 0) { + prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; + prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; + } + + else { + ASSERT(ucPreferedChnl != 0); + prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prP2pSpecificBssInfo->eRfBand = eBand; + } +#else + if (ucPreferedChnl) { + prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prP2pSpecificBssInfo->eRfBand = eBand; + } else { + ASSERT(prP2pConnSettings->ucOperatingChnl != 0); + prP2pSpecificBssInfo->ucPreferredChannel = prP2pConnSettings->ucOperatingChnl; + prP2pSpecificBssInfo->eRfBand = prP2pConnSettings->eBand; + } + +#endif + prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel; + prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + + DBGLOG(P2P, INFO, "p2pFsmRunEventStartAP GO Scan\n"); + } + + /* If channel is specified, use active scan to shorten the scan time. */ + p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, eNextState); + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventStartAP */ + +VOID p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_NETDEV_REGISTER_T prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventNetDeviceRegister\n"); + + prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T) prMsgHdr; + + if (prNetDevRegisterMsg->fgIsEnable) { + p2pSetMode((prNetDevRegisterMsg->ucMode == 1) ? TRUE : FALSE); + + if (p2pLaunch(prAdapter->prGlueInfo)) + ASSERT(prAdapter->fgIsP2PRegistered); + + } else { + if (prAdapter->fgIsP2PRegistered) + p2pRemove(prAdapter->prGlueInfo); + + } + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventNetDeviceRegister */ + +VOID p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_MGMT_FRAME_UPDATE_T prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventUpdateMgmtFrame\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T) prMsgHdr; + + switch (prP2pMgmtFrameUpdateMsg->eBufferType) { + case ENUM_FRAME_TYPE_EXTRA_IE_BEACON: + break; + case ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP: + break; + case ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP: + break; + case ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE: + break; + case ENUM_FRAME_TYPE_BEACON_TEMPLATE: + break; + default: + break; + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventUpdateMgmtFrame */ + +VOID p2pFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_MSG_P2P_BEACON_UPDATE_T prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconUpdate\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) prMsgHdr; + + p2pFuncBeaconUpdate(prAdapter, + prP2pBssInfo, + &prP2pFsmInfo->rBcnContentInfo, + prBcnUpdateMsg->pucBcnHdr, + prBcnUpdateMsg->u4BcnHdrLen, + prBcnUpdateMsg->pucBcnBody, prBcnUpdateMsg->u4BcnBodyLen); + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { + /* AP is created, Beacon Update. */ + /* nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventBeaconUpdate */ + +VOID p2pFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventStopAP\n"); + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) + && (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { + /* AP is created, Beacon Update. */ + + p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); + + DBGLOG(P2P, TRACE, "Stop Beaconing\n"); + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Reset RLM related field of BSSINFO. */ + rlmBssAborted(prAdapter, prP2pBssInfo); + } + /* 20120118: Moved to p2pFuncSwitchOPMode(). */ + /* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + /* Enter IDLE state. */ + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + DBGLOG(P2P, INFO, "Re activate P2P Network.\n"); + nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + + nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); + +#if CFG_SUPPORT_WFD + p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); +#endif + + /* p2pFsmRunEventAbort(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo); */ + p2pFsmStateTransition(prAdapter, prAdapter->rWifiVar.prP2pFsmInfo, P2P_STATE_IDLE); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventStopAP */ + +VOID p2pFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) prMsgHdr; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionRequest\n"); + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + break; + + SET_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Make sure the state is in IDLE state. */ + p2pFsmRunEventAbort(prAdapter, prP2pFsmInfo); + + /* Update connection request information. */ + prConnReqInfo->fgIsConnRequest = TRUE; + COPY_MAC_ADDR(prConnReqInfo->aucBssid, prConnReqMsg->aucBssid); + kalMemCopy(&(prConnReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); + kalMemCopy(prConnReqInfo->aucIEBuf, prConnReqMsg->aucIEBuf, prConnReqMsg->u4IELen); + prConnReqInfo->u4BufLength = prConnReqMsg->u4IELen; + + /* Find BSS Descriptor first. */ + prP2pFsmInfo->prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); + + if (prP2pFsmInfo->prTargetBss == NULL) { + /* Update scan parameter... to scan target device. */ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest,Trigger New Scan\n"); + + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + prScanReqInfo->arScanChannelList[0].ucChannelNum = prConnReqMsg->rChannelInfo.ucChannelNum; + kalMemCopy(&(prScanReqInfo->rSsidStruct), &(prConnReqMsg->rSsid), sizeof(P2P_SSID_STRUCT_T)); + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ + prScanReqInfo->fgIsAbort = TRUE; + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); + } else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = prConnReqMsg->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prConnReqMsg->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prConnReqMsg->eChnlSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; + DBGLOG(P2P, INFO, "p2pFsmRunEventConnectionRequest, Report the Connecting BSS Again.\n"); + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_REQING_CHANNEL); + } + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + + return; + +} /* p2pFsmRunEventConnectionRequest */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to handle Connection Request from Supplicant. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; + /* P_STA_RECORD_T prTargetStaRec = (P_STA_RECORD_T)NULL; */ + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionAbort: Connection Abort.\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) prMsgHdr; + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + { + UINT_8 aucBCBSSID[] = BC_BSSID; + + if (!prP2pBssInfo->prStaRecOfAP) { + DBGLOG(P2P, TRACE, "GO's StaRec is NULL\n"); + break; + } + if (UNEQUAL_MAC_ADDR(prP2pBssInfo->prStaRecOfAP->aucMacAddr, prDisconnMsg->aucTargetID) + && UNEQUAL_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCBSSID)) { + DBGLOG(P2P, TRACE, + "Unequal MAC ADDR [ %pM : %pM ]\n", + prP2pBssInfo->prStaRecOfAP->aucMacAddr, + prDisconnMsg->aucTargetID); + break; + } + + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, NULL, 0, 0, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + + /* Stop rejoin timer if it is started. */ + /* TODO: If it has. */ + + p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, prDisconnMsg->fgSendDeauth, + prDisconnMsg->u2ReasonCode); + + /* prTargetStaRec = prP2pBssInfo->prStaRecOfAP; */ + + /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). */ + /* hit prStaRecOfAP == NULL. */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + prP2pBssInfo->prStaRecOfAP = NULL; + + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + + } + break; + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + /* Search specific client device, and disconnect. */ + /* 1. Send deauthentication frame. */ + /* 2. Indication: Device disconnect. */ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; + + DBGLOG(P2P, TRACE, + "Disconnecting with Target ID: %pM\n", + prDisconnMsg->aucTargetID); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prDisconnMsg->aucTargetID)) { + + DBGLOG(P2P, TRACE, + "Disconnecting: %pM\n", + prCurrStaRec->aucMacAddr); + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, + &prCurrStaRec->rLinkEntry); + + /* Glue layer indication. */ + /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ + + /* Send deauth & do indication. */ + p2pFuncDisconnect(prAdapter, prCurrStaRec, prDisconnMsg->fgSendDeauth, + prDisconnMsg->u2ReasonCode); + + /* prTargetStaRec = prCurrStaRec; */ + + break; + } + } + + } + break; + case OP_MODE_P2P_DEVICE: + default: + ASSERT(FALSE); + break; + } + + } while (FALSE); + + /* 20120830 moved into p2pFuncDisconnect() */ + /* if ((!prDisconnMsg->fgSendDeauth) && (prTargetStaRec)) { */ + /* cnmStaRecFree(prAdapter, prTargetStaRec, TRUE); */ + /* } */ + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventConnectionAbort */ + +VOID p2pFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + + /* TODO: */ + + DBGLOG(P2P, TRACE, "p2pFsmRunEventDissolve\n"); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} + +WLAN_STATUS +p2pFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + DBGLOG(P2P, INFO, "Deauth TX Done Status: %d, seqNo %d\n", + rTxDoneStatus, prMsduInfo->ucTxSeqNum); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, "Station Record NULL, Index:%d\n", prMsduInfo->ucStaRecIndex); + break; + } + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + eOriMediaStatus = prP2pBssInfo->eConnectionState; + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + + /**/ cnmStaRecFree(prAdapter, prStaRec, TRUE); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { + DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + } + + /* Because the eConnectionState is changed before Deauth TxDone. Dont Check eConnectionState */ + /* if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { */ + /* Update Disconnected state to FW. */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + /* } */ + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; +} /* p2pFsmRunEventDeauthTxDone */ + +WLAN_STATUS +p2pFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = (P_P2P_MGMT_TX_REQ_INFO_T) NULL; + BOOLEAN fgIsSuccess = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prMgmtTxReqInfo = &(prP2pFsmInfo->rMgmtTxInfo); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(P2P, INFO, "Mgmt Frame TX Fail, Status: %d, seq NO. %d, Cookie: 0x%llx\n", + rTxDoneStatus, prMsduInfo->ucTxSeqNum, prMgmtTxReqInfo->u8Cookie); + } else { + fgIsSuccess = TRUE; + DBGLOG(P2P, TRACE, "Mgmt Frame TX Done.\n"); + } + + if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + fgIsSuccess, + prMsduInfo->prPacket, (UINT_32) prMsduInfo->u2FrameLength); + + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; + +} /* p2pFsmRunEventMgmtFrameTxDone */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called when JOIN complete message event is received from SAA. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; + P_MSG_JOIN_COMP_T prJoinCompMsg = (P_MSG_JOIN_COMP_T) NULL; + P_SW_RFB_T prAssocRspSwRfb = (P_SW_RFB_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + DBGLOG(P2P, TRACE, "P2P Join Complete\n"); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + if (prP2pFsmInfo == NULL) { + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + prJoinInfo = &(prP2pFsmInfo->rJoinInfo); + if (prMsgHdr == NULL) + return; + prJoinCompMsg = (P_MSG_JOIN_COMP_T) prMsgHdr; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + prStaRec = prJoinCompMsg->prStaRec; + + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prJoinInfo->ucSeqNumOfReqMsg) { + ASSERT(prStaRec == prJoinInfo->prTargetStaRec); + prJoinInfo->fgIsJoinComplete = TRUE; + + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + + /* 4 <1.1> Change FW's Media State immediately. */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if ((prP2pBssInfo->prStaRecOfAP) && (prP2pBssInfo->prStaRecOfAP != prStaRec)) { + cnmStaRecChangeState(prAdapter, prP2pBssInfo->prStaRecOfAP, + STA_STATE_1); + + cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); + + prP2pBssInfo->prStaRecOfAP = NULL; + } + /* 4 <1.3> Update BSS_INFO_T */ + p2pFuncUpdateBssInfoForJOIN(prAdapter, prP2pFsmInfo->prTargetBss, prStaRec, + prAssocRspSwRfb); + + /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + DBGLOG(P2P, INFO, "P2P GC Join Success\n"); + +#if CFG_SUPPORT_P2P_RSSI_QUERY + /* <1.5> Update RSSI if necessary */ + nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, + (INT_8) (RCPI_TO_dBm(prStaRec->ucRCPI)), 0); +#endif + + /* 4 <1.6> Indicate Connected Event to Host immediately. */ + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T */ + /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, */ + /* prStaRec->aucMacAddr); */ + if (prP2pFsmInfo->prTargetBss) + scanReportBss2Cfg80211(prAdapter, OP_MODE_P2P_DEVICE, + prP2pFsmInfo->prTargetBss); + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + &prP2pFsmInfo->rConnReqInfo, + prJoinInfo->aucIEBuf, prJoinInfo->u4BufLength, + prStaRec->u2StatusCode, + WLAN_STATUS_MEDIA_CONNECT); + + } else { + /* Join Fail */ + /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ + if (p2pFuncRetryJOIN(prAdapter, prStaRec, prJoinInfo) == FALSE) { + P_BSS_DESC_T prBssDesc; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + prBssDesc = prP2pFsmInfo->prTargetBss; + + ASSERT(prBssDesc); + ASSERT(prBssDesc->fgIsConnecting); + + prBssDesc->fgIsConnecting = FALSE; + + if (prStaRec->ucJoinFailureCount >= 3) { + + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + &prP2pFsmInfo->rConnReqInfo, + prJoinInfo->aucIEBuf, + prJoinInfo->u4BufLength, + prStaRec->u2StatusCode, + WLAN_STATUS_MEDIA_CONNECT); + } else { + /* Sometime the GO is not ready to response auth. */ + /* Connect it again */ + prP2pFsmInfo->prTargetBss = NULL; + } + DBGLOG(P2P, INFO, "P2P GC Join Failed\n"); + + } + + } + } + } + + if (prAssocRspSwRfb) + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + + if (prP2pFsmInfo->eCurrentState == P2P_STATE_GC_JOIN) { + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* Return to IDLE state. */ + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } else { + /* p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); */ + /* one more scan */ + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_SCAN); + } + } + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + +} /* p2pFsmRunEventJoinComplete */ + +VOID p2pFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) prMsgHdr; + + p2pFuncMgmtFrameRegister(prAdapter, + prMgmtFrameRegister->u2FrameType, + prMgmtFrameRegister->fgIsRegister, &prP2pFsmInfo->u4P2pPacketFilter); + + } while (FALSE); + + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + + return; + +} /* p2pFsmRunEventMgmtFrameRegister */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when RX deauthentication frame from the AIR. +* If we are under STA mode, we would go back to P2P Device. +* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) +{ + + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + UINT_16 u2ReasonCode = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + if (prStaRec == NULL) + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + if (!prStaRec) + break; + + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + if (prStaRec->ucStaState == STA_STATE_1) + break; + + DBGLOG(P2P, TRACE, "RX Deauth\n"); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (authProcessRxDeauthFrame(prSwRfb, + prStaRec->aucMacAddr, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; + UINT_16 u2IELength = 0; + + if (prP2pBssInfo->prStaRecOfAP != prStaRec) + break; + + prStaRec->u2ReasonCode = u2ReasonCode; + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, + prDeauthFrame->aucInfoElem, u2IELength, u2ReasonCode, + WLAN_STATUS_MEDIA_DISCONNECT); + + prP2pBssInfo->prStaRecOfAP = NULL; + DBGLOG(P2P, INFO, "GC RX Deauth Reason: %d\n", u2ReasonCode); + + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + } + break; + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (authProcessRxDeauthFrame(prSwRfb, + prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, + &prCurrStaRec->rLinkEntry); + + /* Indicate to Host. */ + /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ + + /* Indicate disconnect to Host. */ + DBGLOG(P2P, INFO, "GO RX Deauth Reason: %d\n", u2ReasonCode); + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + + break; + } + } + } + break; + case OP_MODE_P2P_DEVICE: + default: + /* Findout why someone sent deauthentication frame to us. */ + ASSERT(FALSE); + break; + } + + DBGLOG(P2P, TRACE, "Deauth Reason:%d\n", u2ReasonCode); + + } while (FALSE); +} /* p2pFsmRunEventRxDeauthentication */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is call when RX deauthentication frame from the AIR. +* If we are under STA mode, we would go back to P2P Device. +* If we are under AP mode, we would stay in AP mode until disconnect event from HOST. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + UINT_16 u2ReasonCode = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo == NULL) + break; + + if (prStaRec == NULL) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (prStaRec == NULL) + break; + } + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prStaRec->ucStaState == STA_STATE_1) + break; + + DBGLOG(P2P, TRACE, "RX Disassoc\n"); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; + UINT_16 u2IELength = 0; + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + if (prP2pBssInfo->prStaRecOfAP != prStaRec) + break; + + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, + prDisassocFrame->aucInfoElem, + u2IELength, prStaRec->u2ReasonCode, + WLAN_STATUS_MEDIA_DISCONNECT); + + prP2pBssInfo->prStaRecOfAP = NULL; + + DBGLOG(P2P, INFO, "GC RX Disassoc Reason %d\n", prStaRec->u2ReasonCode); + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, prStaRec->u2ReasonCode); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + + } + break; + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + prCurrStaRec = LINK_ENTRY(prLinkEntry, STA_RECORD_T, rLinkEntry); + + ASSERT(prCurrStaRec); + + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prStaRec->aucMacAddr)) { + + /* Remove STA from client list. */ + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, + &prCurrStaRec->rLinkEntry); + + /* Indicate to Host. */ + /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); */ + + /* Indicate disconnect to Host. */ + DBGLOG(P2P, INFO, "GO RX Disassoc Reason %d\n", u2ReasonCode); + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, u2ReasonCode); + + break; + } + } + } + break; + case OP_MODE_P2P_DEVICE: + default: + ASSERT(FALSE); + break; + } + + } while (FALSE); +} /* p2pFsmRunEventRxDisassociation */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called when a probe request frame is received. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is accepted & need cancel scan request. +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFsmRunEventRxProbeResponseFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_BSS_DESC_T prBssDesc) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (prBssDesc != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + /* There is a connection request. */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T) prSwRfb->pvHeader; + + } while (FALSE); + +} /* p2pFsmRunEventRxProbeResponseFrame */ + +VOID p2pFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventBeaconTimeout: Beacon Timeout\n"); + + /* Only client mode would have beacon lost event. */ + ASSERT(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, NULL, 0, REASON_CODE_DISASSOC_INACTIVITY, + WLAN_STATUS_MEDIA_DISCONNECT); + + if (prP2pBssInfo->prStaRecOfAP != NULL) { + P_STA_RECORD_T prStaRec = prP2pBssInfo->prStaRecOfAP; + + prP2pBssInfo->prStaRecOfAP = NULL; + + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_DISASSOC_LEAVING_BSS); + + /* 20120830 moved into p2pFuncDisconnect() */ + /* cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP, TRUE); */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + SET_NET_PWR_STATE_IDLE(prAdapter, NETWORK_TYPE_P2P_INDEX); + p2pFsmStateTransition(prAdapter, prP2pFsmInfo, P2P_STATE_IDLE); + + } + } + } while (FALSE); + +} /* p2pFsmRunEventBeaconTimeout */ + +VOID p2pFsmRunEventExtendListen(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = NULL; + struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prExtListenMsg = NULL; + + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prExtListenMsg = (struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *) prMsgHdr; + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + ASSERT_BREAK(prP2pFsmInfo); + + if (!prExtListenMsg->wait) { + DBGLOG(P2P, INFO, "reset listen interval\n"); + prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + if (prP2pFsmInfo && (prP2pFsmInfo->eListenExted == P2P_DEV_NOT_EXT_LISTEN)) { + DBGLOG(P2P, INFO, "try to ext listen, p2p state: %d\n", prP2pFsmInfo->eCurrentState); + if (prP2pFsmInfo->eCurrentState == P2P_STATE_CHNL_ON_HAND) { + DBGLOG(P2P, INFO, "here to ext listen interval\n"); + prP2pFsmInfo->eListenExted = P2P_DEV_EXT_LISTEN_ING; + } + } + if (prMsgHdr) + cnmMemFree(prAdapter, prMsgHdr); +} /* p2pFsmRunEventUpdateMgmtFrame */ + +#if CFG_SUPPORT_WFD +VOID p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; + WLAN_STATUS rStatus; + + DBGLOG(P2P, INFO, "p2pFsmRunEventWfdSettingUpdate\n"); + + do { + ASSERT_BREAK((prAdapter != NULL)); + + if (prMsgHdr != NULL) { + prMsgWfdCfgSettings = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) prMsgHdr; + prWfdCfgSettings = prMsgWfdCfgSettings->prWfdCfgSettings; + } else { + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + } + + DBGLOG(P2P, INFO, "WFD Enalbe %x info %x state %x flag %x adv %x\n", + prWfdCfgSettings->ucWfdEnable, + prWfdCfgSettings->u2WfdDevInfo, + (UINT_32) prWfdCfgSettings->u4WfdState, + (UINT_32) prWfdCfgSettings->u4WfdFlag, + (UINT_32) prWfdCfgSettings->u4WfdAdvancedFlag); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_WFD_CTRL, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(WFD_CFG_SETTINGS_T), /* u4SetQueryInfoLen */ + (PUINT_8) prWfdCfgSettings, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + } while (FALSE); + + return; + +} + +/* p2pFsmRunEventWfdSettingUpdate */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pGenerateP2P_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec != NULL) { + if (IS_STA_P2P_TYPE(prStaRec)) { + /* Do nothing */ + /* TODO: */ + } + } + + } while (FALSE); + + return; + +} /* end of p2pGenerateP2P_IEForAssocReq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Probe Request frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pGenerateP2P_IEForProbeReq(IN P_ADAPTER_T prAdapter, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + ASSERT(prAdapter); + ASSERT(pucBuf); + + /* TODO: */ + + return; + +} /* end of p2pGenerateP2P_IEForProbReq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to calculate P2P IE length for Beacon frame. +* +* @param[in] eNetTypeIndex Specify which network +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return The length of P2P IE added +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +p2pCalculateP2P_IELenForProbeReq(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) + return 0; + /* TODO: */ + + return 0; + +} /* end of p2pCalculateP2P_IELenForProbeReq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Event of Tx Fail of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pRunEventAAATxFail(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + + p2pFuncDisconnect(prAdapter, prStaRec, FALSE, REASON_CODE_UNSPECIFIED); + + /* 20120830 moved into p2puUncDisconnect. */ + /* cnmStaRecFree(prAdapter, prStaRec, TRUE); */ + +} /* p2pRunEventAAATxFail */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS p2pRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaState; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + eOriMediaState = prP2pBssInfo->eConnectionState; + + if (prStaRec != NULL) + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + else + break; + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || + kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + + bssAddStaRecToClientList(prAdapter, prP2pBssInfo, prStaRec); + + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem > P2P_MAXIMUM_CLIENT_COUNT || + kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + DBGLOG(P2P, INFO, "P2P GO Join Complete\n"); + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* Update Connected state to FW. */ + if (eOriMediaState != prP2pBssInfo->eConnectionState) + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + } while (FALSE); + + return rStatus; +} /* p2pRunEventAAAComplete */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will indicate the Event of Successful Completion of AAA Module. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS p2pRunEventAAASuccess(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + /* Glue layer indication. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, TRUE); + + } while (FALSE); + + return rStatus; +} /* p2pRunEventAAASuccess */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS p2pRxPublicActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_P2P_PUBLIC_ACTION_FRAME_T prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + ASSERT(prSwRfb); + ASSERT(prAdapter); + + prPublicActionFrame = (P_P2P_PUBLIC_ACTION_FRAME_T) prSwRfb->pvHeader; + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + DBGLOG(P2P, TRACE, "RX Public Action Frame Token:%d.\n", prPublicActionFrame->ucDialogToken); + + if (prPublicActionFrame->ucCategory != CATEGORY_PUBLIC_ACTION) + return rWlanStatus; + + switch (prPublicActionFrame->ucAction) { + case ACTION_PUBLIC_WIFI_DIRECT: + break; + case ACTION_GAS_INITIAL_REQUEST: + case ACTION_GAS_INITIAL_RESPONSE: + case ACTION_GAS_COMEBACK_REQUEST: + case ACTION_GAS_COMEBACK_RESPONSE: + break; + default: + break; + } + + return rWlanStatus; +} /* p2pRxPublicActionFrame */ + +WLAN_STATUS p2pRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_P2P_ACTION_FRAME_T prP2pActionFrame = (P_P2P_ACTION_FRAME_T) NULL; + UINT_8 aucOui[3] = VENDOR_OUI_WFA_SPECIFIC; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pActionFrame = (P_P2P_ACTION_FRAME_T) prSwRfb->pvHeader; + + if (prP2pActionFrame->ucCategory != CATEGORY_VENDOR_SPECIFIC_ACTION) { + DBGLOG(P2P, TRACE, "RX Action Frame but not vendor specific.\n"); + break; + } + + if ((prP2pActionFrame->ucOuiType != VENDOR_OUI_TYPE_P2P) || + (prP2pActionFrame->aucOui[0] != aucOui[0]) || + (prP2pActionFrame->aucOui[1] != aucOui[1]) || (prP2pActionFrame->aucOui[2] != aucOui[2])) { + DBGLOG(P2P, TRACE, "RX Vendor Specific Action Frame but not P2P Type or not WFA OUI.\n"); + break; + } + + } while (FALSE); + + return rWlanStatus; +} /* p2pRxActionFrame */ + +VOID +p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, + UINT_8 ucNetTypeIndex, P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + UINT_32 i; + BOOLEAN fgNoaAttrExisted = FALSE; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIndex]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + prP2pSpecificBssInfo->fgEnableOppPS = prEventUpdateNoaParam->fgEnableOppPS; + prP2pSpecificBssInfo->u2CTWindow = prEventUpdateNoaParam->u2CTWindow; + prP2pSpecificBssInfo->ucNoAIndex = prEventUpdateNoaParam->ucNoAIndex; + prP2pSpecificBssInfo->ucNoATimingCount = prEventUpdateNoaParam->ucNoATimingCount; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->fgEnableOppPS; + + DBGLOG(P2P, INFO, "Update NoA Count=%d.\n", prEventUpdateNoaParam->ucNoATimingCount); + + ASSERT(prP2pSpecificBssInfo->ucNoATimingCount <= P2P_MAXIMUM_NOA_COUNT); + + for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { + /* in used */ + prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse = prEventUpdateNoaParam->arEventNoaTiming[i].fgIsInUse; + /* count */ + prP2pSpecificBssInfo->arNoATiming[i].ucCount = prEventUpdateNoaParam->arEventNoaTiming[i].ucCount; + /* duration */ + prP2pSpecificBssInfo->arNoATiming[i].u4Duration = prEventUpdateNoaParam->arEventNoaTiming[i].u4Duration; + /* interval */ + prP2pSpecificBssInfo->arNoATiming[i].u4Interval = prEventUpdateNoaParam->arEventNoaTiming[i].u4Interval; + /* start time */ + prP2pSpecificBssInfo->arNoATiming[i].u4StartTime = + prEventUpdateNoaParam->arEventNoaTiming[i].u4StartTime; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse; + } + + prP2pSpecificBssInfo->fgIsNoaAttrExisted = fgNoaAttrExisted; + + /* update beacon content by the change */ + bssUpdateBeaconContent(prAdapter, ucNetTypeIndex); +} + +#endif /* CFG_ENABLE_WIFI_DIRECT */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c new file mode 100644 index 0000000000000..586a74721b3bf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_func.c @@ -0,0 +1,3796 @@ +#include "precomp.h" +#include + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wformat" +#endif + +APPEND_VAR_ATTRI_ENTRY_T txAssocRspAttributesTable[] = { + {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS), NULL, p2pFuncAppendAttriStatusForAssocRsp} /* 0 */ + , {(P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING), NULL, p2pFuncAppendAttriExtListenTiming} /* 8 */ +}; + +APPEND_VAR_IE_ENTRY_T txProbeRspIETable[] = { + {(ELEM_HDR_LEN + (RATE_NUM - ELEM_MAX_LEN_SUP_RATES)), NULL, bssGenerateExtSuppRate_IE} /* 50 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE} /* 42 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE} /* 45 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE} /* 61 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE} /* 48 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE} /* 74 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE} /* 127 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE} /* 221 */ + , {(ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE} /* 221 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Function for requesting scan. There is an option to do ACTIVE or PASSIVE scan. +* +* @param eScanType - Specify the scan type of the scan request. It can be an ACTIVE/PASSIVE +* Scan. +* eChannelSet - Specify the preferred channel set. +* A FULL scan would request a legacy full channel normal scan.(usually ACTIVE). +* A P2P_SOCIAL scan would scan 1+6+11 channels.(usually ACTIVE) +* A SPECIFIC scan would only 1/6/11 channels scan. (Passive Listen/Specific Search) +* ucChannelNum - A specific channel number. (Only when channel is specified) +* eBand - A specific band. (Only when channel is specified) +* +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + + P_MSG_SCN_SCAN_REQ prScanReq = (P_MSG_SCN_SCAN_REQ) NULL; + /*NFC Beam + Indication */ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + BOOLEAN fgIsPureAP = FALSE; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; + + DEBUGFUNC("p2pFuncRequestScan()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); + + if (prScanReqInfo->eChannelSet == SCAN_CHANNEL_SPECIFIED) { + ASSERT_BREAK(prScanReqInfo->ucNumChannelList > 0); + DBGLOG(P2P, LOUD, + "P2P Scan Request Channel:%d\n", prScanReqInfo->arScanChannelList[0].ucChannelNum); + } + + prScanReq = (P_MSG_SCN_SCAN_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + if (!prScanReq) { + ASSERT(0); /* Can't trigger SCAN FSM */ + break; + } + + prScanReq->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_REQ; + prScanReq->ucSeqNum = ++prScanReqInfo->ucSeqNumOfScnMsg; + prScanReq->ucNetTypeIndex = (UINT_8) NETWORK_TYPE_P2P_INDEX; + prScanReq->eScanType = prScanReqInfo->eScanType; + prScanReq->eScanChannel = prScanReqInfo->eChannelSet; + prScanReq->u2IELen = 0; + + /* Copy IE for Probe Request. */ + if (prScanReqInfo->u4BufLength > MAX_IE_LENGTH) + prScanReqInfo->u4BufLength = MAX_IE_LENGTH; + kalMemCopy(prScanReq->aucIE, prScanReqInfo->aucIEBuf, prScanReqInfo->u4BufLength); + prScanReq->u2IELen = (UINT_16) prScanReqInfo->u4BufLength; + + prScanReq->u2ChannelDwellTime = prScanReqInfo->u2PassiveDewellTime; + + switch (prScanReqInfo->eChannelSet) { + case SCAN_CHANNEL_SPECIFIED: + { + UINT_32 u4Idx = 0; + P_RF_CHANNEL_INFO_T prDomainInfo = + (P_RF_CHANNEL_INFO_T) prScanReqInfo->arScanChannelList; + UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; + + + if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) + prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; + + for (u4Idx = 0; u4Idx < prScanReqInfo->ucNumChannelList; u4Idx++) { + prScanReq->arChnlInfoList[u4Idx].ucChannelNum = prDomainInfo->ucChannelNum; + prScanReq->arChnlInfoList[u4Idx].eBand = prDomainInfo->eBand; + prDomainInfo++; + } + + prScanReq->ucChannelListNum = prScanReqInfo->ucNumChannelList; + + /*NFC Beam + Indication */ + prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; + if (prChnlReqInfo->eChannelReqType == CHANNEL_REQ_TYPE_GO_START_BSS && + prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + !fgIsPureAP) { + prScanReq->ucChannelListNum = 1; + prScanReq->arChnlInfoList[0].ucChannelNum = prChnlReqInfo->ucReqChnlNum; + prScanReq->arChnlInfoList[0].eBand = prChnlReqInfo->eBand; + + DBGLOG(P2P, INFO, + "NFC:GO Skip Scan and Only Froce on %s[%d]\n", + prChnlReqInfo->eBand == 1 ? "2.4G" : "5G", + prChnlReqInfo->ucReqChnlNum); + } + + COPY_SSID(prScanReq->aucSSID, + prScanReq->ucSSIDLength, + prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); + + /* For compatible. */ + if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, + prScanReq->aucSSID, prScanReq->ucSSIDLength)) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } else if (prScanReq->ucSSIDLength != 0) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + + } + break; + + case SCAN_CHANNEL_FULL: + { + UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; + + COPY_SSID(prScanReq->aucSSID, + prScanReq->ucSSIDLength, + prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); + + /* For compatible. */ + if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, + prScanReq->aucSSID, prScanReq->ucSSIDLength)) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } else if (prScanReq->ucSSIDLength != 0) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + } + break; + + case SCAN_CHANNEL_2G4: + { + UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; + + COPY_SSID(prScanReq->aucSSID, + prScanReq->ucSSIDLength, + prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); + + /* For compatible. */ + if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, + prScanReq->aucSSID, prScanReq->ucSSIDLength)) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } else if (prScanReq->ucSSIDLength != 0) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + } + break; + + case SCAN_CHANNEL_P2P_SOCIAL: + { + UINT_8 aucP2pSsid[] = P2P_WILDCARD_SSID; + + COPY_SSID(prScanReq->aucSSID, + prScanReq->ucSSIDLength, + prScanReqInfo->rSsidStruct.aucSsid, prScanReqInfo->rSsidStruct.ucSsidLen); + + /* For compatible. */ + if (EQUAL_SSID(aucP2pSsid, P2P_WILDCARD_SSID_LEN, + prScanReq->aucSSID, prScanReq->ucSSIDLength)) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } else if (prScanReq->ucSSIDLength != 0) { + prScanReq->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + } + break; + default: + /* Currently there is no other scan channel set. */ + ASSERT(FALSE); + break; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReq, MSG_SEND_METHOD_BUF); + + } while (FALSE); + +} /* p2pFuncRequestScan */ + +VOID p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN P_P2P_SCAN_REQ_INFO_T prScanInfo) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanInfo != NULL)); + + if (!prScanInfo->fgIsScanRequest) + break; + + if (prScanInfo->ucSeqNumOfScnMsg) { + /* There is a channel privilege on hand. */ + DBGLOG(P2P, TRACE, "P2P Cancel Scan\n"); + + prScanCancelMsg = + (P_MSG_SCN_SCAN_CANCEL) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + /* Buffer not enough, can not cancel scan request. */ + DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); + ASSERT(FALSE); + break; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; + prScanCancelMsg->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prScanCancelMsg->ucSeqNum = prScanInfo->ucSeqNumOfScnMsg++; + prScanCancelMsg->fgIsChannelExt = FALSE; + prScanInfo->fgIsScanRequest = FALSE; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanCancelMsg, MSG_SEND_METHOD_BUF); + + } + + } while (FALSE); + +} /* p2pFuncCancelScan */ + +VOID +p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_OP_MODE_T eOpMode, IN BOOLEAN fgSyncToFW) +{ + if (!prAdapter) + return; + if (!prAdapter->prGlueInfo) + return; + if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) + return; + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (eOpMode < OP_MODE_NUM)); + + if (prP2pBssInfo->eCurrentOPMode != eOpMode) { + DBGLOG(P2P, TRACE, + "p2pFuncSwitchOPMode: Switch to from %d, to %d.\n", prP2pBssInfo->eCurrentOPMode, + eOpMode); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + p2pFuncDissolve(prAdapter, prP2pBssInfo, TRUE, REASON_CODE_DEAUTH_LEAVING_BSS); + + p2pFsmRunEventStopAP(prAdapter, NULL); + break; + default: + break; + } + + prP2pBssInfo->eIntendOPMode = eOpMode; + prP2pBssInfo->eCurrentOPMode = eOpMode; + switch (eOpMode) { + case OP_MODE_INFRASTRUCTURE: + DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to Client.\n"); + case OP_MODE_ACCESS_POINT: +/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ +/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +/* } */ + + /* Change interface address. */ + if (eOpMode == OP_MODE_ACCESS_POINT) { + DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to AP.\n"); + prP2pBssInfo->ucSSIDLen = 0; + } + + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucInterfaceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucInterfaceAddress); + + break; + case OP_MODE_P2P_DEVICE: + { + /* Change device address. */ + DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch back to P2P Device.\n"); + +/* if (!IS_BSS_ACTIVE(prP2pBssInfo)) { */ +/* SET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +/* } */ + + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAdapter->rWifiVar.aucDeviceAddress); + + } + break; + default: +/* if (IS_BSS_ACTIVE(prP2pBssInfo)) { */ +/* UNSET_NET_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + +/* nicDeactivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +/* } */ + ASSERT(FALSE); + break; + } + + if (1) { + P2P_DISCONNECT_INFO rP2PDisInfo; + + rP2PDisInfo.ucRole = 2; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_P2P_ABORT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(P2P_DISCONNECT_INFO), (PUINT_8)&rP2PDisInfo, NULL, 0); + } + + DBGLOG(P2P, TRACE, + "The device address is changed to %pM\n", + prP2pBssInfo->aucOwnMacAddr); + DBGLOG(P2P, TRACE, "The BSSID is changed to %pM\n", prP2pBssInfo->aucBSSID); + + /* Update BSS INFO to FW. */ + if ((fgSyncToFW) && (eOpMode != OP_MODE_ACCESS_POINT)) + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } while (FALSE); + +} /* p2pFuncSwitchOPMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will start a P2P Group Owner and send Beacon Frames. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncStartGO(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN PUINT_8 pucSsidBuf, + IN UINT_8 ucSsidLen, + IN UINT_8 ucChannelNum, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN BOOLEAN fgIsPureAP) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL)); + + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); + + prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 1; + DBGLOG(P2P, INFO, + "p2pFuncStartGO:NFC Done[%d]\n", + prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone); + /* AP mode started. */ + p2pFuncSwitchOPMode(prAdapter, prBssInfo, prBssInfo->eIntendOPMode, FALSE); + + prBssInfo->eIntendOPMode = OP_MODE_NUM; + + /* 4 <1.1> Assign SSID */ + COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, pucSsidBuf, ucSsidLen); + + DBGLOG(P2P, TRACE, "GO SSID:%s\n", prBssInfo->aucSSID); + + /* 4 <1.2> Clear current AP's STA_RECORD_T and current AID */ + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + prBssInfo->u2AssocId = 0; + + /* 4 <1.3> Setup Channel, Band and Phy Attributes */ + prBssInfo->ucPrimaryChannel = ucChannelNum; + prBssInfo->eBand = eBand; + prBssInfo->eBssSCO = eSco; + + DBGLOG(P2P, TRACE, "GO Channel:%d\n", ucChannelNum); + + if (prBssInfo->eBand == BAND_5G) { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AN); + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; + } else if (fgIsPureAP) { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11BGN); + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; + } else { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11GN); + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + } + + prBssInfo->ucNonHTBasicPhyType = (UINT_8) + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode].u2BSSBasicRateSet; + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType].u2SupportedRateSet; + + if (prBssInfo->ucAllSupportedRatesLen == 0) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + } + /* 4 <1.5> Setup MIB for current BSS */ + prBssInfo->u2ATIMWindow = 0; + prBssInfo->ucBeaconTimeoutCount = 0; + + /* 3 <2> Update BSS_INFO_T common part */ +#if CFG_SUPPORT_AAA + if (!fgIsPureAP) { + prBssInfo->fgIsProtection = TRUE; /* Always enable protection at P2P GO */ + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); + } else { + if (kalP2PGetCipher(prAdapter->prGlueInfo)) + prBssInfo->fgIsProtection = TRUE; + } + + /* 20120106 frog: I want separate OP_Mode & Beacon TX Function. */ + /* p2pFuncSwitchOPMode(prAdapter, prBssInfo, OP_MODE_ACCESS_POINT, FALSE); */ + + bssInitForAP(prAdapter, prBssInfo, FALSE); + + nicQmUpdateWmmParms(prAdapter, NETWORK_TYPE_P2P_INDEX); +#endif /* CFG_SUPPORT_AAA */ + + /* 3 <3> Set MAC HW */ + /* 4 <3.1> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + + /* 4 <3.2> Reset HW TSF Update Mode and Beacon Mode */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* 4 <3.3> Update Beacon again for network phy type confirmed. */ + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); + +#if 0 /* CFG_SUPPORT_HOTSPOT_OPTIMIZATION */ + { + CMD_HOTSPOT_OPTIMIZATION_CONFIG arHotspotOptimizationCfg; + + arHotspotOptimizationCfg.fgHotspotOptimizationEn = TRUE; + arHotspotOptimizationCfg.u4Level = (0x3) << 8 | 0x5; + wlanoidSendSetQueryP2PCmd(prAdapter, + CMD_ID_SET_HOTSPOT_OPTIMIZATION, + TRUE, + FALSE, + TRUE, + NULL, + NULL, + sizeof(CMD_HOTSPOT_OPTIMIZATION_CONFIG), + (PUINT_8)&arHotspotOptimizationCfg, NULL, 0); + } +#endif + + /* 4 <3.4> Setup BSSID */ + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + + } while (FALSE); + +} /* p2pFuncStartGO() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to inform CNM that channel privilege +* has been released +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + P_MSG_CH_ABORT_T prMsgChRelease = (P_MSG_CH_ABORT_T) NULL; + + DEBUGFUNC("p2pFuncReleaseCh()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + if (!prChnlReqInfo->fgIsChannelRequested) + break; + + DBGLOG(P2P, TRACE, "P2P Release Channel\n"); + prChnlReqInfo->fgIsChannelRequested = FALSE; + + /* 1. return channel privilege to CNM immediately */ + prMsgChRelease = (P_MSG_CH_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_ABORT_T)); + if (!prMsgChRelease) { + ASSERT(0); /* Can't release Channel to CNM */ + break; + } + + prMsgChRelease->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChRelease->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prMsgChRelease->ucTokenID = prChnlReqInfo->ucSeqNumOfChReq++; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChRelease, MSG_SEND_METHOD_BUF); + + } while (FALSE); + +} /* p2pFuncReleaseCh */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of CHANNEL_REQ_JOIN Initial. Enter CHANNEL_REQ_JOIN State. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + P_MSG_CH_REQ_T prMsgChReq = (P_MSG_CH_REQ_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_CH_REQ_T)); + + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel acquiring */ + break; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + prMsgChReq->ucTokenID = ++prChnlReqInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + if (prChnlReqInfo->u4MaxInterval < P2P_EXT_LISTEN_TIME_MS) + prMsgChReq->u4MaxInterval = P2P_EXT_LISTEN_TIME_MS; + else + prMsgChReq->u4MaxInterval = prChnlReqInfo->u4MaxInterval; + + prMsgChReq->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; + prMsgChReq->eRfSco = prChnlReqInfo->eChnlSco; + prMsgChReq->eRfBand = prChnlReqInfo->eBand; + + kalMemZero(prMsgChReq->aucBSSID, MAC_ADDR_LEN); + + /* Channel request join BSSID. */ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChReq, MSG_SEND_METHOD_BUF); + + prChnlReqInfo->fgIsChannelRequested = TRUE; + + } while (FALSE); + +} /* p2pFuncAcquireCh */ + +#if 0 +WLAN_STATUS +p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBcnHdr, + IN UINT_32 u4HdrLen, + IN PUINT_8 pucBcnBody, IN UINT_32 u4BodyLen, IN UINT_32 u4DtimPeriod, IN UINT_32 u4BcnInterval) +{ + WLAN_STATUS rResultStatus = WLAN_STATUS_INVALID_DATA; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; + PUINT_8 pucTIMBody = (PUINT_8) NULL; + UINT_16 u2FrameLength = 0, UINT_16 u2OldBodyLen = 0; + UINT_8 aucIEBuf[MAX_IE_LENGTH]; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prBcnMsduInfo = prP2pBssInfo->prBeacon ASSERT_BREAK(prBcnMsduInfo != NULL); + + /* TODO: Find TIM IE pointer. */ + prBcnFrame = prBcnMsduInfo->prPacket; + + ASSERT_BREAK(prBcnFrame != NULL); + + do { + /* Ori header. */ + UINT_16 u2IELength = 0, u2Offset = 0; + PUINT_8 pucIEBuf = prBcnFrame->aucInfoElem; + + u2IELength = prBcnMsduInfo->u2FrameLength - prBcnMsduInfo->ucMacHeaderLength; + + IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { + if ((IE_ID(pucIEBuf) == ELEM_ID_TIM) || ((IE_ID(pucIEBuf) > ELEM_ID_IBSS_PARAM_SET))) { + pucTIMBody = pucIEBuf; + break; + } + u2FrameLength += IE_SIZE(pucIEBuf); + } + + if (pucTIMBody == NULL) + pucTIMBody = pucIEBuf; + + /* Body not change. */ + u2OldBodyLen = (UINT_16) ((UINT_32) pucTIMBody - (UINT_32) prBcnFrame->aucInfoElem); + /* Move body. */ + kalMemCmp(aucIEBuf, pucTIMBody, u2OldBodyLen); + } while (FALSE); + + if (pucBcnHdr) { + kalMemCopy(prBcnMsduInfo->prPacket, pucBcnHdr, u4HdrLen); + pucTIMBody = (PUINT_8) ((UINT_32) prBcnMsduInfo->prPacket + u4HdrLen); + prBcnMsduInfo->ucMacHeaderLength = (WLAN_MAC_MGMT_HEADER_LEN + + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)); + u2FrameLength = u4HdrLen; /* Header + Partial Body. */ + } else { + /* Header not change. */ + u2FrameLength += prBcnMsduInfo->ucMacHeaderLength; + } + + if (pucBcnBody) { + kalMemCopy(pucTIMBody, pucBcnBody, u4BodyLen); + u2FrameLength += (UINT_16) u4BodyLen; + } else { + kalMemCopy(pucTIMBody, aucIEBuf, u2OldBodyLen); + u2FrameLength += u2OldBodyLen; + } + + /* Frame Length */ + prBcnMsduInfo->u2FrameLength = u2FrameLength; + prBcnMsduInfo->fgIs802_11 = TRUE; + prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + prP2pBssInfo->u2BeaconInterval = (UINT_16) u4BcnInterval; + prP2pBssInfo->ucDTIMPeriod = (UINT_8) u4DtimPeriod; + prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; + prBcnMsduInfo->ucPacketType = 3; + rResultStatus = nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + NETWORK_TYPE_P2P_INDEX, + prP2pBssInfo->u2CapInfo, + (PUINT_8) prBcnFrame->aucInfoElem, + prBcnMsduInfo->u2FrameLength - + OFFSET_OF(WLAN_BEACON_FRAME_T, + aucInfoElem)); + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + /* AP is created, Beacon Update. */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } while (FALSE); + return rResultStatus; +} /* p2pFuncBeaconUpdate */ + +#else +WLAN_STATUS + p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN PUINT_8 pucNewBcnHdr, IN UINT_32 u4NewHdrLen, IN PUINT_8 pucNewBcnBody, IN UINT_32 u4NewBodyLen) +{ +WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; +P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; +P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T) NULL; +PUINT_8 pucIEBuf = (PUINT_8) NULL; +PUINT_8 paucIEBuf = (PUINT_8) NULL;/*[MAX_IE_LENGTH]; aucIEBuf*/ + +do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && (prBcnUpdateInfo != NULL)); + + prBcnMsduInfo = prP2pBssInfo->prBeacon; + +#if DBG + if (prBcnUpdateInfo->pucBcnHdr != NULL) { + ASSERT((UINT_32) prBcnUpdateInfo->pucBcnHdr == + ((UINT_32) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD)); + } + + if (prBcnUpdateInfo->pucBcnBody != NULL) { + ASSERT((UINT_32) prBcnUpdateInfo->pucBcnBody == + ((UINT_32) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen)); + } +#endif + prBcnFrame = (P_WLAN_BEACON_FRAME_T) ((ULONG) prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD); + + if (!pucNewBcnBody) { + /* Old body. */ + pucNewBcnBody = prBcnUpdateInfo->pucBcnBody; + ASSERT(u4NewBodyLen == 0); + u4NewBodyLen = prBcnUpdateInfo->u4BcnBodyLen; + } else { + prBcnUpdateInfo->u4BcnBodyLen = u4NewBodyLen; + } + + paucIEBuf = kalMemAlloc(MAX_IE_LENGTH, VIR_MEM_TYPE); + if (paucIEBuf == NULL) { + DBGLOG(P2P, TRACE, "p2p alloc paucIEBuf fail\n"); + return WLAN_STATUS_FAILURE; + } + + /* Temp buffer body part. */ + kalMemCopy(paucIEBuf, pucNewBcnBody, u4NewBodyLen); + + if (pucNewBcnHdr) { + kalMemCopy(prBcnFrame, pucNewBcnHdr, u4NewHdrLen); + prBcnUpdateInfo->pucBcnHdr = (PUINT_8) prBcnFrame; + prBcnUpdateInfo->u4BcnHdrLen = u4NewHdrLen; + } + + pucIEBuf = (PUINT_8) ((ULONG) prBcnUpdateInfo->pucBcnHdr + (UINT_32) prBcnUpdateInfo->u4BcnHdrLen); + kalMemCopy(pucIEBuf, paucIEBuf, u4NewBodyLen); + kalMemFree(paucIEBuf, VIR_MEM_TYPE, MAX_IE_LENGTH); + prBcnUpdateInfo->pucBcnBody = pucIEBuf; + + /* Frame Length */ + prBcnMsduInfo->u2FrameLength = (UINT_16) (prBcnUpdateInfo->u4BcnHdrLen + prBcnUpdateInfo->u4BcnBodyLen); + + prBcnMsduInfo->ucPacketType = 3; + prBcnMsduInfo->fgIs802_11 = TRUE; + prBcnMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + + /* Update BSS INFO related information. */ + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prBcnFrame->aucSrcAddr); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prBcnFrame->aucBSSID); + prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; + + p2pFuncParseBeaconContent(prAdapter, + prP2pBssInfo, + (PUINT_8) prBcnFrame->aucInfoElem, + (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); + +#if 1 + /* bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); */ +#else + nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + NETWORK_TYPE_P2P_INDEX, + prBcnFrame->u2CapInfo, + (PUINT_8) prBcnFrame->aucInfoElem, + (prBcnMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); +#endif +} while (FALSE); + +return rWlanStatus; +} /* p2pFuncBeaconUpdate */ + +#endif + +/* TODO: We do not apply IE in deauth frame set from upper layer now. */ +WLAN_STATUS +p2pFuncDeauth(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucPeerMacAddr, + IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDeauth) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + BOOLEAN fgIsStaFound = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + + prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); + fgIsStaFound = TRUE; + break; + } + } + + } + break; + case OP_MODE_INFRASTRUCTURE: + ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); + if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) + break; + prP2pBssInfo->prStaRecOfAP = NULL; + fgIsStaFound = TRUE; + break; + default: + break; + } + + if (fgIsStaFound) + p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDeauth, u2ReasonCode); + + rWlanStatus = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncDeauth */ + +/* TODO: We do not apply IE in disassoc frame set from upper layer now. */ +WLAN_STATUS +p2pFuncDisassoc(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucPeerMacAddr, + IN UINT_16 u2ReasonCode, IN PUINT_8 pucIEBuf, IN UINT_16 u2IELen, IN BOOLEAN fgSendDisassoc) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prCliStaRec = (P_STA_RECORD_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + BOOLEAN fgIsStaFound = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucPeerMacAddr != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + prCliStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, pucPeerMacAddr); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + { + P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + + prStaRecOfClientList = &(prP2pBssInfo->rStaRecOfClientList); + + LINK_FOR_EACH(prLinkEntry, prStaRecOfClientList) { + if ((ULONG) prCliStaRec == (ULONG) prLinkEntry) { + LINK_REMOVE_KNOWN_ENTRY(prStaRecOfClientList, &prCliStaRec->rLinkEntry); + fgIsStaFound = TRUE; + /* p2pFuncDisconnect(prAdapter, prCliStaRec, + * fgSendDisassoc, u2ReasonCode); */ + break; + } + } + + } + break; + case OP_MODE_INFRASTRUCTURE: + ASSERT(prCliStaRec == prP2pBssInfo->prStaRecOfAP); + if (prCliStaRec != prP2pBssInfo->prStaRecOfAP) + break; + /* p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); */ + prP2pBssInfo->prStaRecOfAP = NULL; + fgIsStaFound = TRUE; + break; + default: + break; + } + + if (fgIsStaFound) { + + p2pFuncDisconnect(prAdapter, prCliStaRec, fgSendDisassoc, u2ReasonCode); + /* 20120830 moved into p2pFuncDisconnect(). */ + /* cnmStaRecFree(prAdapter, prCliStaRec, TRUE); */ + + } + + rWlanStatus = WLAN_STATUS_SUCCESS; + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncDisassoc */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) +* 1. GC: Disconnect from AP. (Send Deauth) +* 2. GO: Disconnect all STA +* +* @param[in] prAdapter Pointer to the adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncDissolve(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) +{ + DEBUGFUNC("p2pFuncDissolve()"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + /* Reset station record status. */ + if (prP2pBssInfo->prStaRecOfAP) { + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + NULL, NULL, 0, REASON_CODE_DEAUTH_LEAVING_BSS, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + + /* 2012/02/14 frog: After formation before join group, prStaRecOfAP is NULL. */ + p2pFuncDisconnect(prAdapter, prP2pBssInfo->prStaRecOfAP, fgSendDeauth, u2ReasonCode); + } + + /* Fix possible KE when RX Beacon & call nicPmIndicateBssConnected(). + * hit prStaRecOfAP == NULL. */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + prP2pBssInfo->prStaRecOfAP = NULL; + + break; + case OP_MODE_ACCESS_POINT: + /* Under AP mode, we would net send deauthentication frame to each STA. + * We only stop the Beacon & let all stations timeout. + */ + { + P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; + + /* Send deauth. */ + authSendDeauthFrame(prAdapter, + NULL, (P_SW_RFB_T) NULL, u2ReasonCode, (PFN_TX_DONE_HANDLER) NULL); + + prStaRecOfClientList = &prP2pBssInfo->rStaRecOfClientList; + + while (!LINK_IS_EMPTY(prStaRecOfClientList)) { + P_STA_RECORD_T prCurrStaRec; + + LINK_REMOVE_HEAD(prStaRecOfClientList, prCurrStaRec, P_STA_RECORD_T); + + /* Indicate to Host. */ + /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, prCurrStaRec, FALSE); */ + + p2pFuncDisconnect(prAdapter, prCurrStaRec, TRUE, u2ReasonCode); + + } + prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone = 0; + } + + break; + default: + return; /* 20110420 -- alreay in Device Mode. */ + } + + /* Make the deauth frame send to FW ASAP. */ + wlanAcquirePowerControl(prAdapter); + wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); + wlanReleasePowerControl(prAdapter); + + kalMdelay(100); + + /* Change Connection Status. */ + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + } while (FALSE); + +} /* p2pFuncDissolve */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to dissolve from group or one group. (Would not change P2P FSM.) +* 1. GC: Disconnect from AP. (Send Deauth) +* 2. GO: Disconnect all STA +* +* @param[in] prAdapter Pointer to the adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN BOOLEAN fgSendDeauth, IN UINT_16 u2ReasonCode) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + eOriMediaStatus = prP2pBssInfo->eConnectionState; + + /* Indicate disconnect. */ + /* TODO: */ + /* kalP2PGOStationUpdate */ + /* kalP2PGCIndicateConnectionStatus */ + /* p2pIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, prStaRec->aucMacAddr); */ + DBGLOG(P2P, INFO, "p2pFuncDisconnect, eCurrentOPMode: %d, sendDeauth: %s\n", + prP2pBssInfo->eCurrentOPMode, fgSendDeauth ? "True" : "False"); + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) + kalP2PGOStationUpdate(prAdapter->prGlueInfo, prStaRec, FALSE); + + if (fgSendDeauth) { + /* Send deauth. */ + authSendDeauthFrame(prAdapter, + prStaRec, + (P_SW_RFB_T) NULL, + u2ReasonCode, (PFN_TX_DONE_HANDLER) p2pFsmRunEventDeauthTxDone); + } else { + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + cnmStaRecFree(prAdapter, prStaRec, TRUE); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->rStaRecOfClientList.u4NumElem == 0)) { + DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); + p2pChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + } + + if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { + /* Update Disconnected state to FW. */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + } + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + /* GO: It would stop Beacon TX. GC: Stop all BSS related PS function. */ + nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* Reset RLM related field of BSSINFO. */ + rlmBssAborted(prAdapter, prP2pBssInfo); + } + + } while (FALSE); + + return; + +} /* p2pFuncDisconnect */ + +/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ +#define WLAN_ACTION_SPECTRUM_MGMT 0 +#define WLAN_ACTION_QOS 1 +#define WLAN_ACTION_DLS 2 +#define WLAN_ACTION_BLOCK_ACK 3 +#define WLAN_ACTION_PUBLIC 4 +#define WLAN_ACTION_RADIO_MEASUREMENT 5 +#define WLAN_ACTION_FT 6 +#define WLAN_ACTION_HT 7 +#define WLAN_ACTION_SA_QUERY 8 +#define WLAN_ACTION_PROTECTED_DUAL 9 +#define WLAN_ACTION_WNM 10 +#define WLAN_ACTION_UNPROTECTED_WNM 11 +#define WLAN_ACTION_TDLS 12 +#define WLAN_ACTION_SELF_PROTECTED 15 +#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ +#define WLAN_ACTION_VENDOR_SPECIFIC 127 + +/* Public action codes */ +#define WLAN_PA_20_40_BSS_COEX 0 +#define WLAN_PA_VENDOR_SPECIFIC 9 +#define WLAN_PA_GAS_INITIAL_REQ 10 +#define WLAN_PA_GAS_INITIAL_RESP 11 +#define WLAN_PA_GAS_COMEBACK_REQ 12 +#define WLAN_PA_GAS_COMEBACK_RESP 13 +#define WLAN_TDLS_DISCOVERY_RESPONSE 14 + +/* P2P public action frames */ +enum p2p_action_frame_type { + P2P_GO_NEG_REQ = 0, + P2P_GO_NEG_RESP = 1, + P2P_GO_NEG_CONF = 2, + P2P_INVITATION_REQ = 3, + P2P_INVITATION_RESP = 4, + P2P_DEV_DISC_REQ = 5, + P2P_DEV_DISC_RESP = 6, + P2P_PROV_DISC_REQ = 7, + P2P_PROV_DISC_RESP = 8 +}; + +const char *p2p_to_string(enum p2p_action_frame_type p2p_action) +{ + switch (p2p_action) { + case P2P_GO_NEG_REQ: + return "GO_NEG_REQ"; + case P2P_GO_NEG_RESP: + return "GO_NEG_RESP"; + case P2P_GO_NEG_CONF: + return "GO_NEG_CONF"; + case P2P_INVITATION_REQ: + return "INVITATION_REQ"; + case P2P_INVITATION_RESP: + return "INVITATION_RESP"; + case P2P_DEV_DISC_REQ: + return "DEV_DISC_REQ"; + case P2P_DEV_DISC_RESP: + return "DEV_DISC_RESP"; + case P2P_PROV_DISC_REQ: + return "PROV_DISC_REQ"; + case P2P_PROV_DISC_RESP: + return "PROV_DISC_RESP"; + } + + return "UNKNOWN P2P Public Action"; +} +const char *pa_to_string(int pa_action) +{ + switch (pa_action) { + case WLAN_PA_20_40_BSS_COEX: + return "PA_20_40_BSS_COEX"; + case WLAN_PA_VENDOR_SPECIFIC: + return "PA_VENDOR_SPECIFIC"; + case WLAN_PA_GAS_INITIAL_REQ: + return "PA_GAS_INITIAL_REQ"; + case WLAN_PA_GAS_INITIAL_RESP: + return "PA_GAS_INITIAL_RESP"; + case WLAN_PA_GAS_COMEBACK_REQ: + return "PA_GAS_COMEBACK_REQ"; + case WLAN_PA_GAS_COMEBACK_RESP: + return "PA_GAS_COMEBACK_RESP"; + case WLAN_TDLS_DISCOVERY_RESPONSE: + return "TDLS_DISCOVERY_RESPONSE"; + } + + return "UNKNOWN Public Action"; +} + +const char *action_to_string(int wlan_action) +{ + switch (wlan_action) { + case WLAN_ACTION_SPECTRUM_MGMT: + return "SPECTRUM_MGMT"; + case WLAN_ACTION_QOS: + return "QOS"; + case WLAN_ACTION_DLS: + return "DLS"; + case WLAN_ACTION_BLOCK_ACK: + return "BLOCK_ACK"; + case WLAN_ACTION_PUBLIC: + return "PUBLIC"; + case WLAN_ACTION_RADIO_MEASUREMENT: + return "RADIO_MEASUREMENT"; + case WLAN_ACTION_FT: + return "FT"; + case WLAN_ACTION_HT: + return "HT"; + case WLAN_ACTION_SA_QUERY: + return "SA_QUERY"; + case WLAN_ACTION_PROTECTED_DUAL: + return "PROTECTED_DUAL"; + case WLAN_ACTION_WNM: + return "WNM"; + case WLAN_ACTION_UNPROTECTED_WNM: + return "UNPROTECTED_WNM"; + case WLAN_ACTION_TDLS: + return "TDLS"; + case WLAN_ACTION_SELF_PROTECTED: + return "SELF_PROTECTED"; + case WLAN_ACTION_WMM: + return "WMM"; + case WLAN_ACTION_VENDOR_SPECIFIC: + return "VENDOR_SPECIFIC"; + } + + return "UNKNOWN Action Frame"; +} + +VOID p2pFuncTagActionActionP2PFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, + IN P_WLAN_ACTION_FRAME prActFrame, + IN UINT_8 ucP2pAction, IN UINT_64 u8Cookie) +{ + DBGLOG(P2P, INFO, "Found P2P_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNO: %d\n", + p2p_to_string(ucP2pAction), + prActFrame->aucSrcAddr, + prActFrame->aucDestAddr, + u8Cookie, + prMgmtTxMsdu->ucTxSeqNum); +} + +VOID p2pFuncTagActionActionFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, + IN P_WLAN_ACTION_FRAME prActFrame, + IN UINT_8 ucAction, IN UINT_64 u8Cookie) +{ + PUINT_8 pucVendor = NULL; + + DBGLOG(P2P, INFO, "Found WLAN_%s, SA: %pM - DA: %pM, cookie: 0x%llx, SeqNo: %d\n", + pa_to_string(ucAction), + prActFrame->aucSrcAddr, + prActFrame->aucDestAddr, + u8Cookie, + prMgmtTxMsdu->ucTxSeqNum); + + if (ucAction == WLAN_PA_VENDOR_SPECIFIC) { + pucVendor = (PUINT_8)prActFrame + 26; + if (*(pucVendor + 0) == 0x50 && + *(pucVendor + 1) == 0x6f && + *(pucVendor + 2) == 0x9a) { + if (*(pucVendor + 3) == 0x09) + /* found p2p IE */ + p2pFuncTagActionActionP2PFrame(prMgmtTxMsdu, + prActFrame, *(pucVendor + 4), u8Cookie); + else if (*(pucVendor + 3) == 0x0a) + /* found WFD IE */ + DBGLOG(P2P, INFO, "Found WFD IE, SA: %pM - DA: %pM\n", + prActFrame->aucSrcAddr, + prActFrame->aucDestAddr); + else + DBGLOG(P2P, INFO, "Found Other vendor 0x%x, SA: %pM - DA: %pM\n", + *(pucVendor + 3), + prActFrame->aucSrcAddr, + prActFrame->aucDestAddr); + } + } +} + +VOID p2pFuncTagActionCategoryFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, + P_WLAN_ACTION_FRAME prActFrame, + IN UINT_8 ucCategory, + IN UINT_64 u8Cookie) +{ + + UINT_8 ucAction = 0; + + DBGLOG(P2P, INFO, "Found WLAN_ACTION_%s, SA: %pM - DA: %pM, u8Cookie: 0x%llx, SeqNO: %d\n", + action_to_string(ucCategory), + prActFrame->aucSrcAddr, + prActFrame->aucDestAddr, + u8Cookie, + prMgmtTxMsdu->ucTxSeqNum); + + if (ucCategory == WLAN_ACTION_PUBLIC) { + ucAction = prActFrame->ucAction; + p2pFuncTagActionActionFrame(prMgmtTxMsdu, prActFrame, ucAction, u8Cookie); + + } +} + +/* + * used to debug p2p mgmt frame: + * GO Nego Req + * GO Nego Res + * GO Nego Confirm + * GO Invite Req + * GO Invite Res + * Device Discoverability Req + * Device Discoverability Res + * Provision Discovery Req + * Provision Discovery Res + */ + +VOID +p2pFuncTagMgmtFrame(IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) +{ + /* P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; */ + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; + P_WLAN_PROBE_RSP_FRAME_T prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T)NULL; + UINT_16 u2TxFrameCtrl; + P_WLAN_ACTION_FRAME prActFrame; + UINT_8 ucCategory; + + prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + /* + * mgmt frame MASK_FC_TYPE = 0 + * use MASK_FRAME_TYPE is oK for frame type/subtype judge + */ + u2TxFrameCtrl = prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE; + + switch (u2TxFrameCtrl) { + case MAC_FRAME_PROBE_RSP: + + prProbRspHdr = (P_WLAN_PROBE_RSP_FRAME_T) prWlanHdr; + DBGLOG(P2P, INFO, "TX Probe Response Frame, SA: %pM - DA: %pM, cookie: 0x%llx, seqNo: %d\n", + prProbRspHdr->aucSrcAddr, prProbRspHdr->aucDestAddr, + u8Cookie, + prMgmtTxMsdu->ucTxSeqNum); + + break; + + case MAC_FRAME_ACTION: + + prActFrame = (P_WLAN_ACTION_FRAME)prWlanHdr; + ucCategory = prActFrame->ucCategory; + p2pFuncTagActionCategoryFrame(prMgmtTxMsdu, prActFrame, + ucCategory, u8Cookie); + + break; + default: + DBGLOG(P2P, INFO, "MGMT:, un-tagged frame type: 0x%x, A1: %pM, A2: %pM, A3: %pM seqNo: %d\n", + u2TxFrameCtrl, + prWlanHdr->aucAddr1, + prWlanHdr->aucAddr2, + prWlanHdr->aucAddr3, + prMgmtTxMsdu->ucTxSeqNum); + break; + } +} + +WLAN_STATUS +p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, IN P_MSDU_INFO_T prMgmtTxMsdu, IN UINT_64 u8Cookie) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T) NULL; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + BOOLEAN fgIsProbrsp = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); + + if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { + + /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ + /* Packet on driver, not done yet, drop it. */ + prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; + if (prTxMsduInfo != NULL) { + + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, + FALSE, + prTxMsduInfo->prPacket, + (UINT_32) prTxMsduInfo->u2FrameLength); + + /* Leave it to TX Done handler. */ + /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + DBGLOG(P2P, INFO, "p2pFuncTxMgmtFrame: Drop MGMT cookie: 0x%llx\n", + prMgmtTxReqInfo->u8Cookie); + } + /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ + /* Packet transmitted, wait tx done. (cookie issue) */ + /* 20120105 frog - use another u8cookie to store this value. */ + } + + ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); + + prWlanHdr = (P_WLAN_MAC_HEADER_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_P2P_INDEX, prWlanHdr->aucAddr1); + prMgmtTxMsdu->ucNetworkType = (UINT_8) NETWORK_TYPE_P2P_INDEX; + + switch (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) { + case MAC_FRAME_PROBE_RSP: + DBGLOG(P2P, TRACE, "p2pFuncTxMgmtFrame: TX MAC_FRAME_PROBE_RSP\n"); + fgIsProbrsp = TRUE; + prMgmtTxMsdu = p2pFuncProcessP2pProbeRsp(prAdapter, prMgmtTxMsdu); + break; + default: + break; + } + + prMgmtTxReqInfo->u8Cookie = u8Cookie; + prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; + prMgmtTxReqInfo->fgIsMgmtTxRequested = TRUE; + + prMgmtTxMsdu->eSrc = TX_PACKET_MGMT; + prMgmtTxMsdu->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? (prStaRec->ucIndex) : (0xFF); + if (prStaRec != NULL) + DBGLOG(P2P, TRACE, "Mgmt with station record: %pM.\n", prStaRec->aucMacAddr); + + prMgmtTxMsdu->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; /* TODO: undcertain. */ + prMgmtTxMsdu->fgIs802_1x = FALSE; + prMgmtTxMsdu->fgIs802_11 = TRUE; + prMgmtTxMsdu->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMgmtTxMsdu->pfTxDoneHandler = p2pFsmRunEventMgmtFrameTxDone; + prMgmtTxMsdu->fgIsBasicRate = TRUE; + + p2pFuncTagMgmtFrame(prMgmtTxMsdu, u8Cookie); + + nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); + + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncTxMgmtFrame */ + +VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN P_RF_CHANNEL_INFO_T prRfChannelInfo) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prRfChannelInfo != NULL)); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + prP2pConnSettings->ucOperatingChnl = prRfChannelInfo->ucChannelNum; + prP2pConnSettings->eBand = prRfChannelInfo->eBand; + + } while (FALSE); + +} + +/* p2pFuncSetChannel */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @retval TRUE We will retry JOIN +* @retval FALSE We will not retry JOIN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; + BOOLEAN fgRetValue = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && (prJoinInfo != NULL)); + + /* Retry other AuthType if possible */ + if (!prJoinInfo->ucAvailableAuthTypes) + break; + + if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { + + DBGLOG(P2P, INFO, "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); + + prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; + } else { + DBGLOG(P2P, ERROR, "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); + ASSERT(0); + break; + } + + prJoinInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + ASSERT(0); /* Can't trigger SAA FSM */ + break; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); + + fgRetValue = TRUE; + } while (FALSE); + + return fgRetValue; + +} /* end of p2pFuncRetryJOIN() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will update the contain of BSS_INFO_T for AIS network once +* the association was completed. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prAssocRspSwRfb) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; + UINT_16 u2IELength; + PUINT_8 pucIE; + + DEBUGFUNC("p2pUpdateBssInfoForJOIN()"); + + ASSERT(prAdapter); + ASSERT(prStaRec); + ASSERT(prAssocRspSwRfb); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prAssocRspSwRfb->pvHeader; + + DBGLOG(P2P, INFO, "Update P2P_BSS_INFO_T and apply settings to MAC\n"); + + /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ + /* 4 <1.1> Setup Operation Mode */ + prP2pBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen); + + if (prBssDesc == NULL) { + /* Target BSS NULL. */ + DBGLOG(P2P, TRACE, "Target BSS NULL\n"); + return; + } + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAssocRspFrame->aucBSSID)) + ASSERT(FALSE); + /* 4 <1.3> Setup Channel, Band */ + prP2pBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prP2pBssInfo->eBand = prBssDesc->eBand; + + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ + prP2pBssInfo->prStaRecOfAP = prStaRec; + prP2pBssInfo->u2AssocId = prStaRec->u2AssocId; + + /* 4 <2.2> Setup Capability */ + prP2pBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as BSS Cap Info */ + + if (prP2pBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) + prP2pBssInfo->fgIsShortPreambleAllowed = TRUE; + else + prP2pBssInfo->fgIsShortPreambleAllowed = FALSE; + + /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prP2pBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prP2pBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prP2pBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prP2pBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ + /* 4 <3.1> Setup BSSID */ + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + u2IELength = (UINT_16) ((prAssocRspSwRfb->u2PacketLen - prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + /* 4 <3.2> Parse WMM and setup QBSS flag */ + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prP2pBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + ASSERT(prBssDesc); + + prBssDesc->fgIsConnecting = FALSE; + prBssDesc->fgIsConnected = TRUE; + + /* 4 <4.1> Setup MIB for current BSS */ + prP2pBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after connection */ + prP2pBssInfo->ucDTIMPeriod = 0; + prP2pBssInfo->u2ATIMWindow = 0; + + prP2pBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; + + /* 4 <4.2> Update HT information and set channel */ + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + /* 4 <4.3> Sync with firmware for BSS-INFO */ + nicUpdateBss(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked */ + /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received */ + +} /* end of p2pUpdateBssInfoForJOIN() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Auth Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Auth +* @retval FALSE Don't reply the Auth +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, OUT PUINT_16 pu2StatusCode) +{ + BOOLEAN fgReplyAuth = TRUE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T) NULL; + + DBGLOG(P2P, INFO, "p2pValidate Authentication Frame\n"); + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prSwRfb != NULL) && (pprStaRec != NULL) && (pu2StatusCode != NULL)); + + /* P2P 3.2.8 */ + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prAuthFrame = (P_WLAN_AUTH_FRAME_T) prSwRfb->pvHeader; + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) + || (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { + /* We are not under AP Mode yet. */ + fgReplyAuth = FALSE; + DBGLOG(P2P, WARN, + "Current OP mode is not under AP mode. (%d)\n", prP2pBssInfo->eCurrentOPMode); + break; + } + + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX, prAuthFrame->aucSrcAddr); + + if (!prStaRec) { + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_P2P_INDEX); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + /* Sent a message event to clean un-used STA_RECORD_T. */ + ASSERT(prStaRec); + if (!prStaRec) { + DBGLOG(AAA, INFO, "Station Limit Full. Decline a new Authentication.\n"); + break; + } + + COPY_MAC_ADDR(prStaRec->aucMacAddr, prAuthFrame->aucSrcAddr); + + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + prStaRec->u2BSSBasicRateSet = prP2pBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = RATE_SET_ERP_P2P; + + prStaRec->u2OperationalRateSet = RATE_SET_ERP_P2P; + prStaRec->ucPhyTypeSet = PHY_TYPE_SET_802_11GN; + prStaRec->eStaType = STA_TYPE_P2P_GC; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } else { + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + if ((prStaRec->ucStaState > STA_STATE_1) && (IS_STA_IN_P2P(prStaRec))) { + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + } + + } + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT || + kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem)) { + /* GROUP limit full. */ + /* P2P 3.2.8 */ + DBGLOG(P2P, WARN, + "Group Limit Full. (%d)\n", (INT_16) prP2pBssInfo->rStaRecOfClientList.u4NumElem); + + bssRemoveStaRecFromClientList(prAdapter, prP2pBssInfo, prStaRec); + + cnmStaRecFree(prAdapter, prStaRec, FALSE); + fgReplyAuth = TRUE; + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD; + break; + } + /* Hotspot Blacklist */ + if (prAuthFrame->aucSrcAddr) { + if (kalP2PCmpBlackList(prAdapter->prGlueInfo, prAuthFrame->aucSrcAddr)) { + fgReplyAuth = TRUE; + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD; + return fgReplyAuth; + } + } + + /* prStaRec->eStaType = STA_TYPE_INFRA_CLIENT; */ + prStaRec->eStaType = STA_TYPE_P2P_GC; + + prStaRec->ucNetTypeIndex = NETWORK_TYPE_P2P_INDEX; + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + prStaRec->ucJoinFailureCount = 0; + + *pprStaRec = prStaRec; + + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + + } while (FALSE); + + return fgReplyAuth; + +} /* p2pFuncValidateAuth */ + +VOID p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + do { + if ((prAdapter == NULL) || (prStaRec == NULL)) { + ASSERT(FALSE); + break; + } + + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->u2ReasonCode = REASON_CODE_RESERVED; + prStaRec->ucJoinFailureCount = 0; + prStaRec->fgTransmitKeyExist = FALSE; + + prStaRec->fgSetPwrMgtBit = FALSE; + + } while (FALSE); + +} /* p2pFuncResetStaRecStatus */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function is used to initialize the value of the connection settings for +* P2P network +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings) +{ + P_DEVICE_TYPE_T prDevType; + UINT_8 aucDefaultDevName[] = P2P_DEFAULT_DEV_NAME; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; +#if CFG_SUPPORT_CFG_FILE + P_WIFI_VAR_T prWifiVar = NULL; +#endif + + ASSERT(prP2PConnSettings); +#if CFG_SUPPORT_CFG_FILE + prWifiVar = &(prAdapter->rWifiVar); + ASSERT(prWifiVar); +#endif + + /* Setup Default Device Name */ + prP2PConnSettings->ucDevNameLen = P2P_DEFAULT_DEV_NAME_LEN; + kalMemCopy(prP2PConnSettings->aucDevName, aucDefaultDevName, sizeof(aucDefaultDevName)); + + /* Setup Primary Device Type (Big-Endian) */ + prDevType = &prP2PConnSettings->rPrimaryDevTypeBE; + + prDevType->u2CategoryId = HTONS(P2P_DEFAULT_PRIMARY_CATEGORY_ID); + prDevType->u2SubCategoryId = HTONS(P2P_DEFAULT_PRIMARY_SUB_CATEGORY_ID); + + prDevType->aucOui[0] = aucWfaOui[0]; + prDevType->aucOui[1] = aucWfaOui[1]; + prDevType->aucOui[2] = aucWfaOui[2]; + prDevType->aucOui[3] = VENDOR_OUI_TYPE_WPS; + + /* Setup Secondary Device Type */ + prP2PConnSettings->ucSecondaryDevTypeCount = 0; + + /* Setup Default Config Method */ + prP2PConnSettings->eConfigMethodSelType = ENUM_CONFIG_METHOD_SEL_AUTO; + prP2PConnSettings->u2ConfigMethodsSupport = P2P_DEFAULT_CONFIG_METHOD; + prP2PConnSettings->u2TargetConfigMethod = 0; + prP2PConnSettings->u2LocalConfigMethod = 0; + prP2PConnSettings->fgIsPasswordIDRdy = FALSE; + + /* For Device Capability */ + prP2PConnSettings->fgSupportServiceDiscovery = FALSE; + prP2PConnSettings->fgSupportClientDiscoverability = TRUE; + prP2PConnSettings->fgSupportConcurrentOperation = TRUE; + prP2PConnSettings->fgSupportInfraManaged = FALSE; + prP2PConnSettings->fgSupportInvitationProcedure = FALSE; + + /* For Group Capability */ +#if CFG_SUPPORT_PERSISTENT_GROUP + prP2PConnSettings->fgSupportPersistentP2PGroup = TRUE; +#else + prP2PConnSettings->fgSupportPersistentP2PGroup = FALSE; +#endif + prP2PConnSettings->fgSupportIntraBSSDistribution = TRUE; + prP2PConnSettings->fgSupportCrossConnection = TRUE; + prP2PConnSettings->fgSupportPersistentReconnect = FALSE; + + prP2PConnSettings->fgSupportOppPS = FALSE; + prP2PConnSettings->u2CTWindow = P2P_CTWINDOW_DEFAULT; + + /* For Connection Settings. */ + prP2PConnSettings->eAuthMode = AUTH_MODE_OPEN; + + prP2PConnSettings->prTargetP2pDesc = NULL; + prP2PConnSettings->ucSSIDLen = 0; + + /* Misc */ + prP2PConnSettings->fgIsScanReqIssued = FALSE; + prP2PConnSettings->fgIsServiceDiscoverIssued = FALSE; + prP2PConnSettings->fgP2pGroupLimit = FALSE; + prP2PConnSettings->ucOperatingChnl = 0; + prP2PConnSettings->ucListenChnl = 0; + prP2PConnSettings->ucTieBreaker = (UINT_8) (kalRandomNumber() & 0x1); + + prP2PConnSettings->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; +#if CFG_SUPPORT_CFG_FILE + /* prP2PConnSettings->fgIsWPSMode = prWifiVar->ucApWpsMode; */ + prAdapter->rWifiVar.prP2pFsmInfo->fgIsWPSMode = prWifiVar->ucApWpsMode; +#endif +} /* p2pFuncInitConnectionSettings */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Assoc Req Frame and then return +* the status code to AAA to indicate if need to perform following actions +* when the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu2StatusCode The Status Code of Validation Result +* +* @retval TRUE Reply the Assoc Resp +* @retval FALSE Don't reply the Assoc Resp +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_16 pu2StatusCode) +{ + BOOLEAN fgReplyAssocResp = TRUE; + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; +#if CFG_SUPPORT_WFD + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_WFD_ATTRIBUTE_T prWfdAttribute = (P_WFD_ATTRIBUTE_T) NULL; + BOOLEAN fgNeedFree = FALSE; +#endif + /* UINT_16 u2AttriListLen = 0; */ + UINT_16 u2WfdDevInfo = 0; + P_WFD_DEVICE_INFORMATION_IE_T prAttriWfdDevInfo; + + /* TODO(Kevin): Call P2P functions to check .. + 2. Check we can accept connection from thsi peer + a. If we are in PROVISION state, only accept the peer we do the GO formation previously. + b. If we are in OPERATION state, only accept the other peer when P2P_GROUP_LIMIT is 0. + 3. Check Black List here. + */ + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && (pu2StatusCode != NULL)); + + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) { + /* Station record should be ready while RX AUTH frame. */ + fgReplyAssocResp = FALSE; + ASSERT(FALSE); + break; + } + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + + prStaRec->u2DesiredNonHTRateSet &= prP2pBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & prP2pBssInfo->ucPhyTypeSet; + + if (prStaRec->ucDesiredPhyTypeSet == 0) { + /* The station only support 11B rate. */ + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } +#if CFG_SUPPORT_WFD && 1 + /* LOG_FUNC("Skip check WFD IE because some API is not ready\n"); */ + if (!prAdapter->rWifiVar.prP2pFsmInfo) { + fgReplyAssocResp = FALSE; + ASSERT(FALSE); + break; + } + + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + DBGLOG(P2P, INFO, "AssocReq, wfd_en %u wfd_info 0x%x wfd_policy 0x%x wfd_flag 0x%x\n", + prWfdCfgSettings->ucWfdEnable, prWfdCfgSettings->u2WfdDevInfo, + prWfdCfgSettings->u4WfdPolicy, prWfdCfgSettings->u4WfdFlag); /* Eddie */ + if (prWfdCfgSettings->ucWfdEnable) { + if (prWfdCfgSettings->u4WfdPolicy & BIT(6)) { + /* Rejected all. */ + break; + } + + /* fgNeedFree = p2pFuncGetAttriList(prAdapter, */ + /* VENDOR_OUI_TYPE_WFD, */ + /* (PUINT_8)prAssocReqFrame->aucInfoElem, */ + /* (prSwRfb->u2PacketLen - OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), */ + /* (PPUINT_8)&prWfdAttribute, */ + /* &u2AttriListLen); */ + + prAttriWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) + p2pFuncGetSpecAttri(prAdapter, + VENDOR_OUI_TYPE_WFD, + (PUINT_8) prAssocReqFrame->aucInfoElem, + (prSwRfb->u2PacketLen - + OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem)), + WFD_ATTRI_ID_DEV_INFO); + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(5)) && (prAttriWfdDevInfo != NULL)) { + /* Rejected with WFD IE. */ + break; + } + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(0)) && (prAttriWfdDevInfo == NULL)) { + /* Rejected without WFD IE. */ + break; + } + + if (prAttriWfdDevInfo == NULL) { + /* + * Without WFD IE. + * Do nothing. Accept the connection request. + */ + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + break; + } + + /* prAttriWfdDevInfo = */ + /* (P_WFD_DEVICE_INFORMATION_IE_T)p2pFuncGetSpecAttri(prAdapter, */ + /* VENDOR_OUI_TYPE_WFD, */ + /* (PUINT_8)prWfdAttribute, */ + /* u2AttriListLen, */ + /* WFD_ATTRI_ID_DEV_INFO); */ + /* if (prAttriWfdDevInfo == NULL) { */ + /* No such attribute. */ + /* break; */ + /* } */ + + WLAN_GET_FIELD_BE16(&prAttriWfdDevInfo->u2WfdDevInfo, &u2WfdDevInfo); + DBGLOG(P2P, INFO, "RX Assoc Req WFD Info:0x%x.\n", u2WfdDevInfo); + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(1)) && ((u2WfdDevInfo & 0x3) == 0x0)) { + /* Rejected because of SOURCE. */ + break; + } + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(2)) && ((u2WfdDevInfo & 0x3) == 0x1)) { + /* Rejected because of Primary Sink. */ + break; + } + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(3)) && ((u2WfdDevInfo & 0x3) == 0x2)) { + /* Rejected because of Secondary Sink. */ + break; + } + + if ((prWfdCfgSettings->u4WfdPolicy & BIT(4)) && ((u2WfdDevInfo & 0x3) == 0x3)) { + /* Rejected because of Source & Primary Sink. */ + break; + } + + /* Check role */ + + if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) && + ((prWfdCfgSettings->u2WfdDevInfo & BITS(0, 1)) == 0x3)) { + /* P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = + * (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)NULL; */ + UINT_16 u2DevInfo = prWfdCfgSettings->u2WfdDevInfo; + + /* We may change role here if we are dual role */ + + if ((u2WfdDevInfo & BITS(0, 1)) == 0x00 /* Peer is Source */) { + DBGLOG(P2P, INFO, "WFD: Switch role to primary sink\n"); + + prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); + prWfdCfgSettings->u2WfdDevInfo |= 0x1; + + /* event to annonce the role is chanaged to P-Sink */ + + } else if ((u2WfdDevInfo & BITS(0, 1)) == 0x01 /* Peer is P-Sink */) { + DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); + + prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); + /* event to annonce the role is chanaged to Source */ + } else { + DBGLOG(P2P, INFO, "WFD: Peer role is wrong type(dev 0x%x)\n", + (u2DevInfo)); + DBGLOG(P2P, INFO, "WFD: Switch role to source\n"); + + prWfdCfgSettings->u2WfdDevInfo &= ~BITS(0, 1); + /* event to annonce the role is chanaged to Source */ + } + + p2pFsmRunEventWfdSettingUpdate(prAdapter, NULL); + + } /* Dual role p2p->wfd_params->WfdDevInfo */ + + /* WFD_FLAG_DEV_INFO_VALID */ + } + /* ucWfdEnable */ +#endif + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + } while (FALSE); + +#if CFG_SUPPORT_WFD + if ((prWfdAttribute) && (fgNeedFree)) + kalMemFree(prWfdAttribute, VIR_MEM_TYPE, WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE); +#endif + + return fgReplyAssocResp; + +} /* p2pFuncValidateAssocReq */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to check the P2P IE +* +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType) +{ + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + P_IE_WFA_T prWfaIE = (P_IE_WFA_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pucOuiType != NULL)); + + prWfaIE = (P_IE_WFA_T) pucBuf; + + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + + return TRUE; + } while (FALSE); + + return FALSE; +} /* p2pFuncParseCheckForP2PInfoElem */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT PUINT_32 pu4ControlFlags) +{ + BOOLEAN fgIsReplyProbeRsp = FALSE; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + DEBUGFUNC("p2pFuncValidateProbeReq"); + DBGLOG(P2P, TRACE, "p2pFuncValidateProbeReq\n"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ) { + + DBGLOG(P2P, TRACE, "report probe req to OS\n"); + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + } while (FALSE); + + return fgIsReplyProbeRsp; + +} /* end of p2pFuncValidateProbeReq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will validate the Rx Probe Request Frame and then return +* result to BSS to indicate if need to send the corresponding Probe Response +* Frame if the specified conditions were matched. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to SW RFB data structure. +* @param[out] pu4ControlFlags Control flags for replying the Probe Response +* +* @retval TRUE Reply the Probe Response +* @retval FALSE Don't reply the Probe Response +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + + DEBUGFUNC("p2pFuncValidateProbeReq"); + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + if (prP2pFsmInfo->u4P2pPacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME) { + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + } while (FALSE); + + return; + +} /* p2pFuncValidateRxMgmtFrame */ + +BOOLEAN p2pFuncIsAPMode(IN P_P2P_FSM_INFO_T prP2pFsmInfo) +{ + if (prP2pFsmInfo) { + if (prP2pFsmInfo->fgIsWPSMode == 1) + return FALSE; + return prP2pFsmInfo->fgIsApMode; + } else { + return FALSE; + } +} + +/* p2pFuncIsAPMode */ + +VOID +p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN PUINT_8 pucIEInfo, IN UINT_32 u4IELen) +{ + PUINT_8 pucIE = (PUINT_8) NULL; + UINT_16 u2Offset = 0; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + BOOLEAN ucNewSecMode = FALSE; + BOOLEAN ucOldSecMode = FALSE; + UINT_8 ucOuiType; + UINT_16 u2SubTypeVersion; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + if (u4IELen == 0) + break; + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pSpecificBssInfo->u2AttributeLen = 0; + + ASSERT_BREAK(pucIEInfo != NULL); + + pucIE = pucIEInfo; + + ucOldSecMode = kalP2PGetCipher(prAdapter->prGlueInfo); + + IE_FOR_EACH(pucIE, u4IELen, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + { + /* 0 */ /* V */ /* Done */ + /* DBGLOG(P2P, TRACE, ("SSID update\n")); */ + /* SSID is saved when start AP/GO */ + /* SSID IE set in beacon from supplicant will not always be */ + /* the true since hidden SSID case */ + /* + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + + COPY_SSID(prP2pSpecificBssInfo->aucGroupSsid, + prP2pSpecificBssInfo->u2GroupSsidLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + */ + } + break; + case ELEM_ID_SUP_RATES: + { + /* 1 */ /* V */ /* Done */ + DBGLOG(P2P, TRACE, "Support Rate IE\n"); + kalMemCopy(prP2pBssInfo->aucAllSupportedRates, + SUP_RATES_IE(pucIE)->aucSupportedRates, + SUP_RATES_IE(pucIE)->ucLength); + + prP2pBssInfo->ucAllSupportedRatesLen = SUP_RATES_IE(pucIE)->ucLength; + + DBGLOG_MEM8(P2P, TRACE, SUP_RATES_IE(pucIE)->aucSupportedRates, + SUP_RATES_IE(pucIE)->ucLength); + } + break; + case ELEM_ID_DS_PARAM_SET: + { + /* 3 */ /* V */ /* Done */ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = + prAdapter->rWifiVar.prP2PConnSettings; + + DBGLOG(P2P, TRACE, "DS PARAM IE\n"); + + ASSERT(prP2pConnSettings->ucOperatingChnl == DS_PARAM_IE(pucIE)->ucCurrChnl); + + if (prP2pConnSettings->eBand != BAND_2G4) { + ASSERT(FALSE); + break; + } + /* prP2pBssInfo->ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; */ + + /* prP2pBssInfo->eBand = BAND_2G4; */ + } + break; + case ELEM_ID_TIM: /* 5 */ /* V */ + DBGLOG(P2P, TRACE, "TIM IE\n"); + TIM_IE(pucIE)->ucDTIMPeriod = prP2pBssInfo->ucDTIMPeriod; + break; + case ELEM_ID_ERP_INFO: /* 42 */ /* V */ + { +#if 1 + /* This IE would dynamic change due to FW detection change is required. */ + DBGLOG(P2P, TRACE, "ERP IE will be over write by driver\n"); + DBGLOG(P2P, TRACE, " ucERP: %x.\n", ERP_INFO_IE(pucIE)->ucERP); + +#else + /* This IE would dynamic change due to FW detection change is required. */ + DBGLOG(P2P, TRACE, "ERP IE.\n"); + + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11GN; + + ASSERT(prP2pBssInfo->eBand == BAND_2G4); + + prP2pBssInfo->fgObssErpProtectMode = + ((ERP_INFO_IE(pucIE)->ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE); + + prP2pBssInfo->fgErpProtectMode = + ((ERP_INFO_IE(pucIE)->ucERP & + (ERP_INFO_USE_PROTECTION | ERP_INFO_NON_ERP_PRESENT)) ? TRUE : FALSE); +#endif + + } + break; + case ELEM_ID_HT_CAP: /* 45 */ /* V */ + { +#if 1 + DBGLOG(P2P, TRACE, "HT CAP IE would be overwritten by driver\n"); + + DBGLOG(P2P, TRACE, + "HT Cap Info:%x, AMPDU Param:%x\n", HT_CAP_IE(pucIE)->u2HtCapInfo, + HT_CAP_IE(pucIE)->ucAmpduParam); + + DBGLOG(P2P, TRACE, + "HT Extended Cap Info%x,TX Beamforming Cap Info%x,Ant Selection Cap Info%x\n", + HT_CAP_IE(pucIE)->u2HtExtendedCap, HT_CAP_IE(pucIE)->u4TxBeamformingCap, + HT_CAP_IE(pucIE)->ucAselCap); +#else + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + + /* u2HtCapInfo */ + if ((HT_CAP_IE(pucIE)->u2HtCapInfo & + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | + HT_CAP_INFO_DSSS_CCK_IN_40M)) == 0) { + prP2pBssInfo->fgAssoc40mBwAllowed = FALSE; + } else { + prP2pBssInfo->fgAssoc40mBwAllowed = TRUE; + } + + if ((HT_CAP_IE(pucIE)->u2HtCapInfo & + (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M)) == 0) { + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = TRUE; + } else { + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled = FALSE; + } + + /* ucAmpduParam */ + DBGLOG(P2P, TRACE, + "AMPDU setting from supplicant:0x%x, & default value:0x%x\n", + (UINT_8) HT_CAP_IE(pucIE)->ucAmpduParam, + (UINT_8) AMPDU_PARAM_DEFAULT_VAL); + + /* rSupMcsSet */ + /* Can do nothing. the field is default value from other configuration. */ + /* HT_CAP_IE(pucIE)->rSupMcsSet; */ + + /* u2HtExtendedCap */ + ASSERT(HT_CAP_IE(pucIE)->u2HtExtendedCap == + (HT_EXT_CAP_DEFAULT_VAL & + ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE))); + + /* u4TxBeamformingCap */ + ASSERT(HT_CAP_IE(pucIE)->u4TxBeamformingCap == TX_BEAMFORMING_CAP_DEFAULT_VAL); + + /* ucAselCap */ + ASSERT(HT_CAP_IE(pucIE)->ucAselCap == ASEL_CAP_DEFAULT_VAL); +#endif + } + break; + case ELEM_ID_RSN: /* 48 */ /* V */ + { + RSN_INFO_T rRsnIe; + + DBGLOG(P2P, TRACE, "RSN IE\n"); + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP); + ucNewSecMode = TRUE; + + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) { + prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; + prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap; + } + } + break; + case ELEM_ID_EXTENDED_SUP_RATES: /* 50 */ /* V */ + /* Be attention, + * ELEM_ID_SUP_RATES should be placed before ELEM_ID_EXTENDED_SUP_RATES. */ + DBGLOG(P2P, TRACE, "Ex Support Rate IE\n"); + kalMemCopy(&(prP2pBssInfo->aucAllSupportedRates[prP2pBssInfo->ucAllSupportedRatesLen]), + EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, + EXT_SUP_RATES_IE(pucIE)->ucLength); + + DBGLOG_MEM8(P2P, TRACE, EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, + EXT_SUP_RATES_IE(pucIE)->ucLength); + + prP2pBssInfo->ucAllSupportedRatesLen += EXT_SUP_RATES_IE(pucIE)->ucLength; + break; + case ELEM_ID_HT_OP: + { + /* 61 */ /* V */ /* TODO: */ +#if 1 + DBGLOG(P2P, TRACE, "HT OP IE would be overwritten by driver\n"); + + DBGLOG(P2P, TRACE, + " Primary Channel: %x, Info1: %x, Info2: %x, Info3: %x\n", + HT_OP_IE(pucIE)->ucPrimaryChannel, HT_OP_IE(pucIE)->ucInfo1, + HT_OP_IE(pucIE)->u2Info2, HT_OP_IE(pucIE)->u2Info3); +#else + UINT_16 u2Info2 = 0; + + prP2pBssInfo->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + + DBGLOG(P2P, TRACE, "HT OP IE\n"); + + /* ucPrimaryChannel. */ + ASSERT(HT_OP_IE(pucIE)->ucPrimaryChannel == prP2pBssInfo->ucPrimaryChannel); + + /* ucInfo1 */ + prP2pBssInfo->ucHtOpInfo1 = HT_OP_IE(pucIE)->ucInfo1; + + /* u2Info2 */ + u2Info2 = HT_OP_IE(pucIE)->u2Info2; + + if (u2Info2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { + ASSERT(prP2pBssInfo->eGfOperationMode != GF_MODE_NORMAL); + u2Info2 &= ~HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (u2Info2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) { + prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; + u2Info2 &= ~HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + switch (u2Info2 & HT_OP_INFO2_HT_PROTECTION) { + case HT_PROTECT_MODE_NON_HT: + prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NON_HT; + break; + case HT_PROTECT_MODE_NON_MEMBER: + prP2pBssInfo->eHtProtectMode = HT_PROTECT_MODE_NONE; + prP2pBssInfo->eObssHtProtectMode = HT_PROTECT_MODE_NON_MEMBER; + break; + default: + prP2pBssInfo->eHtProtectMode = HT_OP_IE(pucIE)->u2Info2; + break; + } + + /* u2Info3 */ + prP2pBssInfo->u2HtOpInfo3 = HT_OP_IE(pucIE)->u2Info3; + + /* aucBasicMcsSet */ + DBGLOG_MEM8(P2P, TRACE, HT_OP_IE(pucIE)->aucBasicMcsSet, 16); +#endif + } + break; + case ELEM_ID_OBSS_SCAN_PARAMS: /* 74 */ /* V */ + { + DBGLOG(P2P, TRACE, + "ELEM_ID_OBSS_SCAN_PARAMS IE would be replaced by driver\n"); + } + break; + case ELEM_ID_EXTENDED_CAP: /* 127 */ /* V */ + { + DBGLOG(P2P, TRACE, "ELEM_ID_EXTENDED_CAP IE would be replaced by driver\n"); + } + break; + case ELEM_ID_VENDOR: /* 221 */ /* V */ + DBGLOG(P2P, TRACE, "Vender Specific IE\n"); + if (rsnParseCheckForWFAInfoElem + (prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) + && (u2SubTypeVersion == VERSION_WPA)) { + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_TKIP); + ucNewSecMode = TRUE; + kalMemCopy(prP2pSpecificBssInfo->aucWpaIeBuffer, pucIE, + IE_SIZE(pucIE)); + prP2pSpecificBssInfo->u2WpaIeLen = IE_SIZE(pucIE); + } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 0, pucIE, + IE_SIZE(pucIE)); + } + /* WMM here. */ + } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { + /* TODO Store the whole P2P IE & generate later. */ + /* Be aware that there may be one or more P2P IE. */ + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache + [prP2pSpecificBssInfo->u2AttributeLen], pucIE, + IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache + [prP2pSpecificBssInfo->u2AttributeLen], pucIE, + IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + } + } else { + + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache + [prP2pSpecificBssInfo->u2AttributeLen], pucIE, + IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + DBGLOG(P2P, TRACE, "Driver unprocessed Vender Specific IE\n"); + ASSERT(FALSE); + } + + /* TODO: Store other Vender IE except for WMM Param. */ + break; + default: + DBGLOG(P2P, TRACE, "Unprocessed element ID:%d\n", IE_ID(pucIE)); + break; + } + } + + if (!ucNewSecMode && ucOldSecMode) + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_NONE); + + } while (FALSE); + +} /* p2pFuncParseBeaconContent */ + +P_BSS_DESC_T +p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + P_BSS_DESC_T prTargetBss = (P_BSS_DESC_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prConnReqInfo != NULL) && (prChnlReqInfo != NULL) && (prScanReqInfo != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + break; + /* Update connection request information. */ + ASSERT(prConnReqInfo->fgIsConnRequest == TRUE); + + /* Find BSS Descriptor first. */ + prTargetBss = scanP2pSearchDesc(prAdapter, prP2pBssInfo, prConnReqInfo); + + if (prTargetBss == NULL) { + /* Update scan parameter... to scan target device. */ + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ + prScanReqInfo->fgIsAbort = TRUE; + } else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = prTargetBss->ucChannelNum; + prChnlReqInfo->eBand = prTargetBss->eBand; + prChnlReqInfo->eChnlSco = prTargetBss->eSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GC_JOIN_REQ; + } + + } while (FALSE); + + return prTargetBss; +} /* p2pFuncKeepOnConnection */ + +/* Currently Only for ASSOC Response Frame. */ +VOID p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T) NULL; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) NULL; + INT_16 i2IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T) prSwRfb->pvHeader; + + if (prAssocRspFrame->u2FrameCtrl != MAC_FRAME_ASSOC_RSP) + break; + + i2IELen = prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + + CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); + + if (i2IELen <= 0) + break; + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + prJoinInfo = &(prP2pFsmInfo->rJoinInfo); + prJoinInfo->u4BufLength = (UINT_32) i2IELen; + + kalMemCopy(prJoinInfo->aucIEBuf, prAssocRspFrame->aucInfoElem, prJoinInfo->u4BufLength); + + } while (FALSE); + +} /* p2pFuncStoreAssocRspIEBuffer */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set Packet Filter. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_SUPPORTED +* \retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN UINT_16 u2FrameType, IN BOOLEAN fgIsRegistered, OUT PUINT_32 pu4P2pPacketFilter) +{ + UINT_32 u4NewPacketFilter = 0; + + DEBUGFUNC("p2pFuncMgmtFrameRegister"); + + do { + ASSERT_BREAK(prAdapter != NULL); + + if (pu4P2pPacketFilter) + u4NewPacketFilter = *pu4P2pPacketFilter; + + switch (u2FrameType) { + case MAC_FRAME_PROBE_REQ: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); + } else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); + } + break; + case MAC_FRAME_ACTION: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); + } else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); + } + break; + default: + DBGLOG(P2P, TRACE, "Ask frog to add code for mgmt:%x\n", u2FrameType); + break; + } + + if (pu4P2pPacketFilter) + *pu4P2pPacketFilter = u4NewPacketFilter; + + /* u4NewPacketFilter |= prAdapter->u4OsPacketFilter; */ + + prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RX_FILTER, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(UINT_32), + (PUINT_8) &prAdapter->u4OsPacketFilter, + &u4NewPacketFilter, sizeof(u4NewPacketFilter) + ); + + } while (FALSE); + +} /* p2pFuncMgmtFrameRegister */ + +VOID p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN UINT_32 u4OsFilter) +{ + + do { + + prAdapter->rWifiVar.prP2pFsmInfo->u4P2pPacketFilter = u4OsFilter; + + if ((prAdapter->u4OsPacketFilter & PARAM_PACKET_FILTER_P2P_MASK) ^ u4OsFilter) { + + prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; + + prAdapter->u4OsPacketFilter |= (u4OsFilter & PARAM_PACKET_FILTER_P2P_MASK); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RX_FILTER, + TRUE, + FALSE, + FALSE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(UINT_32), + (PUINT_8) &prAdapter->u4OsPacketFilter, &u4OsFilter, sizeof(u4OsFilter) + ); + DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%x\n", prAdapter->u4OsPacketFilter); + } + + } while (FALSE); + +} /* p2pFuncUpdateMgmtFrameRegister */ + +VOID p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucMacAddr, OUT P_P2P_STATION_INFO_T prStaInfo) +{ + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucMacAddr != NULL) && (prStaInfo != NULL)); + + prStaInfo->u4InactiveTime = 0; + prStaInfo->u4RxBytes = 0; + prStaInfo->u4TxBytes = 0; + prStaInfo->u4RxPackets = 0; + prStaInfo->u4TxPackets = 0; + /* TODO: */ + + } while (FALSE); + +} /* p2pFuncGetStationInfo */ + +BOOLEAN +p2pFuncGetAttriList(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, + IN PUINT_8 pucIE, IN UINT_16 u2IELength, OUT PPUINT_8 ppucAttriList, OUT PUINT_16 pu2AttriListLen) +{ + BOOLEAN fgIsAllocMem = FALSE; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + UINT_16 u2Offset = 0; + P_IE_P2P_T prIe = (P_IE_P2P_T) NULL; + PUINT_8 pucAttriListStart = (PUINT_8) NULL; + UINT_16 u2AttriListLen = 0, u2BufferSize = 0; + BOOLEAN fgBackupAttributes = FALSE; + UINT_16 u2CopyLen; + + ASSERT(prAdapter); + ASSERT(pucIE); + ASSERT(ppucAttriList); + ASSERT(pu2AttriListLen); + + if (ppucAttriList) + *ppucAttriList = NULL; + if (pu2AttriListLen) + *pu2AttriListLen = 0; + + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + aucWfaOui[0] = 0x00; + aucWfaOui[1] = 0x50; + aucWfaOui[2] = 0xF2; + } else if ((ucOuiType != VENDOR_OUI_TYPE_P2P) +#if CFG_SUPPORT_WFD + && (ucOuiType != VENDOR_OUI_TYPE_WFD) +#endif + ) { + DBGLOG(P2P, INFO, "Not supported OUI Type to parsing 0x%x\n", ucOuiType); + return fgIsAllocMem; + } + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + if (ELEM_ID_VENDOR != IE_ID(pucIE)) + continue; + + prIe = (P_IE_P2P_T) pucIE; + + if (prIe->ucLength <= P2P_OUI_TYPE_LEN) + continue; + + if ((prIe->aucOui[0] == aucWfaOui[0]) && + (prIe->aucOui[1] == aucWfaOui[1]) && + (prIe->aucOui[2] == aucWfaOui[2]) && (ucOuiType == prIe->ucOuiType)) { + + if (!pucAttriListStart) { + pucAttriListStart = &prIe->aucP2PAttributes[0]; + if (prIe->ucLength > P2P_OUI_TYPE_LEN) + u2AttriListLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); + else + ASSERT(FALSE); + continue; + } +/* More than 2 attributes. */ + + if (FALSE == fgBackupAttributes) { + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo; + + fgBackupAttributes = TRUE; + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache[0], + pucAttriListStart, u2AttriListLen); + + pucAttriListStart = + &prP2pSpecificBssInfo->aucAttributesCache[0]; + + u2BufferSize = P2P_MAXIMUM_ATTRIBUTE_LEN; + } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalMemCopy(&prP2pSpecificBssInfo->aucWscAttributesCache + [0], pucAttriListStart, u2AttriListLen); + pucAttriListStart = + &prP2pSpecificBssInfo->aucWscAttributesCache[0]; + + u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; + } +#if CFG_SUPPORT_WFD + else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + PUINT_8 pucTmpBuf = (PUINT_8) NULL; + + pucTmpBuf = (PUINT_8) + kalMemAlloc(WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE, + VIR_MEM_TYPE); + + if (pucTmpBuf != NULL) { + fgIsAllocMem = TRUE; + } else { + /* Can't alloca memory for WFD IE relocate. */ + ASSERT(FALSE); + break; + } + + kalMemCopy(pucTmpBuf, + pucAttriListStart, u2AttriListLen); + + pucAttriListStart = pucTmpBuf; + + u2BufferSize = WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE; + } +#endif + else + fgBackupAttributes = FALSE; + } + + u2CopyLen = (UINT_16) (prIe->ucLength - P2P_OUI_TYPE_LEN); + + if ((u2AttriListLen + u2CopyLen) > u2BufferSize) { + u2CopyLen = u2BufferSize - u2AttriListLen; + DBGLOG(P2P, WARN, + "Length of received P2P attributes > maximum cache size.\n"); + } + + if (u2CopyLen) { + kalMemCopy((PUINT_8) + ((ULONG) pucAttriListStart + + (UINT_32) u2AttriListLen), + &prIe->aucP2PAttributes[0], u2CopyLen); + + u2AttriListLen += u2CopyLen; + } + } /* prIe->aucOui */ + } /* IE_FOR_EACH */ + + if (pucAttriListStart) { + PUINT_8 pucAttribute = pucAttriListStart; + + DBGLOG(P2P, LOUD, "Checking Attribute Length.\n"); + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + P2P_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset); + } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + /* Do nothing */ + } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + /* Big Endian: WSC, WFD. */ + WSC_ATTRI_FOR_EACH(pucAttribute, u2AttriListLen, u2Offset) { + DBGLOG(P2P, LOUD, "Attribute ID:%d, Length:%d.\n", + WSC_ATTRI_ID(pucAttribute), WSC_ATTRI_LEN(pucAttribute)); + } + } else { + } + + ASSERT(u2Offset == u2AttriListLen); + + if (ppucAttriList) + *ppucAttriList = pucAttriListStart; + if (pu2AttriListLen) + *pu2AttriListLen = u2AttriListLen; + + } else { + if (ppucAttriList) + *ppucAttriList = (PUINT_8) NULL; + if (pu2AttriListLen) + *pu2AttriListLen = 0; + } + + return fgIsAllocMem; +} /* p2pFuncGetAttriList */ + +P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMgmtTxMsdu) +{ + P_MSDU_INFO_T prRetMsduInfo = prMgmtTxMsdu; + P_WLAN_PROBE_RSP_FRAME_T prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) NULL; + PUINT_8 pucIEBuf = (PUINT_8) NULL; + UINT_16 u2Offset = 0, u2IELength = 0, u2ProbeRspHdrLen = 0; + BOOLEAN fgIsP2PIE = FALSE, fgIsWSCIE = FALSE; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + UINT_16 u2EstimateSize = 0, u2EstimatedExtraIELen = 0; + UINT_32 u4IeArraySize = 0, u4Idx = 0; + UINT_8 ucOuiType = 0; + UINT_16 u2SubTypeVersion = 0; + + BOOLEAN fgIsPureAP = prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxMsdu != NULL)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + /* 3 Make sure this is probe response frame. */ + prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T) ((ULONG) prMgmtTxMsdu->prPacket + MAC_TX_RESERVED_FIELD); + ASSERT_BREAK((prProbeRspFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_PROBE_RSP); + + if (prP2pBssInfo->u2BeaconInterval) + prProbeRspFrame->u2BeaconInterval = prP2pBssInfo->u2BeaconInterval; + + /* 3 Get the importent P2P IE. */ + u2ProbeRspHdrLen = + (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + pucIEBuf = prProbeRspFrame->aucInfoElem; + u2IELength = prMgmtTxMsdu->u2FrameLength - u2ProbeRspHdrLen; + +#if CFG_SUPPORT_WFD + prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen = 0; +#endif + + IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset) { + switch (IE_ID(pucIEBuf)) { + case ELEM_ID_SSID: + { + + COPY_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + SSID_IE(pucIEBuf)->aucSSID, SSID_IE(pucIEBuf)->ucLength); + } + break; + case ELEM_ID_VENDOR: +#if !CFG_SUPPORT_WFD + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 2, pucIEBuf, + IE_SIZE(pucIEBuf)); + fgIsWSCIE = TRUE; + } + + } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIEBuf, &ucOuiType)) { + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + /* 2 Note(frog): I use WSC IE buffer for Probe Request to + * store the P2P IE for Probe Response. */ + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 1, pucIEBuf, + IE_SIZE(pucIEBuf)); + fgIsP2PIE = TRUE; + } + + } else { + if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + + IE_SIZE(pucIEBuf)) < 512) { + kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, + pucIEBuf, IE_SIZE(pucIEBuf)); + prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += + IE_SIZE(pucIEBuf); + } + } +#else + /* Eddie May be WFD */ + if (rsnParseCheckForWFAInfoElem + (prAdapter, pucIEBuf, &ucOuiType, &u2SubTypeVersion)) { + if (ucOuiType == VENDOR_OUI_TYPE_WMM) + break; + + } + if ((prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen + IE_SIZE(pucIEBuf)) < + 1024) { + kalMemCopy(prAdapter->prGlueInfo->prP2PInfo->aucVenderIE + + prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen, pucIEBuf, + IE_SIZE(pucIEBuf)); + prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen += IE_SIZE(pucIEBuf); + } +#endif + break; + default: + break; + } + + } + + /* 3 Check the total size & current frame. */ + u2EstimateSize = WLAN_MAC_MGMT_HEADER_LEN + + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + + CAP_INFO_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET); + + u2EstimatedExtraIELen = 0; + + u4IeArraySize = sizeof(txProbeRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += txProbeRspIETable[u4Idx].u2EstimatedFixedIELen; + } + + else { + ASSERT(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += + (UINT_16) (txProbeRspIETable[u4Idx].pfnCalculateVariableIELen + (prAdapter, NETWORK_TYPE_P2P_INDEX, NULL)); + } + + } + + if (fgIsWSCIE) + u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); + + if (fgIsP2PIE) { + u2EstimatedExtraIELen += kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); + u2EstimatedExtraIELen += p2pFuncCalculateP2P_IE_NoA(prAdapter, 0, NULL); + } +#if CFG_SUPPORT_WFD + u2EstimatedExtraIELen += prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; +#endif + + u2EstimateSize += u2EstimatedExtraIELen; + if (u2EstimateSize > (prRetMsduInfo->u2FrameLength)) { + prRetMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimateSize); + + if (prRetMsduInfo == NULL) { + DBGLOG(P2P, WARN, "No packet for sending new probe response, use original one\n"); + prRetMsduInfo = prMgmtTxMsdu; + break; + } + + prRetMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + } + /* 3 Compose / Re-compose probe response frame. */ + bssComposeBeaconProbeRespFrameHeaderAndFF((PUINT_8) + ((ULONG) (prRetMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prProbeRspFrame->aucDestAddr, prProbeRspFrame->aucSrcAddr, + prProbeRspFrame->aucBSSID, prProbeRspFrame->u2BeaconInterval, + fgIsPureAP ? prP2pBssInfo-> + u2CapInfo : prProbeRspFrame->u2CapInfo); + + prRetMsduInfo->u2FrameLength = + (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + + bssBuildBeaconProbeRespFrameCommonIEs(prRetMsduInfo, prP2pBssInfo, prProbeRspFrame->aucDestAddr); + + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].pfnAppendIE) + txProbeRspIETable[u4Idx].pfnAppendIE(prAdapter, prRetMsduInfo); + + } + + if (fgIsWSCIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, + 2, + (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + + (UINT_32) prRetMsduInfo->u2FrameLength)); + + prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 2); + } + + if (fgIsP2PIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, + 1, + (PUINT_8) ((ULONG) prRetMsduInfo->prPacket + + (UINT_32) prRetMsduInfo->u2FrameLength)); + + prRetMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 1); + p2pFuncGenerateP2P_IE_NoA(prAdapter, prRetMsduInfo); + } +#if CFG_SUPPORT_WFD + if (prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen > 0) { + kalMemCopy((PUINT_8) ((ULONG) prRetMsduInfo->prPacket + (UINT_32) prRetMsduInfo->u2FrameLength), + prAdapter->prGlueInfo->prP2PInfo->aucVenderIE, + prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen); + prRetMsduInfo->u2FrameLength += (UINT_16) prAdapter->prGlueInfo->prP2PInfo->u2VenderIELen; + } +#endif + + } while (FALSE); + + if (prRetMsduInfo != prMgmtTxMsdu) + cnmMgtPktFree(prAdapter, prMgmtTxMsdu); + + return prRetMsduInfo; +} /* p2pFuncProcessP2pProbeRsp */ + +#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ +UINT_32 +p2pFuncCalculateExtra_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + UINT_32 u4IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) + break; + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + u4IELen = prP2pSpeBssInfo->u2IELenForBCN; + + } while (FALSE); + + return u4IELen; +} /* p2pFuncCalculateP2p_IELenForBeacon */ + +VOID p2pFuncGenerateExtra_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + PUINT_8 pucIEBuf = (PUINT_8) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) + break; + + pucIEBuf = (PUINT_8) ((UINT_32) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucBeaconIECache, prP2pSpeBssInfo->u2IELenForBCN); + + prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2IELenForBCN; + + } while (FALSE); + +} /* p2pFuncGenerateExtra_IEForBeacon */ + +#else +UINT_32 +p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + UINT_32 u4IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX)); + + if (!prAdapter->fgIsP2PRegistered) + break; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) + break; + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + u4IELen = prP2pSpeBssInfo->u2AttributeLen; + + } while (FALSE); + + return u4IELen; +} /* p2pFuncCalculateP2p_IELenForBeacon */ + +VOID p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + PUINT_8 pucIEBuf = (PUINT_8) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + if (!prAdapter->fgIsP2PRegistered) + break; + + prP2pSpeBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) + break; + + pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucAttributesCache, prP2pSpeBssInfo->u2AttributeLen); + + prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2AttributeLen; + + } while (FALSE); + +} /* p2pFuncGenerateP2p_IEForBeacon */ + +UINT_32 +p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) + return 0; + + return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); +} /* p2pFuncCalculateP2p_IELenForBeacon */ + +VOID p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + PUINT_8 pucBuffer; + UINT_16 u2IELen = 0; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) + return; + + u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* TODO: Check P2P FSM State. */ + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); + + prMsduInfo->u2FrameLength += u2IELen; + +} /* p2pFuncGenerateP2p_IEForBeacon */ + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to calculate P2P IE length for Beacon frame. +* +* @param[in] eNetTypeIndex Specify which network +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return The length of P2P IE added +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 +p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) + return 0; + + return p2pFuncCalculateP2P_IELen(prAdapter, + eNetTypeIndex, + prStaRec, + txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + +} /* p2pFuncCalculateP2p_IELenForAssocRsp */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + if (!prStaRec) + break; + + if (IS_STA_P2P_TYPE(prStaRec)) { + DBGLOG(P2P, TRACE, "Generate NULL P2P IE for Assoc Rsp.\n"); + + p2pFuncGenerateP2P_IE(prAdapter, + TRUE, + &prMsduInfo->u2FrameLength, + prMsduInfo->prPacket, + 1500, + txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + } else { + + DBGLOG(P2P, TRACE, "Legacy device, no P2P IE.\n"); + } + + } while (FALSE); + + return; + +} /* p2pFuncGenerateP2p_IEForAssocRsp */ + +UINT_32 +p2pFuncCalculateWSC_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + DBGLOG(P2P, TRACE, "p2pFuncCalculateWSC_IELenForAssocRsp\n"); + if (eNetTypeIndex != NETWORK_TYPE_P2P_INDEX) + return 0; + + return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); +} /* p2pFuncCalculateP2p_IELenForAssocRsp */ + +VOID p2pFuncGenerateWSC_IEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + PUINT_8 pucBuffer; + UINT_16 u2IELen = 0; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_P2P_INDEX) + return; + DBGLOG(P2P, TRACE, "p2pFuncGenerateWSC_IEForAssocRsp\n"); + + u2IELen = (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* TODO: Check P2P FSM State. */ + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer); + + prMsduInfo->u2FrameLength += u2IELen; + +} + +/* p2pFuncGenerateP2p_IEForAssocRsp */ + +UINT_32 +p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) +{ + + UINT_32 u4OverallAttriLen, u4Dummy; + UINT_16 u2EstimatedFixedAttriLen; + UINT_32 i; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + u2EstimatedFixedAttriLen = arAppendAttriTable[i].u2EstimatedFixedAttriLen; + + if (u2EstimatedFixedAttriLen) { + u4OverallAttriLen += u2EstimatedFixedAttriLen; + } else { + ASSERT(arAppendAttriTable[i].pfnCalculateVariableAttriLen); + + u4OverallAttriLen += arAppendAttriTable[i].pfnCalculateVariableAttriLen(prAdapter, prStaRec); + } + } + + u4Dummy = u4OverallAttriLen; + u4OverallAttriLen += P2P_IE_OUI_HDR; + + for (; (u4Dummy > P2P_MAXIMUM_ATTRIBUTE_LEN);) { + u4OverallAttriLen += P2P_IE_OUI_HDR; + u4Dummy -= P2P_MAXIMUM_ATTRIBUTE_LEN; + } + + return u4OverallAttriLen; +} /* p2pFuncCalculateP2P_IELen */ + +VOID +p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) +{ + PUINT_8 pucBuffer = (PUINT_8) NULL; + P_IE_P2P_T prIeP2P = (P_IE_P2P_T) NULL; + UINT_32 u4OverallAttriLen; + UINT_32 u4AttriLen; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; + UINT_32 i; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + /* Check buffer length is still enough. */ + ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= P2P_IE_OUI_HDR); + + prIeP2P = (P_IE_P2P_T) pucBuffer; + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + (*pu2Offset) += P2P_IE_OUI_HDR; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + + if (arAppendAttriTable[i].pfnAppendAttri) { + u4AttriLen = + arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, + u2BufSize); + + u4OverallAttriLen += u4AttriLen; + + if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { + u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; + + prIeP2P->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); + + pucBuffer = + (PUINT_8) ((ULONG) prIeP2P + + (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN)); + + prIeP2P = (P_IE_P2P_T) ((ULONG) prIeP2P + + (ELEM_HDR_LEN + + (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN))); + + kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + kalMemCopy(prIeP2P->aucP2PAttributes, aucTempBuffer, u4OverallAttriLen); + (*pu2Offset) += P2P_IE_OUI_HDR; + } + + } + + } + + prIeP2P->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); + + } while (FALSE); + +} /* p2pFuncGenerateP2P_IE */ + +UINT_32 +p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + PUINT_8 pucBuffer; + P_P2P_ATTRI_STATUS_T prAttriStatus; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + UINT_32 u4AttriLen = 0; + + ASSERT(prAdapter); + ASSERT(pucBuf); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (fgIsAssocFrame) + return u4AttriLen; + /* TODO: For assoc request P2P IE check in driver & return status in P2P IE. */ + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT(pucBuffer); + prAttriStatus = (P_P2P_ATTRI_STATUS_T) pucBuffer; + + ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); + + prAttriStatus->ucId = P2P_ATTRI_ID_STATUS; + WLAN_SET_FIELD_16(&prAttriStatus->u2Length, P2P_ATTRI_MAX_LEN_STATUS); + + prAttriStatus->ucStatusCode = P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} /* p2pFuncAppendAttriStatusForAssocRsp */ + +UINT_32 +p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + P_P2P_ATTRI_EXT_LISTEN_TIMING_T prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + PUINT_8 pucBuffer = NULL; + + ASSERT(prAdapter); + ASSERT(pucBuf); + + if (fgIsAssocFrame) + return u4AttriLen; + /* TODO: For extend listen timing. */ + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + + ASSERT(u2BufSize >= ((*pu2Offset) + (UINT_16) u4AttriLen)); + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT(pucBuffer); + + prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T) pucBuffer; + + prP2pExtListenTiming->ucId = P2P_ATTRI_ID_EXT_LISTEN_TIMING; + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2Length, P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailInterval, prP2pSpecificBssInfo->u2AvailabilityInterval); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailPeriod, prP2pSpecificBssInfo->u2AvailabilityPeriod); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} /* p2pFuncAppendAttriExtListenTiming */ + +P_IE_HDR_T +p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_8 ucElemID, IN PBOOLEAN pfgIsMore) +{ + P_IE_HDR_T prTargetIE = (P_IE_HDR_T) NULL; + PUINT_8 pucIE = (PUINT_8) NULL; + UINT_16 u2Offset = 0; + + if (pfgIsMore) + *pfgIsMore = FALSE; + + do { + ASSERT_BREAK((prAdapter != NULL) + && (pucIEBuf != NULL)); + + pucIE = pucIEBuf; + + IE_FOR_EACH(pucIE, u2BufferLen, u2Offset) { + if (IE_ID(pucIE) == ucElemID) { + if ((prTargetIE) && (pfgIsMore)) { + + *pfgIsMore = TRUE; + break; + } + prTargetIE = (P_IE_HDR_T) pucIE; + + if (pfgIsMore == NULL) + break; + + } + } + + } while (FALSE); + + return prTargetIE; +} /* p2pFuncGetSpecIE */ + +P_ATTRIBUTE_HDR_T +p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucOuiType, IN PUINT_8 pucIEBuf, IN UINT_16 u2BufferLen, IN UINT_16 u2AttriID) +{ + P_IE_P2P_T prP2pIE = (P_IE_P2P_T) NULL; + P_ATTRIBUTE_HDR_T prTargetAttri = (P_ATTRIBUTE_HDR_T) NULL; + BOOLEAN fgIsMore = FALSE; + PUINT_8 pucIE = (PUINT_8) NULL, pucAttri = (PUINT_8) NULL; + UINT_16 u2OffsetAttri = 0; + UINT_16 u2BufferLenLeft = 0; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + + DBGLOG(P2P, INFO, "Check AssocReq Oui type %u attri %u for len %u\n", ucOuiType, u2AttriID, u2BufferLen); + + ASSERT(prAdapter); + ASSERT(pucIEBuf); + + u2BufferLenLeft = u2BufferLen; + pucIE = pucIEBuf; + do { + fgIsMore = FALSE; + prP2pIE = (P_IE_P2P_T) p2pFuncGetSpecIE(prAdapter, + pucIE, u2BufferLenLeft, ELEM_ID_VENDOR, &fgIsMore); + if (prP2pIE == NULL) + continue; + + ASSERT((ULONG) prP2pIE >= (ULONG) pucIE); + + u2BufferLenLeft = u2BufferLen - (UINT_16) (((ULONG) prP2pIE) - ((ULONG) pucIEBuf)); + + DBGLOG(P2P, INFO, "Find vendor id %u len %u oui %u more %u LeftLen %u\n", + IE_ID(prP2pIE), IE_LEN(prP2pIE), prP2pIE->ucOuiType, fgIsMore, + u2BufferLenLeft); + + if ((IE_LEN(prP2pIE) > P2P_OUI_TYPE_LEN) && (prP2pIE->ucOuiType == ucOuiType)) { + switch (ucOuiType) { + case VENDOR_OUI_TYPE_WPS: + aucWfaOui[0] = 0x00; + aucWfaOui[1] = 0x50; + aucWfaOui[2] = 0xF2; + break; + case VENDOR_OUI_TYPE_P2P: + break; + case VENDOR_OUI_TYPE_WPA: + case VENDOR_OUI_TYPE_WMM: + case VENDOR_OUI_TYPE_WFD: + default: + break; + } + + if ((prP2pIE->aucOui[0] != aucWfaOui[0]) + || (prP2pIE->aucOui[1] != aucWfaOui[1]) + || (prP2pIE->aucOui[2] != aucWfaOui[2])) + continue; + + u2OffsetAttri = 0; + pucAttri = prP2pIE->aucP2PAttributes; + + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + WSC_ATTRI_FOR_EACH(pucAttri, + (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { + /* LOG_FUNC("WSC: attri id=%u len=%u\n", + * WSC_ATTRI_ID(pucAttri), + * WSC_ATTRI_LEN(pucAttri)); */ + if (WSC_ATTRI_ID(pucAttri) == u2AttriID) { + prTargetAttri = + (P_ATTRIBUTE_HDR_T) pucAttri; + break; + } + } + + } else if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + P2P_ATTRI_FOR_EACH(pucAttri, + (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { + /* LOG_FUNC("P2P: attri id=%u len=%u\n", + * ATTRI_ID(pucAttri), ATTRI_LEN(pucAttri)); */ + if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { + prTargetAttri = (P_ATTRIBUTE_HDR_T) pucAttri; + break; + } + } + } +#if CFG_SUPPORT_WFD + else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + WFD_ATTRI_FOR_EACH(pucAttri, + (IE_LEN(prP2pIE) - P2P_OUI_TYPE_LEN), u2OffsetAttri) { + /* DBGLOG(P2P, INFO, ("WFD: attri id=%u + * len=%u\n",WFD_ATTRI_ID(pucAttri), + * WFD_ATTRI_LEN(pucAttri))); */ + if (ATTRI_ID(pucAttri) == (UINT_8) u2AttriID) { + prTargetAttri = + (P_ATTRIBUTE_HDR_T) pucAttri; + break; + } + } + } +#endif + /* Do nothing */ + /* Possible or else. */ + } /* ucOuiType */ + /* P2P_OUI_TYPE_LEN */ + pucIE = (PUINT_8) (((ULONG) prP2pIE) + IE_SIZE(prP2pIE)); + /* prP2pIE */ + } while (prP2pIE && fgIsMore && u2BufferLenLeft); + + return prTargetAttri; +} + +/* p2pFuncGetSpecAttri */ + +WLAN_STATUS +p2pFuncGenerateBeaconProbeRsp(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, IN P_MSDU_INFO_T prMsduInfo, IN BOOLEAN fgIsProbeRsp) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T) NULL; +/* P_APPEND_VAR_IE_ENTRY_T prAppendIeTable = (P_APPEND_VAR_IE_ENTRY_T)NULL; */ + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL) && (prMsduInfo != NULL)); + +/* txBcnIETable */ + +/* txProbeRspIETable */ + + prBcnFrame = (P_WLAN_BEACON_FRAME_T) prMsduInfo->prPacket; + + return nicUpdateBeaconIETemplate(prAdapter, + IE_UPD_METHOD_UPDATE_ALL, + NETWORK_TYPE_P2P_INDEX, + prBssInfo->u2CapInfo, + (PUINT_8) prBcnFrame->aucInfoElem, + prMsduInfo->u2FrameLength - OFFSET_OF(WLAN_BEACON_FRAME_T, + aucInfoElem)); + + } while (FALSE); + + return rWlanStatus; +} /* p2pFuncGenerateBeaconProbeRsp */ + +WLAN_STATUS +p2pFuncComposeBeaconProbeRspTemplate(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBcnBuffer, + IN UINT_32 u4BcnBufLen, + IN BOOLEAN fgIsProbeRsp, + IN P_P2P_PROBE_RSP_UPDATE_INFO_T prP2pProbeRspInfo, IN BOOLEAN fgSynToFW) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; + P_WLAN_MAC_HEADER_T prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + PUINT_8 pucBuffer = (PUINT_8) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBcnBuffer != NULL)); + + prWlanBcnFrame = (P_WLAN_MAC_HEADER_T) pucBcnBuffer; + + if ((prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_BEACON) && (!fgIsProbeRsp)) { + rWlanStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + else if (prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_PROBE_RSP) { + rWlanStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + if (fgIsProbeRsp) { + ASSERT_BREAK(prP2pProbeRspInfo != NULL); + + if (prP2pProbeRspInfo->prProbeRspMsduTemplate) + cnmMgtPktFree(prAdapter, prP2pProbeRspInfo->prProbeRspMsduTemplate); + + prP2pProbeRspInfo->prProbeRspMsduTemplate = cnmMgtPktAlloc(prAdapter, u4BcnBufLen); + + prMsduInfo = prP2pProbeRspInfo->prProbeRspMsduTemplate; + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucStaRecIndex = 0xFF; + prMsduInfo->ucNetworkType = NETWORK_TYPE_P2P_INDEX; + + } else { + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prMsduInfo = prP2pBssInfo->prBeacon; + + if (prMsduInfo == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + + if (u4BcnBufLen > (OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH)) { + /* Unexpected error, buffer overflow. */ + ASSERT(FALSE); + break; + } + + } + + pucBuffer = (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucBuffer, pucBcnBuffer, u4BcnBufLen); + + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = (UINT_16) u4BcnBufLen; + + if (fgSynToFW && prP2pBssInfo) + rWlanStatus = p2pFuncGenerateBeaconProbeRsp(prAdapter, prP2pBssInfo, prMsduInfo, fgIsProbeRsp); + + } while (FALSE); + + return rWlanStatus; + +} /* p2pFuncComposeBeaconTemplate */ + +#if CFG_SUPPORT_WFD +WLAN_STATUS wfdAdjustResource(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) +{ +#if 1 + /* The API shall be called in tx_thread */ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); + if (fgEnable) { + prQM->au4MinReservedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; + if (QM_GUARANTEED_TC0_RESOURCE > 2) { + prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE - 2; + prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; + } + if (QM_GUARANTEED_TC1_RESOURCE > 2) { + prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE - 2; + prQM->au4GuaranteedTcResource[TC2_INDEX] += 2; + } + } else { + prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; + prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; + prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; + prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; + } +#endif + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wfdAdjustThread(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable) +{ +#define WFD_TX_THREAD_PRIORITY 70 + DBGLOG(P2P, INFO, "wfdAdjustResource %d\n", fgEnable); + if (prAdapter->prGlueInfo->main_thread != NULL) { + if (fgEnable) { +#ifdef LINUX + /* TODO the change schedule API shall be provided by OS glue layer */ + /* Or the API shall be put in os glue layer */ + struct sched_param param = {.sched_priority = WFD_TX_THREAD_PRIORITY }; + + sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_RR, ¶m); +#endif + } else { +#ifdef LINUX + /* TODO the change schedule API shall be provided by OS glue layer */ + struct sched_param param = {.sched_priority = 0 }; + + sched_setscheduler(prAdapter->prGlueInfo->main_thread, SCHED_NORMAL, ¶m); +#endif + } + } else { + + DBGLOG(P2P, WARN, "main_thread is null, please check if the wlanRemove is called in advance\n"); + } + return WLAN_STATUS_SUCCESS; +} + +#endif /* CFG_SUPPORT_WFD */ + +WLAN_STATUS wfdChangeMediaState(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx, ENUM_PARAM_MEDIA_STATE_T eConnectionState) +{ +#if CFG_SUPPORT_WFD + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + if (prAdapter->fgIsP2PRegistered == FALSE) + return WLAN_STATUS_SUCCESS; + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + + if ((prWfdCfgSettings->ucWfdEnable) && ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID))) { + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + wfdAdjustResource(prAdapter, TRUE); + wfdAdjustThread(prAdapter, TRUE); + } else { + wfdAdjustResource(prAdapter, FALSE); + wfdAdjustThread(prAdapter, FALSE); + } + + } +#endif + return WLAN_STATUS_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c new file mode 100644 index 0000000000000..991861f736082 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_ie.c @@ -0,0 +1,612 @@ +#include "p2p_precomp.h" + +#if CFG_SUPPORT_WFD +#if CFG_SUPPORT_WFD_COMPOSE_IE +#if 0 +APPEND_VAR_ATTRI_ENTRY_T txProbeRspWFDAttributesTable[] = { + {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_EXT_CAPABILITY), NULL, wfdFuncAppendAttriExtCapability} /* 7 */ + , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ +}; + +APPEND_VAR_ATTRI_ENTRY_T txBeaconWFDAttributesTable[] = { + {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ +}; + +APPEND_VAR_ATTRI_ENTRY_T txAssocReqWFDAttributesTable[] = { + {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ +}; +#endif + +APPEND_VAR_ATTRI_ENTRY_T txAssocRspWFDAttributesTable[] = { + {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_DEV_INFO), NULL, wfdFuncAppendAttriDevInfo} /* 0 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_ASSOC_BSSID), NULL, wfdFuncAppendAttriAssocBssid} /* 1 */ + , {(WFD_ATTRI_HDR_LEN + WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO), NULL, wfdFuncAppendAttriCoupledSinkInfo} /* 6 */ + , {0, wfdFuncCalculateAttriLenSessionInfo, wfdFuncAppendAttriSessionInfo} /* 9 */ + +}; + +#endif + +UINT_32 +p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; + UINT_32 u4RetValue = 0; + + do { + ASSERT_BREAK((eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) && (prAdapter != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + u4RetValue = prConnReqInfo->u4BufLength; + + /* ADD HT Capability */ + u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP); + + /* ADD WMM Information Element */ + u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO); + + } while (FALSE); + + return u4RetValue; +} /* p2pCalculate_IEForAssocReq */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to generate P2P IE for Beacon frame. +* +* @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL; + PUINT_8 pucIEBuf = (PUINT_8) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pFsmInfo = prAdapter->rWifiVar.prP2pFsmInfo; + + prConnReqInfo = &(prP2pFsmInfo->rConnReqInfo); + + pucIEBuf = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prConnReqInfo->aucIEBuf, prConnReqInfo->u4BufLength); + + prMsduInfo->u2FrameLength += prConnReqInfo->u4BufLength; + + rlmReqGenerateHtCapIE(prAdapter, prMsduInfo); + mqmGenerateWmmInfoIE(prAdapter, prMsduInfo); + + } while (FALSE); + + return; + +} /* p2pGenerate_IEForAssocReq */ + +UINT_32 +wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + PUINT_8 pucBuffer = NULL; + P_WFD_DEVICE_INFORMATION_IE_T prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if ((prWfdCfgSettings->ucWfdEnable == 0) || + ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0)) { + break; + } + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T) pucBuffer; + + prWfdDevInfo->ucElemID = WFD_ATTRI_ID_DEV_INFO; + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevInfo, prWfdCfgSettings->u2WfdDevInfo); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2SessionMgmtCtrlPort, prWfdCfgSettings->u2WfdControlPort); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevMaxSpeed, prWfdCfgSettings->u2WfdMaximumTp); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2Length, WFD_ATTRI_MAX_LEN_DEV_INFO); + + u4AttriLen = WFD_ATTRI_MAX_LEN_DEV_INFO + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriDevInfo */ + +UINT_32 +wfdFuncAppendAttriAssocBssid(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + PUINT_8 pucBuffer = NULL; + P_WFD_ASSOCIATED_BSSID_IE_T prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_BSS_INFO_T prAisBssInfo = (P_BSS_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if (prWfdCfgSettings->ucWfdEnable == 0) + break; + + /* AIS network. */ + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if ((!IS_NET_ACTIVE(prAdapter, NETWORK_TYPE_AIS_INDEX)) || + (prAisBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED)) { + break; + } + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdAssocBssid = (P_WFD_ASSOCIATED_BSSID_IE_T) pucBuffer; + + prWfdAssocBssid->ucElemID = WFD_ATTRI_ID_ASSOC_BSSID; + + WLAN_SET_FIELD_BE16(&prWfdAssocBssid->u2Length, WFD_ATTRI_MAX_LEN_ASSOC_BSSID); + + COPY_MAC_ADDR(prWfdAssocBssid->aucAssocBssid, prAisBssInfo->aucBSSID); + + u4AttriLen = WFD_ATTRI_MAX_LEN_ASSOC_BSSID + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriAssocBssid */ + +UINT_32 +wfdFuncAppendAttriCoupledSinkInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + PUINT_8 pucBuffer = NULL; + P_WFD_COUPLE_SINK_INFORMATION_IE_T prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if ((prWfdCfgSettings->ucWfdEnable == 0) || + ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_SINK_INFO_VALID) == 0)) { + break; + } + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdCoupleSinkInfo = (P_WFD_COUPLE_SINK_INFORMATION_IE_T) pucBuffer; + + prWfdCoupleSinkInfo->ucElemID = WFD_ATTRI_ID_COUPLED_SINK_INFO; + + WLAN_SET_FIELD_BE16(&prWfdCoupleSinkInfo->u2Length, WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO); + + COPY_MAC_ADDR(prWfdCoupleSinkInfo->aucCoupleSinkMac, prWfdCfgSettings->aucWfdCoupleSinkAddress); + + prWfdCoupleSinkInfo->ucCoupleSinkStatusBp = prWfdCfgSettings->ucWfdCoupleSinkStatus; + + u4AttriLen = WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriCoupledSinkInfo */ + +UINT_32 +wfdFuncAppendAttriExtCapability(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + PUINT_8 pucBuffer = NULL; + P_WFD_EXTENDED_CAPABILITY_IE_T prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if ((prWfdCfgSettings->ucWfdEnable == 0) || + ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_EXT_CAPABILITY_VALID) == 0)) { + break; + } + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdExtCapability = (P_WFD_EXTENDED_CAPABILITY_IE_T) pucBuffer; + + prWfdExtCapability->ucElemID = WFD_ATTRI_ID_EXT_CAPABILITY; + + WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2Length, WFD_ATTRI_MAX_LEN_EXT_CAPABILITY); + + WLAN_SET_FIELD_BE16(&prWfdExtCapability->u2WfdExtCapabilityBp, prWfdCfgSettings->u2WfdExtendCap); + + u4AttriLen = WFD_ATTRI_MAX_LEN_EXT_CAPABILITY + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriExtCapability */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to calculate length of Channel List Attribute +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return The length of Attribute added +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 wfdFuncCalculateAttriLenSessionInfo(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + UINT_16 u2AttriLen = 0; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + if (prWfdCfgSettings->ucWfdEnable == 0) + break; + + u2AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + return (UINT_32) u2AttriLen; + +} /* wfdFuncCalculateAttriLenSessionInfo */ + +UINT_32 +wfdFuncAppendAttriSessionInfo(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, IN PUINT_16 pu2Offset, IN PUINT_8 pucBuf, IN UINT_16 u2BufSize) +{ + UINT_32 u4AttriLen = 0; + PUINT_8 pucBuffer = NULL; + P_WFD_SESSION_INFORMATION_IE_T prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if ((prWfdCfgSettings->ucWfdEnable == 0) || (prWfdCfgSettings->u2WfdSessionInformationIELen == 0)) + break; + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (UINT_32) (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdSessionInfo = (P_WFD_SESSION_INFORMATION_IE_T) pucBuffer; + + prWfdSessionInfo->ucElemID = WFD_ATTRI_ID_SESSION_INFO; + + /* TODO: Check endian issue? */ + kalMemCopy(prWfdSessionInfo->pucWfdDevInfoDesc, prWfdCfgSettings->aucWfdSessionInformationIE, + prWfdCfgSettings->u2WfdSessionInformationIELen); + + WLAN_SET_FIELD_16(&prWfdSessionInfo->u2Length, prWfdCfgSettings->u2WfdSessionInformationIELen); + + u4AttriLen = prWfdCfgSettings->u2WfdSessionInformationIELen + WFD_ATTRI_HDR_LEN; + + } while (FALSE); + + (*pu2Offset) += (UINT_16) u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriSessionInfo */ + +#if CFG_SUPPORT_WFD_COMPOSE_IE +VOID +wfdFuncGenerateWfd_IE(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgIsAssocFrame, + IN PUINT_16 pu2Offset, + IN PUINT_8 pucBuf, + IN UINT_16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], IN UINT_32 u4AttriTableSize) +{ + + PUINT_8 pucBuffer = (PUINT_8) NULL; + P_IE_WFD_T prIeWFD = (P_IE_WFD_T) NULL; + UINT_32 u4OverallAttriLen; + UINT_32 u4AttriLen; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + UINT_8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; + UINT_32 i; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); + + pucBuffer = (PUINT_8) ((ULONG) pucBuf + (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + /* Check buffer length is still enough. */ + ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= WFD_IE_OUI_HDR); + + prIeWFD = (P_IE_WFD_T) pucBuffer; + + prIeWFD->ucId = ELEM_ID_WFD; + + prIeWFD->aucOui[0] = aucWfaOui[0]; + prIeWFD->aucOui[1] = aucWfaOui[1]; + prIeWFD->aucOui[2] = aucWfaOui[2]; + prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; + + (*pu2Offset) += WFD_IE_OUI_HDR; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + + if (arAppendAttriTable[i].pfnAppendAttri) { + u4AttriLen = + arAppendAttriTable[i].pfnAppendAttri(prAdapter, fgIsAssocFrame, pu2Offset, pucBuf, + u2BufSize); + + u4OverallAttriLen += u4AttriLen; + + if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { + u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; + + prIeWFD->ucLength = (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); + + pucBuffer = + (PUINT_8) ((ULONG) prIeWFD + (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); + + prIeWFD = + (P_IE_WFD_T) ((ULONG) prIeWFD + + (WFD_IE_OUI_HDR + P2P_MAXIMUM_ATTRIBUTE_LEN)); + + kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); + + prIeWFD->ucId = ELEM_ID_WFD; + + prIeWFD->aucOui[0] = aucWfaOui[0]; + prIeWFD->aucOui[1] = aucWfaOui[1]; + prIeWFD->aucOui[2] = aucWfaOui[2]; + prIeWFD->ucOuiType = VENDOR_OUI_TYPE_WFD; + + kalMemCopy(prIeWFD->aucWFDAttributes, aucTempBuffer, u4OverallAttriLen); + (*pu2Offset) += WFD_IE_OUI_HDR; + } + + } + + } + + prIeWFD->ucLength = (UINT_8) (VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); + + } while (FALSE); + +} /* wfdFuncGenerateWfd_IE */ + +#endif /* CFG_SUPPORT_WFD_COMPOSE_IE */ + +UINT_32 +wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, IN P_STA_RECORD_T prStaRec) +{ + +#if CFG_SUPPORT_WFD_COMPOSE_IE + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + if (!IS_STA_P2P_TYPE(prStaRec) || (prWfdCfgSettings->ucWfdEnable == 0)) + return 0; + + return p2pFuncCalculateP2P_IELen(prAdapter, + eNetTypeIndex, + prStaRec, + txAssocRspWFDAttributesTable, + sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + +#else + return 0; +#endif +} /* wfdFuncCalculateWfdIELenForAssocRsp */ + +VOID wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + +#if CFG_SUPPORT_WFD_COMPOSE_IE + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_STA_RECORD_T prStaRec; + + do { + ASSERT_BREAK((prMsduInfo != NULL) && (prAdapter != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + ASSERT(FALSE); + } else if (IS_STA_P2P_TYPE(prStaRec)) { + + if (prWfdCfgSettings->ucWfdEnable == 0) + break; + if ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == 0) + break; + + wfdFuncGenerateWfd_IE(prAdapter, + FALSE, + &prMsduInfo->u2FrameLength, + prMsduInfo->prPacket, + 1500, + txAssocRspWFDAttributesTable, + sizeof(txAssocRspWFDAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + } + } while (FALSE); + + return; +#else + + return; +#endif +} /* wfdFuncGenerateWfdIEForAssocRsp */ + +VOID p2pFuncComposeNoaAttribute(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + + P_IE_P2P_T prIeP2P; + P_P2P_ATTRI_NOA_T prNoaAttr = NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; + P_NOA_DESCRIPTOR_T prNoaDesc = NULL; + + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + UINT_32 u4AttributeLen; + UINT_32 u4NumOfNoaDesc = 0; + UINT_32 i = 0; + /*P2P IE format */ + prIeP2P = (P_IE_P2P_T) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + prIeP2P->ucId = ELEM_ID_P2P; + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + /*P2P Attribute--NoA */ + prNoaAttr = (P_P2P_ATTRI_NOA_T) prIeP2P->aucP2PAttributes; + + prNoaAttr->ucId = P2P_ATTRI_ID_NOTICE_OF_ABSENCE; + prNoaAttr->ucIndex = prP2pSpecificBssInfo->ucNoAIndex; + /*OPP*/ if (prP2pSpecificBssInfo->fgEnableOppPS) { + prNoaAttr->ucCTWOppPSParam = P2P_CTW_OPPPS_PARAM_OPPPS_FIELD | + (prP2pSpecificBssInfo->u2CTWindow & P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK); + } else { + prNoaAttr->ucCTWOppPSParam = 0; + } + /*NoA Description */ + DBGLOG(P2P, INFO, "Compose NoA count=%d.\n", prP2pSpecificBssInfo->ucNoATimingCount); + for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { + if (prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse) { + + prNoaDesc = (P_NOA_DESCRIPTOR_T) &prNoaAttr->aucNoADesc[u4NumOfNoaDesc]; + + prNoaDesc->ucCountType = prP2pSpecificBssInfo->arNoATiming[i].ucCount; + prNoaDesc->u4Duration = prP2pSpecificBssInfo->arNoATiming[i].u4Duration; + prNoaDesc->u4Interval = prP2pSpecificBssInfo->arNoATiming[i].u4Interval; + prNoaDesc->u4StartTime = prP2pSpecificBssInfo->arNoATiming[i].u4StartTime; + + u4NumOfNoaDesc++; + } + } + + /* include "index" + "OppPs Params" + "NOA descriptors" */ + prNoaAttr->u2Length = 2 + u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T); + u4NumOfNoaDesc++; + + /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ + u4AttributeLen = P2P_ATTRI_HDR_LEN + prNoaAttr->u2Length; + + prIeP2P->ucLength = VENDOR_OUI_TYPE_LEN + u4AttributeLen; + prMsduInfo->u2FrameLength += (ELEM_HDR_LEN + prIeP2P->ucLength); + +} + +UINT_32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN UINT_32 ucBssIdx, IN P_STA_RECORD_T prStaRec) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; + UINT_8 ucIdx; + UINT_32 u4NumOfNoaDesc = 0; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) + return 0; + + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + for (ucIdx = 0; ucIdx < prP2pSpecificBssInfo->ucNoATimingCount; ucIdx++) { + if (prP2pSpecificBssInfo->arNoATiming[ucIdx].fgIsInUse) + u4NumOfNoaDesc++; + } + + /* include "index" + "OppPs Params" + "NOA descriptors" */ + /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA descriptors" */ + + return P2P_ATTRI_LEN_NOTICE_OF_ABSENCE + (u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T)); +} + +VOID p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo)) { /* Hotspot */ + return; + } + + /* Compose NoA attribute */ + p2pFuncComposeNoaAttribute(prAdapter, + prMsduInfo /*prMsduInfo->ucBssIndex, prIeP2P->aucP2PAttributes, &u4AttributeLen */); + +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c new file mode 100644 index 0000000000000..f25df82d9ca76 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm.c @@ -0,0 +1,905 @@ +/* +** Id: @(#) p2p_rlm.c@@ +*/ + +/*! \file "p2p_rlm.c" + \brief + +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init AP Bss +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ENUM_BAND_T eBand; + UINT_8 ucChannel; + ENUM_CHNL_EXT_T eSCO; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) + return; + + /* Operation band, channel shall be ready before invoking this function. + * Bandwidth may be ready if other network is connected + */ + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + + if (RLM_AP_IS_BW_40_ALLOWED(prAdapter, prBssInfo)) { + /* In this case, the first BSS's SCO is 40MHz and known, so AP can + * apply 40MHz bandwidth, but the first BSS's SCO may be changed + * later if its Beacon lost timeout occurs + */ + if (cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) && + eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel && eBand == prBssInfo->eBand) { + prBssInfo->eBssSCO = eSCO; + } else if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex)) { + prBssInfo->eBssSCO = rlmDecideScoForAP(prAdapter, prBssInfo); + } + + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prBssInfo->fg40mBwAllowed = TRUE; + prBssInfo->fgAssoc40mBwAllowed = TRUE; + + prBssInfo->ucHtOpInfo1 = (UINT_8) + (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); + + rlmUpdateBwByChListForAP(prAdapter, prBssInfo); + } + } + + DBGLOG(RLM, INFO, "WLAN AP SCO=%d\n", prBssInfo->eBssSCO); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_IE_OBSS_SCAN_PARAM_T prObssScanIe; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11N(prBssInfo) && !RLM_NET_IS_BOW(prBssInfo) && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) && + prBssInfo->eBand == BAND_2G4 && prBssInfo->eBssSCO != CHNL_EXT_SCN) { + + prObssScanIe = (P_IE_OBSS_SCAN_PARAM_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add 20/40 BSS coexistence IE */ + prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS; + prObssScanIe->ucLength = sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN; + + prObssScanIe->u2ScanPassiveDwell = dot11OBSSScanPassiveDwell; + prObssScanIe->u2ScanActiveDwell = dot11OBSSScanActiveDwell; + prObssScanIe->u2TriggerScanInterval = dot11BSSWidthTriggerScanInterval; + prObssScanIe->u2ScanPassiveTotalPerChnl = dot11OBSSScanPassiveTotalPerChannel; + prObssScanIe->u2ScanActiveTotalPerChnl = dot11OBSSScanActiveTotalPerChannel; + prObssScanIe->u2WidthTransDelayFactor = dot11BSSWidthChannelTransitionDelayFactor; + prObssScanIe->u2ScanActivityThres = dot11OBSSScanActivityThreshold; + + ASSERT(IE_SIZE(prObssScanIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN)); + + prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P GO. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + UINT_8 ucLevel; + BOOLEAN fgBwChange; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + fgBwChange = FALSE; + + if (prBssInfo->eBssSCO == CHNL_EXT_SCN) + return fgBwChange; + + ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO); + + if (ucLevel == CHNL_LEVEL0) { + /* Forced to 20MHz, so extended channel is SCN and STA width is zero */ + prBssInfo->fgObssActionForcedTo20M = TRUE; + + if (prBssInfo->ucHtOpInfo1 != (UINT_8) CHNL_EXT_SCN) { + prBssInfo->ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; + fgBwChange = TRUE; + } + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, OBSS_20_40M_TIMEOUT * MSEC_PER_SEC); + } + + /* Clear up all channel lists */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + return fgBwChange; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_20_40_COEXIST_FRAME prRxFrame; + P_IE_20_40_COEXIST_T prCoexist; + P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + PUINT_8 pucIE; + UINT_16 u2IELength, u2Offset; + UINT_8 i, j; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || + !prStaRec || prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || + HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != NETWORK_TYPE_P2P_INDEX) { + return; + } + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || prBssInfo->eBssSCO == CHNL_EXT_SCN) { + return; + } + + prCoexist = &prRxFrame->rBssCoexist; + if (prCoexist->ucData & (BSS_COEXIST_40M_INTOLERANT | BSS_COEXIST_20M_REQ)) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == prBssInfo->ucPrimaryChannel) + break; + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_20mReqChnlList[i] = prBssInfo->ucPrimaryChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + + /* Process intolerant channel report IE */ + pucIE = (PUINT_8) &prRxFrame->rChnlReport; + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT: + prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T) pucIE; + + if (prChnlReport->ucLength <= 1) + break; + + /* To do: process regulatory class. Now we assume 2.4G band */ + + for (j = 0; j < prChnlReport->ucLength - 1; j++) { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_NonHtChnlList[i] == prChnlReport->aucChannelList[j]) + break; + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = prChnlReport->aucChannelList[j]; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + } + break; + + default: + break; + } + } /* end of IE_FOR_EACH */ + + if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) { + bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); + rlmSyncOperationParams(prAdapter, prBssInfo); + } + + /* Check if OBSS scan exemption response should be sent */ + if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ) + rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_NOTIFY_CHNL_WIDTH_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_NOTIFY_CHNL_WIDTH_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prRxFrame->ucAction != ACTION_HT_NOTIFY_CHANNEL_WIDTH || + !prStaRec || prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < sizeof(ACTION_NOTIFY_CHNL_WIDTH_FRAME)) { + return; + } + + /* To do: depending regulation class 13 and 14 based on spec + * Note: (ucChannelWidth==1) shall restored back to original capability, + * not current setting to 40MHz BW here + */ + if (prRxFrame->ucChannelWidth == 0) + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + else if (prRxFrame->ucChannelWidth == 1) + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prObssStatus); + ASSERT(prObssStatus->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prObssStatus->ucNetTypeIndex]; + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT); + + prBssInfo->fgObssErpProtectMode = (BOOLEAN) prObssStatus->ucObssErpProtectMode; + prBssInfo->eObssHtProtectMode = (ENUM_HT_PROTECT_MODE_T) prObssStatus->ucObssHtProtectMode; + prBssInfo->eObssGfOperationMode = (ENUM_GF_MODE_T) prObssStatus->ucObssGfOperationMode; + prBssInfo->fgObssRifsOperationMode = (BOOLEAN) prObssStatus->ucObssRifsOperationMode; + prBssInfo->fgObssBeaconForcedTo20M = (BOOLEAN) prObssStatus->ucObssBeaconForcedTo20M; + + /* Check if Beacon content need to be updated */ + rlmUpdateParamsForAP(prAdapter, prBssInfo, TRUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon) +{ + P_LINK_T prStaList; + P_STA_RECORD_T prStaRec; + BOOLEAN fgErpProtectMode, fgSta40mIntolerant; + BOOLEAN fgUseShortPreamble, fgUseShortSlotTime; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + UINT_8 ucHtOpInfo1; +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + P_GLUE_INFO_T prGlueInfo; +#endif + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) + return; + + fgErpProtectMode = FALSE; + eHtProtectMode = HT_PROTECT_MODE_NONE; + eGfOperationMode = GF_MODE_NORMAL; + fgSta40mIntolerant = FALSE; + fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + fgUseShortSlotTime = TRUE; + ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN; + + prStaList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) { + /* ASSERT(prStaRec); */ + if (!prStaRec) { + DBGLOG(P2P, TRACE, "prStaRec is NULL in rlmUpdateParamsForAP()\n"); + break; + } + if (prStaRec->fgIsInUse && prStaRec->ucStaState == STA_STATE_3 && + prStaRec->ucNetTypeIndex == prBssInfo->ucNetTypeIndex) { + if (!(prStaRec->ucPhyTypeSet & (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) { + /* B-only mode, so mode 1 (ERP protection) */ + fgErpProtectMode = TRUE; + } + + if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + /* BG-only or A-only */ + eHtProtectMode = HT_PROTECT_MODE_NON_HT; + } else if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { + /* 20MHz-only */ + /* + The HT Protection field may be set to 20 MHz protection + mode only if the following are true: + \A1X All STAs detected (by any means) in the primary channel + and all STAs detected (by any means) in the secondary + channel are HT STAs and all STAs that are members of + this BSS are HT STAs, and + \A1X This BSS is a 20/40 MHz BSS, and + \A1X There is at least one 20 MHz HT STA associated with this BSS. + */ + if (eHtProtectMode == HT_PROTECT_MODE_NONE && prBssInfo->fgAssoc40mBwAllowed) + eHtProtectMode = HT_PROTECT_MODE_20M; + } + + if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF)) + eGfOperationMode = GF_MODE_PROTECT; + + if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) + fgUseShortPreamble = FALSE; + + if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME)) + fgUseShortSlotTime = FALSE; + + if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) + fgSta40mIntolerant = TRUE; + } + } /* end of LINK_FOR_EACH_ENTRY */ + + /* Check if HT operation IE about 20/40M bandwidth shall be updated */ + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + if (/*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant && + !prBssInfo->fgObssActionForcedTo20M && !prBssInfo->fgObssBeaconForcedTo20M) { + + ucHtOpInfo1 = (UINT_8) + (((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH); + } + } +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + prGlueInfo = prAdapter->prGlueInfo; + if (prGlueInfo->prP2PInfo->u4PsLevel & BITS(8, 15)) + fgErpProtectMode = TRUE; +#endif + + /* Check if any new parameter may be updated */ + if (prBssInfo->fgErpProtectMode != fgErpProtectMode || + prBssInfo->eHtProtectMode != eHtProtectMode || + prBssInfo->eGfOperationMode != eGfOperationMode || + prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 || + prBssInfo->fgUseShortPreamble != fgUseShortPreamble || + prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) { + + prBssInfo->fgErpProtectMode = fgErpProtectMode; + prBssInfo->eHtProtectMode = eHtProtectMode; + prBssInfo->eGfOperationMode = eGfOperationMode; + prBssInfo->ucHtOpInfo1 = ucHtOpInfo1; + prBssInfo->fgUseShortPreamble = fgUseShortPreamble; + prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime; + + if (fgUseShortSlotTime) + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + else + prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + + rlmSyncOperationParams(prAdapter, prBssInfo); + fgUpdateBeacon = TRUE; + } + + /* Update Beacon content if related IE content is changed */ + if (fgUpdateBeacon) + bssUpdateBeaconContent(prAdapter, prBssInfo->ucNetTypeIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initial the channel list from the domain information. +* This function is called after P2P initial and Domain information changed. +* Make sure the device is disconnected while changing domain information. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_DOMAIN_INFO_ENTRY prDomainInfoEntry = (P_DOMAIN_INFO_ENTRY) NULL; + P_DOMAIN_SUBBAND_INFO prDomainSubBand = (P_DOMAIN_SUBBAND_INFO) NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; + UINT_32 u4Idx = 0, u4IdxII = 0; + UINT_8 ucBufferSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE; +#if 0 + UINT_8 ucSocialChnlSupport = 0, ucAutoChnl = 0; +#endif + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; +#if 0 + ucAutoChnl = prP2pConnSetting->ucOperatingChnl; +#endif + + prDomainInfoEntry = rlmDomainGetDomainInfo(prAdapter); + + ASSERT_BREAK((prDomainInfoEntry != NULL) && (prP2pConnSetting != NULL)); + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; + + for (u4Idx = 0; u4Idx < MAX_SUBBAND_NUM; u4Idx++) { + prDomainSubBand = &prDomainInfoEntry->rSubBand[u4Idx]; + + if (((prDomainSubBand->ucBand == BAND_5G) && (!prAdapter->fgEnable5GBand)) || + (prDomainSubBand->ucBand == BAND_NULL)) { + continue; + } + + if (ucBufferSize < (P2P_ATTRI_LEN_CHANNEL_ENTRY + prDomainSubBand->ucNumChannels)) { + /* Buffer is not enough to include all supported channels. */ + break; /* for */ + } + + prChannelEntryField->ucRegulatoryClass = prDomainSubBand->ucRegClass; + prChannelEntryField->ucNumberOfChannels = prDomainSubBand->ucNumChannels; + + for (u4IdxII = 0; u4IdxII < prDomainSubBand->ucNumChannels; u4IdxII++) { + prChannelEntryField->aucChannelList[u4IdxII] = prDomainSubBand->ucFirstChannelNum + + (u4IdxII * prDomainSubBand->ucChannelSpan); + +#if 0 + switch (prChannelEntryField->aucChannelList[u4IdxII]) { + case 1: + ucSocialChnlSupport = 1; + break; + case 6: + ucSocialChnlSupport = 6; + break; + case 11: + ucSocialChnlSupport = 11; + break; + default: + break; + } + +#endif + } + + if (ucBufferSize >= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels)) + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + else + break; + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG) + prChannelEntryField->ucNumberOfChannels); + + } + +#if 0 + if (prP2pConnSetting->ucListenChnl == 0) { + prP2pConnSetting->ucListenChnl = P2P_DEFAULT_LISTEN_CHANNEL; + + if (ucSocialChnlSupport != 0) { + /* 1. User Not Set LISTEN channel. + * 2. Social channel is not empty. + */ + prP2pConnSetting->ucListenChnl = ucSocialChnlSupport; + } + } +#endif + + /* TODO: 20110921 frog - */ + /* If LISTEN channel is not set, + * a random supported channel would be set. + * If no social channel is supported, DEFAULT channel would be set. + */ + + prP2pConnSetting->ucRfChannelListSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE - ucBufferSize; + +#if 0 + if (prP2pConnSetting->ucOperatingChnl == 0) { /* User not set OPERATE channel. */ + + if (scnQuerySparseChannel(prAdapter, NULL, &ucAutoChnl)) + break; /* while */ + + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; + + while (ucBufferSize != 0) { + if (prChannelEntryField->ucNumberOfChannels != 0) { + ucAutoChnl = prChannelEntryField->aucChannelList[0]; + break; /* while */ + } + + else { + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((UINT_32) prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (UINT_32)prChannelEntryField->ucNumberOfChannels); + + ucBufferSize -= + (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + } + + } + + } +#endif + /* We assume user would not set a channel not in the channel list. + * If so, the operating channel still depends on target device supporting capability. + */ + + /* TODO: 20110921 frog - */ + /* If the Operating channel is not set, a channel from supported channel list is set automatically. + * If there is no supported channel in channel list, a DEFAULT channel is set. + */ + + } while (FALSE); + +#if 0 + prP2pConnSetting->ucOperatingChnl = ucAutoChnl; +#endif + +} /* rlmFuncInitialChannelList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find a common channel list from the local channel list info & target channel list info. +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return boolean value if probe response frame is +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, + IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize) +{ + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) NULL, prChannelEntryIII = + (P_CHANNEL_ENTRY_FIELD_T) NULL; + UINT_8 aucCommonChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE] = {0}; + UINT_8 ucOriChnlSize = 0, ucNewChnlSize = 0; + + do { + + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + + prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) aucCommonChannelList; + + while (ucChannelListSize > 0) { + + prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; + ucOriChnlSize = prP2pConnSetting->ucRfChannelListSize; + + while (ucOriChnlSize > 0) { + if (prChannelEntryI->ucRegulatoryClass == prChannelEntryII->ucRegulatoryClass) { + prChannelEntryIII->ucRegulatoryClass = prChannelEntryI->ucRegulatoryClass; + /* TODO: Currently we assume that the regulatory class the same, + * the channels are the same. */ + kalMemCopy(prChannelEntryIII->aucChannelList, prChannelEntryII->aucChannelList, + prChannelEntryII->ucNumberOfChannels); + prChannelEntryIII->ucNumberOfChannels = prChannelEntryII->ucNumberOfChannels; + + ucNewChnlSize += + P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryIII->ucNumberOfChannels; + + prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryIII + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG)prChannelEntryIII->ucNumberOfChannels); + } + + ucOriChnlSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryI->ucNumberOfChannels); + + prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryI + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG) + prChannelEntryI->ucNumberOfChannels); + + } + + ucChannelListSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryII->ucNumberOfChannels); + + prChannelEntryII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryII + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG) prChannelEntryII->ucNumberOfChannels); + + } + + kalMemCopy(prP2pConnSetting->aucChannelEntriesField, aucCommonChannelList, ucNewChnlSize); + prP2pConnSetting->ucRfChannelListSize = ucNewChnlSize; + + } while (FALSE); + +} /* rlmFuncCommonChannelList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum) +{ + UINT_8 ucRegulatoryClass = 0, ucBufferSize = 0; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL; + UINT_32 u4Idx = 0; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; + + while (ucBufferSize != 0) { + + for (u4Idx = 0; u4Idx < prChannelEntryField->ucNumberOfChannels; u4Idx++) { + if (prChannelEntryField->aucChannelList[u4Idx] == ucChannelNum) { + ucRegulatoryClass = prChannelEntryField->ucRegulatoryClass; + break; + } + + } + + if (ucRegulatoryClass != 0) + break; /* while */ + + prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG)prChannelEntryField->ucNumberOfChannels); + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels); + + } + + } while (FALSE); + + return ucRegulatoryClass; +} /* rlmFuncFindOperatingClass */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucCheckChnl, + IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel) +{ + BOOLEAN fgIsResultAvailable = FALSE; + P_CHANNEL_ENTRY_FIELD_T prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL; + UINT_8 ucBufferSize = 0, ucIdx = 0, ucChannelSelected = 0; + + do { + ASSERT_BREAK(prAdapter != NULL); + + if (fgIsDefaultChannel) + ucChannelSelected = P2P_DEFAULT_LISTEN_CHANNEL; + + prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings; + ucBufferSize = prP2pConnSetting->ucRfChannelListSize; + prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField; + + while ((ucBufferSize != 0) && (!fgIsResultAvailable)) { + + for (ucIdx = 0; ucIdx < prChannelEntry->ucNumberOfChannels; ucIdx++) { + if ((!fgIsSocialChannel) || + (prChannelEntry->aucChannelList[ucIdx] == 1) || + (prChannelEntry->aucChannelList[ucIdx] == 6) || + (prChannelEntry->aucChannelList[ucIdx] == 11)) { + + if (prChannelEntry->aucChannelList[ucIdx] <= 11) { + /* 2.4G. */ + ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; + } else if ((prChannelEntry->aucChannelList[ucIdx] < 52) && + (prChannelEntry->aucChannelList[ucIdx] > 14)) { + /* 2.4G + 5G. */ + ucChannelSelected = prChannelEntry->aucChannelList[ucIdx]; + } + + if (ucChannelSelected == ucCheckChnl) { + fgIsResultAvailable = TRUE; + break; + } + } + + } + + ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntry->ucNumberOfChannels); + + prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntry + + P2P_ATTRI_LEN_CHANNEL_ENTRY + + (ULONG) prChannelEntry->ucNumberOfChannels); + + } + + if ((!fgIsResultAvailable) && (pucSuggestChannel != NULL)) { + DBGLOG(P2P, TRACE, + "The request channel %d is not available, sugguested channel:%d\n", ucCheckChnl, + ucChannelSelected); + /* Given a suggested channel. */ + *pucSuggestChannel = ucChannelSelected; + } + + } while (FALSE); + + return fgIsResultAvailable; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + UINT_8 ucSecondChannel, i, j; + ENUM_CHNL_EXT_T eSCO; + + eSCO = CHNL_EXT_SCN; + + if (prBssInfo->eBand == BAND_2G4) { + if (prBssInfo->ucPrimaryChannel != 14) + eSCO = (prBssInfo->ucPrimaryChannel > 7) ? CHNL_EXT_SCB : CHNL_EXT_SCA; + } else { + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + if (prSubband->ucBand == prBssInfo->eBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) + == prBssInfo->ucPrimaryChannel) { + eSCO = (j & 1) ? CHNL_EXT_SCB : CHNL_EXT_SCA; + break; + } + } + + if (j < prSubband->ucNumChannels) + break; /* Found */ + } + } + } + + /* Check if it is boundary channel and 40MHz BW is permitted */ + if (eSCO != CHNL_EXT_SCN) { + ucSecondChannel = (eSCO == CHNL_EXT_SCA) ? + (prBssInfo->ucPrimaryChannel + 4) : (prBssInfo->ucPrimaryChannel - 4); + + if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel)) + eSCO = CHNL_EXT_SCN; + } + + return eSCO; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c new file mode 100644 index 0000000000000..154f1e5db0f73 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_rlm_obss.c @@ -0,0 +1,313 @@ +/* +** Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_cfg80211.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + using cfg80211 interface + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#include "precomp.h" + +static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); + +static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend); + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Different concurrent network has itself channel lists, and +* concurrent networks should have been recorded in channel lists. +* If role of active P2P is GO, assume associated AP of AIS will +* record our Beacon for P2P GO because of same channel. +* +* Note: If we have scenario of different channel in the future, +* the internal FW communication channel shall be established. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) +{ + UINT_8 ucChannelLevel; + + ASSERT(prBssInfo); + + if (eBand == BAND_2G4) { + ucChannelLevel = rlmObssChnlLevelIn2G4(prBssInfo, ucPriChannel, eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } else if (eBand == BAND_5G) { + ucChannelLevel = rlmObssChnlLevelIn5G(prBssInfo, ucPriChannel, eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } else { + ucChannelLevel = CHNL_LEVEL0; + } + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) +{ + UINT_8 i, ucChannelLevel; + UINT_8 ucSecChannel, ucCenterChannel; + UINT_8 ucAffectedChnl_L, ucAffectedChnl_H; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) { + ucCenterChannel = ucPriChannel + 2; + ucSecChannel = ucPriChannel + 4; + } else if (eExtend == CHNL_EXT_SCB) { + ucCenterChannel = ucPriChannel - 2; + ucSecChannel = ucPriChannel - 4; + } else { + return CHNL_LEVEL0; + } + ASSERT(ucCenterChannel >= 1 && ucCenterChannel <= 14); + + /* Calculated low/upper channels in affected freq range */ + ucAffectedChnl_L = (ucCenterChannel <= AFFECTED_CHNL_OFFSET) ? 1 : (ucCenterChannel - AFFECTED_CHNL_OFFSET); + + ucAffectedChnl_H = (ucCenterChannel >= (14 - AFFECTED_CHNL_OFFSET)) ? + 14 : (ucCenterChannel + AFFECTED_CHNL_OFFSET); + + /* Check intolerant (Non-HT) channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_NonHtChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_NonHtChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_NonHtChnlList[i] != ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 20M BW request channel list */ + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_20mReqChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_20mReqChnlList[i] <= ucAffectedChnl_H)) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G primary channel list */ + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_PriChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_PriChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_PriChnlList[i] != ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G secondary channel list */ + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if ((prBssInfo->auc2G_SecChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_SecChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_SecChnlList[i] != ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + +L_2G4_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) +{ + UINT_8 i, ucChannelLevel; + UINT_8 ucSecChannel; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) + ucSecChannel = ucPriChannel + 4; + else if (eExtend == CHNL_EXT_SCB) + ucSecChannel = ucPriChannel - 4; + else + return CHNL_LEVEL0; + ASSERT(ucSecChannel >= 36); + + /* Check 5G primary channel list */ + ASSERT(prBssInfo->auc5G_PriChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_PriChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_PriChnlList[i] == ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } else if (prBssInfo->auc5G_PriChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check non-HT channel list */ + ASSERT(prBssInfo->auc5G_NonHtChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_NonHtChnlList[i] == ucSecChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } else if (prBssInfo->auc5G_NonHtChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check secondary channel list */ + ASSERT(prBssInfo->auc5G_SecChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; i <= prBssInfo->auc5G_SecChnlList[0] && i <= CHNL_LIST_SZ_5G; i++) { + if (prBssInfo->auc5G_SecChnlList[i] == ucPriChannel) { + + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } + } + +L_5G_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + + /* To do: need an algorithm to do judgement. Now always reject request */ + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfo == NULL) + return; + + DBGLOG(RLM, INFO, "Send 20/40 coexistence rsp frame!\n"); + + prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) prMsduInfo->prPacket; + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, ((P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader)->aucSrcAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = 0; + + ASSERT((WLAN_MAC_HEADER_LEN + 5) <= PUBLIC_ACTION_MAX_LEN); + + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfo->ucStaRecIndex = prSwRfb->ucStaRecIdx; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_HTC_LEN + 5; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c new file mode 100644 index 0000000000000..b5bd23965fe35 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_scan.c @@ -0,0 +1,756 @@ +/* +** Id: @(#) p2p_scan.c@@ +*/ + +/*! \file "p2p_scan.c" + \brief This file defines the p2p scan profile and the processing function of + scan result for SCAN Module. + + The SCAN Profile selection is part of SCAN MODULE and responsible for defining + SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. + In this file we also define the process of SCAN Result including adding, searching + and removing SCAN record from the list. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +P_P2P_DEVICE_DESC_T +scanSearchTargetP2pDesc(IN P_ADAPTER_T prAdapter, IN UINT_8 aucDeviceID[], IN PP_BSS_DESC_T pprBssDesc) +{ + + P_P2P_DEVICE_DESC_T prTargetP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; + P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + + ASSERT(prAdapter); + ASSERT(aucDeviceID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + /* 4 <1> The outer loop to search for a candidate. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + /* Loop for each prBssDesc */ + prTargetP2pDesc = scanFindP2pDeviceDesc(prAdapter, prBssDesc, aucDeviceID, TRUE, FALSE); + + if (prTargetP2pDesc != NULL) + break; + } + + if ((pprBssDesc) && (prTargetP2pDesc != NULL)) { + /* Only valid if prTargetP2pDesc is not NULL. */ + *pprBssDesc = prBssDesc; + } + + return prTargetP2pDesc; +} /* scanSearchTargetP2pDesc */ + +VOID scanInvalidAllP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (prTargetDesc->fgDevInfoValid) + prTargetDesc->fgDevInfoValid = FALSE; + } + +} /* scanRenewP2pClientDevice */ + +VOID scanRemoveInvalidP2pClientDevice(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL, prNexEntry = (P_LINK_ENTRY_T) NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + LINK_FOR_EACH_SAFE(prLinkEntry, prNexEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (!prTargetDesc->fgDevInfoValid) { + LINK_REMOVE_KNOWN_ENTRY(&prBssDesc->rP2pDeviceList, prLinkEntry); + if ((prP2pConnSettings) && (prP2pConnSettings->prTargetP2pDesc == prTargetDesc)) + prP2pConnSettings->prTargetP2pDesc = NULL; + kalMemFree(prTargetDesc, VIR_MEM_TYPE, sizeof(P2P_DEVICE_DESC_T)); + } + } + +} /* scanRenewP2pClientDevice */ + +P_P2P_DEVICE_DESC_T +scanFindP2pDeviceDesc(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN UINT_8 aucMacAddr[], IN BOOLEAN fgIsDeviceAddr, IN BOOLEAN fgAddIfNoFound) +{ + + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssDesc != NULL) && (aucMacAddr != NULL)); + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + if (fgIsDeviceAddr) { + if (EQUAL_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr)) + break; + } else { + if (EQUAL_MAC_ADDR(prTargetDesc->aucInterfaceAddr, aucMacAddr)) + break; + } + + prTargetDesc = NULL; + } + + if ((fgAddIfNoFound) && (prTargetDesc == NULL)) { + /* Target Not Found. */ + /* TODO: Use memory pool in the future. */ + prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); + + if (prTargetDesc) { + kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); + LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); + COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, aucMacAddr); + LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); + prTargetDesc->fgDevInfoValid = TRUE; + } else { + ASSERT(FALSE); + } + } + + } while (FALSE); + + return prTargetDesc; +} /* scanFindP2pDeviceDesc */ + +P_P2P_DEVICE_DESC_T scanGetP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; + + ASSERT(prAdapter); + ASSERT(prBssDesc); + + if (prBssDesc->prP2pDesc == NULL) { + + prTargetDesc = kalMemAlloc(sizeof(P2P_DEVICE_DESC_T), VIR_MEM_TYPE); + + if (prTargetDesc) { + kalMemZero(prTargetDesc, sizeof(P2P_DEVICE_DESC_T)); + LINK_ENTRY_INITIALIZE(&(prTargetDesc->rLinkEntry)); + LINK_INSERT_TAIL(&prBssDesc->rP2pDeviceList, &prTargetDesc->rLinkEntry); + prTargetDesc->fgDevInfoValid = TRUE; + prBssDesc->prP2pDesc = prTargetDesc; + /* We are not sure the SrcAddr is Device Address or Interface Address. */ + COPY_MAC_ADDR(prTargetDesc->aucDeviceAddr, prBssDesc->aucSrcAddr); + COPY_MAC_ADDR(prTargetDesc->aucInterfaceAddr, prBssDesc->aucSrcAddr); + } else { + + ASSERT(FALSE); + } + } else { + prTargetDesc = prBssDesc->prP2pDesc; + } + + return prTargetDesc; + +} /* scanFindP2pDeviceDesc */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_P2P_DEVICE_DESC_T prP2pDesc = (P_P2P_DEVICE_DESC_T) NULL; + P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; + UINT_16 u2AttributeLen = 0; + UINT_32 u4Idx = 0; + BOOLEAN fgUpdateDevInfo = FALSE; + + P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; + P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; + + ASSERT(prAdapter); + + prP2pDesc = scanGetP2pDeviceDesc(prAdapter, prBssDesc); + + if (!prP2pDesc) { + ASSERT(FALSE); + return fgUpdateDevInfo; + } + + p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, + &u2AttributeLen); + + while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { + switch (prP2pAttribute->ucId) { + case P2P_ATTRI_ID_P2P_CAPABILITY: /* Beacon, Probe Response */ + { + P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; + + prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; + ASSERT(prP2pAttriCapability->u2Length == 2); + + prP2pDesc->ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; + prP2pDesc->ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; + } + break; + case P2P_ATTRI_ID_P2P_DEV_ID: /* Beacon */ + { + P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; + + prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; + ASSERT(prP2pAttriDevID->u2Length == P2P_ATTRI_MAX_LEN_P2P_DEV_ID); + + kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); + } + break; + case P2P_ATTRI_ID_P2P_DEV_INFO: /* Probe Response */ + { + P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; + UINT_16 u2NameLen = 0, u2Id = 0; + + fgUpdateDevInfo = TRUE; + + prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; + + kalMemCopy(prP2pDesc->aucDeviceAddr, prP2pAttriDevInfo->aucDevAddr, MAC_ADDR_LEN); + + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); + + prP2pDevType = &prP2pDesc->rPriDevType; + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId, + &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId, + &prP2pDevType->u2SubCategoryID); + + ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= + P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); + /* TODO: Fixme if secondary device type is more than 2. */ + prP2pDesc->ucSecDevTypeNum = 0; + for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { + if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { + prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> + arSecondaryDevTypeListBE[u4Idx].u2CategoryId, + &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prP2pAttriDevInfo-> + arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, + &prP2pDevType->u2SubCategoryID); + prP2pDesc->ucSecDevTypeNum++; + } + + } + prP2pDevName = + (P_DEVICE_NAME_TLV_T) ((PUINT_8) prP2pAttriDevInfo->arSecondaryDevTypeListBE + + (u4Idx * sizeof(DEVICE_TYPE_T))); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &u2NameLen); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Id, &u2Id); + ASSERT(u2Id == WPS_ATTRI_ID_DEVICE_NAME); + if (u2NameLen > WPS_ATTRI_MAX_LEN_DEVICE_NAME) + u2NameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + prP2pDesc->u2NameLength = u2NameLen; + kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); + } + break; + case P2P_ATTRI_ID_P2P_GROUP_INFO: /* Probe Response */ + prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; + break; + case P2P_ATTRI_ID_NOTICE_OF_ABSENCE: + break; + case P2P_ATTRI_ID_EXT_LISTEN_TIMING: + /* TODO: Not implement yet. */ + /* ASSERT(FALSE); */ + break; + default: + break; + } + + u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); + + prP2pAttribute = + (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); + + } + + if (prP2pAttriGroupInfo != NULL) { + P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; + + scanInvalidAllP2pClientDevice(prAdapter, prBssDesc); + + /* GO/Device itself. */ + prP2pDesc->fgDevInfoValid = TRUE; + + prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) prP2pAttriGroupInfo->arClientDesc; + u2AttributeLen = prP2pAttriGroupInfo->u2Length; + + while (u2AttributeLen > 0) { + prP2pDesc = + scanFindP2pDeviceDesc(prAdapter, prBssDesc, prClientInfoDesc->aucDevAddr, TRUE, TRUE); + + if (!prP2pDesc) { + ASSERT(FALSE); + break; /* while */ + } + + prP2pDesc->fgDevInfoValid = TRUE; + + /* Basic size for P2P client info descriptor. */ + ASSERT(u2AttributeLen >= 25); + if (u2AttributeLen < 25) { + DBGLOG(P2P, WARN, "Length incorrect warning.\n"); + break; + } + COPY_MAC_ADDR(prP2pDesc->aucInterfaceAddr, prClientInfoDesc->aucIfAddr); + + prP2pDesc->ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; + + WLAN_GET_FIELD_BE16(&prClientInfoDesc->u2ConfigMethodsBE, &prP2pDesc->u2ConfigMethod); + + prP2pDevType = &(prP2pDesc->rPriDevType); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId, + &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId, + &prP2pDevType->u2SubCategoryID); + + ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT); + prP2pDesc->ucSecDevTypeNum = 0; + for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { + if (u4Idx < P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT) { + prP2pDevType = &(prP2pDesc->arSecDevType[u4Idx]); + WLAN_GET_FIELD_BE16(&prClientInfoDesc-> + arSecondaryDevTypeListBE[u4Idx].u2CategoryId, + &prP2pDevType->u2CategoryID); + WLAN_GET_FIELD_BE16(&prClientInfoDesc-> + arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId, + &prP2pDevType->u2SubCategoryID); + prP2pDesc->ucSecDevTypeNum++; + } + + } + prP2pDevName = + (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + + (u4Idx * sizeof(DEVICE_TYPE_T))); + WLAN_GET_FIELD_BE16(&prP2pDevName->u2Length, &prP2pDesc->u2NameLength); + if (prP2pDesc->u2NameLength > WPS_ATTRI_MAX_LEN_DEVICE_NAME) + prP2pDesc->u2NameLength = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + + kalMemCopy(prP2pDesc->aucName, prP2pDevName->aucName, prP2pDesc->u2NameLength); + + u2AttributeLen -= (prClientInfoDesc->ucLength + P2P_CLIENT_INFO_DESC_HDR_LEN); + prClientInfoDesc = + (P_P2P_CLIENT_INFO_DESC_T) ((UINT_32) prClientInfoDesc + + (UINT_32) prClientInfoDesc->ucLength + + P2P_CLIENT_INFO_DESC_HDR_LEN); + } + + scanRemoveInvalidP2pClientDevice(prAdapter, prBssDesc); + } + + return fgUpdateDevInfo; +} /* end of scanAddP2pDeviceInfo() */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to Event Packet +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS scanSendDeviceDiscoverEvent(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) +{ + EVENT_P2P_DEV_DISCOVER_RESULT_T rEventDevInfo; +#if 1 + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T) NULL; + P_P2P_DEVICE_DESC_T prTargetDesc = (P_P2P_DEVICE_DESC_T) NULL; + + LINK_FOR_EACH(prLinkEntry, &prBssDesc->rP2pDeviceList) { + prTargetDesc = LINK_ENTRY(prLinkEntry, P2P_DEVICE_DESC_T, rLinkEntry); + + COPY_MAC_ADDR(rEventDevInfo.aucDeviceAddr, prTargetDesc->aucDeviceAddr); + COPY_MAC_ADDR(rEventDevInfo.aucInterfaceAddr, prTargetDesc->aucInterfaceAddr); + + rEventDevInfo.ucDeviceCapabilityBitmap = prTargetDesc->ucDeviceCapabilityBitmap; + rEventDevInfo.ucGroupCapabilityBitmap = prTargetDesc->ucGroupCapabilityBitmap; + rEventDevInfo.u2ConfigMethod = prTargetDesc->u2ConfigMethod; + + kalMemCopy(&rEventDevInfo.rPriDevType, &prTargetDesc->rPriDevType, sizeof(P2P_DEVICE_TYPE_T)); + + kalMemCopy(rEventDevInfo.arSecDevType, + prTargetDesc->arSecDevType, (prTargetDesc->ucSecDevTypeNum * sizeof(P2P_DEVICE_TYPE_T))); + + rEventDevInfo.ucSecDevTypeNum = prTargetDesc->ucSecDevTypeNum; + + rEventDevInfo.u2NameLength = prTargetDesc->u2NameLength; + kalMemCopy(rEventDevInfo.aucName, prTargetDesc->aucName, prTargetDesc->u2NameLength); + + COPY_MAC_ADDR(rEventDevInfo.aucBSSID, prBssDesc->aucBSSID); + + if (prTargetDesc == prBssDesc->prP2pDesc) + nicRxAddP2pDevice(prAdapter, &rEventDevInfo, prBssDesc->aucIEBuf, prBssDesc->u2IELength); + else + nicRxAddP2pDevice(prAdapter, &rEventDevInfo, NULL, 0); + } + + kalP2PIndicateFound(prAdapter->prGlueInfo); + +#else + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + P_P2P_ATTRIBUTE_T prP2pAttribute = (P_P2P_ATTRIBUTE_T) NULL; + UINT_16 u2AttributeLen = 0; + UINT_32 u4Idx = 0; + P_P2P_ATTRI_GROUP_INFO_T prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) NULL; + P_DEVICE_NAME_TLV_T prP2pDevName = (P_DEVICE_NAME_TLV_T) NULL; + + ASSERT(prAdapter); + + prP2pSpecificBssInfo = &prAdapter->rWifiVar.rP2pSpecificBssInfo; + +#if 1 + p2pGetP2PAttriList(prAdapter, prBssDesc->aucIEBuf, prBssDesc->u2IELength, (PPUINT_8) & prP2pAttribute, + &u2AttributeLen); +#else + prP2pAttribute = (P_P2P_ATTRIBUTE_T) &prP2pSpecificBssInfo->aucAttributesCache[0]; + u2AttributeLen = prP2pSpecificBssInfo->u2AttributeLen; +#endif + rEventDevInfo.fgDevInfoValid = FALSE; + + while (u2AttributeLen >= P2P_ATTRI_HDR_LEN) { + switch (prP2pAttribute->ucId) { + case P2P_ATTRI_ID_P2P_CAPABILITY: + { + P_P2P_ATTRI_CAPABILITY_T prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) NULL; + + prP2pAttriCapability = (P_P2P_ATTRI_CAPABILITY_T) prP2pAttribute; + ASSERT(prP2pAttriCapability->u2Length == 2); + rEventDevInfo.ucDeviceCapabilityBitmap = prP2pAttriCapability->ucDeviceCap; + rEventDevInfo.ucGroupCapabilityBitmap = prP2pAttriCapability->ucGroupCap; + } + break; + case P2P_ATTRI_ID_P2P_DEV_ID: + { + P_P2P_ATTRI_DEV_ID_T prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) NULL; + + prP2pAttriDevID = (P_P2P_ATTRI_DEV_ID_T) prP2pAttribute; + ASSERT(prP2pAttriDevID->u2Length == 6); + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevID->aucDevAddr, MAC_ADDR_LEN); + } + break; + case P2P_ATTRI_ID_P2P_DEV_INFO: + { + P_P2P_ATTRI_DEV_INFO_T prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; + + prP2pAttriDevInfo = (P_P2P_ATTRI_DEV_INFO_T) prP2pAttribute; + rEventDevInfo.fgDevInfoValid = TRUE; + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prP2pAttriDevInfo->aucDevAddr, + MAC_ADDR_LEN); + rEventDevInfo.u2ConfigMethod = prP2pAttriDevInfo->u2ConfigMethodsBE; + + prP2pDevType = &rEventDevInfo.rPriDevType; + prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; + + ASSERT(prP2pAttriDevInfo->ucNumOfSecondaryDevType <= 2); + /* TODO: Fixme if secondary device type is more than 2. */ + for (u4Idx = 0; u4Idx < prP2pAttriDevInfo->ucNumOfSecondaryDevType; u4Idx++) { + /* TODO: Current sub device type can only support 2. */ + prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; + prP2pDevType->u2CategoryID = prP2pAttriDevInfo->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = + prP2pAttriDevInfo->rPrimaryDevTypeBE.u2SubCategoryId; + } + + prP2pDevName = + (P_DEVICE_NAME_TLV_T) (prP2pAttriDevInfo->arSecondaryDevTypeListBE + + (u4Idx * sizeof(DEVICE_TYPE_T))); + ASSERT(prP2pDevName->u2Id == 0x1011); + ASSERT(prP2pDevName->u2Length <= 32); + /* TODO: Fixme if device name length is longer than 32 bytes. */ + kalMemCopy(rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); + } + break; + case P2P_ATTRI_ID_P2P_GROUP_INFO: + prP2pAttriGroupInfo = (P_P2P_ATTRI_GROUP_INFO_T) prP2pAttribute; + break; + } + + u2AttributeLen -= (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN); + + prP2pAttribute = + (P_P2P_ATTRIBUTE_T) ((UINT_32) prP2pAttribute + (prP2pAttribute->u2Length + P2P_ATTRI_HDR_LEN)); + + } + + nicRxAddP2pDevice(prAdapter, &rEventDevInfo); + + if (prP2pAttriGroupInfo != NULL) { + P_P2P_CLIENT_INFO_DESC_T prClientInfoDesc = (P_P2P_CLIENT_INFO_DESC_T) NULL; + P_P2P_DEVICE_TYPE_T prP2pDevType = (P_P2P_DEVICE_TYPE_T) NULL; + + prClientInfoDesc = prP2pAttriGroupInfo->arClientDesc; + u2AttributeLen = prP2pAttriGroupInfo->u2Length; + + while (u2AttributeLen > 0) { + /* Basic size for P2P client info descriptor. */ + ASSERT(u2AttributeLen >= 25); + rEventDevInfo.fgDevInfoValid = TRUE; + kalMemCopy(rEventDevInfo.aucCommunicateAddr, prClientInfoDesc->aucIfAddr, MAC_ADDR_LEN); + rEventDevInfo.ucDeviceCapabilityBitmap = prClientInfoDesc->ucDeviceCap; + rEventDevInfo.u2ConfigMethod = prClientInfoDesc->u2ConfigMethodsBE; + + prP2pDevType = &rEventDevInfo.rPriDevType; + prP2pDevType->u2CategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2CategoryId; + prP2pDevType->u2SubCategoryID = prClientInfoDesc->rPrimaryDevTypeBE.u2SubCategoryId; + + ASSERT(prClientInfoDesc->ucNumOfSecondaryDevType <= 2); + /* TODO: Fixme if secondary device type is more than 2. */ + for (u4Idx = 0; u4Idx < prClientInfoDesc->ucNumOfSecondaryDevType; u4Idx++) { + /* TODO: Current sub device type can only support 2. */ + prP2pDevType = &rEventDevInfo.arSecDevType[u4Idx]; + prP2pDevType->u2CategoryID = + prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2CategoryId; + prP2pDevType->u2SubCategoryID = + prClientInfoDesc->arSecondaryDevTypeListBE[u4Idx].u2SubCategoryId; + } + + prP2pDevName = + (P_DEVICE_NAME_TLV_T) (prClientInfoDesc->arSecondaryDevTypeListBE + + (u4Idx * sizeof(DEVICE_TYPE_T))); + ASSERT(prP2pDevName->u2Id == 0x1011); + ASSERT(prP2pDevName->u2Length <= 32); + /* TODO: Fixme if device name length is longer than 32 bytes. */ + kalMemCopy(&rEventDevInfo.aucName, prP2pDevName->aucName, prP2pDevName->u2Length); + + nicRxAddP2pDevice(prAdapter, &rEventDevInfo); + + u2AttributeLen -= prP2pAttriGroupInfo->u2Length; + prP2pAttriGroupInfo = prP2pAttriGroupInfo + prP2pAttriGroupInfo->u2Length + 1; + } + + } +#endif + return WLAN_STATUS_SUCCESS; +} /* scanSendDeviceDiscoverEvent */ + +VOID +scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame) +{ + BOOLEAN fgIsSkipThisBeacon; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + fgIsSkipThisBeacon = FALSE; + if (prBssDesc->fgIsP2PPresent) { + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && /* P2P GC */ + (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && /* Connected */ + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { /* TX Beacon */ + + fgIsSkipThisBeacon = TRUE; + } + + if ((!prP2pBssInfo->ucDTIMPeriod) && /* First time. */ + fgIsSkipThisBeacon && (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen))) { /* SSID Match */ + prP2pBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_P2P_INDEX); + } + + do { + RF_CHANNEL_INFO_T rChannelInfo; + + ASSERT_BREAK((prSwRfb != NULL) && (prBssDesc != NULL)); + + if (((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) != MAC_FRAME_PROBE_RSP)) { + /* Only report Probe Response frame to supplicant. */ + /* Probe response collect much more information. */ + + if (fgIsSkipThisBeacon || prBssDesc->eBand == BAND_2G4) + break; + } + + rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; + rChannelInfo.eBand = prBssDesc->eBand; + prBssDesc->fgIsP2PReport = TRUE; + + DBGLOG(P2P, INFO, "indicate %s [%d]\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prSwRfb->pvHeader, + (UINT_32) prSwRfb->u2PacketLen, + &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); + + } while (FALSE); + } +} + +VOID scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucScnSeqNum) +{ + + CMD_SCAN_CANCEL rCmdScanCancel; + + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = ucScnSeqNum; + rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_CANCEL, + TRUE, + FALSE, FALSE, NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8)&rCmdScanCancel, NULL, 0); + +} /* scnEventReturnChannel */ + +VOID scanRemoveAllP2pBssDesc(IN P_ADAPTER_T prAdapter) +{ + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prBSSDescNext; + + ASSERT(prAdapter); + + prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + scanRemoveP2pBssDesc(prAdapter, prBssDesc); + } +} /* scanRemoveAllP2pBssDesc */ + +VOID scanRemoveP2pBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + + +} /* scanRemoveP2pBssDesc */ + +P_BSS_DESC_T +scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo) +{ + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL, prBssDesc = (P_BSS_DESC_T) NULL; + P_LINK_T prBssDescList = (P_LINK_T) NULL; + + do { + if ((prAdapter == NULL) || (prP2pBssInfo == NULL) || (prConnReqInfo == NULL)) + break; + + prBssDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + DBGLOG(P2P, LOUD, "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); + DBGLOG(P2P, LOUD, "Connecting to SSID:%s, length:%d\n", + prConnReqInfo->rSsidStruct.aucSsid, prConnReqInfo->rSsidStruct.ucSsidLen); + + LINK_FOR_EACH_ENTRY(prBssDesc, prBssDescList, rLinkEntry, BSS_DESC_T) { + DBGLOG(P2P, LOUD, "Checking BSS: %pM\n", prBssDesc->aucBSSID); + + if (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) { + DBGLOG(P2P, LOUD, "Ignore mismatch BSS type.\n"); + continue; + } + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnReqInfo->aucBssid)) { + DBGLOG(P2P, LOUD, "Ignore mismatch BSSID.\n"); + continue; + } + + /* SSID should be the same? SSID is vary for each connection. so... */ + if (UNEQUAL_SSID(prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen)) { + + DBGLOG(P2P, TRACE, + "Connecting to BSSID: %pM\n", prConnReqInfo->aucBssid); + DBGLOG(P2P, TRACE, + "Connecting to SSID:%s, length:%d\n", prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen); + DBGLOG(P2P, TRACE, + "Checking SSID:%s, length:%d\n", prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + DBGLOG(P2P, TRACE, "Ignore mismatch SSID, (But BSSID match).\n"); + ASSERT(FALSE); + continue; + } + + if (!prBssDesc->fgIsP2PPresent) { + DBGLOG(P2P, ERROR, "SSID, BSSID, BSSTYPE match, but no P2P IE present.\n"); + continue; + } + + /* Final decision. */ + prCandidateBssDesc = prBssDesc; + break; + } + + } while (FALSE); + + return prCandidateBssDesc; +} /* scanP2pSearchDesc */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c new file mode 100644 index 0000000000000..befb9978f4735 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/p2p_state.c @@ -0,0 +1,466 @@ +#include "p2p_precomp.h" + +BOOLEAN +p2pStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_BSS_INFO_T prP2pBssInfo, OUT P_ENUM_P2P_STATE_T peNextState) +{ + BOOLEAN fgIsTransOut = FALSE; +/* P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; */ + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL) && (prP2pBssInfo != NULL) && (peNextState != NULL)); + + if ((prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) + && IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + fgIsTransOut = TRUE; + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + + DBGLOG(P2P, INFO, "p2pStateInit_IDLE GO Scan\n"); + *peNextState = P2P_STATE_REQING_CHANNEL; + + } else { +#if 0 + else + if (IS_NET_PWR_STATE_ACTIVE(prAdapter, NETWORK_TYPE_P2P_INDEX)) { + + ASSERT((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)); + + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + if (prChnlReqInfo->fgIsChannelRequested) { + /* Start a timer for return channel. */ + DBGLOG(P2P, TRACE, "start a GO channel timer.\n"); + } + + } +#endif + cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), 5000); + } + + } while (FALSE); + + return fgIsTransOut; +} /* p2pStateInit_IDLE */ + +VOID p2pStateAbort_IDLE(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) +{ + + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prChnlReqInfo = &prP2pFsmInfo->rChnlReqInfo; + + if (prChnlReqInfo->fgIsChannelRequested) { + /* Release channel before timeout. */ + p2pFuncReleaseCh(prAdapter, prChnlReqInfo); + } + + /* Stop timer for leaving this state. */ + cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); + + } while (FALSE); + +} /* p2pStateAbort_IDLE */ + +VOID p2pStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_FSM_INFO_T prP2pFsmInfo) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + /* Store the original channel info. */ + prChnlReqInfo->ucOriChnlNum = prP2pBssInfo->ucPrimaryChannel; + prChnlReqInfo->eOriBand = prP2pBssInfo->eBand; + prChnlReqInfo->eOriChnlSco = prP2pBssInfo->eBssSCO; + + /* RX Probe Request would check primary channel. */ + prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; + prP2pBssInfo->eBand = prChnlReqInfo->eBand; + prP2pBssInfo->eBssSCO = prChnlReqInfo->eChnlSco; + + DBGLOG(P2P, TRACE, "start a channel on hand timer.\n"); + if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING) { + cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), + prChnlReqInfo->u4MaxInterval); + + kalP2PIndicateChannelReady(prAdapter->prGlueInfo, + prChnlReqInfo->u8Cookie, + prChnlReqInfo->ucReqChnlNum, + prChnlReqInfo->eBand, prChnlReqInfo->eChnlSco, prChnlReqInfo->u4MaxInterval); + } else + cnmTimerStartTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer), + (P2P_EXT_LISTEN_TIME_MS - prChnlReqInfo->u4MaxInterval)); + } while (FALSE); + +} /* p2pStateInit_CHNL_ON_HAND */ + +VOID +p2pStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, IN ENUM_P2P_STATE_T eNextState) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); + + /* Restore the original channel info. */ + prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucOriChnlNum; + prP2pBssInfo->eBand = prChnlReqInfo->eOriBand; + prP2pBssInfo->eBssSCO = prChnlReqInfo->eOriChnlSco; + + DBGLOG(P2P, INFO, "p2p state trans abort chann on hand, eListenExted: %d, eNextState: %d\n", + prP2pFsmInfo->eListenExted, eNextState); + if (prP2pFsmInfo->eListenExted != P2P_DEV_EXT_LISTEN_ING || + eNextState != P2P_STATE_CHNL_ON_HAND) { + /* Here maybe have a bug, when it's extlistening, a new remain_on_channel + was sent to driver? need to verify */ + prP2pFsmInfo->eListenExted = P2P_DEV_NOT_EXT_LISTEN; + /* Indicate channel return. */ + kalP2PIndicateChannelExpired(prAdapter->prGlueInfo, &prP2pFsmInfo->rChnlReqInfo); + + /* Return Channel. */ + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + } while (FALSE); +} /* p2pStateAbort_CHNL_ON_HAND */ + +VOID +p2pStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (eNextState < P2P_STATE_NUM)); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + if (eNextState == P2P_STATE_IDLE) { + if (prP2pBssInfo->eIntendOPMode == OP_MODE_ACCESS_POINT) { + /* Intend to be AP. */ + /* Setup for AP mode. */ + p2pFuncStartGO(prAdapter, + prP2pBssInfo, + prP2pSpecificBssInfo->aucGroupSsid, + prP2pSpecificBssInfo->u2GroupSsidLen, + prP2pSpecificBssInfo->ucPreferredChannel, + prP2pSpecificBssInfo->eRfBand, + prP2pSpecificBssInfo->eRfSco, prP2pFsmInfo->fgIsApMode); + + } else { + /* Return Channel. */ + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + } + + } + + } while (FALSE); + +} /* p2pStateInit_AP_CHANNEL_DETECT */ + +VOID p2pStateInit_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) +{ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prScanReqInfo = &(prP2pFsmInfo->rScanReqInfo); + + prScanReqInfo->eScanType = SCAN_TYPE_PASSIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_2G4; + prScanReqInfo->u2PassiveDewellTime = 50; /* 50ms for passive channel load detection */ + prScanReqInfo->fgIsAbort = TRUE; + prScanReqInfo->fgIsScanRequest = TRUE; + prScanReqInfo->ucNumChannelList = 0; + prScanReqInfo->u4BufLength = 0; + prScanReqInfo->rSsidStruct.ucSsidLen = 0; + + p2pFuncRequestScan(prAdapter, prScanReqInfo); + + } while (FALSE); + +} /* p2pStateInit_AP_CHANNEL_DETECT */ + +VOID +p2pStateAbort_AP_CHANNEL_DETECT(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, IN ENUM_P2P_STATE_T eNextState) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + do { + + if (eNextState == P2P_STATE_REQING_CHANNEL) { + UINT_8 ucPreferedChnl = 0; + ENUM_BAND_T eBand = BAND_NULL; + ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; + + prChnlReqInfo = &(prP2pFsmInfo->rChnlReqInfo); + + /* Determine the channel for AP. */ + if (cnmPreferredChannel(prAdapter, &eBand, &ucPreferedChnl, &eSco) == FALSE) { + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + ucPreferedChnl = prP2pConnSettings->ucOperatingChnl; + if (ucPreferedChnl == 0) { + + if (scnQuerySparseChannel(prAdapter, &eBand, &ucPreferedChnl) == FALSE) { + + /* What to do? */ + ASSERT(FALSE); + /* TODO: Pick up a valid channel from channel list. */ + ucPreferedChnl = 1; + eBand = BAND_2G4; + } + } + } + + prChnlReqInfo->eChannelReqType = CHANNEL_REQ_TYPE_GO_START_BSS; + + DBGLOG(P2P, INFO, "p2pStateAbort_AP_CHANNEL_DETECT GO Scan\n"); + prChnlReqInfo->ucReqChnlNum = prP2pSpecificBssInfo->ucPreferredChannel = ucPreferedChnl; + prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand = eBand; + prChnlReqInfo->eChnlSco = prP2pSpecificBssInfo->eRfSco = eSco; + } else { + p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); + } + + } while (FALSE); + +} /* p2pStateAbort_AP_CHANNEL_DETECT */ + +VOID p2pStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo) +{ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T) NULL; + + do { + + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL)); + + prScanReqInfo = &prP2pFsmInfo->rScanReqInfo; + + prScanReqInfo->fgIsScanRequest = TRUE; + + p2pFuncRequestScan(prAdapter, prScanReqInfo); + + } while (FALSE); + +} /* p2pStateInit_SCAN */ + +VOID p2pStateAbort_SCAN(IN P_ADAPTER_T prAdapter, IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN ENUM_P2P_STATE_T eNextState) +{ + do { + ASSERT_BREAK(prAdapter != NULL); + + /* 1. Scan cancel. (Make sure the scan request is invalid. */ + p2pFuncCancelScan(prAdapter, &(prP2pFsmInfo->rScanReqInfo)); + + /* Scan done indication. */ + kalP2PIndicateScanDone(prAdapter->prGlueInfo, prP2pFsmInfo->rScanReqInfo.fgIsAbort); + } while (FALSE); + +} /* p2pStateAbort_SCAN */ + +VOID +p2pStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN P_BSS_DESC_T prBssDesc) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T) NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pFsmInfo != NULL) && + (prP2pBssInfo != NULL) && (prJoinInfo != NULL) && (prBssDesc != NULL)); + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prP2pConnSettings->aucSSID, + prP2pConnSettings->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } + /* Setup a join timer. */ + DBGLOG(P2P, TRACE, "Start a join init timer\n"); + cnmTimerStartTimer(prAdapter, + &(prAdapter->rP2pFsmTimeoutTimer), + (prP2pFsmInfo->u4GrantInterval - AIS_JOIN_CH_GRANT_THRESHOLD)); + + /* 2 <1> We are goin to connect to this BSS */ + prBssDesc->fgIsConnecting = TRUE; + + /* 2 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, + (prBssDesc->fgIsP2PPresent ? (STA_TYPE_P2P_GO) + : (STA_TYPE_LEGACY_AP)), NETWORK_TYPE_P2P_INDEX, prBssDesc); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, "Create station record fail\n"); + break; + } + + prJoinInfo->prTargetStaRec = prStaRec; + prJoinInfo->fgIsJoinComplete = FALSE; + prJoinInfo->u4BufLength = 0; + + /* 2 <2.1> Sync. to FW domain */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + prStaRec->fgIsReAssoc = FALSE; + + prP2pConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + switch (prP2pConnSettings->eAuthMode) { + case AUTH_MODE_OPEN: /* Note: Omit break here. */ + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_OPEN_SYSTEM; + break; + case AUTH_MODE_SHARED: + prJoinInfo->ucAvailableAuthTypes = (UINT_8) AUTH_TYPE_SHARED_KEY; + break; + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(P2P, LOUD, "JOIN INIT: eAuthMode == AUTH_MODE_AUTO_SWITCH\n"); + prJoinInfo->ucAvailableAuthTypes = (UINT_8) (AUTH_TYPE_OPEN_SYSTEM | + AUTH_TYPE_SHARED_KEY); + break; + default: + ASSERT(!(prP2pConnSettings->eAuthMode == AUTH_MODE_WPA_NONE)); + DBGLOG(P2P, ERROR, "JOIN INIT: Auth Algorithm : %d was not supported by JOIN\n", + prP2pConnSettings->eAuthMode); + /* TODO(Kevin): error handling ? */ + return; + } + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + } else { + ASSERT(FALSE); + /* TODO: Shall we considering ROAMIN case for P2P Device?. */ + } + + /* 2 <4> Use an appropriate Authentication Algorithm Number among the ucAvailableAuthTypes. */ + if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_OPEN_SYSTEM) { + + DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); + + prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_SHARED_KEY) { + + DBGLOG(P2P, TRACE, "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); + + prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY; + } else if (prJoinInfo->ucAvailableAuthTypes & (UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION) { + + DBGLOG(P2P, TRACE, + "JOIN INIT: Try to do Authentication with AuthType == FAST_BSS_TRANSITION.\n"); + + prJoinInfo->ucAvailableAuthTypes &= ~(UINT_8) AUTH_TYPE_FAST_BSS_TRANSITION; + + prStaRec->ucAuthAlgNum = (UINT_8) AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; + } else { + ASSERT(0); + } + + /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used by Assoc Req) */ + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prJoinInfo->rSsidStruct.aucSsid, + prJoinInfo->rSsidStruct.ucSsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } + /* 2 <5> Backup desired channel. */ + + /* 2 <6> Send a Msg to trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_REQ_T)); + + if (!prJoinReqMsg) { + DBGLOG(P2P, TRACE, "Allocation Join Message Fail\n"); + ASSERT(FALSE); + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + /* TODO: Consider fragmentation info in station record. */ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinReqMsg, MSG_SEND_METHOD_BUF); + + } while (FALSE); + +} /* p2pStateInit_GC_JOIN */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process of JOIN Abort. Leave JOIN State & Abort JOIN. +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +p2pStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_FSM_INFO_T prP2pFsmInfo, IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_STATE_T eNextState) +{ + P_MSG_JOIN_ABORT_T prJoinAbortMsg = (P_MSG_JOIN_ABORT_T) NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pFsmInfo != NULL) && (prJoinInfo != NULL)); + + if (prJoinInfo->fgIsJoinComplete == FALSE) { + + prJoinAbortMsg = + (P_MSG_JOIN_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + DBGLOG(P2P, TRACE, "Fail to allocate join abort message buffer\n"); + ASSERT(FALSE); + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prJoinInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prJoinInfo->prTargetStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prJoinAbortMsg, MSG_SEND_METHOD_BUF); + + } + + /* Stop Join Timer. */ + cnmTimerStopTimer(prAdapter, &(prAdapter->rP2pFsmTimeoutTimer)); + + /* Release channel requested. */ + p2pFuncReleaseCh(prAdapter, &(prP2pFsmInfo->rChnlReqInfo)); + + } while (FALSE); + + return; + +} /* p2pStateAbort_GC_JOIN */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c new file mode 100644 index 0000000000000..72fa52e761da5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/privacy.c @@ -0,0 +1,915 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/privacy.c#1 +*/ + +/*! \file "privacy.c" + \brief This file including the protocol layer privacy function. + + This file provided the macros and functions library support for the + protocol layer security setting from rsn.c and nic_privacy.c + +*/ + +/* +** Log: privacy.c + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 20 2011 terry.wu + * NULL + * Fix Hotspot deauth send failed. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 06 28 2011 tsaiyuan.hsu + * [WCXRP00000819] [MT6620 Wi-Fi][Driver] check if staRec is NULL or not in secCheckClassError + * check if staRec is NULL or not in secCheckClassError. + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T + * and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 20 2010 wh.su + * + * adding the wapi code. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * adding the compiling flag for migration. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 04 22 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the wpi same key id rx issue and fixed the remove wep key issue. + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Send Deauth for Class 3 Error and Leave Network Support + * + * 04 15 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * remove the assert code for allow ad-hoc pkt. + * + * 04 13 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the Klocwork error and refine the class error message. + * + * 03 04 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Code refine, and remove non-used code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, + * and modify the security related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 26 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * change the waning message shown level, and clear the global transmit flag for CMD INFRASTRUCTURE. + * + * 02 25 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * For support the WHQL test, do the remove key code refine. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 12 25 2009 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Integrated modifications for 1st connection (mainly on FW modules MQM, TXM, and RXM) + * * * * * * * * * MQM: BA handling + * * * * * * * * * TXM: Macros updates + * * * * * * * * * RXM: Macros/Duplicate Removal updates + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 11 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * modify the cmd with result return + * + * Dec 11 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * fixed the value not initialize issue + * + * Dec 10 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the cmd return type + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function to update the auth mode and encryption status for cmd build connection + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some code for wapi mode + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the call to check the 4th and eapol error report frame + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the function name + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code for parsing the EAPoL frame, and do some code refine + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the class error check + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the cmd_802_11_pmkid code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * doing some function rename, and adding the code for cmd CMD_ADD_REMOVE_KEY + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the clear pmkid function + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix eStaType check for AIS + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the ap selection related code + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_PRIVACY_MIGRATION + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to initialize the privacy-related +* parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] ucNetTypeIdx Pointer to netowrk type index +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID secInit(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetTypeIdx) +{ + UINT_8 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secInit"); + + ASSERT(prAdapter); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + prBssInfo->u4RsnSelectedGroupCipher = 0; + prBssInfo->u4RsnSelectedPairwiseCipher = 0; + prBssInfo->u4RsnSelectedAKMSuite = 0; + +#if CFG_ENABLE_WIFI_DIRECT + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX]; + + prBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; +#endif + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[0].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[1].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[2].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[3].dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP104; + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[4].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[5].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[6].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[7].dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP104; + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; + + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[0].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[1].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[2].dot11RSNAConfigAuthenticationSuite = + WPA_AKM_SUITE_PSK; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[3].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[4].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[5].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_PSK; + +#if CFG_SUPPORT_802_11W + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[6].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_802_1X_SHA256; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[7].dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_PSK_SHA256; +#endif + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i].dot11RSNAConfigAuthenticationSuiteEnabled = + FALSE; + } + + secClearPmkid(prAdapter); + + cnmTimerInitTimer(prAdapter, + &prAisSpecBssInfo->rPreauthenticationTimer, + (PFN_MGMT_TIMEOUT_FUNC) rsnIndicatePmkidCand, (ULONG) NULL); + +#if CFG_SUPPORT_802_11W + cnmTimerInitTimer(prAdapter, + &prAisSpecBssInfo->rSaQueryTimer, (PFN_MGMT_TIMEOUT_FUNC) rsnStartSaQueryTimer, (ULONG) NULL); +#endif + + prAisSpecBssInfo->fgCounterMeasure = FALSE; + prAisSpecBssInfo->ucWEPDefaultKeyID = 0; + +#if 0 + for (i = 0; i < WTBL_SIZE; i++) { + g_prWifiVar->arWtbl[i].fgUsed = FALSE; + g_prWifiVar->arWtbl[i].prSta = NULL; + g_prWifiVar->arWtbl[i].ucNetTypeIdx = NETWORK_TYPE_INDEX_NUM; + + } + nicPrivacyInitialize((UINT_8) NETWORK_TYPE_INDEX_NUM); +#endif +} /* secInit */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Rx Class Error" to SEC_FSM for +* JOIN Module. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSwRfb Pointer to the SW RFB. +* +* \return FALSE Class Error +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN P_STA_RECORD_T prStaRec) +{ + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (!prStaRec) + return FALSE; + + eNetTypeIndex = prStaRec->ucNetTypeIndex; + if (!IS_NET_ACTIVE(prAdapter, eNetTypeIndex)) + return FALSE; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]; + if ((STA_STATE_3 != prStaRec->ucStaState) && prBssInfo->fgIsNetAbsent == FALSE) { + /*(IS_AP_STA(prStaRec) || IS_CLIENT_STA(prStaRec))) { */ + +#if 0 /* by scott's suggestions, do not put work-around in JB2,we need to find the root cause */ + /* work-around for CR ALPS00816361 */ + if (eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + DBGLOG(RSN, INFO, + "p2p> skip to send Deauth to MAC:[%pM] for Rx Class 3.\n", + prStaRec->aucMacAddr); + return TRUE; + } +#endif + + if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, + prStaRec, + NULL, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER) NULL)) + + DBGLOG(RSN, INFO, "Send Deauth to [ %pM ] for Rx Class 3 Error.\n", + prStaRec->aucMacAddr); + else + DBGLOG(RSN, INFO, "Host sends Deauth to [ %pM ] for Rx Class 3 fail.\n", + prStaRec->aucMacAddr); + return FALSE; + } + + return secRxPortControlCheck(prAdapter, prSwRfb); +} /* end of secCheckClassError() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to setting the sta port status. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer to the sta +* \param[in] fgPortBlock The port status +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID secSetPortBlocked(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgPortBlock) +{ + if (prSta == NULL) + return; + + prSta->fgPortBlock = fgPortBlock; + + DBGLOG(RSN, TRACE, + "The STA %pM port %s\n", prSta->aucMacAddr, fgPortBlock == TRUE ? "BLOCK" : " OPEN"); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to report the sta port status. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer to the sta +* \param[out] fgPortBlock The port status +* +* \return TRUE sta exist, FALSE sta not exist +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secGetPortStatus(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, OUT PBOOLEAN pfgPortStatus) +{ + if (prSta == NULL) + return FALSE; + + *pfgPortStatus = prSta->fgPortBlock; + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle Peer device Tx Security process MSDU. +* +* \param[in] prMsduInfo pointer to the packet info pointer +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port blocked +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN /* ENUM_PORT_CONTROL_RESULT */ +secTxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(prStaRec); + + if (prStaRec) { + + /* Todo:: */ + if (prMsduInfo->fgIs802_1x) + return TRUE; + + if (prStaRec->fgPortBlock == TRUE) { + DBGLOG(SEC, TRACE, "Drop Tx packet due Port Control!\n"); + return FALSE; + } +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) + return TRUE; +#endif + if (IS_STA_IN_AIS(prStaRec)) { + if (!prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist && + (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED)) { + DBGLOG(SEC, TRACE, "Drop Tx packet due the key is removed!!!\n"); + return FALSE; + } + } + } + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle The Rx Security process MSDU. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSWRfb SW rfb pinter +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port control +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb) +{ + ASSERT(prSWRfb); + +#if 0 + /* whsu:Todo: Process MGMT and DATA */ + if (prSWRfb->prStaRec) { + if (prSWRfb->prStaRec->fgPortBlock == TRUE) { + if (1 /* prSWRfb->fgIsDataFrame and not 1x */ && + (g_prWifiVar->rConnSettings.eAuthMode >= AUTH_MODE_WPA)) { + /* DBGLOG(SEC, WARN, ("Drop Rx data due port control !\r\n")); */ + return TRUE; /* Todo: whsu FALSE; */ + } + /* if (!RX_STATUS_IS_PROTECT(prSWRfb->prRxStatus)) { */ + /* DBGLOG(RSN, WARN, ("Drop rcv non-encrypted data frame!\n")); */ + /* return FALSE; */ + /* } */ + } + } else { + } +#endif + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine will enable/disable the cipher suite +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] u4CipherSuitesFlags flag for cipher suite +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4CipherSuitesFlags) +{ + UINT_32 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + P_IEEE_802_11_MIB_T prMib; + + ASSERT(prAdapter); + + prMib = &prAdapter->rMib; + + ASSERT(prMib); + + if (u4CipherSuitesFlags == CIPHER_FLAG_NONE) { + /* Disable all the pairwise cipher suites. */ + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prMib->dot11RSNAConfigPairwiseCiphersTable[i].dot11RSNAConfigPairwiseCipherEnabled = FALSE; + + /* Update the group cipher suite. */ + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + + return; + } + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prMib->dot11RSNAConfigPairwiseCiphersTable[i]; + + switch (prEntry->dot11RSNAConfigPairwiseCipher) { + case WPA_CIPHER_SUITE_WEP40: + case RSN_CIPHER_SUITE_WEP40: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP40) + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + else + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (u4CipherSuitesFlags & CIPHER_FLAG_TKIP) + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + else + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + break; + + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (u4CipherSuitesFlags & CIPHER_FLAG_CCMP) + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + else + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + break; + + case WPA_CIPHER_SUITE_WEP104: + case RSN_CIPHER_SUITE_WEP104: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP104) + prEntry->dot11RSNAConfigPairwiseCipherEnabled = TRUE; + else + prEntry->dot11RSNAConfigPairwiseCipherEnabled = FALSE; + break; + default: + break; + } + } + + /* Update the group cipher suite. */ + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_CCMP; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_TKIP; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP104; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP40; + else + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + +} /* secSetCipherSuite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle The 2nd Tx EAPoL Frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prMsduInfo pointer to the packet info pointer +* \param[in] pucPayload pointer to the 1x hdr +* \param[in] u2PayloadLen the 1x payload length +* +* \retval TRUE Accept the packet +* \retval FALSE Refuse the MSDU packet due port control +* +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +secProcessEAPOL(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN PUINT_8 pucPayload, IN UINT_16 u2PayloadLen) +{ + P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; + P_IEEE_802_1X_HDR pr1xHdr; + UINT_16 u2KeyInfo; + + ASSERT(prMsduInfo); + ASSERT(prStaRec); + + /* prStaRec = &(g_arStaRec[prMsduInfo->ucStaRecIndex]); */ + ASSERT(prStaRec); + + if (prStaRec && IS_AP_STA(prStaRec)) { + pr1xHdr = (P_IEEE_802_1X_HDR) pucPayload; + if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { + prEapol = (P_EAPOL_KEY) ((PUINT_32) (pucPayload + 4)); + WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); + if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { + if (u2KeyInfo & WPA_KEY_INFO_SECURE) { + /* 4th EAPoL check at secHandleTxDoneCallback() */ + /* DBGLOG(RSN, TRACE, ("Tx 4th EAPoL frame\r\n")); */ + } else if (u2PayloadLen == 123 /* Not include LLC */) { + DBGLOG(RSN, INFO, "Tx 2nd EAPoL frame\r\n"); + secFsmEvent2ndEapolTx(prAdapter, prStaRec); + } + } + } + } + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will handle the 4th EAPoL Tx done and mic Error Report frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secHandleTxDoneCallback(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec, IN WLAN_STATUS rStatus) +{ + PUINT_8 pucPayload; + P_IEEE_802_1X_HDR pr1xHdr = (P_IEEE_802_1X_HDR) NULL; + P_EAPOL_KEY prEapol = (P_EAPOL_KEY) NULL; + UINT_16 u2KeyInfo; + UINT_16 u2PayloadLen; + + DEBUGFUNC("secHandleTxDoneCallback"); + + ASSERT(prMsduInfo); + /* Todo:: Notice if using the TX free immediate after send to firmware, the payload may not correcttly!!!! */ + + ASSERT(prStaRec); + + /* Todo:: This call back may not need because the order of set key and send 4th 1x can be make sure */ + /* Todo:: Notice the LLC offset */ +#if 1 + pucPayload = (PUINT_8) prMsduInfo->prPacket; + ASSERT(pucPayload); + + u2PayloadLen = prMsduInfo->u2FrameLength; + + if (0 /* prMsduInfo->fgIs1xFrame */) { + + if (prStaRec && IS_AP_STA(prStaRec)) { + pr1xHdr = (P_IEEE_802_1X_HDR) (PUINT_32) (pucPayload + 8); + if ((pr1xHdr->ucType == 3) /* EAPoL key */ && ((u2PayloadLen - 4) > sizeof(EAPOL_KEY))) { + prEapol = (P_EAPOL_KEY) (PUINT_32) (pucPayload + 12); + WLAN_GET_FIELD_BE16(prEapol->aucKeyInfo, &u2KeyInfo); + if ((prEapol->ucType == 254) && (u2KeyInfo & MASK_2ND_EAPOL)) { + if (prStaRec->rSecInfo.fg2nd1xSend == TRUE + && u2PayloadLen == + 107 /* include LLC *//* u2KeyInfo & WPA_KEY_INFO_SECURE */) { + DBGLOG(RSN, INFO, "Tx 4th EAPoL frame\r\n"); + secFsmEvent4ndEapolTxDone(prAdapter, prStaRec); + } else if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone) { + DBGLOG(RSN, INFO, "Tx EAPoL Error report frame\r\n"); + /* secFsmEventEapolTxDone(prAdapter, (UINT_32)prMsduInfo->prStaRec); */ + } + } + } + } + + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to initialize the pmkid parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID secClearPmkid(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secClearPmkid"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + DBGLOG(RSN, TRACE, "secClearPmkid\n"); + prAisSpecBssInfo->u4PmkidCandicateCount = 0; + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCandicate, sizeof(PMKID_CANDICATE_T) * CFG_MAX_PMKID_CACHE); + kalMemZero((PVOID) prAisSpecBssInfo->arPmkidCache, sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Whether WPA, or WPA2 but not WPA-None is enabled. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval BOOLEAN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prAdapter); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + + ASSERT(prConnSettings); + + ASSERT(prConnSettings->eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); + + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION_DISABLED) + return FALSE; + + ASSERT(prConnSettings->eAuthMode < AUTH_MODE_NUM); + if ((prConnSettings->eAuthMode >= AUTH_MODE_WPA) && (prConnSettings->eAuthMode != AUTH_MODE_WPA_NONE)) + return TRUE; + + return FALSE; +} /* secRsnKeyHandshakeEnabled */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return whether the transmit key alread installed. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prSta Pointer the sta record +* +* \retval TRUE Default key or Transmit key installed +* FALSE Default key or Transmit key not installed +* +* \note: +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + ASSERT(prSta); + + if (prSta->fgTransmitKeyExist) + return TRUE; + else + return FALSE; +} /* secTransmitKeyExist */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Whether 802.11 privacy is enabled. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval BOOLEAN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secEnabledInAis(IN P_ADAPTER_T prAdapter) +{ + DEBUGFUNC("secEnabled"); + + ASSERT(prAdapter->rWifiVar.rConnSettings.eEncStatus < ENUM_ENCRYPTION3_KEY_ABSENT); + + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION_DISABLED: + return FALSE; + case ENUM_ENCRYPTION1_ENABLED: + case ENUM_ENCRYPTION2_ENABLED: + case ENUM_ENCRYPTION3_ENABLED: + return TRUE; + default: + DBGLOG(RSN, TRACE, "Unknown encryption setting %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); + break; + } + return FALSE; +} /* secEnabled */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the privacy bit at mac header for TxM +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] prMsdu the msdu for known the sta record +* +* \return TRUE the privacy need to set +* FALSE the privacy no need to set +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prAdapter); + + ASSERT(prMsdu); + + ASSERT(prStaRec); + /* prStaRec = &(g_arStaRec[prMsdu->ucStaRecIndex]); */ + + if (prStaRec == NULL) { + if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) + return TRUE; + return FALSE; /* No privacy bit */ + } + + /* Todo:: */ + if (0 /* prMsdu->fgIs1xFrame */) { + if (IS_STA_IN_AIS(prStaRec) && prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) { + DBGLOG(RSN, LOUD, "For AIS Legacy 1x, always not encryped\n"); + return FALSE; + } else if (!prStaRec->fgTransmitKeyExist) { + DBGLOG(RSN, LOUD, "1x Not Protected.\n"); + return FALSE; + } else if (prStaRec->rSecInfo.fgKeyStored) { + DBGLOG(RSN, LOUD, "1x not Protected due key stored!\n"); + return FALSE; + } + DBGLOG(RSN, LOUD, "1x Protected.\n"); + return TRUE; + } + if (!prStaRec->fgTransmitKeyExist) { + /* whsu , check for AIS only */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist) { + DBGLOG(RSN, LOUD, "Protected\n"); + return TRUE; + } + } else { + DBGLOG(RSN, LOUD, "Protected.\n"); + return TRUE; + } + + /* No sec or key is removed!!! */ + return FALSE; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c new file mode 100644 index 0000000000000..fd0a8772a6665 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rate.c @@ -0,0 +1,497 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rate.c#1 +*/ + +/*! \file "rate.c" + \brief This file contains the transmission rate handling routines. + + This file contains the transmission rate handling routines for setting up + ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do + conversion between Rate Set and Data Rates. +*/ + +/* +** Log: rate.c + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add rate.c. + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comments + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix DBGLOG + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +** \main\maintrunk.MT5921\12 2008-12-19 17:19:32 GMT mtk01461 +** Fix the problem that do not ASSERT the length of Supported Rate IE == 8 +** \main\maintrunk.MT5921\11 2008-12-01 18:17:42 GMT mtk01088 +** fixed the lint "possible using null pointer" warning +** \main\maintrunk.MT5921\10 2008-08-20 00:16:36 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\9 2008-04-13 21:17:13 GMT mtk01461 +** Revise GEN Link Speed OID +** \main\maintrunk.MT5921\8 2008-03-28 10:40:13 GMT mtk01461 +** Add rateGetRateSetFromDataRates() for set desired rate OID +** \main\maintrunk.MT5921\7 2008-03-26 09:16:20 GMT mtk01461 +** Add adopt operational rate as ACK rate if BasicRateSet was not found +** Add comments +** \main\maintrunk.MT5921\6 2008-02-21 15:01:39 GMT mtk01461 +** Add initial rate according rx signal quality support +** \main\maintrunk.MT5921\5 2008-01-07 15:06:44 GMT mtk01461 +** Fix typo of rate adaptation of CtrlResp Frame +** \main\maintrunk.MT5921\4 2007-10-25 18:05:12 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* The list of valid data rates. */ +const UINT_8 aucDataRate[] = { + RATE_1M, /* RATE_1M_INDEX = 0 */ + RATE_2M, /* RATE_2M_INDEX */ + RATE_5_5M, /* RATE_5_5M_INDEX */ + RATE_11M, /* RATE_11M_INDEX */ + RATE_22M, /* RATE_22M_INDEX */ + RATE_33M, /* RATE_33M_INDEX */ + RATE_6M, /* RATE_6M_INDEX */ + RATE_9M, /* RATE_9M_INDEX */ + RATE_12M, /* RATE_12M_INDEX */ + RATE_18M, /* RATE_18M_INDEX */ + RATE_24M, /* RATE_24M_INDEX */ + RATE_36M, /* RATE_36M_INDEX */ + RATE_48M, /* RATE_48M_INDEX */ + RATE_54M, /* RATE_54M_INDEX */ + RATE_HT_PHY /* RATE_HT_PHY_INDEX */ +}; + +static const UINT_8 aucDefaultAckCtsRateIndex[RATE_NUM] = { + RATE_1M_INDEX, /* RATE_1M_INDEX = 0 */ + RATE_2M_INDEX, /* RATE_2M_INDEX */ + RATE_5_5M_INDEX, /* RATE_5_5M_INDEX */ + RATE_11M_INDEX, /* RATE_11M_INDEX */ + RATE_1M_INDEX, /* RATE_22M_INDEX - Not supported */ + RATE_1M_INDEX, /* RATE_33M_INDEX - Not supported */ + RATE_6M_INDEX, /* RATE_6M_INDEX */ + RATE_6M_INDEX, /* RATE_9M_INDEX */ + RATE_12M_INDEX, /* RATE_12M_INDEX */ + RATE_12M_INDEX, /* RATE_18M_INDEX */ + RATE_24M_INDEX, /* RATE_24M_INDEX */ + RATE_24M_INDEX, /* RATE_36M_INDEX */ + RATE_24M_INDEX, /* RATE_48M_INDEX */ + RATE_24M_INDEX /* RATE_54M_INDEX */ +}; + +const BOOLEAN afgIsOFDMRate[RATE_NUM] = { + FALSE, /* RATE_1M_INDEX = 0 */ + FALSE, /* RATE_2M_INDEX */ + FALSE, /* RATE_5_5M_INDEX */ + FALSE, /* RATE_11M_INDEX */ + FALSE, /* RATE_22M_INDEX - Not supported */ + FALSE, /* RATE_33M_INDEX - Not supported */ + TRUE, /* RATE_6M_INDEX */ + TRUE, /* RATE_9M_INDEX */ + TRUE, /* RATE_12M_INDEX */ + TRUE, /* RATE_18M_INDEX */ + TRUE, /* RATE_24M_INDEX */ + TRUE, /* RATE_36M_INDEX */ + TRUE, /* RATE_48M_INDEX */ + TRUE /* RATE_54M_INDEX */ +}; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the given Supported Rate & Extended Supported Rate IE to the +* Operational Rate Set and Basic Rate Set, and also check if any Basic +* Rate Code is unknown by driver. +* +* @param[in] prIeSupportedRate Pointer to the Supported Rate IE +* @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE +* @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set +* @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set +* @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that Basic +* Rate Set has unknown Rate Code +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT PUINT_16 pu2OperationalRateSet, + OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate) +{ + UINT_16 u2OperationalRateSet = 0; + UINT_16 u2BSSBasicRateSet = 0; + BOOLEAN fgIsUnknownBSSBasicRate = FALSE; + UINT_8 ucRate; + UINT_32 i, j; + + ASSERT(pu2OperationalRateSet); + ASSERT(pu2BSSBasicRateSet); + ASSERT(pfgIsUnknownBSSBasicRate); + + if (prIeSupportedRate) { + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + /* ASSERT(prIeSupportedRate->ucLength <= ELEM_MAX_LEN_SUP_RATES); */ + ASSERT(prIeSupportedRate->ucLength <= RATE_NUM); + + for (i = 0; i < prIeSupportedRate->ucLength; i++) { + ucRate = prIeSupportedRate->aucSupportedRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT) + u2BSSBasicRateSet |= BIT(j); + + break; + } + } + + if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && + (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ + } + } + } + + if (prIeExtSupportedRate) { + /* ASSERT(prIeExtSupportedRate->ucLength <= ELEM_MAX_LEN_EXTENDED_SUP_RATES); */ + + for (i = 0; i < prIeExtSupportedRate->ucLength; i++) { + ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT) + u2BSSBasicRateSet |= BIT(j); + + break; + } + } + + if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) && + (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */ + } + } + } + + *pu2OperationalRateSet = u2OperationalRateSet; + *pu2BSSBasicRateSet = u2BSSBasicRateSet; + *pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate; + + return; + +} /* end of rateGetRateSetFromIEs() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate Code +* Format for used in (Ext)Supportec Rate IE. +* +* @param[in] u2OperationalRateSet Operational Rate Set +* @param[in] u2BSSBasicRateSet Basic Rate Set +* @param[out] pucDataRates Pointer to the Data Rate Buffer +* @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen) +{ + UINT_32 i, j; + + ASSERT(pucDataRates); + ASSERT(pucDataRatesLen); + + ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); + + for (i = RATE_1M_INDEX, j = 0; i < RATE_NUM; i++) { + if (u2OperationalRateSet & BIT(i)) { + + *(pucDataRates + j) = aucDataRate[i]; + + if (u2BSSBasicRateSet & BIT(i)) + *(pucDataRates + j) |= RATE_BASIC_BIT; + + j++; + } + } + + *pucDataRatesLen = (UINT_8) j; + + return; + +} /* end of rateGetDataRatesFromRateSet() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the highest rate from given Rate Set. +* +* \param[in] u2RateSet Rate Set +* \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index +* +* \retval TRUE Highest Rate Index was found +* \retval FALSE Highest Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex) +{ + INT_32 i; + + ASSERT(pucHighestRateIndex); + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2RateSet & BIT(i)) { + *pucHighestRateIndex = (UINT_8) i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetHighestRateIndexFromRateSet() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the lowest rate from given Rate Set. +* +* \param[in] u2RateSet Rate Set +* \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index +* +* \retval TRUE Lowest Rate Index was found +* \retval FALSE Lowest Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex) +{ + UINT_32 i; + + ASSERT(pucLowestRateIndex); + + for (i = RATE_1M_INDEX; i <= RATE_54M_INDEX; i++) { + if (u2RateSet & BIT(i)) { + *pucLowestRateIndex = (UINT_8) i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetLowestRateIndexFromRateSet() */ + +#if 0 /* NOTE(Kevin): For reference */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief Convert the given Data Rates to the Rate Set. +* +* \param[in] pucDataRates Pointer to the Data Rates +* \param[in] ucDataRatesLen Length of given Data Rates +* \param[out] pu2RateSet Pointer to the Rate Set +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rateGetRateSetFromDataRates(IN PUINT_8 pucDataRates, IN UINT_8 ucDataRatesLen, OUT PUINT_16 pu2RateSet) +{ + UINT_16 u2RateSet = 0; + UINT_8 ucRate; + UINT_32 i, j; + + ASSERT(pucDataRates); + ASSERT(pu2RateSet); + + if (pucDataRates) { + for (i = 0; i < ucDataRatesLen; i++) { + ucRate = pucDataRates[i] & RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) { + if (ucRate == aucDataRate[j]) { + u2RateSet |= BIT(j); + break; + } + } + } + } + + *pu2RateSet = u2RateSet; + + return; + +} /* end of rateGetRateSetFromDataRates() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the Operational Rate Set and Basic Rate Set to get the corresponding +* ACK/CTS(Respnose) TX Rates. +* +* \param[in] u2OperationalRateSet Operational Rate Set +* \param[in] u2BSSBasicRateSet Basic Rate Set +* \param[out] aucAckCtsRateIndex Pointer to the Ack/Cts Data Rate Buffer +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +rateSetAckCtsDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet, + IN UINT_16 u2BSSBasicRateSet, IN OUT UINT_8 aucAckCtsRateIndex[]) +{ + INT_32 i, j; + + ASSERT(aucAckCtsRateIndex); + ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); + + /* Setup default ACK/CTS response rate */ + kalMemCopy(aucAckCtsRateIndex, (PVOID) aucDefaultAckCtsRateIndex, sizeof(aucDefaultAckCtsRateIndex)); + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2OperationalRateSet & BIT(i)) { + for (j = i; j >= RATE_1M_INDEX; j--) { + if (u2BSSBasicRateSet & BIT(j)) { + /* Reply ACK Frame at the same Modulation Scheme. */ + if ((afgIsOFDMRate[i] && afgIsOFDMRate[j]) || + (!afgIsOFDMRate[i] && !afgIsOFDMRate[j])) + aucAckCtsRateIndex[i] = (UINT_8) j; + break; + } + } + + /* NOTE(Kevin 2008/03/25): Following code is used for those AP which has + * NULL BasicRateSet. + * e.g. If input Operational Rate Set = [18M 12M 9M], Basic Rate Set = NULL. + * Originally we'll get Ack Rate for [18M 12M 9M] is [12M 12M "6M"]. + * Now we'll get Ack Rate for [18M 12M 9M] is [12M 12M 9M], + * The Ack Rate for Tx Rates which are not list in Operational Rate Set is still + * use highest mandatory rate as default. + */ + if (j < RATE_1M_INDEX) { /* The ACK/CTS rate was not found in BasicRateSet */ + if (!(BIT(aucAckCtsRateIndex[i]) & u2OperationalRateSet)) + aucAckCtsRateIndex[i] = (UINT_8) i; + } + } + } + + return; + +} /* end of rateSetAckCtsDataRatesFromRateSet() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the proper initial rate from Rate Set according to given RCPI value +* +* \param[in] u2RateSet Rate Set +* \param[in] rRcpi RCPI value from AP or Peer STA +* \param[out] pucInitialRateIndex Pointer to buffer of the initial Rate Index +* +* \retval TRUE Initial Rate Index was found +* \retval FALSE Initial Rate Index was not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rateGetBestInitialRateIndex(IN UINT_16 u2RateSet, IN RCPI rRcpi, OUT PUINT_8 pucInitialRateIndex) +{ + UINT_16 u2InitRateSet; + INT_32 i; + + ASSERT(pucInitialRateIndex); + + DBGLOG(MGT, TRACE, "rRcpi = %d\n", rRcpi); + + if (rRcpi >= RCPI_100) { /* Best Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_100); + } else if (rRcpi >= RCPI_80) { /* Better Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_80); + } else if (rRcpi >= RCPI_60) { /* Good Signal */ + u2InitRateSet = INITIAL_RATE_SET(RCPI_60); + } else { /* Worse Signal */ + /* NOTE(Kevin): If return FALSE, we should assign the BSS Basic Rate Index + * (prBssInfo->ucBasicRateIndex) to the initial rate. It was determined in + * function - bssUpdateTxRateForControlFrame(). + */ + return FALSE; + } + + u2RateSet &= u2InitRateSet; + + for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) { + if (u2RateSet & BIT(i)) { + *pucInitialRateIndex = (UINT_8) i; + return TRUE; + } + } + + return FALSE; + +} /* end of rateGetBestInitialRateIndex() */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c new file mode 100644 index 0000000000000..244346983f405 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm.c @@ -0,0 +1,1858 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm.c#2 +*/ + +/*! \file "rlm.c" + \brief + +*/ + +/* +** Log: rlm.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 11 15 2011 cm.chang + * NULL + * Check length HT cap IE about RX associate request frame + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 03 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Fix preamble type of STA mode + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * Not send ERP IE if peer STA is 802.11b-only + * + * 10 11 2011 cm.chang + * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter + * Ignore HT OP IE if its length field is not valid + * + * 09 28 2011 cm.chang + * NULL + * Add length check to reduce possibility to adopt wrong IE + * + * 09 20 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * Handle client mode about preamble type and slot time + * + * 09 01 2011 cm.chang + * [WCXRP00000971] [MT6620 Wi-Fi][Driver][FW] Not set Beacon timeout interval when CPTT + * Final channel number only adopts the field from assoc response + * + * 06 10 2011 cm.chang + * [WCXRP00000773] [MT6620 Wi-Fi][Driver] Workaround some AP fill primary channel field with its secondary channel + * If DS IE exists, ignore the primary channel field in HT OP IE + * + * 05 03 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Fix compiling error + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Refine range of valid channel number + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Check if channel is valided before record ing BSS channel + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode + * and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 10 15 2010 cm.chang + * [WCXRP00000094] [MT6620 Wi-Fi][Driver] Connect to 2.4GHz AP, Driver crash. + * Add exception handle when no mgmt buffer in free build + * + * 10 08 2010 cm.chang + * NULL + * When 20M only setting, ignore OBSS IE + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 23 2010 chinghwa.yu + * NULL + * Temporary add rlmUpdateParamByStaForBow() and rlmBssInitForBow(). + * + * 08 23 2010 chinghwa.yu + * NULL + * Add CFG_ENABLE_BT_OVER_WIFI. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 02 2010 yuche.tsai + * NULL + * P2P Group Negotiation Code Check in. + * + * 07 26 2010 yuche.tsai + * + * Fix compile error while enabling WiFi Direct function. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 06 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix channel ID definition in RFB status to primary channel instead of center channel + * + * 06 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add TX short GI compiling option + * + * 06 02 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Roll back to remove CFG_SUPPORT_BCM_TEST. + * + * 06 01 2010 chinghwa.yu + * [BORA00000563]Add WiFi CoEx BCM module + * Update BCM Test and RW configuration. + * + * 05 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add some compiling options to control 11n functions + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set RTS threshold of 2K bytes initially + * + * 05 18 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Ad-hoc Beacon should not carry HT OP and OBSS IEs + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 04 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Utilize status of swRfb to know channel number and band + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Different invoking order for WTBL entry of associated AP + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 04 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process Beacon only ready for infra STA now + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 24 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * fixed some WHQL testing error. + * + * 03 15 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide draft measurement and quiet functions + * + * 03 09 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * If bss is not 11n network, zero WTBL HT parameters + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 03 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Generate HT IE only depending on own phyTypeSet + * + * 03 02 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not fill HT related IE if BssInfo does not include 11n phySet + * + * 03 01 2010 tehuang.liu + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * To store field AMPDU Parameters in STA_REC + * + * 02 26 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable RDG RX, but disable RDG TX for IOT and LongNAV + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 07 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Modify the parameter of rlmRecAssocRspHtInfo function + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix prBssInfo->ucPrimaryChannel handle for assoc resp + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add some function to process HT operation + * + * Nov 28 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Call rlmStatisticsInit() to handle MIB counters + * + * Nov 18 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); + +static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); + +static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo); + +static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength); + +static BOOLEAN +rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); + +static BOOLEAN +rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength); + +static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmFsmEventInit(P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* Note: assume TIMER_T structures are reset to zero or stopped + * before invoking this function. + */ + + /* Initialize OBSS FSM */ + rlmObssInit(prAdapter); +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + rlmDomainCheckCountryPowerLimitTable(prAdapter); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmFsmEventUninit(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 ucNetIdx; + + ASSERT(prAdapter); + + RLM_NET_FOR_EACH(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + /* Note: all RLM timers will also be stopped. + * Now only one OBSS scan timer. + */ + rlmBssReset(prAdapter, prBssInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe request, association request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe request, association request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); +#if CFG_SUPPORT_HOTSPOT_2_0 + else if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) + hs20FillExtCapIE(prAdapter, prBssInfo, prMsduInfo); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11N(prBssInfo) && (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) + rlmFillHtOpIE(prAdapter, prBssInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief For probe response (GO, IBSS) and association response +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + P_IE_ERP_T prErpIe; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucNetworkType)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]; + ASSERT(prBssInfo); + + if (RLM_NET_IS_11GN(prBssInfo) && prBssInfo->eBand == BAND_2G4 && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11GN))) { + prErpIe = (P_IE_ERP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add ERP IE */ + prErpIe->ucId = ELEM_ID_ERP_INFO; + prErpIe->ucLength = 1; + + prErpIe->ucERP = prBssInfo->fgObssErpProtectMode ? ERP_INFO_USE_PROTECTION : 0; + + if (prBssInfo->fgErpProtectMode) + prErpIe->ucERP |= (ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION); + + /* Handle barker preamble */ + if (!prBssInfo->fgUseShortPreamble) + prErpIe->ucERP |= ERP_INFO_BARKER_PREAMBLE_MODE; + + ASSERT(IE_SIZE(prErpIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prErpIe); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT32 +rlmFillHtCapIEByParams(BOOLEAN fg40mAllowed, + BOOLEAN fgShortGIDisabled, + UINT_8 u8SupportRxSgi20, + UINT_8 u8SupportRxSgi40, + UINT_8 u8SupportRxGf, UINT_8 u8SupportRxSTBC, ENUM_OP_MODE_T eCurrentOPMode, UINT_8 *pOutBuf) +{ + P_IE_HT_CAP_T prHtCap; + P_SUP_MCS_SET_FIELD prSupMcsSet; + + ASSERT(pOutBuf); + + prHtCap = (P_IE_HT_CAP_T) pOutBuf; + + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + if (!fg40mAllowed) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); + } + if (fgShortGIDisabled) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + + if (u8SupportRxSgi20 == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); + if (u8SupportRxSgi40 == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); + if (u8SupportRxGf == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); + if (u8SupportRxSTBC == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_RX_STBC_1_SS); + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); + + prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); + + if (fg40mAllowed) + prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + return IE_SIZE(prHtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) +{ + P_IE_HT_CAP_T prHtCap; +/* P_SUP_MCS_SET_FIELD prSupMcsSet; */ + BOOLEAN fg40mAllowed; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + prHtCap = (P_IE_HT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + +#if 0 + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + if (!fg40mAllowed) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_DSSS_CCK_IN_40M); + if (prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + + if (prAdapter->rWifiVar.u8SupportRxSgi20 == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); + if (prAdapter->rWifiVar.u8SupportRxSgi40 == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); + if (prAdapter->rWifiVar.u8SupportRxGf == 2) + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); + + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((PVOID)&prSupMcsSet->aucRxMcsBitmask[0], SUP_MCS_RX_BITMASK_OCTET_NUM); + + prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); + + if (fg40mAllowed) + prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + prHtCap->u2HtExtendedCap &= ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtCap); +#else + + prMsduInfo->u2FrameLength += rlmFillHtCapIEByParams(fg40mAllowed, + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, + prAdapter->rWifiVar.u8SupportRxSgi20, + prAdapter->rWifiVar.u8SupportRxSgi40, + prAdapter->rWifiVar.u8SupportRxGf, + prAdapter->rWifiVar.u8SupportRxSTBC, + prBssInfo->eCurrentOPMode, (UINT_8 *) prHtCap); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) +{ +#if CFG_SUPPORT_HOTSPOT_2_0 + P_HS20_EXT_CAP_T prHsExtCap; +#else + P_EXT_CAP_T prExtCap; +#endif + BOOLEAN fg40mAllowed; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + +#if CFG_SUPPORT_HOTSPOT_2_0 + prHsExtCap = (P_HS20_EXT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + prHsExtCap->ucId = ELEM_ID_EXTENDED_CAP; + + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) + prHsExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; + else + prHsExtCap->ucLength = 3 - ELEM_HDR_LEN; + + kalMemZero(prHsExtCap->aucCapabilities, sizeof(prHsExtCap->aucCapabilities)); + + prHsExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (!fg40mAllowed) + prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + prHsExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; + + if (prAdapter->prGlueInfo->fgConnectHS20AP == TRUE) { + SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_INTERWORKING_BIT); + + /* For R2 WNM-Notification */ + SET_EXT_CAP(prHsExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, ELEM_EXT_CAP_WNM_NOTIFICATION_BIT); + } + + ASSERT(IE_SIZE(prHsExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHsExtCap); + +#else + /* Add Extended Capabilities IE */ + prExtCap = (P_EXT_CAP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + prExtCap->ucId = ELEM_ID_EXTENDED_CAP; + + prExtCap->ucLength = 3 - ELEM_HDR_LEN; + kalMemZero(prExtCap->aucCapabilities, sizeof(prExtCap->aucCapabilities)); + + prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (!fg40mAllowed) + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; + + ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT32 rlmFillHtOpIeBody(P_BSS_INFO_T prBssInfo, UINT_8 *pFme) +{ + P_IE_HT_OP_T prHtOp; + UINT_16 i; + + prHtOp = (P_IE_HT_OP_T) pFme; + + /* Add HT operation IE */ + prHtOp->ucId = ELEM_ID_HT_OP; + prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; + + /* RIFS and 20/40 bandwidth operations are included */ + prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; + + /* Decide HT protection mode field */ + if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; + else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; + else { + /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ + prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; + } + + if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { + /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED + * Note: it will also be set in ad-hoc network + */ + prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (0 /* Regulatory class 16 */ && + prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { + /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection + * although it is possible to have no protection by spec. + */ + prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ + + /* No basic MCSx are needed temporarily */ + for (i = 0; i < 16; i++) + prHtOp->aucBasicMcsSet[i] = 0; + + return sizeof(IE_HT_OP_T); +} + +static VOID rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo) +{ +/* P_IE_HT_OP_T prHtOp; */ +/* UINT_16 i; */ + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prMsduInfo->u2FrameLength += rlmFillHtOpIeBody(prBssInfo, + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength)); +#if 0 + prHtOp = (P_IE_HT_OP_T) + (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength); + + /* Add HT operation IE */ + prHtOp->ucId = ELEM_ID_HT_OP; + prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; + + /* RIFS and 20/40 bandwidth operations are included */ + prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; + + /* Decide HT protection mode field */ + if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_HT; + else if (prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) + prHtOp->u2Info2 = (UINT_8) HT_PROTECT_MODE_NON_MEMBER; + else { + /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ + prHtOp->u2Info2 = (UINT_8) prBssInfo->eHtProtectMode; + } + + if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { + /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED + * Note: it will also be set in ad-hoc network + */ + prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (0 /* Regulatory class 16 */ && + prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { + /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection + * although it is possible to have no protection by spec. + */ + prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ + + /* No basic MCSx are needed temporarily */ + for (i = 0; i < 16; i++) + prHtOp->aucBasicMcsSet[i] = 0; + + ASSERT(IE_SIZE(prHtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtOp); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked to update parameters of associated AP. +* (Association response and Beacon) +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, PUINT_8 pucIE, UINT_16 u2IELength) +{ + UINT_16 u2Offset; + P_STA_RECORD_T prStaRec; + P_IE_HT_CAP_T prHtCap; + P_IE_HT_OP_T prHtOp; + P_IE_OBSS_SCAN_PARAM_T prObssScnParam; + UINT_8 ucERP, ucPrimaryChannel; +#if CFG_SUPPORT_QUIET && 0 + BOOLEAN fgHasQuietIE = FALSE; +#endif + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(pucIE); + + prStaRec = prBssInfo->prStaRecOfAP; + ASSERT(prStaRec); + if (!prStaRec) + return 0; + + prBssInfo->fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + ucPrimaryChannel = 0; + prObssScnParam = NULL; + + /* Note: HT-related members in staRec may not be zero before, so + * if following IE does not exist, they are still not zero. + * These HT-related parameters are valid only when the corresponding + * BssInfo supports 802.11n, i.e., RLM_NET_IS_11N() + */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) + break; + prHtCap = (P_IE_HT_CAP_T) pucIE; + prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + + case ELEM_ID_HT_OP: + if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) + break; + prHtOp = (P_IE_HT_OP_T) pucIE; + /* Workaround that some APs fill primary channel field by its + * secondary channel, but its DS IE is correct 20110610 + */ + if (ucPrimaryChannel == 0) + ucPrimaryChannel = prHtOp->ucPrimaryChannel; + prBssInfo->ucHtOpInfo1 = prHtOp->ucInfo1; + prBssInfo->u2HtOpInfo2 = prHtOp->u2Info2; + prBssInfo->u2HtOpInfo3 = prHtOp->u2Info3; + + if (!prBssInfo->fg40mBwAllowed) + prBssInfo->ucHtOpInfo1 &= ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); + + if ((prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) + prBssInfo->eBssSCO = (ENUM_CHNL_EXT_T)(prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO); + + prBssInfo->eHtProtectMode = (ENUM_HT_PROTECT_MODE_T) + (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_HT_PROTECTION); + + /* To do: process regulatory class 16 */ + if ((prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) + && 0 /* && regulatory class is 16 */) + prBssInfo->eGfOperationMode = GF_MODE_DISALLOWED; + else if (prBssInfo->u2HtOpInfo2 & HT_OP_INFO2_NON_GF_HT_STA_PRESENT) + prBssInfo->eGfOperationMode = GF_MODE_PROTECT; + else + prBssInfo->eGfOperationMode = GF_MODE_NORMAL; + + prBssInfo->eRifsOperationMode = + (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_RIFS_MODE) ? RIFS_MODE_NORMAL : RIFS_MODE_DISALLOWED; + + break; + + case ELEM_ID_20_40_BSS_COEXISTENCE: + if (!RLM_NET_IS_11N(prBssInfo)) + break; + /* To do: store if scanning exemption grant to BssInfo */ + break; + + case ELEM_ID_OBSS_SCAN_PARAMS: + if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_OBSS_SCAN_PARAM_T) - 2)) + break; + /* Store OBSS parameters to BssInfo */ + prObssScnParam = (P_IE_OBSS_SCAN_PARAM_T) pucIE; + break; + + case ELEM_ID_EXTENDED_CAP: + if (!RLM_NET_IS_11N(prBssInfo)) + break; + /* To do: store extended capability (PSMP, coexist) to BssInfo */ + break; + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) != (sizeof(IE_ERP_T) - 2) || prBssInfo->eBand != BAND_2G4) + break; + ucERP = ERP_INFO_IE(pucIE)->ucERP; + prBssInfo->fgErpProtectMode = (ucERP & ERP_INFO_USE_PROTECTION) ? TRUE : FALSE; + + if (ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) + prBssInfo->fgUseShortPreamble = FALSE; + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) + ucPrimaryChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + break; + +#if CFG_SUPPORT_DFS /* Add by Enlai */ + case ELEM_ID_CH_SW_ANNOUNCEMENT: + { + rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) pucIE); + } + break; + +#if CFG_SUPPORT_QUIET && 0 + /* Note: RRM code should be moved to independent RRM function by + * component design rule. But we attach it to RLM temporarily + */ + case ELEM_ID_QUIET: + rrmQuietHandleQuietIE(prBssInfo, (P_IE_QUIET_T) pucIE); + fgHasQuietIE = TRUE; + break; +#endif +#endif + + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ + + /* Some AP will have wrong channel number (255) when running time. + * Check if correct channel number information. 20110501 + */ + if ((prBssInfo->eBand == BAND_2G4 && ucPrimaryChannel > 14) || + (prBssInfo->eBand != BAND_2G4 && (ucPrimaryChannel >= 200 || ucPrimaryChannel <= 14))) + ucPrimaryChannel = 0; +#if CFG_SUPPORT_QUIET && 0 + if (!fgHasQuietIE) + rrmQuietIeNotExist(prAdapter, prBssInfo); +#endif + + /* Check if OBSS scan process will launch */ + if (!prAdapter->fgEnOnlineScan || !prObssScnParam || + !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH) || + prBssInfo->eBand != BAND_2G4 || !prBssInfo->fg40mBwAllowed) { + + /* Note: it is ok not to stop rObssScanTimer() here */ + prBssInfo->u2ObssScanInterval = 0; + } else { + if (prObssScnParam->u2TriggerScanInterval < OBSS_SCAN_MIN_INTERVAL) + prObssScnParam->u2TriggerScanInterval = OBSS_SCAN_MIN_INTERVAL; + if (prBssInfo->u2ObssScanInterval != prObssScnParam->u2TriggerScanInterval) { + + prBssInfo->u2ObssScanInterval = prObssScnParam->u2TriggerScanInterval; + + /* Start timer to trigger OBSS scanning */ + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + } + } + + return ucPrimaryChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief AIS or P2P GC. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) +{ + UINT_16 u2Offset, i; + UINT_8 ucPriChannel, ucSecChannel; + ENUM_CHNL_EXT_T eSCO; + BOOLEAN fgHtBss, fg20mReq; + + if ((prAdapter == NULL) + || (pucIE == NULL) + || (prBssInfo == NULL) + || (prSwRfb == NULL)) { + ASSERT(FALSE); + return FALSE; + } + + /* Record it to channel list to change 20/40 bandwidth */ + ucPriChannel = 0; + eSCO = CHNL_EXT_SCN; + + fgHtBss = FALSE; + fg20mReq = FALSE; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + { + P_IE_HT_CAP_T prHtCap; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) + break; + + prHtCap = (P_IE_HT_CAP_T) pucIE; + if (prHtCap->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) + fg20mReq = TRUE; + fgHtBss = TRUE; + break; + } + case ELEM_ID_HT_OP: + { + P_IE_HT_OP_T prHtOp; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) + break; + + prHtOp = (P_IE_HT_OP_T) pucIE; + /* Workaround that some APs fill primary channel field by its + * secondary channel, but its DS IE is correct 20110610 + */ + if (ucPriChannel == 0) + ucPriChannel = prHtOp->ucPrimaryChannel; + + if ((prHtOp->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) + eSCO = (ENUM_CHNL_EXT_T) (prHtOp->ucInfo1 & HT_OP_INFO1_SCO); + break; + } + case ELEM_ID_20_40_BSS_COEXISTENCE: + { + P_IE_20_40_COEXIST_T prCoexist; + + if (IE_LEN(pucIE) != (sizeof(IE_20_40_COEXIST_T) - 2)) + break; + + prCoexist = (P_IE_20_40_COEXIST_T) pucIE; + if (prCoexist->ucData & BSS_COEXIST_40M_INTOLERANT) + fg20mReq = TRUE; + break; + } + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) != (sizeof(IE_DS_PARAM_SET_T) - 2)) + break; + ucPriChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + break; + + default: + break; + } + } + + /* To do: Update channel list and 5G band. All channel lists have the same + * update procedure. We should give it the entry pointer of desired + * channel list. + */ + if (HIF_RX_HDR_GET_RF_BAND(prSwRfb->prHifRxHdr) != BAND_2G4) + return FALSE; + + if (ucPriChannel == 0 || ucPriChannel > 14) + ucPriChannel = HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr); + + if (fgHtBss) { + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_PriChnlList[i] == ucPriChannel) + break; + } + if ((i > prBssInfo->auc2G_PriChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_PriChnlList[i] = ucPriChannel; + prBssInfo->auc2G_PriChnlList[0]++; + } + + /* Update secondary channel */ + if (eSCO != CHNL_EXT_SCN) { + ucSecChannel = (eSCO == CHNL_EXT_SCA) ? (ucPriChannel + 4) : (ucPriChannel - 4); + + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_SecChnlList[i] == ucSecChannel) + break; + } + if ((i > prBssInfo->auc2G_SecChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_SecChnlList[i] = ucSecChannel; + prBssInfo->auc2G_SecChnlList[0]++; + } + } + + /* Update 20M bandwidth request channels */ + if (fg20mReq) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == ucPriChannel) + break; + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_20mReqChnlList[i] = ucPriChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + } else { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) { + if (prBssInfo->auc2G_NonHtChnlList[i] == ucPriChannel) + break; + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = ucPriChannel; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief AIS or P2P GC. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN +rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) +{ + if ((prAdapter == NULL) + || (pucIE == NULL) + || (prBssInfo == NULL) + || (prSwRfb == NULL)) { + ASSERT(FALSE); + return FALSE; + } + +#if 0 /* SW migration 2010/8/20 */ + /* Note: we shall not update parameters when scanning, otherwise + * channel and bandwidth will not be correct or asserted failure + * during scanning. + * Note: remove channel checking. All received Beacons should be processed + * if measurement or other actions are executed in adjacent channels + * and Beacon content checking mechanism is not disabled. + */ + if (IS_SCAN_ACTIVE() + /* || prBssInfo->ucPrimaryChannel != CHNL_NUM_BY_SWRFB(prSwRfb) */ + ) { + return FALSE; + } +#endif + + /* Handle change of slot time */ + prBssInfo->u2CapInfo = ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->u2CapInfo; + prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; + + rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + BOOLEAN fgNewParameter; + UINT_8 ucNetIdx; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + fgNewParameter = FALSE; + + /* When concurrent networks exist, GO shall have the same handle as + * the other BSS, so the Beacon shall be processed for bandwidth and + * protection mechanism. + * Note1: we do not have 2 AP (GO) cases simultaneously now. + * Note2: If we are GO, concurrent AIS AP should detect it and reflect + * action in its Beacon, so AIS STA just follows Beacon from AP. + */ + RLM_NET_FOR_EACH_NO_BOW(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* P2P client or AIS infra STA */ + if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID, ((P_WLAN_MAC_MGMT_HEADER_T) + (prSwRfb->pvHeader))->aucBSSID)) { + + fgNewParameter = rlmRecBcnInfoForClient(prAdapter, + prBssInfo, prSwRfb, pucIE, u2IELength); + } else { + fgNewParameter = rlmRecBcnFromNeighborForClient(prAdapter, + prBssInfo, prSwRfb, pucIE, + u2IELength); + } + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT || + prBssInfo->eCurrentOPMode == OP_MODE_P2P_DEVICE)) { + /* AP scan to check if 20/40M bandwidth is permitted */ + rlmRecBcnFromNeighborForClient(prAdapter, prBssInfo, prSwRfb, pucIE, u2IELength); + } +#endif + else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + /* Do nothing */ + /* To do: Ad-hoc */ + } + + /* Appy new parameters if necessary */ + if (fgNewParameter) { + DBGLOG(RLM, TRACE, "rlmProcessBcn\n"); + rlmSyncOperationParams(prAdapter, prBssInfo); + fgNewParameter = FALSE; + } + } /* end of IS_BSS_ACTIVE() */ + } /* end of RLM_NET_FOR_EACH_NO_BOW */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + UINT_8 ucPriChannel; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + if (!prStaRec) + return; + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + ASSERT(prStaRec == prBssInfo->prStaRecOfAP); + + /* To do: the invoked function is used to clear all members. It may be + * done by center mechanism in invoker. + */ + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fgUseShortSlotTime = (prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) ? TRUE : FALSE; + + ucPriChannel = rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + if (ucPriChannel > 0) + prBssInfo->ucPrimaryChannel = ucPriChannel; + + if (!RLM_NET_IS_11N(prBssInfo) || !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) + prBssInfo->fg40mBwAllowed = FALSE; + + /* Note: Update its capabilities to WTBL by cnmStaRecChangeState(), which + * shall be invoked afterwards. + * Update channel, bandwidth and protection mode by nicUpdateBss() + */ +#if 1 + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + + DBGLOG(P2P, WARN, "Force P2P BW to 20\n"); + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prCmdBody && prBssInfo); + if (!prCmdBody || !prBssInfo) + return; + + prCmdBody->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; + prCmdBody->ucRfBand = (UINT_8) prBssInfo->eBand; + prCmdBody->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prCmdBody->ucRfSco = (UINT_8) prBssInfo->eBssSCO; + prCmdBody->ucErpProtectMode = (UINT_8) prBssInfo->fgErpProtectMode; + prCmdBody->ucHtProtectMode = (UINT_8) prBssInfo->eHtProtectMode; + prCmdBody->ucGfOperationMode = (UINT_8) prBssInfo->eGfOperationMode; + prCmdBody->ucTxRifsMode = (UINT_8) prBssInfo->eRifsOperationMode; + prCmdBody->u2HtOpInfo3 = prBssInfo->u2HtOpInfo3; + prCmdBody->u2HtOpInfo2 = prBssInfo->u2HtOpInfo2; + prCmdBody->ucHtOpInfo1 = prBssInfo->ucHtOpInfo1; + prCmdBody->ucUseShortPreamble = prBssInfo->fgUseShortPreamble; + prCmdBody->ucUseShortSlotTime = prBssInfo->fgUseShortSlotTime; + prCmdBody->ucCheckId = 0x72; + + if (RLM_NET_PARAM_VALID(prBssInfo)) { + DBGLOG(RLM, INFO, "N=%d b=%d c=%d s=%d e=%d h=%d I=0x%02x l=%d p=%d\n", + prCmdBody->ucNetTypeIndex, prCmdBody->ucRfBand, + prCmdBody->ucPrimaryChannel, prCmdBody->ucRfSco, + prCmdBody->ucErpProtectMode, prCmdBody->ucHtProtectMode, + prCmdBody->ucHtOpInfo1, prCmdBody->ucUseShortSlotTime, + prCmdBody->ucUseShortPreamble); + } else { + DBGLOG(RLM, TRACE, "N=%d closed\n", prCmdBody->ucNetTypeIndex); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will operation parameters based on situations of +* concurrent networks. Channel, bandwidth, protection mode, supported +* rate will be modified. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_CMD_SET_BSS_RLM_PARAM_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + prCmdBody = (P_CMD_SET_BSS_RLM_PARAM_T) + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_BSS_RLM_PARAM_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(RLM, WARN, "No buf for sync RLM params (Net=%d)\n", prBssInfo->ucNetTypeIndex); + return; + } + + rlmFillSyncCmdParam(prCmdBody, prBssInfo); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_BSS_RLM_PARAM, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_BSS_RLM_PARAM_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + cnmMemFree(prAdapter, prCmdBody); +} + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function should be invoked after judging successful association. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + P_IE_HT_CAP_T prHtCap; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + if (!prStaRec) + return; + ASSERT(prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) + break; + prHtCap = (P_IE_HT_CAP_T) pucIE; + prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ +} +#endif /* CFG_SUPPORT_AAA */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is for both STA and AP modes +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) + rlmBssInitForAP(prAdapter, prBssInfo); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief It is for both STA and AP modes +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + + /* Assume FW state is updated by CMD_ID_SET_BSS_INFO, so + * the sync CMD is not needed here. + */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief All RLM timers will also be stopped. +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + /* HT related parameters */ + prBssInfo->ucHtOpInfo1 = 0; /* RIFS disabled. 20MHz */ + prBssInfo->u2HtOpInfo2 = 0; + prBssInfo->u2HtOpInfo3 = 0; + + prBssInfo->eBssSCO = 0; + prBssInfo->fgErpProtectMode = 0; + prBssInfo->eHtProtectMode = 0; + prBssInfo->eGfOperationMode = 0; + prBssInfo->eRifsOperationMode = 0; + + /* OBSS related parameters */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + /* All RLM timers will also be stopped */ + cnmTimerStopTimer(prAdapter, &prBssInfo->rObssScanTimer); + prBssInfo->u2ObssScanInterval = 0; + + prBssInfo->fgObssErpProtectMode = 0; /* GO only */ + prBssInfo->eObssHtProtectMode = 0; /* GO only */ + prBssInfo->eObssGfOperationMode = 0; /* GO only */ + prBssInfo->fgObssRifsOperationMode = 0; /* GO only */ + prBssInfo->fgObssActionForcedTo20M = 0; /* GO only */ + prBssInfo->fgObssBeaconForcedTo20M = 0; /* GO only */ +} + +#if CFG_SUPPORT_DFS /* Add by Enlai */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function handle spectrum management action frame +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_CHANNEL_SWITCH_FRAME prRxFrame; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + DBGLOG(RLM, INFO, "[5G DFS]rlmProcessSpecMgtAction \r\n"); + + prRxFrame = (P_ACTION_CHANNEL_SWITCH_FRAME) prSwRfb->pvHeader; + DBGLOG(RLM, INFO, "[5G DFS]prRxFrame->ucAction[%d] \r\n", prRxFrame->ucAction); + if (prRxFrame->ucAction == ACTION_CHNL_SWITCH) + rlmProcessChannelSwitchIE(prAdapter, (P_IE_CHANNEL_SWITCH_T) prRxFrame->aucInfoElem); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function process Channel Switch IE +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmProcessChannelSwitchIE(P_ADAPTER_T prAdapter, P_IE_CHANNEL_SWITCH_T prChannelSwitchIE) +{ + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + ASSERT(prChannelSwitchIE); + + DBGLOG(RLM, INFO, "[5G DFS] rlmProcessChannelSwitchIE \r\n"); + DBGLOG(RLM, INFO, "[5G DFS] ucChannelSwitchMode[%d], ucChannelSwitchCount[%d], ucNewChannelNum[%d] \r\n", + prChannelSwitchIE->ucChannelSwitchMode, + prChannelSwitchIE->ucChannelSwitchCount, prChannelSwitchIE->ucNewChannelNum); + if (prChannelSwitchIE->ucChannelSwitchMode == 1) { + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + DBGLOG(RLM, INFO, "[5G DFS] switch channel [%d]->[%d] \r\n", prAisBssInfo->ucPrimaryChannel, + prChannelSwitchIE->ucNewChannelNum); + prAisBssInfo->ucPrimaryChannel = prChannelSwitchIE->ucNewChannelNum; + nicUpdateBss(prAdapter, prAisBssInfo->ucNetTypeIndex); + } + +} + +#endif + +#if (CFG_SUPPORT_TXR_ENC == 1) +VOID +rlmTxRateEnhanceConfig( + P_ADAPTER_T prAdapter + ) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + CMD_RLM_INFO_T rTxRInfo; + UINT_32 u4SetInfoLen = 0; + + + /* init */ + prGlueInfo = prAdapter->prGlueInfo; + + /* suggestion from Tsaiyuan.Hsu */ + kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); + rTxRInfo.fgIsErrRatioEnhanceApplied = TRUE; + rTxRInfo.ucErrRatio2LimitMinRate = 3; + rTxRInfo.ucMinLegacyRateIdx = 2; + rTxRInfo.cMinRssiThreshold = -60; + rTxRInfo.fgIsRtsApplied = TRUE; + rTxRInfo.ucRecoverTime = 60; + + DBGLOG(RLM, INFO, "Enable tx rate enhance function\n"); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetTxRateInfo, + &rTxRInfo, + sizeof(rTxRInfo), + TRUE, + TRUE, + TRUE, + FALSE, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(RLM, WARN, "set tx rate advance info fail 0x%lx\n", rStatus); +} + + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a command to TX Auto Rate module. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + UINT_32 u4Subcmd; + + + /* parse TAR sub-command */ + u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(RLM, INFO, " sub command = %u\n", (UINT32)u4Subcmd); + + /* handle different sub-command */ + switch (u4Subcmd) { + case 0x00: /* configure */ + /* iwpriv wlan0 set_str_cmd 1_0_0_1_3_2_60_1_60 */ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + CMD_RLM_INFO_T rTxRInfo; + UINT_32 u4SetInfoLen = 0; + + kalMemZero(&rTxRInfo, sizeof(CMD_RLM_INFO_T)); + rTxRInfo.u4Version = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.fgIsErrRatioEnhanceApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.ucErrRatio2LimitMinRate = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.ucMinLegacyRateIdx = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.cMinRssiThreshold = 0 - CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.fgIsRtsApplied = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rTxRInfo.ucRecoverTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(RLM, INFO, " rlmCmd = %u %u %u %u %d %u %u\n", + rTxRInfo.u4Version, + rTxRInfo.fgIsErrRatioEnhanceApplied, + rTxRInfo.ucErrRatio2LimitMinRate, + rTxRInfo.ucMinLegacyRateIdx, + rTxRInfo.cMinRssiThreshold, + rTxRInfo.fgIsRtsApplied, + rTxRInfo.ucRecoverTime)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetTxRateInfo, + &rTxRInfo, + sizeof(rTxRInfo), + TRUE, + TRUE, + TRUE, + FALSE, + &u4SetInfoLen); + break; + + default: + break; + } +} +#endif /* CFG_SUPPORT_TXR_ENC */ + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c new file mode 100644 index 0000000000000..5e127488ea499 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_domain.c @@ -0,0 +1,1791 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_domain.c#1 +*/ + +/*! \file "rlm_domain.c" + \brief + +*/ + +/* +** Log: rlm_domain.c + * + * 11 10 2011 cm.chang + * NULL + * Modify debug message for XLOG + * + * 09 29 2011 cm.chang + * NULL + * Change the function prototype of rlmDomainGetChnlList() + * + * 09 23 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Let channel number to zero if band is illegal + * + * 09 22 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Exclude channel list with illegal band + * + * 09 15 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use defined country group to have a change to add new group + * + * 09 08 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 06 01 2011 cm.chang + * [WCXRP00000756] [MT6620 Wi-Fi][Driver] 1. AIS follow channel of BOW 2. Provide legal channel function + * Provide legal channel function based on domain + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Network. + * + * 03 02 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Export rlmDomainGetDomainInfo for p2p driver. + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 03 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Filter out not supported RF freq when reporting available chnl list + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Provide query function about full channel list. + * + * Dec 1 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" +#include "rlm_txpwr_init.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* The following country or domain shall be set from host driver. + * And host driver should pass specified DOMAIN_INFO_ENTRY to MT6620 as + * the channel list of being a STA to do scanning/searching AP or being an + * AP to choose an adequate channel if auto-channel is set. + */ + +/* Define mapping tables between country code and its channel set + */ +static const UINT_16 g_u2CountryGroup0[] = { + COUNTRY_CODE_AO, COUNTRY_CODE_BZ, COUNTRY_CODE_BJ, COUNTRY_CODE_BT, + COUNTRY_CODE_BO, COUNTRY_CODE_BI, COUNTRY_CODE_CM, COUNTRY_CODE_CF, + COUNTRY_CODE_TD, COUNTRY_CODE_KM, COUNTRY_CODE_CD, COUNTRY_CODE_CG, + COUNTRY_CODE_CI, COUNTRY_CODE_DJ, COUNTRY_CODE_GQ, COUNTRY_CODE_ER, + COUNTRY_CODE_FJ, COUNTRY_CODE_GA, COUNTRY_CODE_GM, COUNTRY_CODE_GN, + COUNTRY_CODE_GW, COUNTRY_CODE_RKS, COUNTRY_CODE_KG, COUNTRY_CODE_LY, + COUNTRY_CODE_MG, COUNTRY_CODE_ML, COUNTRY_CODE_NR, COUNTRY_CODE_NC, + COUNTRY_CODE_ST, COUNTRY_CODE_SC, COUNTRY_CODE_SL, COUNTRY_CODE_SB, + COUNTRY_CODE_SO, COUNTRY_CODE_SR, COUNTRY_CODE_SZ, COUNTRY_CODE_TJ, + COUNTRY_CODE_TG, COUNTRY_CODE_TO, COUNTRY_CODE_TM, COUNTRY_CODE_TV, + COUNTRY_CODE_VU, COUNTRY_CODE_YE +}; + +static const UINT_16 g_u2CountryGroup1[] = { + COUNTRY_CODE_AS, COUNTRY_CODE_AI, COUNTRY_CODE_BM, COUNTRY_CODE_CA, + COUNTRY_CODE_KY, COUNTRY_CODE_GU, COUNTRY_CODE_FM, COUNTRY_CODE_PR, + COUNTRY_CODE_US, COUNTRY_CODE_VI +}; + +static const UINT_16 g_u2CountryGroup2[] = { + COUNTRY_CODE_AR, COUNTRY_CODE_AU, COUNTRY_CODE_AZ, COUNTRY_CODE_BW, + COUNTRY_CODE_KH, COUNTRY_CODE_CX, COUNTRY_CODE_CO, COUNTRY_CODE_CR, +#if (CFG_CN_SUPPORT_CLASS121 == 1) + COUNTRY_CODE_CN, +#endif + COUNTRY_CODE_EC, COUNTRY_CODE_GD, COUNTRY_CODE_GT, COUNTRY_CODE_HK, + COUNTRY_CODE_KI, COUNTRY_CODE_LB, COUNTRY_CODE_LR, COUNTRY_CODE_MN, + COUNTRY_CODE_AN, COUNTRY_CODE_NZ, COUNTRY_CODE_NI, COUNTRY_CODE_PW, + COUNTRY_CODE_PY, COUNTRY_CODE_PE, COUNTRY_CODE_PH, COUNTRY_CODE_WS, + COUNTRY_CODE_SG, COUNTRY_CODE_LK, COUNTRY_CODE_TH, COUNTRY_CODE_TT, + COUNTRY_CODE_UY, COUNTRY_CODE_VN +}; + +static const UINT_16 g_u2CountryGroup3[] = { + COUNTRY_CODE_AW, COUNTRY_CODE_LA, COUNTRY_CODE_SA, COUNTRY_CODE_AE, + COUNTRY_CODE_UG +}; + +static const UINT_16 g_u2CountryGroup4[] = { COUNTRY_CODE_MM }; + +static const UINT_16 g_u2CountryGroup5[] = { + COUNTRY_CODE_AL, COUNTRY_CODE_DZ, COUNTRY_CODE_AD, COUNTRY_CODE_AT, + COUNTRY_CODE_BY, COUNTRY_CODE_BE, COUNTRY_CODE_BA, COUNTRY_CODE_VG, + COUNTRY_CODE_BG, COUNTRY_CODE_CV, COUNTRY_CODE_HR, COUNTRY_CODE_CY, + COUNTRY_CODE_CZ, COUNTRY_CODE_DK, COUNTRY_CODE_EE, COUNTRY_CODE_ET, + COUNTRY_CODE_FI, COUNTRY_CODE_FR, COUNTRY_CODE_GF, COUNTRY_CODE_PF, + COUNTRY_CODE_TF, COUNTRY_CODE_GE, COUNTRY_CODE_DE, COUNTRY_CODE_GH, + COUNTRY_CODE_GR, COUNTRY_CODE_GP, COUNTRY_CODE_HU, COUNTRY_CODE_IS, + COUNTRY_CODE_IQ, COUNTRY_CODE_IE, COUNTRY_CODE_IT, COUNTRY_CODE_KE, + COUNTRY_CODE_LV, COUNTRY_CODE_LS, COUNTRY_CODE_LI, COUNTRY_CODE_LT, + COUNTRY_CODE_LU, COUNTRY_CODE_MK, COUNTRY_CODE_MT, COUNTRY_CODE_MQ, + COUNTRY_CODE_MR, COUNTRY_CODE_MU, COUNTRY_CODE_YT, COUNTRY_CODE_MD, + COUNTRY_CODE_MC, COUNTRY_CODE_ME, COUNTRY_CODE_MS, COUNTRY_CODE_NL, + COUNTRY_CODE_NO, COUNTRY_CODE_OM, COUNTRY_CODE_PL, COUNTRY_CODE_PT, + COUNTRY_CODE_RE, COUNTRY_CODE_RO, COUNTRY_CODE_MF, COUNTRY_CODE_SM, + COUNTRY_CODE_SN, COUNTRY_CODE_RS, COUNTRY_CODE_SK, COUNTRY_CODE_SI, + COUNTRY_CODE_ZA, COUNTRY_CODE_ES, COUNTRY_CODE_SE, COUNTRY_CODE_CH, + COUNTRY_CODE_TR, COUNTRY_CODE_TC, COUNTRY_CODE_GB, COUNTRY_CODE_VA, + COUNTRY_CODE_EU +}; + +static const UINT_16 g_u2CountryGroup6[] = { COUNTRY_CODE_JP }; + +static const UINT_16 g_u2CountryGroup7[] = { + COUNTRY_CODE_AM, COUNTRY_CODE_IL, COUNTRY_CODE_KW, COUNTRY_CODE_MA, + COUNTRY_CODE_NE, COUNTRY_CODE_TN, COUNTRY_CODE_MA +}; + +static const UINT_16 g_u2CountryGroup8[] = { COUNTRY_CODE_NP }; + +static const UINT_16 g_u2CountryGroup9[] = { COUNTRY_CODE_AF }; + +static const UINT_16 g_u2CountryGroup10[] = { + COUNTRY_CODE_AG, COUNTRY_CODE_BS, COUNTRY_CODE_BH, COUNTRY_CODE_BB, + COUNTRY_CODE_BN, COUNTRY_CODE_CL, COUNTRY_CODE_EG, +#if (CFG_CN_SUPPORT_CLASS121 == 0) + COUNTRY_CODE_CN, +#endif + COUNTRY_CODE_SV, COUNTRY_CODE_IN, COUNTRY_CODE_MY, COUNTRY_CODE_MV, + COUNTRY_CODE_PA, COUNTRY_CODE_VE, COUNTRY_CODE_ZM +}; + +static const UINT_16 g_u2CountryGroup11[] = { COUNTRY_CODE_JO, COUNTRY_CODE_PG }; + +static const UINT_16 g_u2CountryGroup12[] = { + COUNTRY_CODE_BF, COUNTRY_CODE_GY, COUNTRY_CODE_HT, COUNTRY_CODE_HN, + COUNTRY_CODE_JM, COUNTRY_CODE_MO, COUNTRY_CODE_MW, COUNTRY_CODE_PK, + COUNTRY_CODE_QA, COUNTRY_CODE_RW, COUNTRY_CODE_KN, COUNTRY_CODE_TZ +}; + +static const UINT_16 g_u2CountryGroup13[] = { COUNTRY_CODE_ID }; + +static const UINT_16 g_u2CountryGroup14[] = { COUNTRY_CODE_KR }; + +static const UINT_16 g_u2CountryGroup15[] = { COUNTRY_CODE_NG }; + +static const UINT_16 g_u2CountryGroup16[] = { + COUNTRY_CODE_BD, COUNTRY_CODE_BR, COUNTRY_CODE_DM, COUNTRY_CODE_DO, + COUNTRY_CODE_FK, COUNTRY_CODE_KZ, COUNTRY_CODE_MX, COUNTRY_CODE_MZ, + COUNTRY_CODE_NA, COUNTRY_CODE_RU, COUNTRY_CODE_LC, COUNTRY_CODE_VC, + COUNTRY_CODE_UA, COUNTRY_CODE_UZ, COUNTRY_CODE_ZW +}; + +static const UINT_16 g_u2CountryGroup17[] = { COUNTRY_CODE_MP }; + +static const UINT_16 g_u2CountryGroup18[] = { COUNTRY_CODE_TW }; + +static const UINT_16 g_u2CountryGroup19[] = { + COUNTRY_CODE_CK, COUNTRY_CODE_CU, COUNTRY_CODE_TL, COUNTRY_CODE_FO, + COUNTRY_CODE_GI, COUNTRY_CODE_GG, COUNTRY_CODE_IR, COUNTRY_CODE_IM, + COUNTRY_CODE_JE, COUNTRY_CODE_KP, COUNTRY_CODE_MH, COUNTRY_CODE_NU, + COUNTRY_CODE_NF, COUNTRY_CODE_PS, COUNTRY_CODE_PN, COUNTRY_CODE_PM, + COUNTRY_CODE_SS, COUNTRY_CODE_SD, COUNTRY_CODE_SY +}; + +static const UINT_16 g_u2CountryGroup20[] = { + COUNTRY_CODE_DF, COUNTRY_CODE_FF + /* When country code is not found and no matched NVRAM setting, + * this domain info will be used. + */ +}; + +static const UINT_16 g_u2CountryGroup21[] = { + COUNTRY_CODE_UDF +}; + +DOMAIN_INFO_ENTRY arSupportedRegDomains[] = { + { + (PUINT_16) g_u2CountryGroup0, sizeof(g_u2CountryGroup0) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_LOW_NA */ + {118, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_MID_NA */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup1, sizeof(g_u2CountryGroup1) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} + , /* CH_SET_2G4_1_11 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup2, sizeof(g_u2CountryGroup2) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup3, sizeof(g_u2CountryGroup3) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} + , /* CH_SET_UNII_UPPER_149_161 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup4, sizeof(g_u2CountryGroup4) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup5, sizeof(g_u2CountryGroup5) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup6, sizeof(g_u2CountryGroup6) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + {82, BAND_2G4, CHNL_SPAN_5, 14, 1, FALSE} + , /* CH_SET_2G4_14_14 */ + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + } + } + , + { + (PUINT_16) g_u2CountryGroup7, sizeof(g_u2CountryGroup7) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup8, sizeof(g_u2CountryGroup8) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} + , /* CH_SET_UNII_UPPER_149_161 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup9, sizeof(g_u2CountryGroup9) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_MID_NA */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_UPPER_NA */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup10, sizeof(g_u2CountryGroup10) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup11, sizeof(g_u2CountryGroup11) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_MID_NA */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup12, sizeof(g_u2CountryGroup12) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_LOW_NA */ + {118, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_MID_NA */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup13, sizeof(g_u2CountryGroup13) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_LOW_NA */ + {118, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_MID_NA */ + {121, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_WW_NA */ + {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} + , /* CH_SET_UNII_UPPER_149_161 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup14, sizeof(g_u2CountryGroup14) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 8, FALSE} + , /* CH_SET_UNII_WW_100_128 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 4, FALSE} + , /* CH_SET_UNII_UPPER_149_161 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup15, sizeof(g_u2CountryGroup15) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_NULL, 0, 0, 0, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup16, sizeof(g_u2CountryGroup16) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup17, sizeof(g_u2CountryGroup17) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} + , /* CH_SET_2G4_1_11 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, TRUE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup18, sizeof(g_u2CountryGroup18) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 11, FALSE} + , /* CH_SET_2G4_1_11 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, FALSE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 11, FALSE} + , /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + (PUINT_16) g_u2CountryGroup19, sizeof(g_u2CountryGroup19) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + /* Note: Default group if no matched country code */ + (PUINT_16) g_u2CountryGroup20, sizeof(g_u2CountryGroup20) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 13, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 4, FALSE} + , /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 4, TRUE} + , /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 12, TRUE} + , /* CH_SET_UNII_WW_100_144 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 5, FALSE} + , /* CH_SET_UNII_UPPER_149_165 */ + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } + , + { + /* Note: for customer configured their own scanning list and passive scan list */ + (PUINT_16) g_u2CountryGroup21, sizeof(g_u2CountryGroup21) / 2, + { + {81, BAND_2G4, CHNL_SPAN_5, 1, 12, FALSE} + , /* CH_SET_2G4_1_13 */ + + {115, BAND_5G, CHNL_SPAN_20, 36, 0, FALSE} + , + {118, BAND_5G, CHNL_SPAN_20, 52, 0, FALSE} + , + {121, BAND_5G, CHNL_SPAN_20, 100, 0, FALSE} + , + {125, BAND_5G, CHNL_SPAN_20, 149, 0, FALSE} + , + {0, BAND_NULL, 0, 0, 0, FALSE} + } + } +}; + +static UINT_16 g_u2CountryGroup0_Passive[] = { + COUNTRY_CODE_UDF +}; + +DOMAIN_INFO_ENTRY arSupportedRegDomains_Passive[] = { + { + /* Default passive scan channel table is empty */ + COUNTRY_CODE_NULL, 0, + { + {81, BAND_2G4, CHNL_SPAN_5, 11, 0, 0}, /* CH_SET_2G4_1_14 */ + {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, + + {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ + } + }, + { + /* User Defined passive scan channel table */ + g_u2CountryGroup0_Passive, 0, + { + {81, BAND_2G4, CHNL_SPAN_5, 12, 1, 0}, /* CH_SET_2G4_1_14 */ + {82, BAND_2G4, CHNL_SPAN_5, 5, 0, 0}, + + {115, BAND_5G, CHNL_SPAN_20, 36, 0, 0}, /* CH_SET_UNII_LOW_36_48 */ + {118, BAND_5G, CHNL_SPAN_20, 52, 0, 0}, /* CH_SET_UNII_MID_52_64 */ + {121, BAND_5G, CHNL_SPAN_20, 100, 0, 0}, /* CH_SET_UNII_WW_100_140 */ + {125, BAND_5G, CHNL_SPAN_20, 149, 0, 0}, /* CH_SET_UNII_UPPER_149_173 */ + } + } +}; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY +SUBBAND_CHANNEL_T g_rRlmSubBand[] = { + + {BAND_2G4_LOWER_BOUND, BAND_2G4_UPPER_BOUND, 1, 0} + , /* 2.4G */ + {UNII1_LOWER_BOUND, UNII1_UPPER_BOUND, 2, 0} + , /* ch36,38,40,..,48 */ + {UNII2A_LOWER_BOUND, UNII2A_UPPER_BOUND, 2, 0} + , /* ch52,54,56,..,64 */ + {UNII2C_LOWER_BOUND, UNII2C_UPPER_BOUND, 2, 0} + , /* ch100,102,104,...,144 */ + {UNII3_LOWER_BOUND, UNII3_UPPER_BOUND, 2, 0} + /* ch149,151,153,....,173 */ +}; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter) +{ +#define REG_DOMAIN_DEF_IDX 20 /* Default country domain */ +#define REG_DOMAIN_GROUP_NUM \ + (sizeof(arSupportedRegDomains) / sizeof(DOMAIN_INFO_ENTRY)) + + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_REG_INFO_T prRegInfo; + UINT_16 u2TargetCountryCode; + UINT_16 i, j; + + ASSERT(prAdapter); + + if (prAdapter->prDomainInfo) + return prAdapter->prDomainInfo; + + prRegInfo = &prAdapter->prGlueInfo->rRegInfo; + + DBGLOG(RLM, TRACE, "eRegChannelListMap=%d, u2CountryCode=0x%04x\n", + prRegInfo->eRegChannelListMap, + prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + /* + * Domain info can be specified by given idx of arSupportedRegDomains table, + * customized, or searched by country code, + * only one is set among these three methods in NVRAM. + */ + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_TBL_IDX && + prRegInfo->ucRegChannelListIndex < REG_DOMAIN_GROUP_NUM) { + /* by given table idx */ + DBGLOG(RLM, TRACE, "ucRegChannelListIndex=%d\n", prRegInfo->ucRegChannelListIndex); + prDomainInfo = &arSupportedRegDomains[prRegInfo->ucRegChannelListIndex]; + } else if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + /* by customized */ + prDomainInfo = &prRegInfo->rDomainInfo; + } else { + /* by country code */ + u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + + for (i = 0; i < REG_DOMAIN_GROUP_NUM; i++) { + prDomainInfo = &arSupportedRegDomains[i]; + + if ((prDomainInfo->u4CountryNum && prDomainInfo->pu2CountryGroup) || + prDomainInfo->u4CountryNum == 0) { + for (j = 0; j < prDomainInfo->u4CountryNum; j++) { + if (prDomainInfo->pu2CountryGroup[j] == u2TargetCountryCode) + break; + } + if (j < prDomainInfo->u4CountryNum) + break; /* Found */ + } + } + + /* If no matched country code, use the default country domain */ + if (i >= REG_DOMAIN_GROUP_NUM) { + DBGLOG(RLM, INFO, "No matched country code, use the default country domain\n"); + prDomainInfo = &arSupportedRegDomains[REG_DOMAIN_DEF_IDX]; + } + } + + prAdapter->prDomainInfo = prDomainInfo; + return prDomainInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] The input variable pointed by pucNumOfChannel is the max +* arrary size. The return value indciates meaning list size. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +rlmDomainGetChnlList(P_ADAPTER_T prAdapter, + ENUM_BAND_T eSpecificBand, BOOLEAN fgNoDfs, + UINT_8 ucMaxChannelNum, PUINT_8 pucNumOfChannel, P_RF_CHANNEL_INFO_T paucChannelList) +{ + UINT_8 i, j, ucNum; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + ASSERT(prAdapter); + ASSERT(paucChannelList); + ASSERT(pucNumOfChannel); + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + ucNum = 0; + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_NULL || prSubband->ucBand >= BAND_NUM || + (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand)) + continue; + + if (fgNoDfs == TRUE && prSubband->fgDfs == TRUE) + continue; + + if (eSpecificBand == BAND_NULL || prSubband->ucBand == eSpecificBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if (ucNum >= ucMaxChannelNum) + break; + paucChannelList[ucNum].eBand = prSubband->ucBand; + paucChannelList[ucNum].ucChannelNum = + prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan; + ucNum++; + } + } + } + + *pucNumOfChannel = ucNum; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainSendCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) +{ + rlmDomainSendDomainInfoCmd(prAdapter, fgIsOid); +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + rlmDomainSendPwrLimitCmd(prAdapter); +#endif + rlmDomainSendPassiveScanInfoCmd(prAdapter, fgIsOid); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) +{ + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_CMD_SET_DOMAIN_INFO_T prCmd; + P_DOMAIN_SUBBAND_INFO prSubBand; + UINT_8 i; + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); + if (!prCmd) { + DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); + return; + } + kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); + + prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + prCmd->u2IsSetPassiveScan = 0; + prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + prCmd->aucReserved[0] = 0; + prCmd->aucReserved[1] = 0; + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubBand = &prDomainInfo->rSubBand[i]; + + prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; + prCmd->rSubBand[i].ucBand = prSubBand->ucBand; + + if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { + prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; + prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; + prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; + } + } + + /* Set domain info to chip */ + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ + (PUINT_8)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + cnmMemFree(prAdapter, prCmd); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, BOOLEAN fgIsOid) +{ +#define REG_DOMAIN_PASSIVE_DEF_IDX 0 +#define REG_DOMAIN_PASSIVE_UDF_IDX 1 + + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_CMD_SET_DOMAIN_INFO_T prCmd; + P_DOMAIN_SUBBAND_INFO prSubBand; + UINT_8 i; + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); + if (!prCmd) { + DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); + return; + } + kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); + + prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + prCmd->u2IsSetPassiveScan = 1; + prCmd->uc2G4Bandwidth = prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + prCmd->aucReserved[0] = 0; + prCmd->aucReserved[1] = 0; + + DBGLOG(RLM, TRACE, "u2CountryCode=0x%04x\n", prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + if (prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_UDF) + prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_UDF_IDX]; + else + prDomainInfo = &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_DEF_IDX]; + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubBand = &prDomainInfo->rSubBand[i]; + + prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; + prCmd->rSubBand[i].ucBand = prSubBand->ucBand; + + if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { + prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; + prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; + prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; + } + } + + /* Set passive scan channel info to chip */ + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + cnmMemFree(prAdapter, prCmd); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] +* +* \return TRUE Legal channel +* FALSE Illegal channel for current regulatory domain +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, UINT_8 ucChannel) +{ + UINT_8 i, j; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) + continue; + + if (prSubband->ucBand == eBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan) + == ucChannel) { + return TRUE; + } + } + } + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in/out] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +UINT_32 rlmDomainSupOperatingClassIeFill(PUINT_8 pBuf) +{ + /* + The Country element should only be included for Status Code 0 (Successful). + */ + UINT_32 u4IeLen; + UINT_8 aucClass[12] = { 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, + 0x1c, 0x1e, 0x20, 0x21 + }; + + /* + The Supported Operating Classes element is used by a STA to advertise the + operating classes that it is capable of operating with in this country. + + The Country element (see 8.4.2.10) allows a STA to configure its PHY and MAC + for operation when the operating triplet of Operating Extension Identifier, + Operating Class, and Coverage Class fields is present. + */ + SUP_OPERATING_CLASS_IE(pBuf)->ucId = ELEM_ID_SUP_OPERATING_CLASS; + SUP_OPERATING_CLASS_IE(pBuf)->ucLength = 1 + sizeof(aucClass); + SUP_OPERATING_CLASS_IE(pBuf)->ucCur = 0x0c; /* 0x51 */ + kalMemCopy(SUP_OPERATING_CLASS_IE(pBuf)->ucSup, aucClass, sizeof(aucClass)); + u4IeLen = (SUP_OPERATING_CLASS_IE(pBuf)->ucLength + 2); + pBuf += u4IeLen; + + COUNTRY_IE(pBuf)->ucId = ELEM_ID_COUNTRY_INFO; + COUNTRY_IE(pBuf)->ucLength = 6; + COUNTRY_IE(pBuf)->aucCountryStr[0] = 0x55; + COUNTRY_IE(pBuf)->aucCountryStr[1] = 0x53; + COUNTRY_IE(pBuf)->aucCountryStr[2] = 0x20; + COUNTRY_IE(pBuf)->arCountryStr[0].ucFirstChnlNum = 1; + COUNTRY_IE(pBuf)->arCountryStr[0].ucNumOfChnl = 11; + COUNTRY_IE(pBuf)->arCountryStr[0].cMaxTxPwrLv = 0x1e; + u4IeLen += (COUNTRY_IE(pBuf)->ucLength + 2); + + return u4IeLen; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (fgValid) : 0 -> inValid, 1 -> Valid +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, UINT_8 ucCentralCh) +{ + BOOLEAN fgValid = FALSE; + UINT_8 ucTemp = 0; + UINT_8 i; + /*Check Power limit table channel efficient or not */ + + for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { + if ((ucCentralCh >= g_rRlmSubBand[i].ucStartCh) && (ucCentralCh <= g_rRlmSubBand[i].ucEndCh)) + ucTemp = (ucCentralCh - g_rRlmSubBand[i].ucStartCh) % g_rRlmSubBand[i].ucInterval; + } + +#if 0 + /*2.4G, ex 1, 2, 3 */ + if (ucCentralCh >= BAND_2G4_LOWER_BOUND && ucCentralCh <= BAND_2G4_UPPER_BOUND) + ucTemp = 0; + /*FCC- Spec : Band UNII-1, ex 36, 38, 40.... */ + else if (ucCentralCh >= UNII1_LOWER_BOUND && ucCentralCh <= UNII1_UPPER_BOUND) + ucTemp = (ucCentralCh - UNII1_LOWER_BOUND) % 2; + /*FCC- Spec : Band UNII-2A, ex 52, 54, 56.... */ + else if (ucCentralCh >= UNII2A_LOWER_BOUND && ucCentralCh <= UNII2A_UPPER_BOUND) + ucTemp = (ucCentralCh - UNII2A_LOWER_BOUND) % 2; + /*FCC- Spec : Band UNII-2C, ex 100, 102, 104.... */ + else if (ucCentralCh >= UNII2C_LOWER_BOUND && ucCentralCh <= UNII2C_UPPER_BOUND) + ucTemp = (ucCentralCh - UNII2C_LOWER_BOUND) % 2; + /*FCC- Spec : Band UNII-3, ex 149, 151, 153... */ + else if (ucCentralCh >= UNII3_LOWER_BOUND && ucCentralCh <= UNII3_UPPER_BOUND) + ucTemp = (ucCentralCh - UNII3_LOWER_BOUND) % 2; +#endif + if (ucTemp == 0) + fgValid = TRUE; + return fgValid; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, UINT_8 ucPriChannel, ENUM_CHNL_EXT_T eExtend) +{ + UINT_8 ucCenterChannel; + + if (eExtend == CHNL_EXT_SCA) + ucCenterChannel = ucPriChannel + 2; + else if (eExtend == CHNL_EXT_SCB) + ucCenterChannel = ucPriChannel - 2; + else + ucCenterChannel = ucPriChannel; + + return ucCenterChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, + ENUM_BAND_T eBand, + UINT_8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend, + ENUM_CHANNEL_WIDTH_T eChannelWidth, UINT_8 ucChannelS1, UINT_8 ucChannelS2) +{ + UINT_8 ucCenterChannel; + BOOLEAN fgValidChannel = TRUE; + BOOLEAN fgValidBW = TRUE; + BOOLEAN fgValidRfSetting = TRUE; + UINT_32 u4PrimaryOffset; + + /*DBG msg for Channel InValid */ + if (eChannelWidth == CW_20_40MHZ) { + ucCenterChannel = rlmDomainGetCenterChannel(eBand, ucPriChannel, eExtend); + + /* Check Central Channel Valid or Not */ + fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + if (fgValidChannel == FALSE) + DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); + } else if (eChannelWidth == CW_80MHZ) { + ucCenterChannel = ucChannelS1; + + /* Check Central Channel Valid or Not */ + fgValidChannel = rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + if (fgValidChannel == FALSE) + DBGLOG(RLM, WARN, "Rf: CentralCh=%d\n", ucCenterChannel); + } else if (eChannelWidth == CW_160MHZ) { + ucCenterChannel = ucChannelS2; + + /* Check Central Channel Valid or Not */ + /*TODo */ + } + + /* Check BW Setting Correct or Not */ + if (eBand == BAND_2G4) { + if (eChannelWidth != CW_20_40MHZ) { + fgValidBW = FALSE; + DBGLOG(RLM, WARN, "Rf: B=%d, W=%d\n", eBand, eChannelWidth); + } + } else { + if (eChannelWidth == CW_80MHZ) { + u4PrimaryOffset = CAL_CH_OFFSET_80M(ucPriChannel, ucCenterChannel); + if (u4PrimaryOffset > 4) { + fgValidBW = FALSE; + DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); + } + } else if (eChannelWidth == CW_160MHZ) { + u4PrimaryOffset = CAL_CH_OFFSET_160M(ucPriChannel, ucCenterChannel); + if (u4PrimaryOffset > 8) { + fgValidBW = FALSE; + DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, eChannelWidth); + } + } + } + + if ((fgValidBW == FALSE) || (fgValidChannel == FALSE)) + fgValidRfSetting = FALSE; + + return fgValidRfSetting; + +} + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (fgValid) : 0 -> inValid, 1 -> Valid +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, + COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, + UINT_8 ucPwrLimitNum) +{ + UINT_8 i; + BOOLEAN fgValid = TRUE; + PINT_8 prPwrLimit; + + prPwrLimit = &rPowerLimitTableConfiguration.aucPwrLimit[0]; + + for (i = 0; i < ucPwrLimitNum; i++, prPwrLimit++) { + if (*prPwrLimit > MAX_TX_POWER || *prPwrLimit < MIN_TX_POWER) { + fgValid = FALSE; + break; /*Find out Wrong Power limit */ + } + } + return fgValid; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter) +{ + UINT_8 i, j; + UINT_16 u2CountryCodeTable, u2CountryCodeCheck; + BOOLEAN fgChannelValid = FALSE; + BOOLEAN fgPowerLimitValid = FALSE; + BOOLEAN fgEntryRepetetion = FALSE; + BOOLEAN fgTableValid = TRUE; + + /*Configuration Table Check */ + for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { + /*Table Country Code */ + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); + + /*Repetition Entry Check */ + for (j = i + 1; + j < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); + j++) { + + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[j].aucCountryCode[0], &u2CountryCodeCheck); + if (((g_rRlmPowerLimitConfiguration[i].ucCentralCh) == + g_rRlmPowerLimitConfiguration[j].ucCentralCh) + && (u2CountryCodeTable == u2CountryCodeCheck)) { + fgEntryRepetetion = TRUE; + DBGLOG(RLM, LOUD, "Domain: Configuration Repetition CC=%c%c, Ch=%d\n", + g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], + g_rRlmPowerLimitConfiguration[i].ucCentralCh); + } + } + + /*Channel Number Check */ + fgChannelValid = + rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); + + /*Power Limit Check */ + fgPowerLimitValid = + rlmDomainCheckPowerLimitValid(prAdapter, g_rRlmPowerLimitConfiguration[i], PWR_LIMIT_NUM); + + if (fgChannelValid == FALSE || fgPowerLimitValid == FALSE) { + fgTableValid = FALSE; + DBGLOG(RLM, LOUD, "Domain: CC=%c%c, Ch=%d, Limit: %d,%d,%d,%d,%d\n", + g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], + g_rRlmPowerLimitConfiguration[i].ucCentralCh, + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]); + } + + if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + DBGLOG(RLM, LOUD, "Domain: Full search down\n"); + break; /*End of country table entry */ + } + + } + + if (fgEntryRepetetion == FALSE) + DBGLOG(RLM, TRACE, "Domain: Configuration Table no Repetiton.\n"); + + /*Configuration Table no error */ + if (fgTableValid == TRUE) + prAdapter->fgIsPowerLimitTableValid = TRUE; + else + prAdapter->fgIsPowerLimitTableValid = FALSE; + + /*Default Table Check */ + fgEntryRepetetion = FALSE; + for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { + + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); + + for (j = i + 1; j < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); j++) { + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[j].aucCountryCode[0], &u2CountryCodeCheck); + if (u2CountryCodeTable == u2CountryCodeCheck) { + fgEntryRepetetion = TRUE; + DBGLOG(RLM, LOUD, + "Domain: Default Repetition CC=%c%c\n", + g_rRlmPowerLimitDefault[j].aucCountryCode[0], + g_rRlmPowerLimitDefault[j].aucCountryCode[1]); + } + } + } + if (fgEntryRepetetion == FALSE) + DBGLOG(RLM, TRACE, "Domain: Default Table no Repetiton.\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (u2TableIndex) : if 0xFFFF -> No Table Match +*/ +/*----------------------------------------------------------------------------*/ +UINT_16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, UINT_16 u2CountryCode) +{ + + UINT_16 i; + UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; + UINT_16 u2TableIndex = POWER_LIMIT_TABLE_NULL; /* No Table Match */ + + /*Default Table Index */ + for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); i++) { + + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], &u2CountryCodeTable); + + if (u2CountryCodeTable == u2CountryCode) { + u2TableIndex = i; + break; /*match country code */ + } else if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + u2TableIndex = i; + break; /*find last one country- Default */ + } + } + + DBGLOG(RLM, TRACE, "Domain: Default Table Index = %d\n", u2TableIndex); + + return u2TableIndex; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainBuildCmdByDefaultTable(P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd, UINT_16 u2DefaultTableIndex) +{ + UINT_8 i, k; + P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT prPwrLimitSubBand; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; + + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + prPwrLimitSubBand = &g_rRlmPowerLimitDefault[u2DefaultTableIndex]; + + /*Build power limit cmd by default table information */ + + for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { + if (prPwrLimitSubBand->aucPwrLimitSubBand[i] < MAX_TX_POWER) { + for (k = g_rRlmSubBand[i].ucStartCh; k <= g_rRlmSubBand[i].ucEndCh; + k += g_rRlmSubBand[i].ucInterval) { + if ((prPwrLimitSubBand->ucPwrUnit & BIT(i)) == 0) { + prCmdPwrLimit->ucCentralCh = k; + prCmdPwrLimit->cPwrLimitCCK = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit20 = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit40 = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit80 = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit160 = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit++; + prCmd->ucNum++; + + } else { + /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 + * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ + prCmdPwrLimit->ucCentralCh = k; + prCmdPwrLimit->cPwrLimitCCK = prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit20 = prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit40 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 6; + if (prCmdPwrLimit->cPwrLimit40 > MAX_TX_POWER) + prCmdPwrLimit->cPwrLimit40 = MAX_TX_POWER; + prCmdPwrLimit->cPwrLimit80 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 12; + if (prCmdPwrLimit->cPwrLimit80 > MAX_TX_POWER) + prCmdPwrLimit->cPwrLimit80 = MAX_TX_POWER; + prCmdPwrLimit->cPwrLimit160 = prPwrLimitSubBand->aucPwrLimitSubBand[i] + 18; + if (prCmdPwrLimit->cPwrLimit160 > MAX_TX_POWER) + prCmdPwrLimit->cPwrLimit160 = MAX_TX_POWER; + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + } + } + +#if 0 + if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4] < MAX_TX_POWER) { + for (i = BAND_2G4_LOWER_BOUND; i <= BAND_2G4_UPPER_BOUND; i++) { + prCmdPwrLimit->ucCentralCh = i; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_2G4], + PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + + if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1] < MAX_TX_POWER) { + if (prCmd->u2CountryCode != COUNTRY_CODE_KR) { + for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { + prCmdPwrLimit->ucCentralCh = i; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, + prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII1], PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } + } else { + for (i = UNII1_LOWER_BOUND; i <= UNII1_UPPER_BOUND; i += 2) { + /* ex: 40MHz power limit(mW\MHz) = 20MHz power limit(mW\MHz) * 2 + * ---> 40MHz power limit(dBm) = 20MHz power limit(dBm) + 6; */ + prCmdPwrLimit->ucCentralCh = i; + prCmdPwrLimit->cPwrLimitCCK = + g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; + prCmdPwrLimit->cPwrLimit20 = + g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1; + prCmdPwrLimit->cPwrLimit40 = + g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 6; + prCmdPwrLimit->cPwrLimit80 = + g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 12; + prCmdPwrLimit->cPwrLimit160 = + g_rRlmPowerLimitDefault[u2DefaultTableIndex].cPwrLimitUnii1 + 18; + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + } + + if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A] < MAX_TX_POWER) { + for (i = UNII2A_LOWER_BOUND; i <= UNII2A_UPPER_BOUND; i += 2) { + prCmdPwrLimit->ucCentralCh = i; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, + prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2A], PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + + if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C] < MAX_TX_POWER) { + for (i = UNII2C_LOWER_BOUND; i <= UNII2C_UPPER_BOUND; i += 2) { + prCmdPwrLimit->ucCentralCh = i; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, + prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII2C], PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + if (prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3] < MAX_TX_POWER) { + for (i = UNII3_LOWER_BOUND; i <= UNII3_UPPER_BOUND; i += 2) { + prCmdPwrLimit->ucCentralCh = i; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, + prPwrLimitSubBand->aucPwrLimitSubBand[POWER_LIMIT_UNII3], PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainBuildCmdByConfigTable(P_ADAPTER_T prAdapter, P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd) +{ + UINT_8 i, k; + UINT_16 u2CountryCodeTable = COUNTRY_CODE_NULL; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; + BOOLEAN fgChannelValid; + + /*Build power limit cmd by configuration table information */ + + for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); i++) { + + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], &u2CountryCodeTable); + + fgChannelValid = + rlmDomainCheckChannelEntryValid(prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); + + if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + DBGLOG(RLM, TRACE, "Domain: full search configuration table done.\n"); + break; /*end of configuration table */ + } else if ((u2CountryCodeTable == prCmd->u2CountryCode) && (fgChannelValid == TRUE)) { + + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + + if (prCmd->ucNum != 0) { + for (k = 0; k < prCmd->ucNum; k++) { + if (prCmdPwrLimit->ucCentralCh == + g_rRlmPowerLimitConfiguration[i].ucCentralCh) { + + /*Cmd setting (Default table information) and + Configuration table has repetition channel entry, + ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, + Configuration table (ex: ch1, limit = 22dBm) --> ch 1 = 22 dBm + Cmd final setting --> ch1 = 22dBm, ch12~14 = 20dBm + */ + prCmdPwrLimit->cPwrLimitCCK = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; + prCmdPwrLimit->cPwrLimit20 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; + prCmdPwrLimit->cPwrLimit40 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; + prCmdPwrLimit->cPwrLimit80 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; + prCmdPwrLimit->cPwrLimit160 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; + + DBGLOG(RLM, LOUD, + "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, + prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, + prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, + prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); + + break; + } + prCmdPwrLimit++; + } + if (k == prCmd->ucNum) { + + /*Full search cmd (Default table setting) no match channey, + ex : Default table (ex: 2.4G, limit = 20dBm) --> ch1~14 limit =20dBm, + Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm + Cmd final setting --> ch1~14 = 20dBm, ch36= 22dBm + */ + prCmdPwrLimit->cPwrLimitCCK = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; + prCmdPwrLimit->cPwrLimit20 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; + prCmdPwrLimit->cPwrLimit40 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; + prCmdPwrLimit->cPwrLimit80 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; + prCmdPwrLimit->cPwrLimit160 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; + prCmd->ucNum++; + + DBGLOG(RLM, LOUD, + "Domain: Full CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), (prCmd->u2CountryCode & 0x00ff), + prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, + prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, + prCmdPwrLimit->ucFlag); + + } + } else { + + /*Default table power limit value are 63--> cmd table no channel entry + ex : Default table (ex: 2.4G, limit = 63Bm) --> no channel entry in cmd, + Configuration table (ex: ch36, limit = 22dBm) --> ch 36 = 22 dBm + Cmd final setting --> ch36= 22dBm + */ + prCmdPwrLimit->ucCentralCh = g_rRlmPowerLimitConfiguration[i].ucCentralCh; + prCmdPwrLimit->cPwrLimitCCK = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK]; + prCmdPwrLimit->cPwrLimit20 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M]; + prCmdPwrLimit->cPwrLimit40 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M]; + prCmdPwrLimit->cPwrLimit80 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M]; + prCmdPwrLimit->cPwrLimit160 = + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]; + prCmd->ucNum++; + + DBGLOG(RLM, LOUD, "Domain: Default table power limit value are 63.\n"); + DBGLOG(RLM, LOUD, "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, + prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, + prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, + prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); + + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param[in] +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter) +{ + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd; + UINT_8 i; + UINT_16 u2DefaultTableIndex; + UINT_32 u4SetCmdTableMaxSize; + UINT_32 u4SetQueryInfoLen; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; /* for print usage */ + + u4SetCmdTableMaxSize = + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + + MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); + + if (!prCmd) { + DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); + return; + } + kalMemZero(prCmd, u4SetCmdTableMaxSize); + + u2DefaultTableIndex = + rlmDomainPwrLimitDefaultTableDecision(prAdapter, prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + if (u2DefaultTableIndex != POWER_LIMIT_TABLE_NULL) { + + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[u2DefaultTableIndex].aucCountryCode[0], + &prCmd->u2CountryCode); + + prCmd->ucNum = 0; + + if (prCmd->u2CountryCode != COUNTRY_CODE_NULL) { + /*Command - default table information */ + rlmDomainBuildCmdByDefaultTable(prCmd, u2DefaultTableIndex); + + /*Command - configuration table information */ + rlmDomainBuildCmdByConfigTable(prAdapter, prCmd); + } + } +#if 0 + u4SetCmdTableMaxSize = + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + + MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); + ASSERT(prCmd); + + /* To do: exception handle */ + if (!prCmd) { + DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); + return; + } + kalMemZero(prCmd, u4SetCmdTableMaxSize); /* TODO memzero */ + + if (u2TableIndex != POWER_LIMIT_TABLE_NULL && u2TableIndex < MAX_DEFAULT_TABLE_COUNTRY_NUM) { + + prCmd->u2CountryCode = (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[0]) << 8) | + (((UINT_16) g_rRlmCountryPowerLimitTable[u2TableIndex].aucCountryCode[1]) & BITS(0, 7)); + prChPwrLimit = &g_rRlmCountryPowerLimitTable[u2TableIndex].rChannelPowerLimit[0]; + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + prCmd->ucNum = 0; + for (i = 0; i < MAX_CMD_SUPPORT_CHANNEL_NUM; i++) { + + if (prChPwrLimit->ucCentralCh != ENDCH) { + + /*Check Power limit table channel efficient or not */ + fgChannelValid = rlmDomainCheckChannelEntryValid(prAdapter, prChPwrLimit->ucCentralCh); + + /*Cmd set up */ + if (fgChannelValid) { + kalMemCopy(prCmdPwrLimit, prChPwrLimit, sizeof(CMD_CHANNEL_POWER_LIMIT)); + DBGLOG(RLM, INFO, + "Domain: ValidCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, + prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, + prCmdPwrLimit->ucFlag); + prCmd->ucNum++; + prCmdPwrLimit++; + } else { + DBGLOG(RLM, INFO, + "Domain: Non-Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + prChPwrLimit->ucCentralCh, prChPwrLimit->cPwrLimitCCK, + prChPwrLimit->cPwrLimit20, prChPwrLimit->cPwrLimit40, + prChPwrLimit->cPwrLimit80, prChPwrLimit->cPwrLimit160, + prChPwrLimit->ucFlag); + } + prChPwrLimit++; + } else { + /*End of the chanel entry */ + break; + } + }; + } +#endif + + if (prCmd->u2CountryCode != 0) { + DBGLOG(RLM, INFO, + "Domain: ValidCC =%c%c, ChNum=%d\n", ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), prCmd->ucNum); + } else { + DBGLOG(RLM, INFO, "Domain: ValidCC =0x%04x, ucNum=%d\n", prCmd->u2CountryCode, prCmd->ucNum); + } + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + + for (i = 0; i < prCmd->ucNum; i++) { + DBGLOG(RLM, TRACE, "Domain: Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", prCmdPwrLimit->ucCentralCh, + prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); + prCmdPwrLimit++; + } + + u4SetQueryInfoLen = + (sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + (prCmd->ucNum) * sizeof(CMD_CHANNEL_POWER_LIMIT)); + + /* Update domain info to chip */ + if (prCmd->ucNum <= MAX_CMD_SUPPORT_CHANNEL_NUM) { + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_COUNTRY_POWER_LIMIT, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + u4SetQueryInfoLen, /* u4SetQueryInfoLen */ + (PUINT_8) prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + } else + DBGLOG(RLM, ERROR, "Domain: illegal power limit table"); + + cnmMemFree(prAdapter, prCmd); + +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c new file mode 100644 index 0000000000000..8450124a3f38e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_obss.c @@ -0,0 +1,436 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_obss.c#2 +*/ + +/*! \file "rlm_obss.c" + \brief + +*/ + +/* +** Log: rlm_obss.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 11 15 2011 cm.chang + * NULL + * Avoid possible OBSS scan when BSS is switched + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * Regulation class is changed to 81 in 20_40_coexistence action frame + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 29 2011 cm.chang + * [WCXRP00000606] [MT6620 Wi-Fi][Driver][FW] Fix klocwork warning + * As CR title + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame + * in AP mode and stop ampdu timer when sta_rec is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 13 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Refine function when rcv a 20/40M public action frame + * + * 01 13 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * Use SCO of BSS_INFO to replace user-defined setting variables + * + * 01 12 2011 cm.chang + * [WCXRP00000354] [MT6620 Wi-Fi][Driver][FW] Follow NVRAM bandwidth setting + * User-defined bandwidth is for 2.4G and 5G individually + * + * 10 18 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * use definition macro to replace hard-coded constant + * + * 09 16 2010 cm.chang + * NULL + * Change conditional compiling options for BOW + * + * 09 10 2010 cm.chang + * NULL + * Always update Beacon content if FW sync OBSS info + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 26 2010 yuche.tsai + * + * Fix compile error while enabling WiFi Direct function. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 05 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Process 20/40 coexistence public action frame in AP mode + * + * 05 05 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft support for 20/40M bandwidth for AP mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add more ASSERT to check exception + * + * 04 07 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add virtual test for OBSS scan + * + * 03 30 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support 2.4G OBSS scan + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 02 05 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmObssInit(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 ucNetIdx; + + RLM_NET_FOR_EACH(ucNetIdx) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[ucNetIdx]; + ASSERT(prBssInfo); + + cnmTimerInitTimer(prAdapter, &prBssInfo->rObssScanTimer, rlmObssScanTimeout, (ULONG) prBssInfo); + } /* end of RLM_NET_FOR_EACH */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rlmObssUpdateChnlLists(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + UINT_16 i, u2PayloadLen; + + ASSERT(prMsgHdr); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) prMsgHdr; + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prScanDoneMsg->ucNetTypeIndex]; + ASSERT(prBssInfo); + + DBGLOG(RLM, INFO, "OBSS Scan Done (NetIdx=%d, Mode=%d)\n", + prScanDoneMsg->ucNetTypeIndex, prBssInfo->eCurrentOPMode); + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_ENABLE_WIFI_DIRECT + /* AP mode */ + if ((prAdapter->fgIsP2PRegistered) && + (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex)) && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + return; + } +#endif + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, "OBSS Scan Done (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); + return; + } + + /* To do: check 2.4G channel list to decide if obss mgmt should be + * sent to associated AP. Note: how to handle concurrent network? + * To do: invoke rlmObssChnlLevel() to decide if 20/40 BSS coexistence + * management frame is needed. + */ + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + if ((prBssInfo->auc2G_20mReqChnlList[0] > 0 || prBssInfo->auc2G_NonHtChnlList[0] > 0) && prMsduInfo != NULL) { + DBGLOG(RLM, INFO, "Send 20/40 coexistence mgmt(20mReq=%d, NonHt=%d)\n", + prBssInfo->auc2G_20mReqChnlList[0], prBssInfo->auc2G_NonHtChnlList[0]); + + prTxFrame = (P_ACTION_20_40_COEXIST_FRAME) + ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = (prBssInfo->auc2G_20mReqChnlList[0] > 0) ? BSS_COEXIST_20M_REQ : 0; + + u2PayloadLen = 2 + 3; + + if (prBssInfo->auc2G_NonHtChnlList[0] > 0) { + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + + prTxFrame->rChnlReport.ucId = ELEM_ID_20_40_INTOLERANT_CHNL_REPORT; + prTxFrame->rChnlReport.ucLength = prBssInfo->auc2G_NonHtChnlList[0] + 1; + prTxFrame->rChnlReport.ucRegulatoryClass = 81; /* 2.4GHz, ch1~13 */ + for (i = 0; i < prBssInfo->auc2G_NonHtChnlList[0] && i < CHNL_LIST_SZ_2G; i++) + prTxFrame->rChnlReport.aucChannelList[i] = prBssInfo->auc2G_NonHtChnlList[i + 1]; + + u2PayloadLen += IE_SIZE(&prTxFrame->rChnlReport); + } + ASSERT((WLAN_MAC_HEADER_LEN + u2PayloadLen) <= PUBLIC_ACTION_MAX_LEN); + + /* Clear up channel lists in 2.4G band */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + + /* 4 Update information of MSDU_INFO_T */ + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + } + /* end of prMsduInfo != NULL */ + if (prBssInfo->u2ObssScanInterval > 0) { + DBGLOG(RLM, INFO, "Set OBSS timer (NetIdx=%d, %d sec)\n", + prBssInfo->ucNetTypeIndex, prBssInfo->u2ObssScanInterval); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +static VOID rlmObssScanTimeout(P_ADAPTER_T prAdapter, ULONG ulData) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = (P_BSS_INFO_T) ulData; + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && (IS_NET_ACTIVE(prAdapter, prBssInfo->ucNetTypeIndex))) { + + /* AP mode */ + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + + prBssInfo->fgObssActionForcedTo20M = FALSE; + + /* Check if Beacon content need to be updated */ + rlmUpdateParamsForAP(prAdapter, prBssInfo, FALSE); + + return; + } +#if CFG_SUPPORT_WFD + /* WFD streaming */ + else { + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = + &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + P_BSS_INFO_T prP2pBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]; + + /* If WFD is enabled & connected */ + if (prWfdCfgSettings->ucWfdEnable && + (prWfdCfgSettings->u4WfdFlag & BIT(0)) && RLM_NET_PARAM_VALID(prP2pBssInfo)) { + + /* Skip OBSS scan */ + prBssInfo->u2ObssScanInterval = 0; + + DBGLOG(RLM, INFO, "WFD is running. Stop net[%u] OBSS scan.\n", + (UINT_32) prBssInfo->ucNetTypeIndex); + + return; + } + } +#endif + } +#endif /* end of CFG_ENABLE_WIFI_DIRECT */ + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, "OBSS Scan timeout (NetIdx=%d) -- Aborted!!\n", prBssInfo->ucNetTypeIndex); + return; + } + + rlmObssTriggerScan(prAdapter, prBssInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_MSG_SCN_SCAN_REQ prScanReqMsg; + + ASSERT(prBssInfo); + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ) + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + ASSERT(prScanReqMsg); + + if (!prScanReqMsg) { + DBGLOG(RLM, WARN, "No buf for OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + return; + } + + /* It is ok that ucSeqNum is set to fixed value because the same network + * OBSS scan interval is limited to OBSS_SCAN_MIN_INTERVAL (min 10 sec) + * and scan module don't care seqNum of OBSS scanning + */ + prScanReqMsg->rMsgHdr.eMsgId = MID_RLM_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = 0x33; + prScanReqMsg->ucNetTypeIndex = prBssInfo->ucNetTypeIndex; + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + prScanReqMsg->ucSSIDLength = 0; + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + prScanReqMsg->u2IELen = 0; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanReqMsg, MSG_SEND_METHOD_BUF); + + DBGLOG(RLM, INFO, "Timeout to trigger OBSS scan (NetIdx=%d)!!\n", prBssInfo->ucNetTypeIndex); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c new file mode 100644 index 0000000000000..d3c5133970956 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rlm_protection.c @@ -0,0 +1,105 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rlm_protection.c#1 +*/ + +/*! \file "rlm_protection.c" + \brief + +*/ + +/* +** Log: rlm_protection.c + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Check draft RLM code for HT cap + * + * 05 28 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Set RTS threshold of 2K bytes initially + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * First draft code to support protection in AP mode + * + * 03 31 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Enable RTS threshold temporarily for AMPDU + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 03 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * To support CFG_SUPPORT_BCM_STP + * + * 02 13 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support PCO in STA mode + * + * 02 12 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Use bss info array for concurrent handle + * + * 01 25 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c new file mode 100644 index 0000000000000..3f088c2839936 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/roaming_fsm.c @@ -0,0 +1,539 @@ +/* +** Id: +*/ + +/*! \file "roaming_fsm.c" + \brief This file defines the FSM for Roaming MODULE. + + This file defines the FSM for Roaming MODULE. +*/ + +/* +** Log: roaming_fsm.c + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 08 31 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * remove obsolete code. + * + * 08 15 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * add swcr in driver reg, 0x9fxx0000, to disable roaming . + * + * 03 16 2011 tsaiyuan.hsu + * [WCXRP00000517] [MT6620 Wi-Fi][Driver][FW] Fine Tune Performance of Roaming + * remove obsolete definition and unused variables. + * + * 02 26 2011 tsaiyuan.hsu + * [WCXRP00000391] [MT6620 Wi-Fi][FW] Add Roaming Support + * not send disassoc or deauth to leaving AP so as to improve performace of roaming. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_ROAMING +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugRoamingState[ROAMING_STATE_NUM] = { + (PUINT_8) DISP_STRING("ROAMING_STATE_IDLE"), + (PUINT_8) DISP_STRING("ROAMING_STATE_DECISION"), + (PUINT_8) DISP_STRING("ROAMING_STATE_DISCOVERY"), + (PUINT_8) DISP_STRING("ROAMING_STATE_ROAM") +}; + +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* +#define ROAMING_ENABLE_CHECK(_roam) \ +{ \ + if (!(_roam->fgIsEnableRoaming)) \ + return; \ +} +*/ +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the value in ROAMING_FSM_INFO_T for ROAMING FSM operation +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmInit(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DBGLOG(ROAMING, LOUD, "->roamingFsmInit(): Current Time = %u\n", kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> Initiate FSM */ + prRoamingFsmInfo->fgIsEnableRoaming = prConnSettings->fgIsEnableRoaming; + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; + prRoamingFsmInfo->rRoamingDiscoveryUpdateTime = 0; + +} /* end of roamingFsmInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Uninitialize the value in AIS_FSM_INFO_T for AIS FSM operation +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + DBGLOG(ROAMING, LOUD, "->roamingFsmUninit(): Current Time = %u\n", kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; + +} /* end of roamingFsmUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Send commands to firmware +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN P_ROAMING_PARAM_T] prParam +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + WLAN_STATUS rStatus; + + DBGLOG(ROAMING, LOUD, "->roamingFsmSendCmd(): Current Time = %u\n", kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_ROAMING_TRANSIT, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(ROAMING_PARAM_T), /* u4SetQueryInfoLen */ + (PUINT_8) prParam, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + +} /* end of roamingFsmSendCmd() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Update the recent time when ScanDone occurred +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + DBGLOG(ROAMING, LOUD, "->roamingFsmScanResultsUpdate(): Current Time = %u", kalGetTimeTick()); + + GET_CURRENT_SYSTIME(&prRoamingFsmInfo->rRoamingDiscoveryUpdateTime); + +} /* end of roamingFsmScanResultsUpdate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of ROAMING for AIS Infra. +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN ENUM_ROAMING_STATE_T] eNextState Enum value of next AIS STATE +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_ROAMING_STATE_T eNextState) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T ePreviousState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + do { + + /* Do entering Next State */ +#if DBG + DBGLOG(ROAMING, STATE, "TRANSITION: [%s] -> [%s]\n", + apucDebugRoamingState[prRoamingFsmInfo->eCurrentState], + apucDebugRoamingState[eNextState]); +#else + DBGLOG(ROAMING, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", + DBG_ROAMING_IDX, prRoamingFsmInfo->eCurrentState, eNextState); +#endif + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + ePreviousState = prRoamingFsmInfo->eCurrentState; + prRoamingFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN) FALSE; + + /* Do tasks of the State that we just entered */ + switch (prRoamingFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of following + * switch case. Instead I would like to use a common lookup table of array + * of function pointer to speed up state search. + */ + case ROAMING_STATE_IDLE: + case ROAMING_STATE_DECISION: + break; + + case ROAMING_STATE_DISCOVERY: + { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prRoamingFsmInfo->rRoamingDiscoveryUpdateTime, + SEC_TO_SYSTIME(ROAMING_DISCOVERY_TIMEOUT_SEC))) { + DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Timeout"); + aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); + } else { + DBGLOG(ROAMING, LOUD, "roamingFsmSteps: DiscoveryUpdateTime Updated"); +#if CFG_SUPPORT_ROAMING_ENC + if (prAdapter->fgIsRoamingEncEnabled == TRUE) + aisFsmRunEventRoamingDiscovery(prAdapter, TRUE); + else +#endif /* CFG_SUPPORT_ROAMING_ENC */ + aisFsmRunEventRoamingDiscovery(prAdapter, FALSE); + } + } + break; + + case ROAMING_STATE_ROAM: + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + } + } while (fgIsTransition); + + return; + +} /* end of roamingFsmSteps() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Decision state after join completion +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + if (prAisBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) + return; + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING START: Current Time = %u\n", kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as DECISION, DISCOVERY -> DECISION */ + if (!(prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE || + prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) + return; + + eNextState = ROAMING_STATE_DECISION; + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_START; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + +} /* end of roamingFsmRunEventStart() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Discovery state when deciding to find a candidate +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING DISCOVERY: Current Time = %u Reason = %u\n", + kalGetTimeTick(), prParam->u2Reason); + + /* DECISION -> DISCOVERY */ + /* Errors as IDLE, DISCOVERY, ROAM -> DISCOVERY */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DECISION) + return; +#if CFG_SUPPORT_ROAMING_ENC + prRoamingFsmInfo->RoamingEntryTimeoutSkipCount = 0; +#endif + + eNextState = ROAMING_STATE_DISCOVERY; + /* DECISION -> DISCOVERY */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + + /* sync. rcpi with firmware */ + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prBssDesc = scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + if (prBssDesc) + prBssDesc->ucRCPI = (UINT_8) (prParam->u2Data & 0xff); + + roamingFsmSteps(prAdapter, eNextState); + } + +} /* end of roamingFsmRunEventDiscovery() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Roam state after Scan Done +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ROAM: Current Time = %u\n", kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, ROAM -> ROAM */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DISCOVERY) + return; + + eNextState = ROAMING_STATE_ROAM; + /* DISCOVERY -> ROAM */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_ROAM; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + +} /* end of roamingFsmRunEventRoam() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Decision state as being failed to find out any candidate +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Param) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING FAIL: reason %x Current Time = %u\n", u4Param, kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, DISCOVERY -> DECISION */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_ROAM) + return; + + eNextState = ROAMING_STATE_DECISION; + /* ROAM -> DECISION */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_FAIL; + rParam.u2Data = (UINT_16) (u4Param & 0xffff); + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + +} /* end of roamingFsmRunEventFail() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Transit to Idle state as beging aborted by other moduels, AIS +* +* @param [IN P_ADAPTER_T] prAdapter +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + ROAMING_PARAM_T rParam; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) + return; + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ABORT: Current Time = %u\n", kalGetTimeTick()); + + eNextState = ROAMING_STATE_IDLE; + /* IDLE, DECISION, DISCOVERY, ROAM -> IDLE */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rParam.u2Event = ROAMING_EVENT_ABORT; + roamingFsmSendCmd(prAdapter, (P_ROAMING_PARAM_T) & rParam); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } + +} /* end of roamingFsmRunEventAbort() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process events from firmware +* +* @param [IN P_ADAPTER_T] prAdapter +* [IN P_ROAMING_PARAM_T] prParam +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, IN P_ROAMING_PARAM_T prParam) +{ + DBGLOG(ROAMING, LOUD, "ROAMING Process Events: Current Time = %u\n", kalGetTimeTick()); + + if (ROAMING_EVENT_DISCOVERY == prParam->u2Event) + roamingFsmRunEventDiscovery(prAdapter, prParam); + + return WLAN_STATUS_SUCCESS; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c new file mode 100644 index 0000000000000..eedd8d12f2fd3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/rsn.c @@ -0,0 +1,2533 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rsn.c#2 +*/ + +/*! \file "rsn.c" + \brief This file including the 802.11i, wpa and wpa2(rsn) related function. + + This file provided the macros and functions library support the wpa/rsn ie parsing, + cipher and AKM check to help the AP seleced deciding, tkip mic error handler and rsn PMKID support. +*/ + +/* +** Log: rsn.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 03 09 2012 chinglan.wang + * NULL + * Fix the condition error. + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 02 09 2011 wh.su + * [WCXRP00000432] [MT6620 Wi-Fi][Driver] Add STA privacy check at hotspot mode + * adding the code for check STA privacy bit at AP mode, . + * + * 12 24 2010 chinglan.wang + * NULL + * [MT6620][Wi-Fi] Modify the key management in the driver for WPS function. + * + * 12 13 2010 cp.wu + * [WCXRP00000260] [MT6620 Wi-Fi][Driver][Firmware] Create V1.1 branch for both firmware and driver + * create branch for Wi-Fi driver v1.1 + * + * 11 05 2010 wh.su + * [WCXRP00000165] [MT6620 Wi-Fi] [Pre-authentication] Assoc req rsn ie use wrong pmkid value + * fixed the.pmkid value mismatch issue + * + * 11 03 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Refine the HT rate disallow TKIP pairwise cipher . + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T + * and replaced by ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 29 2010 yuche.tsai + * NULL + * Fix compile error, remove unused pointer in rsnGenerateRSNIE(). + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 08 30 2010 wh.su + * NULL + * remove non-used code. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * [WPD00003833][MT6620 and MT5931] Driver migration + * enable RX management frame handling. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * [WPD00003840] [MT6620 5931] Security migration + * migration from firmware. + * + * 05 27 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * not indicate pmkid candidate while no new one scanned. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, + * and modify the security related callback function prototype. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * change the name + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * using the Rx0 port to indicate event + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine the code for generate the WPA/RSN IE for assoc req + * + * Dec 3 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust code for pmkid event + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the code for event (mic error and pmkid indicate) and do some function rename + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security function + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding some security feature, including pmkid + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_RSN_MIGRATION + +/* extern PHY_ATTRIBUTE_T rPhyAttributes[]; */ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse RSN IE. +* +* \param[in] prInfoElem Pointer to the RSN IE +* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the +** RSN information from the given RSN IE +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo) +{ + UINT_32 i; + INT_32 u4RemainRsnIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUINT_8 pucPairSuite = NULL; + PUINT_8 pucAuthSuite = NULL; + PUINT_8 cp; + + DEBUGFUNC("rsnParseRsnIE"); + + ASSERT(prInfoElem); + ASSERT(prRsnInfo); + + /* Verify the length of the RSN IE. */ + if (prInfoElem->ucLength < 2) { + DBGLOG(RSN, TRACE, "RSN IE length too short (length=%d)\n", prInfoElem->ucLength); + return FALSE; + } + + /* Check RSN version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE, "Unsupported RSN IE version: %d\n", u2Version); + return FALSE; + } + + cp = (PUCHAR) & prInfoElem->u4GroupKeyCipherSuite; + u4RemainRsnIeLen = (INT_32) prInfoElem->ucLength - 2; + + do { + if (u4RemainRsnIeLen == 0) + break; + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainRsnIeLen < 4) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainRsnIeLen -= 4; + + if (u4RemainRsnIeLen == 0) + break; + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainRsnIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (INT_32) i; + + if (u4RemainRsnIeLen == 0) + break; + + /* Parse the Authentication and Key Management Cipher Suite Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainRsnIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (INT_32) i; + + if (u4RemainRsnIeLen == 0) + break; + + /* Parse the RSN u2Capabilities field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2Cap); + } while (FALSE); + + /* Save the RSN information for the BSS. */ + prRsnInfo->ucElemId = ELEM_ID_RSN; + + prRsnInfo->u2Version = u2Version; + + prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(RSN, LOUD, "RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + + prRsnInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, &prRsnInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for RSN: CCMP. */ + prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1; + prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP; + + DBGLOG(RSN, LOUD, "RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + + prRsnInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, "RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for RSN. */ + prRsnInfo->u4AuthKeyMgtSuiteCount = 1; + prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, "RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); + } + + prRsnInfo->u2RsnCap = u2Cap; +#if CFG_SUPPORT_802_11W + prRsnInfo->fgRsnCapPresent = TRUE; +#endif + DBGLOG(RSN, LOUD, "RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap); + + return TRUE; +} /* rsnParseRsnIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse WPA IE. +* +* \param[in] prInfoElem Pointer to the WPA IE. +* \param[out] prWpaInfo Pointer to the BSSDescription structure to store the +* WPA information from the given WPA IE. +* +* \retval TRUE Succeeded. +* \retval FALSE Failed. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo) +{ + UINT_32 i; + INT_32 u4RemainWpaIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUCHAR pucPairSuite = NULL; + PUCHAR pucAuthSuite = NULL; + PUCHAR cp; + BOOLEAN fgCapPresent = FALSE; + + DEBUGFUNC("rsnParseWpaIE"); + + ASSERT(prInfoElem); + ASSERT(prWpaInfo); + + /* Verify the length of the WPA IE. */ + if (prInfoElem->ucLength < 6) { + DBGLOG(RSN, TRACE, "WPA IE length too short (length=%d)\n", prInfoElem->ucLength); + return FALSE; + } + + /* Check WPA version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE, "Unsupported WPA IE version: %d\n", u2Version); + return FALSE; + } + + cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite; + u4RemainWpaIeLen = (INT_32) prInfoElem->ucLength - 6; + + do { + if (u4RemainWpaIeLen == 0) + break; + + /* WPA_OUI : 4 + Version : 2 + GroupSuite : 4 + PairwiseCount: 2 + PairwiseSuite: 4 * pairSuiteCount + AuthCount : 2 + AuthSuite : 4 * authSuiteCount + Cap : 2 */ + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainWpaIeLen < 4) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainWpaIeLen -= 4; + + if (u4RemainWpaIeLen == 0) + break; + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainWpaIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (INT_32) i; + + if (u4RemainWpaIeLen == 0) + break; + + /* Parse the Authentication and Key Management Cipher Suite Count + field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainWpaIeLen < (INT_32) i) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (INT_32) i; + + if (u4RemainWpaIeLen == 0) + break; + + /* Parse the WPA u2Capabilities field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + fgCapPresent = TRUE; + WLAN_GET_FIELD_16(cp, &u2Cap); + u4RemainWpaIeLen -= 2; + } while (FALSE); + + /* Save the WPA information for the BSS. */ + + prWpaInfo->ucElemId = ELEM_ID_WPA; + + prWpaInfo->u2Version = u2Version; + + prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(RSN, LOUD, "WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + + prWpaInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, &prWpaInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for WPA: TKIP. */ + prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1; + prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP; + + DBGLOG(RSN, LOUD, "WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + + prWpaInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, "WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for WPA. */ + prWpaInfo->u4AuthKeyMgtSuiteCount = 1; + prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, "WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); + } + + if (fgCapPresent) { + prWpaInfo->fgRsnCapPresent = TRUE; + prWpaInfo->u2RsnCap = u2Cap; + DBGLOG(RSN, LOUD, "WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap); + } else { + prWpaInfo->fgRsnCapPresent = FALSE; + prWpaInfo->u2RsnCap = 0; + } + + return TRUE; +} /* rsnParseWpaIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search the desired pairwise +* cipher suite from the MIB Pairwise Cipher Suite +* configuration table. +* +* \param[in] u4Cipher The desired pairwise cipher suite to be searched +* \param[out] pu4Index Pointer to the index of the desired pairwise cipher in +* the table +* +* \retval TRUE - The desired pairwise cipher suite is found in the table. +* \retval FALSE - The desired pairwise cipher suite is not found in the +* table. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index) +{ + UINT_8 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + + DEBUGFUNC("rsnSearchSupportedCipher"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i]; + if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher && + prEntry->dot11RSNAConfigPairwiseCipherEnabled) { + *pu4Index = i; + return TRUE; + } + } + return FALSE; +} /* rsnSearchSupportedCipher */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Whether BSS RSN is matched from upper layer set. +* +* \param[in] prAdapter Pointer to the Adapter structure, BSS RSN Information +* +* \retval BOOLEAN +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo) +{ + UINT_8 i = 0; + + DEBUGFUNC("rsnIsSuitableBSS"); + + do { + + if ((prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite & 0x000000FF) != + GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite)) { + DBGLOG(RSN, TRACE, "Break by GroupKeyCipherSuite\n"); + break; + } + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] & 0x000000FF) != + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])) + && (i == prBssRsnInfo->u4PairwiseKeyCipherSuiteCount - 1)) { + DBGLOG(RSN, TRACE, "Break by PairwiseKeyCipherSuite\n"); + break; + } + } + for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { + if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] & 0x000000FF) != + GET_SELECTOR_TYPE(prBssRsnInfo->au4AuthKeyMgtSuite[0])) + && (i == prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1)) { + DBGLOG(RSN, TRACE, "Break by AuthKeyMgtSuite\n"); + break; + } + } + return TRUE; + } while (FALSE); + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to search the desired +* authentication and key management (AKM) suite from the +* MIB Authentication and Key Management Suites table. +* +* \param[in] u4AkmSuite The desired AKM suite to be searched +* \param[out] pu4Index Pointer to the index of the desired AKM suite in the +* table +* +* \retval TRUE The desired AKM suite is found in the table. +* \retval FALSE The desired AKM suite is not found in the table. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index) +{ + UINT_8 i; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + + DEBUGFUNC("rsnSearchAKMSuite"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite && + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) { + *pu4Index = i; + return TRUE; + } + } + return FALSE; +} /* rsnSearchAKMSuite */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to perform RSNA or TSN policy +* selection for a given BSS. +* +* \param[in] prBss Pointer to the BSS description +* +* \retval TRUE - The RSNA/TSN policy selection for the given BSS is +* successful. The selected pairwise and group cipher suites +* are returned in the BSS description. +* \retval FALSE - The RSNA/TSN policy selection for the given BSS is failed. +* The driver shall not attempt to join the given BSS. +* +* \note The Encrypt status matched score will save to bss for final ap select. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) +{ +#if CFG_SUPPORT_802_11W + INT_32 i; + UINT_32 j; +#else + UINT_32 i, j; +#endif + BOOLEAN fgSuiteSupported; + UINT_32 u4PairwiseCipher = 0; + UINT_32 u4GroupCipher = 0; + UINT_32 u4AkmSuite = 0; + P_RSN_INFO_T prBssRsnInfo; + ENUM_NETWORK_TYPE_INDEX_T eNetwotkType; + BOOLEAN fgIsWpsActive = (BOOLEAN) FALSE; + + DEBUGFUNC("rsnPerformPolicySelection"); + + ASSERT(prBss); + + DBGLOG(RSN, TRACE, "rsnPerformPolicySelection\n"); + /* Todo:: */ + eNetwotkType = NETWORK_TYPE_AIS_INDEX; + + prBss->u4RsnSelectedPairwiseCipher = 0; + prBss->u4RsnSelectedGroupCipher = 0; + prBss->u4RsnSelectedAKMSuite = 0; + prBss->ucEncLevel = 0; + +#if CFG_SUPPORT_WPS + fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo); + + /* CR1640, disable the AP select privacy check */ + if (fgIsWpsActive && + (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) && + (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) { + DBGLOG(RSN, TRACE, "-- Skip the Protected BSS check\n"); + return TRUE; + } +#endif + + /* Protection is not required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0) { + + if (secEnabledInAis(prAdapter) == FALSE) { + DBGLOG(RSN, TRACE, "-- No Protected BSS\n"); + return TRUE; + } + DBGLOG(RSN, TRACE, "-- Protected BSS\n"); + return FALSE; + + } + + /* Protection is required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) { + if (secEnabledInAis(prAdapter) == FALSE) { + DBGLOG(RSN, TRACE, "-- Protected BSS\n"); + return FALSE; + } + } + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { + + if (prBss->fgIEWPA) { + prBssRsnInfo = &prBss->rWPAInfo; + } else { + DBGLOG(RSN, TRACE, "WPA Information Element does not exist.\n"); + return FALSE; + } + } else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) { + + if (prBss->fgIERSN) { + prBssRsnInfo = &prBss->rRSNInfo; + } else { + DBGLOG(RSN, TRACE, "RSN Information Element does not exist.\n"); + return FALSE; + } + } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, ignore this BSS. */ + DBGLOG(RSN, TRACE, "-- Not WEP-only legacy BSS %d\n", prAdapter->rWifiVar.rConnSettings.eEncStatus); + return FALSE; + } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, use this BSS. */ + DBGLOG(RSN, TRACE, "-- WEP-only legacy BSS, fgIERSN %d, fgIEWPA %d\n", + prBss->fgIERSN, prBss->fgIEWPA); + /* if this BSS was configured to WPA/WPA2, don't select this AP */ + return (prBss->fgIERSN || prBss->fgIEWPA) ? FALSE : TRUE; + } + + if (!rsnIsSuitableBSS(prAdapter, prBssRsnInfo)) { + DBGLOG(RSN, TRACE, "RSN info check no matched\n"); + return FALSE; + } + + if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 && + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == CIPHER_SUITE_NONE) { + /* Since the pairwise cipher use the same cipher suite as the group + cipher in the BSS, we check the group cipher suite against the + current encryption status. */ + fgSuiteSupported = FALSE; + + switch (prBssRsnInfo->u4GroupKeyCipherSuite) { + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED) + fgSuiteSupported = TRUE; + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED) + fgSuiteSupported = TRUE; + break; + + case WPA_CIPHER_SUITE_WEP40: + case WPA_CIPHER_SUITE_WEP104: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) + fgSuiteSupported = TRUE; + break; + } + + if (fgSuiteSupported) { + u4PairwiseCipher = WPA_CIPHER_SUITE_NONE; + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } +#if DBG + else { + DBGLOG(RSN, TRACE, "Inproper encryption status %d for group-key-only BSS\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } +#endif + } else { + fgSuiteSupported = FALSE; + + DBGLOG(RSN, TRACE, "eEncStatus %d %d 0x%x\n", prAdapter->rWifiVar.rConnSettings.eEncStatus, + (UINT_32) prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, + (UINT_32) prBssRsnInfo->au4PairwiseKeyCipherSuite[0]); + /* Select pairwise/group ciphers */ + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION3_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_CCMP) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + break; + + case ENUM_ENCRYPTION2_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_TKIP) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_CCMP) + DBGLOG(RSN, TRACE, "Cannot join CCMP BSS\n"); + else + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + break; + + case ENUM_ENCRYPTION1_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) + == CIPHER_SUITE_WEP104) { + u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_CCMP || + GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_TKIP) { + DBGLOG(RSN, TRACE, "Cannot join CCMP/TKIP BSS\n"); + } else { + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } + break; + + default: + break; + } + } + + /* Exception handler */ + /* If we cannot find proper pairwise and group cipher suites to join the + BSS, do not check the supported AKM suites. */ + if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { + DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", + u4PairwiseCipher, u4GroupCipher); + return FALSE; + } +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (eNetwotkType == NETWORK_TYPE_P2P_INDEX)) { + if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || + u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { + DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher for P2P network (0x%08x/0x%08x)\n", + u4PairwiseCipher, u4GroupCipher); + return FALSE; + } + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if (eNetwotkType == NETWORK_TYPE_BOW_INDEX) { + if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || + u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) { + /* Do nothing */ + } + DBGLOG(RSN, TRACE, + "Failed to select pairwise/group cipher for BT over Wi-Fi network (0x%08x/0x%08x)\n", + u4PairwiseCipher, u4GroupCipher); + return FALSE; + } +#endif + + /* Verify if selected pairwisse cipher is supported */ + fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i); + + /* Verify if selected group cipher is supported */ + if (fgSuiteSupported) + fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i); + + if (!fgSuiteSupported) { + DBGLOG(RSN, TRACE, "Failed to support selected pairwise/group cipher (0x%08x/0x%08x)\n", + u4PairwiseCipher, u4GroupCipher); + return FALSE; + } + + /* Select AKM */ + /* If the driver cannot support any authentication suites advertised in + the given BSS, we fail to perform RSNA policy selection. */ + /* Attempt to find any overlapping supported AKM suite. */ +#if CFG_SUPPORT_802_11W + if (i != 0) + for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) { +#else + for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { +#endif + if (rsnSearchAKMSuite(prAdapter, prBssRsnInfo->au4AuthKeyMgtSuite[i], &j)) { + u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i]; + break; + } + } + + if (u4AkmSuite == 0) { + DBGLOG(RSN, TRACE, "Cannot support any AKM suites\n"); + return FALSE; + } + + DBGLOG(RSN, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", + (UINT_8) (u4PairwiseCipher & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), + (UINT_8) (u4GroupCipher & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); + + DBGLOG(RSN, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", + (UINT_8) (u4AkmSuite & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); + +#if CFG_SUPPORT_802_11W + DBGLOG(RSN, TRACE, "MFP setting = %d\n ", kalGetMfpSetting(prAdapter->prGlueInfo)); + + if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { + if (!prBssRsnInfo->fgRsnCapPresent) { + DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability.\n"); + return FALSE; + } else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) { + DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required\n"); + return FALSE; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + } else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) { + if (prBssRsnInfo->u2RsnCap && ((prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR) || + (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC))) { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE; + } else { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + } + } else { + if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { + DBGLOG(RSN, TRACE, "Skip RSN IE, No MFP Required Capability\n"); + return FALSE; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE; + } + DBGLOG(RSN, TRACE, "fgMgmtProtection = %d\n ", prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection); +#endif + + if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP) { + prBss->ucEncLevel = 3; + } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP) { + prBss->ucEncLevel = 2; + } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) { + prBss->ucEncLevel = 1; + } else { + ASSERT(FALSE); + } + prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher; + prBss->u4RsnSelectedGroupCipher = u4GroupCipher; + prBss->u4RsnSelectedAKMSuite = u4AkmSuite; + + return TRUE; + +} /* rsnPerformPolicySelection */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate WPA IE for beacon frame. +* +* \param[in] pucIeStartAddr Pointer to put the generated WPA IE. +* +* \return The append WPA-None IE length +* \note +* Called by: JOIN module, compose beacon IE +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + UINT_32 i; + P_WPA_INFO_ELEM_T prWpaIE; + UINT_32 u4Suite; + UINT_16 u2SuiteCount; + PUINT_8 cp, cp2; + UINT_8 ucExpendedLen = 0; + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + + DEBUGFUNC("rsnGenerateWpaNoneIE"); + + ASSERT(prMsduInfo); + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE) + return; + + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; + + if (eNetworkId != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + prWpaIE = (P_WPA_INFO_ELEM_T) (pucBuffer); + + /* Start to construct a WPA IE. */ + /* Fill the Element ID field. */ + prWpaIE->ucElemId = ELEM_ID_WPA; + + /* Fill the OUI and OUI Type fields. */ + prWpaIE->aucOui[0] = 0x00; + prWpaIE->aucOui[1] = 0x50; + prWpaIE->aucOui[2] = 0xF2; + prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA; + + /* Fill the Version field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */ + ucExpendedLen = 6; + + /* Fill the Pairwise Key Cipher Suite List field. */ + u2SuiteCount = 0; + cp = (PUINT_8) &prWpaIE->aucPairwiseKeyCipherSuite1[0]; + + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) + u4Suite = WPA_CIPHER_SUITE_CCMP; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) + u4Suite = WPA_CIPHER_SUITE_TKIP; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i)) + u4Suite = WPA_CIPHER_SUITE_WEP104; + else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i)) + u4Suite = WPA_CIPHER_SUITE_WEP40; + else + u4Suite = WPA_CIPHER_SUITE_TKIP; + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Group Key Cipher Suite field as the same in pair-wise key. */ + WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite); + ucExpendedLen += 4; + + /* Fill the Pairwise Key Cipher Suite Count field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount); + ucExpendedLen += 2; + + cp2 = cp; + + /* Fill the Authentication and Key Management Suite List field. */ + u2SuiteCount = 0; + cp += 2; + + if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i)) + u4Suite = WPA_AKM_SUITE_802_1X; + else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i)) + u4Suite = WPA_AKM_SUITE_PSK; + else + u4Suite = WPA_AKM_SUITE_NONE; + + /* This shall be the only available value for current implementation */ + ASSERT(u4Suite == WPA_AKM_SUITE_NONE); + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Authentication and Key Management Suite Count field. */ + WLAN_SET_FIELD_16(cp2, u2SuiteCount); + ucExpendedLen += 2; + + /* Fill the Length field. */ + prWpaIE->ucLength = (UINT_8) ucExpendedLen; + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + +} /* rsnGenerateWpaNoneIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WPA IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WPA IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + PUCHAR cp; + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + DEBUGFUNC("rsnGenerateWPAIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + /* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */ + /* return; */ + +#if CFG_ENABLE_WIFI_DIRECT + if ((1 /* prCurrentBss->fgIEWPA */ && + ((prAdapter->fgIsP2PRegistered) && + (eNetworkId == NETWORK_TYPE_P2P_INDEX) && + (kalP2PGetTkipCipher(prAdapter->prGlueInfo)))) || + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) { +#else + if ((1 /* prCurrentBss->fgIEWPA */ && + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK)))) { +#endif + if (prP2pSpecificBssInfo->u2WpaIeLen != 0) { + kalMemCopy(pucBuffer, prP2pSpecificBssInfo->aucWpaIeBuffer, prP2pSpecificBssInfo->u2WpaIeLen); + prMsduInfo->u2FrameLength += prP2pSpecificBssInfo->u2WpaIeLen; + return; + } + + /* Construct a WPA IE for association request frame. */ + WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA; + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + WPA_IE(pucBuffer)->aucOui[0] = 0x00; + WPA_IE(pucBuffer)->aucOui[1] = 0x50; + WPA_IE(pucBuffer)->aucOui[2] = 0xF2; + WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA; + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { + WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, WPA_CIPHER_SUITE_TKIP); + } else +#endif + WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, + prAdapter->rWifiVar. + arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedGroupCipher); + + cp = (PUCHAR) &WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { + WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP); + } else +#endif + WLAN_SET_FIELD_32(cp, + prAdapter->rWifiVar. + arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedPairwiseCipher); + cp += 4; + + WLAN_SET_FIELD_16(cp, 1); + cp += 2; +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && eNetworkId == NETWORK_TYPE_P2P_INDEX) { + WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK); + } else +#endif + WLAN_SET_FIELD_32(cp, + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].u4RsnSelectedAKMSuite); + cp += 4; + + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* rsnGenerateWPAIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate RSN IE for +* associate request frame. +* +* \param[in] prMsduInfo The Selected BSS description +* +* \retval The append RSN IE length +* +* \note +* Called by: AIS module, P2P module, BOW module Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + UINT_32 u4Entry; + PUCHAR cp; + /* UINT_8 ucExpendedLen = 0; */ + PUINT_8 pucBuffer; + ENUM_NETWORK_TYPE_INDEX_T eNetworkId; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("rsnGenerateRSNIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* Todo:: network id */ + eNetworkId = (ENUM_NETWORK_TYPE_INDEX_T) prMsduInfo->ucNetworkType; + + if ( +#if CFG_ENABLE_WIFI_DIRECT + ((prAdapter->fgIsP2PRegistered) && + (eNetworkId == NETWORK_TYPE_P2P_INDEX) && (kalP2PGetCcmpCipher(prAdapter->prGlueInfo))) || +#endif +#if CFG_ENABLE_BT_OVER_WIFI + (eNetworkId == NETWORK_TYPE_BOW_INDEX) || +#endif + (eNetworkId == NETWORK_TYPE_AIS_INDEX /* prCurrentBss->fgIERSN */ && + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK)))) { + /* Construct a RSN IE for association request frame. */ + RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN; + RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED; + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); /* Version */ + WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite, + prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedGroupCipher); /* Group key suite */ + cp = (PUCHAR) &RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedPairwiseCipher); + cp += 4; + WLAN_SET_FIELD_16(cp, 1); /* AKM suite count */ + cp += 2; + WLAN_SET_FIELD_32(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u4RsnSelectedAKMSuite); /* AKM suite */ + cp += 4; + WLAN_SET_FIELD_16(cp, prAdapter->rWifiVar.arBssInfo[eNetworkId].u2RsnSelectedCapInfo);/* Capabilities */ +#if CFG_SUPPORT_802_11W + if (eNetworkId == NETWORK_TYPE_AIS_INDEX && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection) { + if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); /* Capabilities */ + else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); /* Capabilities */ + } +#endif + cp += 2; + + if (eNetworkId == NETWORK_TYPE_AIS_INDEX) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + if (!prStaRec) { + DBGLOG(RSN, TRACE, "rsnGenerateRSNIE: prStaRec is NULL\n"); + return; + } + } + + if (eNetworkId == NETWORK_TYPE_AIS_INDEX && + rsnSearchPmkidEntry(prAdapter, prStaRec->aucMacAddr, &u4Entry)) { + /* DBGLOG(RSN, TRACE, ("Add Pmk at assoc req\n")); */ + /* DBGLOG(RSN, TRACE, ("addr %pM PMKID %pM\n", */ + /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arBSSID),*/ + /* (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID))); */ + if (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].fgPmkidExist) { + RSN_IE(pucBuffer)->ucLength = 38; + WLAN_SET_FIELD_16(cp, 1); /* PMKID count */ + cp += 2; + DBGLOG(RSN, TRACE, + "BSSID %pM ind=%d\n", prStaRec->aucMacAddr, (UINT_32) u4Entry); + DBGLOG(RSN, TRACE, "use PMKID %pM\n", + (prAdapter->rWifiVar.rAisSpecificBssInfo. + arPmkidCache[u4Entry].rBssidInfo.arPMKID)); + kalMemCopy(cp, + (PVOID) prAdapter->rWifiVar.rAisSpecificBssInfo. + arPmkidCache[u4Entry].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE)); + /* ucExpendedLen = 40; */ + } else { + WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ + /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ +#if CFG_SUPPORT_802_11W + cp += 2; + RSN_IE(pucBuffer)->ucLength += 2; +#endif + } + } else { + WLAN_SET_FIELD_16(cp, 0); /* PMKID count */ + /* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */ +#if CFG_SUPPORT_802_11W + cp += 2; + RSN_IE(pucBuffer)->ucLength += 2; +#endif + } + +#if CFG_SUPPORT_802_11W + if ((eNetworkId == NETWORK_TYPE_AIS_INDEX) + && (kalGetMfpSetting(prAdapter->prGlueInfo) != + RSN_AUTH_MFP_DISABLED) /* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */) { + WLAN_SET_FIELD_32(cp, RSN_CIPHER_SUITE_AES_128_CMAC); + cp += 4; + RSN_IE(pucBuffer)->ucLength += 4; + } +#endif + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } + +} /* rsnGenerateRSNIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the given IE buffer and check if it is WFA IE and return Type and +* SubType for further process. +* +* \param[in] pucBuf Pointer to the buffer of WFA Information Element. +* \param[out] pucOuiType Pointer to the storage of OUI Type. +* \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and Version. + +* \retval TRUE Parse IE ok +* \retval FALSE Parse IE fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, + IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion) +{ + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_IE_WFA_T prWfaIE; + + ASSERT(pucBuf); + ASSERT(pucOuiType); + ASSERT(pu2SubTypeVersion); + prWfaIE = (P_IE_WFA_T) pucBuf; + + do { + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion); + + return TRUE; + } while (FALSE); + + return FALSE; + +} /* end of rsnParseCheckForWFAInfoElem() */ + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! +* \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK +* +* \param[in] prAdapter Pointer to Adapter +* \param[in] prSwRfb Pointer to the rx buffer +* \param[in] pIE Pointer rthe buffer of Information Element. +* \param[out] prStatusCode Pointer to the return status code. + +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode) +{ + + RSN_INFO_T rRsnIe; + + ASSERT(prAdapter); + ASSERT(prIe); + ASSERT(pu2StatusCode); + + *pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; + + if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) { + if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1) + || (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) { + *pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER; + return; + } + if (rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP) { + *pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER; + return; + } + if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1) || (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) { + *pu2StatusCode = STATUS_CODE_INVALID_AKMP; + return; + } + + DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n"); + *pu2StatusCode = WLAN_STATUS_SUCCESS; + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate an authentication event to NDIS. +* +* \param[in] u4Flags Authentication event: \n +* PARAM_AUTH_REQUEST_REAUTH 0x01 \n +* PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n +* PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n +* PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgFlags) +{ + P_PARAM_AUTH_EVENT_T prAuthEvent; + + DEBUGFUNC("rsnGenMicErrorEvent"); + + prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; + + /* Status type: Authentication Event */ + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; + + /* Authentication request */ + prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); + kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, + (PVOID) prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucBSSID, MAC_ADDR_LEN); + + if (fgFlags == TRUE) + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; + else + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); + +} /* rsnGenMicErrorEvent */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to handle TKIP MIC failures. +* +* \param[in] adapter_p Pointer to the adapter object data area. +* \param[in] prSta Pointer to the STA which occur MIC Error +* \param[in] fgErrorKeyType type of error key +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType) +{ + /* UINT_32 u4RsnaCurrentMICFailTime; */ + /* P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; */ + + DEBUGFUNC("rsnTkipHandleMICFailure"); + + ASSERT(prAdapter); +#if 1 + rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); + + nicConfigPowerSaveProfile(prAdapter, NETWORK_TYPE_AIS_INDEX, Param_PowerModeCAM, FALSE); + + /* Generate authentication request event. */ + DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); +#else + ASSERT(prSta); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* Record the MIC error occur time. */ + GET_CURRENT_SYSTIME(&u4RsnaCurrentMICFailTime); + + /* Generate authentication request event. */ + DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType); + + /* If less than 60 seconds have passed since a previous TKIP MIC failure, + disassociate from the AP and wait for 60 seconds before (re)associating + with the same AP. */ + if (prAisSpecBssInfo->u4RsnaLastMICFailTime != 0 && + !CHECK_FOR_TIMEOUT(u4RsnaCurrentMICFailTime, + prAisSpecBssInfo->u4RsnaLastMICFailTime, SEC_TO_SYSTIME(TKIP_COUNTERMEASURE_SEC))) { + /* If less than 60 seconds expired since last MIC error, we have to + block traffic. */ + + DBGLOG(RSN, INFO, "Start blocking traffic!\n"); + rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); + + secFsmEventStartCounterMeasure(prAdapter, prSta); + } else { + rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); + DBGLOG(RSN, INFO, "First TKIP MIC error!\n"); + } + + COPY_SYSTIME(prAisSpecBssInfo->u4RsnaLastMICFailTime, u4RsnaCurrentMICFailTime); +#endif +} /* rsnTkipHandleMICFailure */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to select a list of BSSID from +* the scan results for PMKID candidate list. +* +* \param[in] prBssDesc the BSS Desc at scan result list +* \param[out] pu4CandidateCount Pointer to the number of selected candidates. +* It is set to zero if no BSSID matches our requirement. +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("rsnSelectPmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + + /* Search a BSS with the same SSID from the given BSS description set. */ + /* DBGLOG(RSN, TRACE, ("Check scan result [%pM]\n", */ + /* prBssDesc->aucBSSID)); */ + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, "-- SSID not matched\n"); + return; + } +#if 0 + if ((prBssDesc->u2BSSBasicRateSet & + ~(rPhyAttributes[prAisBssInfo->ePhyType].u2SupportedRateSet)) || prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(RSN, TRACE, "-- Rate set not matched\n"); + return; + } + + if (/* prBssDesc->u4RsnSelectedPairwiseCipher != prAisBssInfo->u4RsnSelectedPairwiseCipher || */ + prBssDesc->u4RsnSelectedGroupCipher != prAisBssInfo->u4RsnSelectedGroupCipher /*|| + prBssDesc->u4RsnSelectedAKMSuite != prAisBssInfo->u4RsnSelectedAKMSuite */) { + DBGLOG(RSN, TRACE, "-- Encrypt status not matched for PMKID\n"); + return; + } +#endif + + rsnUpdatePmkidCandidateList(prAdapter, prBssDesc); + +} /* rsnSelectPmkidCandidateList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to select a list of BSSID from +* the scan results for PMKID candidate list. +* +* \param[in] prBssDesc the BSS DESC at scan result list +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + UINT_32 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnUpdatePmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, "-- SSID not matched\n"); + return; + } + + for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) { + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)) + return; + } + + /* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16), + then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache */ + if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE) + prAisSpecBssInfo->u4PmkidCandicateCount--; + + i = prAisSpecBssInfo->u4PmkidCandicateCount; + + COPY_MAC_ADDR((PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, (PVOID) prBssDesc->aucBSSID); + + if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1; + DBGLOG(RSN, TRACE, "Add %pM with pre-auth to candidate list\n", + (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + } else { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0; + DBGLOG(RSN, TRACE, "Add %pM without pre-auth to candidate list\n", + (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + } + + prAisSpecBssInfo->u4PmkidCandicateCount++; + +} /* rsnUpdatePmkidCandidateList */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search the desired entry in +* PMKID cache according to the BSSID +* +* \param[in] pucBssid Pointer to the BSSID +* \param[out] pu4EntryIndex Pointer to place the found entry index +* +* \retval TRUE, if found one entry for specified BSSID +* \retval FALSE, if not found +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex) +{ + UINT_32 i; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnSearchPmkidEntry"); + + ASSERT(pucBssid); + ASSERT(pu4EntryIndex); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE) + return FALSE; + + ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE); + + /* Search for desired BSSID */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, pucBssid, MAC_ADDR_LEN)) + break; + } + + /* If desired BSSID is found, then set the PMKID */ + if (i < prAisSpecBssInfo->u4PmkidCacheCount) { + *pu4EntryIndex = i; + + return TRUE; + } + + return FALSE; +} /* rsnSearchPmkidEntry */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to check if there is difference +* between PMKID candicate list and PMKID cache. If there +* is new candicate that no cache entry is available, then +* add a new entry for the new candicate in the PMKID cache +* and set the PMKID indication flag to TRUE. +* +* \retval TRUE, if new member in the PMKID candicate list +* \retval FALSe, if no new member in the PMKID candicate list +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + UINT_32 i; /* Index for PMKID candicate */ + UINT_32 j; /* Indix for PMKID cache */ + BOOLEAN status = FALSE; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* Check for each candicate */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN)) { + /* DBGLOG(RSN, TRACE, ("%pM at PMKID cache!!\n", + (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); */ + break; + } + } + + /* No entry found in PMKID cache for the candicate, add new one */ + if (j == prAisSpecBssInfo->u4PmkidCacheCount + && prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) { + DBGLOG(RSN, TRACE, + "Add %pM to PMKID cache!!\n", + (prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + kalMemCopy((PVOID) prAisSpecBssInfo-> + arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.arBSSID, + (PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN); + prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].fgPmkidExist = FALSE; + prAisSpecBssInfo->u4PmkidCacheCount++; + + status = TRUE; + } + } + + return status; +} /* rsnCheckPmkidCandicate */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to wait a duration to indicate the pre-auth AP candicate +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) +{ + DBGLOG(RSN, EVENT, "Security - Time to indicate the PMKID cand.\n"); + + /* If the authentication mode is WPA2 and indication PMKID flag + is available, then we indicate the PMKID candidate list to NDIS and + clear the flag, indicatePMKID */ + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED && + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnGeneratePmkidIndication(prAdapter); + } + +} /* end of rsnIndicatePmkidCand() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to check the BSS Desc at scan result +* with pre-auth cap at wpa2 mode. If there +* is candicate that no cache entry is available, then +* add a new entry for the new candicate in the PMKID cache +* and set the PMKID indication flag to TRUE. +* +* \param[in] prBss The BSS Desc at scan result +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) +{ + P_AIS_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + ASSERT(prBss); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + (prConnSettings->eAuthMode == AUTH_MODE_WPA2)) { + rsnSelectPmkidCandidateList(prAdapter, prBss); + + /* Set indication flag of PMKID to TRUE, and then connHandleNetworkConnection() + will indicate this later */ + if (rsnCheckPmkidCandicate(prAdapter)) { + DBGLOG(RSN, TRACE, "Prepare a timer to indicate candidate PMKID Candidate\n"); + cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to generate an PMKID candidate list +* indication to NDIS. +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] u4Flags PMKID candidate list event: +* PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter) +{ + P_PARAM_STATUS_INDICATION_T prStatusEvent; + P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + UINT_8 i, j = 0, count = 0; + UINT_32 u4LenOfUsedBuffer; + + DEBUGFUNC("rsnGeneratePmkidIndication"); + + ASSERT(prAdapter); + + prStatusEvent = (P_PARAM_STATUS_INDICATION_T) prAdapter->aucIndicationEventBuffer; + + /* Status type: PMKID Candidatelist Event */ + prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; + ASSERT(prStatusEvent); + + prPmkidEvent = (P_PARAM_PMKID_CANDIDATE_LIST_T) (&prStatusEvent->eStatusType + 1); + ASSERT(prPmkidEvent); + + prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prAisSpecificBssInfo); + + for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) { + if (EQUAL_MAC_ADDR(prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) && + (prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == TRUE)) { + break; + } + } + if (count >= CFG_MAX_PMKID_CACHE) + break; + + if (j == prAisSpecificBssInfo->u4PmkidCacheCount) { + kalMemCopy((PVOID) prPmkidEvent->arCandidateList[count].arBSSID, + (PVOID) prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, PARAM_MAC_ADDR_LEN); + prPmkidEvent->arCandidateList[count].u4Flags = + prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags; + DBGLOG(RSN, TRACE, "%pM %d\n", (prPmkidEvent->arCandidateList[count].arBSSID), + (UINT_32) prPmkidEvent->arCandidateList[count].u4Flags); + count++; + } + } + + /* PMKID Candidate List */ + prPmkidEvent->u4Version = 1; + prPmkidEvent->u4NumCandidates = count; + DBGLOG(RSN, TRACE, "rsnGeneratePmkidIndication #%d\n", (UINT_32) prPmkidEvent->u4NumCandidates); + u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(UINT_32)) + + (count * sizeof(PARAM_PMKID_CANDIDATE_T)); + /* dumpMemory8((PUINT_8)prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); */ + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); + +} /* rsnGeneratePmkidIndication */ +#endif + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WSC IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WSC IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + PUINT_8 pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (UINT_32) prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 221 :0xDD */ + if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE, + prAdapter->prGlueInfo->u2WSCAssocInfoIELen); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen; + } + +} +#endif + +#if CFG_SUPPORT_802_11W + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the Bip Key installed or not +* +* \param[in] +* prAdapter +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + if (prStaRec && prStaRec->ucNetTypeIndex == (UINT_8) NETWORK_TYPE_AIS_INDEX) + return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled; + else + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to check the Sa query timeout. +* +* +* \note +* Called by: AIS module, Handle by Sa Quert timeout +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + UINT_32 now; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + GET_CURRENT_SYSTIME(&now); + + if (CHECK_FOR_TIMEOUT(now, prBssSpecInfo->u4SaQueryStart, TU_TO_MSEC(1000))) { + LOG_FUNC("association SA Query timed out\n"); + + prBssSpecInfo->ucSaQueryTimedOut = 1; + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + prBssSpecInfo->u4SaQueryCount = 0; + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + /* Re-connect */ + DBGLOG(RSN, TRACE, "DisBy11w\n"); + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to start the 802.11w sa query timer. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prTxFrame; + UINT_16 u2PayloadLen; + PUINT_8 pucTmp = NULL; + UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + ASSERT(prBssInfo); + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + LOG_FUNC("MFP: Start Sa Query\n"); + + if (prBssSpecInfo->u4SaQueryCount > 0 && rsnCheckSaQueryTimeout(prAdapter)) { + LOG_FUNC("MFP: u4SaQueryCount count =%d\n", prBssSpecInfo->u4SaQueryCount); + return; + } + + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) + return; + + prTxFrame = (P_ACTION_SA_QUERY_FRAME) + ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; + + if (prBssSpecInfo->u4SaQueryCount == 0) + GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart); + + if (prBssSpecInfo->u4SaQueryCount) { + pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); + if (!pucTmp) { + DBGLOG(RSN, ERROR, "MFP: Fail to alloc tmp buffer for backup sa query id\n"); + return; + } + kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + } + + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + + ucTransId[0] = (UINT_8) (kalRandomNumber() & 0xFF); + ucTransId[1] = (UINT_8) (kalRandomNumber() & 0xFF); + + kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + prBssSpecInfo->u4SaQueryCount++; + + prBssSpecInfo->pucSaQueryTransId = + kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE); + if (!prBssSpecInfo->pucSaQueryTransId) { + DBGLOG(RSN, ERROR, "MFP: Fail to alloc buffer for sa query id list\n"); + return; + } + + if (pucTmp) { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp, + (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); + kalMemCopy(&prBssSpecInfo->pucSaQueryTransId + [(prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN], ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN); + } else { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + } + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 Update information of MSDU_INFO_T */ + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + DBGLOG(RSN, TRACE, + "Set SA Query timer %d (%d sec)\n", prBssSpecInfo->u4SaQueryCount, prBssInfo->u2ObssScanInterval); + + cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, TU_TO_MSEC(201)); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to start the 802.11w sa query. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQuery(IN P_ADAPTER_T prAdapter) +{ + rsnStartSaQueryTimer(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to stop the 802.11w sa query. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnStopSaQuery(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + prBssSpecInfo->u4SaQueryCount = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w sa query action frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; + UINT_16 u2PayloadLen; + P_STA_RECORD_T prStaRec; + P_ACTION_SA_QUERY_FRAME prTxFrame; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]; + ASSERT(prBssInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; + if (!prRxFrame) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Request from %pM\n", prStaRec->aucMacAddr); + + DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) { + DBGLOG(RSN, TRACE, "IEEE 802.11: Ignore SA Query Request from unassociated STA %pM\n", + prStaRec->aucMacAddr); + return; + } + DBGLOG(RSN, TRACE, "IEEE 802.11: Sending SA Query Response to %pM\n", prStaRec->aucMacAddr); + + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) + return; + + prTxFrame = (P_ACTION_SA_QUERY_FRAME) + ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + /* SA Query always with protected */ + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERT_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; + + kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 Update information of MSDU_INFO_T */ + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = FALSE; + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w sa query action frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + UINT_32 i; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { + DBGLOG(RSN, TRACE, "IEEE 802.11: Too short SA Query Action frame (len=%u)\n", + prSwRfb->u2PacketLen); + return; + } + + if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { + rsnSaQueryRequest(prAdapter, prSwRfb); + return; + } + + if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { + DBGLOG(RSN, TRACE, "IEEE 802.11: Unexpected SA Query " "Action %d\n", prRxFrame->ucAction); + return; + } + + DBGLOG(RSN, TRACE, "IEEE 802.11: Received SA Query Response from %pM\n", prStaRec->aucMacAddr); + + DBGLOG_MEM8(RSN, TRACE, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + + for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) { + if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId + + i * ACTION_SA_QUERY_TR_ID_LEN, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) + break; + } + + if (i >= prBssSpecInfo->u4SaQueryCount) { + DBGLOG(RSN, TRACE, "IEEE 802.11: No matching SA Query " "transaction identifier found\n"); + return; + } + + DBGLOG(RSN, TRACE, "Reply to pending SA Query received\n"); + + rsnStopSaQuery(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11w mgmt frame. +* +* +* \note +* Called by: AIS module, Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN rsnCheckRxMgmt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN UINT_8 ucSubtype) +{ + P_HIF_RX_HEADER_T prHifRxHdr; + BOOLEAN fgUnicast = TRUE; + BOOLEAN fgRobustAction = FALSE; + + prHifRxHdr = prSwRfb->prHifRxHdr; + + if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { + + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T) prSwRfb->pvHeader; + + if (prAssocReqFrame->aucDestAddr[0] & BIT(0)) + fgUnicast = FALSE; + + LOG_FUNC("QM RX MGT: rsnCheckRxMgmt = %d 0x%x %d ucSubtype=%x\n", fgUnicast, prHifRxHdr->ucReserved, + (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC), ucSubtype); + + if (prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC) { + /* "Dropped unprotected Robust Action frame from an MFP STA" */ + /* exclude Public Action */ + if (ucSubtype == 13 /* 0x1011: MAC_FRAME_ACTION */) { + UINT_8 ucAction = *prSwRfb->pucRecvBuff; + + if (ucAction != CATEGORY_PUBLIC_ACTION && ucAction != CATEGORY_HT_ACTION) { +#if DBG && CFG_RX_PKTS_DUMP + LOG_FUNC("QM RX MGT: UnProtected Robust Action frame = %d\n", ucAction); +#endif + fgRobustAction = TRUE; + return TRUE; + } + } + if (fgUnicast && ((ucSubtype == 10 /* 0x1010: MAC_FRAME_DISASSOC */) + || (ucSubtype == 12 /* 0x1100: MAC_FRAME_DEAUTH */))) { + LOG_FUNC("QM RX MGT: rsnStartSaQuery\n"); + /* MFP test plan 5.3.3.5 */ + rsnStartSaQuery(prAdapter); + return TRUE; + } + } +#if 0 + else { + if (fgUnicast && ((ucSubtype == MAC_FRAME_DISASSOC) || (ucSubtype == MAC_FRAME_DEAUTH))) { + /* This done by function handler */ + /* kalIndicateStatusAndComplete(prAdapter->prGlueInfo, */ + /* WLAN_STATUS_MEDIA_DISCONNECT, */ + /* NULL, */ + /* 0); */ + } + } +#endif + } + return FALSE; +} +#endif + +#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE +static BOOLEAN rsnCheckWpaRsnInfo(P_BSS_INFO_T prBss, P_RSN_INFO_T prWpaRsnInfo) +{ + UINT_32 i = 0; + + if (prWpaRsnInfo->u4GroupKeyCipherSuite != prBss->u4RsnSelectedGroupCipher) { + DBGLOG(RSN, INFO, "GroupCipherSuite change, old=0x%04x, new=0x%04x\n", + prBss->u4RsnSelectedGroupCipher, prWpaRsnInfo->u4GroupKeyCipherSuite); + return TRUE; + } + for (; i < prWpaRsnInfo->u4AuthKeyMgtSuiteCount; i++) + if (prBss->u4RsnSelectedAKMSuite == prWpaRsnInfo->au4AuthKeyMgtSuite[i]) + break; + if (i == prWpaRsnInfo->u4AuthKeyMgtSuiteCount) { + DBGLOG(RSN, INFO, "KeyMgmt change, not find 0x%04x in new beacon\n", prBss->u4RsnSelectedAKMSuite); + return TRUE; + } + + for (i = 0; i < prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) + if (prBss->u4RsnSelectedPairwiseCipher == prWpaRsnInfo->au4PairwiseKeyCipherSuite[i]) + break; + if (i == prWpaRsnInfo->u4PairwiseKeyCipherSuiteCount) { + DBGLOG(RSN, INFO, "Pairwise Cipher change, not find 0x%04x in new beacon\n", + prBss->u4RsnSelectedPairwiseCipher); + return TRUE; + } + + return FALSE; +} + +BOOLEAN rsnCheckSecurityModeChanged(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_BSS_DESC_T prBssDesc) +{ + ENUM_PARAM_AUTH_MODE_T eAuthMode = prAdapter->rWifiVar.rConnSettings.eAuthMode; + + switch (eAuthMode) { + case AUTH_MODE_OPEN: /* original is open system */ + if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) && !prAdapter->prGlueInfo->rWpaInfo.fgPrivacyInvoke) { + DBGLOG(RSN, INFO, "security change, open->privacy\n"); + return TRUE; + } + break; + case AUTH_MODE_SHARED: /* original is WEP */ + case AUTH_MODE_AUTO_SWITCH: + if ((prBssDesc->u2CapInfo & CAP_INFO_PRIVACY) == 0) { + DBGLOG(RSN, INFO, "security change, WEP->open\n"); + return TRUE; + } else if (prBssDesc->fgIERSN || prBssDesc->fgIEWPA) { + DBGLOG(RSN, INFO, "security change, WEP->WPA/WPA2\n"); + return TRUE; + } + break; + case AUTH_MODE_WPA: /*original is WPA */ + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA_NONE: + if (prBssDesc->fgIEWPA) + return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rWPAInfo); + DBGLOG(RSN, INFO, "security change, WPA->%s\n", + prBssDesc->fgIERSN ? "WPA2" : + (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); + return TRUE; + case AUTH_MODE_WPA2: /*original is WPA2 */ + case AUTH_MODE_WPA2_PSK: + if (prBssDesc->fgIERSN) + return rsnCheckWpaRsnInfo(prBssInfo, &prBssDesc->rRSNInfo); + DBGLOG(RSN, INFO, "security change, WPA2->%s\n", + prBssDesc->fgIEWPA ? "WPA" : + (prBssDesc->u2CapInfo & CAP_INFO_PRIVACY ? "WEP" : "OPEN")); + return TRUE; + default: + DBGLOG(RSN, WARN, "unknowned eAuthMode=%d\n", eAuthMode); + break; + } + /*DBGLOG(RSN, INFO, ("rsnCheckSecurityModeChanged, eAuthMode=%d, u2CapInfo=0x%02x, fgIEWPA=%d, fgIERSN=%d\n", + eAuthMode, prBssDesc->u2CapInfo, prBssDesc->fgIEWPA, prBssDesc->fgIERSN)); */ + return FALSE; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c new file mode 100644 index 0000000000000..596ede60d7887 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/saa_fsm.c @@ -0,0 +1,1788 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/saa_fsm.c#2 +*/ + +/*! \file "saa_fsm.c" + \brief This file defines the FSM for SAA MODULE. + + This file defines the FSM for SAA MODULE. +*/ + +/* +** Log: saa_fsm.c +** +** 09 04 2013 cp.wu +** fix typo +** +** 09 03 2013 cp.wu +** add path for reassociation + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 04 20 2012 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * correct macro + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 04 2011 cp.wu + * [WCXRP00001086] [MT6620 Wi-Fi][Driver] On Android, indicate an extra DISCONNECT + * for REASSOCIATED cases as an explicit trigger for Android framework + * 1. for DEAUTH/DISASSOC cases, indicate for DISCONNECTION immediately. + * 2. (Android only) when reassociation-and-non-roaming cases happened, + * indicate an extra DISCONNECT indication to Android Wi-Fi framework + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 09 30 2011 cm.chang + * [WCXRP00001020] [MT6620 Wi-Fi][Driver] Handle secondary channel offset of AP in 5GHz band + * Add debug message about 40MHz bandwidth allowed + * + * 05 12 2011 cp.wu + * [WCXRP00000720] [MT6620 Wi-Fi][Driver] Do not do any further operation in case STA-REC + * has been invalidated before SAA-FSM starts to roll + * check for valid STA-REC before SAA-FSM starts to roll. + * + * 04 21 2011 terry.wu + * [WCXRP00000674] [MT6620 Wi-Fi][Driver] Refine AAA authSendAuthFrame + * Add network type parameter to authSendAuthFrame. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 03 31 2011 puff.wen + * NULL + * . + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix compile error of after Station Type Macro modification. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC + * for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete + * and might leads to BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 24 2010 chinghwa.yu + * NULL + * Update for MID_SCN_BOW_SCAN_DONE mboxDummy. + * Update saa_fsm for BOW. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 02 2010 yuche.tsai + * NULL + * Add support for P2P join event start. + * + * 07 12 2010 cp.wu + * + * SAA will take a record for tracking request sequence number. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * AIS-FSM integration with CNM channel request messages + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with main branch for resetting to state 1 when associating with another AP + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration the security related function from firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error when enable WiFi Direct function. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * + * * * Add Connection Policy - Any and Rx Burst Deauth Support for WHQL + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support of Driver STA_RECORD_T activation + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 12 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Fix compile warning due to declared but not used + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Refine Debug Label + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update comment + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * rename the function + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugAAState[AA_STATE_NUM] = { + (PUINT_8) DISP_STRING("AA_STATE_IDLE"), + (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH1"), + (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH2"), + (PUINT_8) DISP_STRING("SAA_STATE_SEND_AUTH3"), + (PUINT_8) DISP_STRING("SAA_STATE_WAIT_AUTH4"), + (PUINT_8) DISP_STRING("SAA_STATE_SEND_ASSOC1"), + (PUINT_8) DISP_STRING("SAA_STATE_WAIT_ASSOC2"), + (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH2"), + (PUINT_8) DISP_STRING("AAA_STATE_SEND_AUTH4"), + (PUINT_8) DISP_STRING("AAA_STATE_SEND_ASSOC2"), + (PUINT_8) DISP_STRING("AA_STATE_RESOURCE") +}; + +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief The Core FSM engine of SAA Module. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] eNextState The value of Next State +* @param[in] prRetainedSwRfb Pointer to the retained SW_RFB_T for JOIN Success +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +saaFsmSteps(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb) +{ + ENUM_AA_STATE_T ePreviousState; + BOOLEAN fgIsTransition; + + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + + do { + +#if DBG + DBGLOG(SAA, STATE, "TRANSITION: [%s] -> [%s]\n", + apucDebugAAState[prStaRec->eAuthAssocState], apucDebugAAState[eNextState]); +#else + DBGLOG(SAA, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", + DBG_SAA_IDX, prStaRec->eAuthAssocState, eNextState); +#endif + ePreviousState = prStaRec->eAuthAssocState; + + /* NOTE(Kevin): This is the only place to change the eAuthAssocState(except initial) */ + prStaRec->eAuthAssocState = eNextState; + + fgIsTransition = (BOOLEAN) FALSE; + switch (prStaRec->eAuthAssocState) { + case AA_STATE_IDLE: + if (ePreviousState != prStaRec->eAuthAssocState) { /* Only trigger this event once */ + + if (prRetainedSwRfb) { + if (saaFsmSendEventJoinComplete(prAdapter, + WLAN_STATUS_SUCCESS, + prStaRec, + prRetainedSwRfb) == WLAN_STATUS_SUCCESS) { + /* Do nothing */ + } else { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = TRUE; + } + } else { + if (saaFsmSendEventJoinComplete(prAdapter, + WLAN_STATUS_FAILURE, + prStaRec, + NULL) == WLAN_STATUS_RESOURCES) { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = TRUE; + } + } + + } + + /* Free allocated TCM memory */ + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; + } + break; + + case SAA_STATE_SEND_AUTH1: + { + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + + /* Update Station Record - Class 1 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if !CFG_SUPPORT_AAA + if (authSendAuthFrame(prAdapter, + prStaRec, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) { +#else + if (authSendAuthFrame(prAdapter, + prStaRec, + prStaRec->ucNetTypeIndex, + NULL, + AUTH_TRANSACTION_SEQ_1, + STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { +#endif /* CFG_SUPPORT_AAA */ + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + } + break; + + case SAA_STATE_WAIT_AUTH2: + break; + + case SAA_STATE_SEND_AUTH3: + { + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + +#if !CFG_SUPPORT_AAA + if (authSendAuthFrame(prAdapter, + prStaRec, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) { +#else + if (authSendAuthFrame(prAdapter, + prStaRec, + prStaRec->ucNetTypeIndex, + NULL, + AUTH_TRANSACTION_SEQ_3, + STATUS_CODE_RESERVED) != WLAN_STATUS_SUCCESS) { +#endif /* CFG_SUPPORT_AAA */ + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + } + break; + + case SAA_STATE_WAIT_AUTH4: + break; + + case SAA_STATE_SEND_ASSOC1: + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= prStaRec->ucTxAuthAssocRetryLimit) { + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = TRUE; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + + if (assocSendReAssocReqFrame(prAdapter, prStaRec) != WLAN_STATUS_SUCCESS) { + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventTxReqTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_ASSOCIATION_RETRY_TIMEOUT_TU)); + } + } + + break; + + case SAA_STATE_WAIT_ASSOC2: + break; + + case AA_STATE_RESOURCE: + /* TODO(Kevin) Can setup a timer and send message later */ + break; + + default: + DBGLOG(SAA, ERROR, "Unknown AA STATE\n"); + ASSERT(0); + break; + } + + } while (fgIsTransition); + + return; + +} /* end of saaFsmSteps() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Event to AIS/BOW/P2P +* +* @param[in] rJoinStatus To indicate JOIN success or failure. +* @param[in] prStaRec Pointer to the STA_RECORD_T +* @param[in] prSwRfb Pointer to the SW_RFB_T + +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, + IN WLAN_STATUS rJoinStatus, IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prStaRec); + if (!prStaRec) + return WLAN_STATUS_INVALID_PACKET; + + /* Store limitation about 40Mhz bandwidth capability during association */ + if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if (rJoinStatus == WLAN_STATUS_SUCCESS) + prBssInfo->fg40mBwAllowed = prBssInfo->fgAssoc40mBwAllowed; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) + return WLAN_STATUS_RESOURCES; + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) + return WLAN_STATUS_RESOURCES; + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + /* @TODO: BOW handler */ + + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) + return WLAN_STATUS_RESOURCES; + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_BOW_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSaaFsmCompMsg, MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#endif + else { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + +} /* end of saaFsmSendEventJoinComplete() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Start Event to SAA FSM. +* +* @param[in] prMsgHdr Message of Join Request for a particular STA. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SAA_FSM_START_T prSaaFsmStartMsg; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prSaaFsmStartMsg = (P_MSG_SAA_FSM_START_T) prMsgHdr; + prStaRec = prSaaFsmStartMsg->prStaRec; + + if ((!prStaRec) || (prStaRec->fgIsInUse == FALSE)) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM.\n"); + + /* record sequence number of request message */ + prStaRec->ucAuthAssocReqSeqNum = prSaaFsmStartMsg->ucSeqNum; + + cnmMemFree(prAdapter, prMsgHdr); + + /* 4 <1> Validation of SAA Start Event */ + if (!IS_AP_STA(prStaRec)) { + + DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", prStaRec->eStaType); + + /* Ignore the return value because don't care the prSwRfb */ + saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, prStaRec, NULL); + + return; + } + /* 4 <2> The previous JOIN process is not completed ? */ + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); + prStaRec->eAuthAssocState = AA_STATE_IDLE; + } + /* 4 <3> Reset Status Code and Time */ + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); + + prStaRec->ucTxAuthAssocRetryCount = 0; + + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T) NULL; + } + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + +#if CFG_PRIVACY_MIGRATION + /* 4 <4> Init the sec fsm */ + secFsmInit(prAdapter, prStaRec); +#endif + + /* 4 <5> Reset the STA STATE */ + /* Update Station Record - Class 1 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for Reconnect issue - + * We won't deactivate the same STA_RECORD_T and then activate it again for the + * case of reconnection. + */ + /* cnmStaRecChangeState(prStaRec, STA_STATE_1); */ + + /* 4 <6> Decide if this BSS 20/40M bandwidth is allowed */ + if (prStaRec->ucNetTypeIndex < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) + && (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + prBssInfo->fgAssoc40mBwAllowed = cnmBss40mBwPermitted(prAdapter, prBssInfo->ucNetTypeIndex); + } else { + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + DBGLOG(RLM, INFO, "STA 40mAllowed=%d\n", prBssInfo->fgAssoc40mBwAllowed); + } + /* 4 <7> Trigger SAA FSM */ + if (prStaRec->ucStaState == STA_STATE_1) + saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_AUTH1, (P_SW_RFB_T) NULL); + else if (prStaRec->ucStaState == STA_STATE_2 || prStaRec->ucStaState == STA_STATE_3) + saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_ASSOC1, (P_SW_RFB_T) NULL); + +} /* end of saaFsmRunEventStart() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle TxDone(Auth1/Auth3/AssocReq) Event of SAA FSM. +* +* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. +* @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. +* +* @retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + + P_STA_RECORD_T prStaRec; + ENUM_AA_STATE_T eNextState; + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + DBGLOG(SAA, INFO, "EVENT-TX DONE: Status %d, Invalid StaRec\n", rTxDoneStatus); + return WLAN_STATUS_INVALID_PACKET; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, INFO, "EVENT-TX DONE: Status: %d, eAuthAssocState: %d , SeqNO: %d ", + rTxDoneStatus, prStaRec->eAuthAssocState, + prMsduInfo->ucTxSeqNum); + + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + { + /* Strictly check the outgoing frame is matched with current AA STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_1) != WLAN_STATUS_SUCCESS) + break; + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH2; + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + } + break; + + case SAA_STATE_SEND_AUTH3: + { + /* Strictly check the outgoing frame is matched with current JOIN STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, AUTH_TRANSACTION_SEQ_3) != WLAN_STATUS_SUCCESS) + break; + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH4; + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + } + break; + + case SAA_STATE_SEND_ASSOC1: + { + /* Strictly check the outgoing frame is matched with current SAA STATE */ + if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != WLAN_STATUS_SUCCESS) + break; + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_ASSOC2; + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) saaFsmRunEventRxRespTimeOut, + (ULONG) prStaRec); + + cnmTimerStartTimer(prAdapter, + &(prStaRec->rTxReqDoneOrRxRespTimer), + TU_TO_MSEC(DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU)); + } + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + } + break; + + default: + break; /* Ignore other cases */ + } + + return WLAN_STATUS_SUCCESS; + +} /* end of saaFsmRunEventTxDone() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Tx Request Timeout Event to SAA FSM. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prStaRec); + if (!prStaRec) + return; + + DBGLOG(SAA, LOUD, "EVENT-TIMER: TX REQ TIMEOUT, Current Time = %u\n", kalGetTimeTick()); + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_SEND_ASSOC1: + saaFsmSteps(prAdapter, prStaRec, prStaRec->eAuthAssocState, (P_SW_RFB_T) NULL); + break; + + default: + return; + } + +} /* end of saaFsmRunEventTxReqTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will send Rx Response Timeout Event to SAA FSM. +* +* @param[in] prStaRec Pointer to the STA_RECORD_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + ENUM_AA_STATE_T eNextState; + + DBGLOG(SAA, LOUD, "EVENT-TIMER: RX RESP TIMEOUT, Current Time = %u\n", kalGetTimeTick()); + + ASSERT(prStaRec); + if (!prStaRec) + return; + + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_WAIT_AUTH2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH1; + break; + + case SAA_STATE_WAIT_AUTH4: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH3; + break; + + case SAA_STATE_WAIT_ASSOC2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_ASSOC1; + break; + + default: + break; /* Ignore other cases */ + } + + if (eNextState != prStaRec->eAuthAssocState) + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + +} /* end of saaFsmRunEventRxRespTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx Auth Response Frame and then +* trigger SAA FSM. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + /* Peter: we can handle the packet without station record */ + /* ASSERT(0); */ + return; + } + + if (!IS_AP_STA(prStaRec)) + return; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_WAIT_AUTH2: + /* Check if the incoming frame is what we are waiting for */ + if (authCheckRxAuthFrameStatus(prAdapter, + prSwRfb, AUTH_TRANSACTION_SEQ_2, &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); + + if (prStaRec->ucAuthAlgNum == (UINT_8) AUTH_ALGORITHM_NUM_SHARED_KEY) { + + eNextState = SAA_STATE_SEND_AUTH3; + } else { + /* Update Station Record - Class 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } + } else { + DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", + (prStaRec->aucMacAddr), u2StatusCode); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + } + break; + + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_WAIT_AUTH4: + /* Check if the incoming frame is what we are waiting for */ + if (authCheckRxAuthFrameStatus(prAdapter, + prSwRfb, AUTH_TRANSACTION_SEQ_4, &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); /* Add for 802.11r handling */ + + /* Update Station Record - Class 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } else { + DBGLOG(SAA, INFO, "Auth Req was rejected by [ %pM ], Status Code = %d\n", + (prStaRec->aucMacAddr), u2StatusCode); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T) NULL); + } + break; + + default: + break; /* Ignore other cases */ + } + +} /* end of saaFsmRunEventRxAuth() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will process the Rx (Re)Association Response Frame and then +* trigger SAA FSM. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS if the status code was not success +* @retval WLAN_STATUS_BUFFER_RETAINED if the status code was success +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + P_SW_RFB_T prRetainedSwRfb = (P_SW_RFB_T) NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + ASSERT(0); + return rStatus; + } + + if (!IS_AP_STA(prStaRec)) + return rStatus; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_ASSOC1: + case SAA_STATE_WAIT_ASSOC2: + /* TRUE if the incoming frame is what we are waiting for */ + if (assocCheckRxReAssocRspFrameStatus(prAdapter, prSwRfb, &u2StatusCode) == WLAN_STATUS_SUCCESS) { + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + + /* Update Station Record - Class 3 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for roaming issue - + * We should deactivate the STA_RECORD_T of previous AP before + * activate new one in Driver. + */ + /* cnmStaRecChangeState(prStaRec, STA_STATE_3); */ + + prStaRec->ucJoinFailureCount = 0; /* Clear history. */ + + prRetainedSwRfb = prSwRfb; + rStatus = WLAN_STATUS_PENDING; + } else { + DBGLOG(SAA, INFO, "Assoc Req was rejected by [ %pM ], Status Code = %d\n", + (prStaRec->aucMacAddr), u2StatusCode); + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* update RCPI */ + prStaRec->ucRCPI = prSwRfb->prHifRxHdr->ucRcpi; + + eNextState = AA_STATE_IDLE; + + saaFsmSteps(prAdapter, prStaRec, eNextState, prRetainedSwRfb); + } + break; + + default: + break; /* Ignore other cases */ + } + + return rStatus; + +} /* end of saaFsmRunEventRxAssoc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Deauth Frame. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain deauthentication frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (prStaRec == NULL) + return WLAN_STATUS_FAILURE; + + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) prSwRfb->pvHeader; + DBGLOG(SAA, INFO, "Rx Deauth frame from BSSID=[ %pM ].\n", prDeauthFrame->aucBSSID); + + do { + if (IS_STA_IN_AIS(prStaRec)) { + P_AIS_BSS_INFO_T prAisBssInfo; + + if (!IS_AP_STA(prStaRec)) + break; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prStaRec->ucStaState <= STA_STATE_1) + break; + + /* Check if this is the AP we are associated or associating with */ + if (authProcessRxDeauthFrame(prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + + DBGLOG(SAA, INFO, "Deauth reason = %d\n", prStaRec->u2ReasonCode); + + if (STA_STATE_2 <= prStaRec->ucStaState) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + /* NOTE(Kevin): Change state immediately to avoid starvation of + * MSG buffer because of too many deauth frames before changing + * the STA state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + prAisAbortMsg = + (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) + break; + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DEAUTHENTICATED; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + } else { + + /* TODO(Kevin): Joining Abort */ + } + prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; + + } + + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + /* TODO(Kevin) */ + p2pFsmRunEventRxDeauthentication(prAdapter, prStaRec, prSwRfb); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) + bowRunEventRxDeAuth(prAdapter, prStaRec, prSwRfb); +#endif + else + ASSERT(0); + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; +} /* end of saaFsmRunEventRxDeauth() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will check the incoming Disassociation Frame. +* +* @param[in] prSwRfb Pointer to the SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS Always not retain disassociation frames +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (prStaRec == NULL) + return WLAN_STATUS_FAILURE; + + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) prSwRfb->pvHeader; + DBGLOG(SAA, INFO, "Rx Disassoc frame from BSSID=[ %pM ].\n", (prDisassocFrame->aucBSSID)); + + do { + if (IS_STA_IN_AIS(prStaRec)) { + P_AIS_BSS_INFO_T prAisBssInfo; + + if (!IS_AP_STA(prStaRec)) + break; + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prStaRec->ucStaState <= STA_STATE_1) + break; + + /* Check if this is the AP we are associated or associating with */ + if (assocProcessRxDisassocFrame(prAdapter, + prSwRfb, + prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + + DBGLOG(SAA, INFO, "Disassoc reason = %d\n", prStaRec->u2ReasonCode); + + if (STA_STATE_3 <= prStaRec->ucStaState) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + /* NOTE(Chaozhong): Change state immediately to avoid starvation of + * MSG buffer because of too many disassoc frames before changing + * the STA state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + prAisAbortMsg = + (P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) + break; + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DISASSOCIATED; + prAisAbortMsg->fgDelayIndication = FALSE; + + mboxSendMsg(prAdapter, + MBOX_ID_0, + (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF); + } else { + + /* TODO(Kevin): Joining Abort */ + } + prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; + + } + + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + /* TODO(Kevin) */ + p2pFsmRunEventRxDisassociation(prAdapter, prStaRec, prSwRfb); + } +#endif +#if CFG_ENABLE_BT_OVER_WIFI + else if (IS_STA_IN_BOW(prStaRec)) { + /* Do nothing */ + /* TODO(Kevin) */ + } +#endif + else + ASSERT(0); + + } while (FALSE); + + return WLAN_STATUS_SUCCESS; +} /* end of saaFsmRunEventRxDisassoc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle the Abort Event to SAA FSM. +* +* @param[in] prMsgHdr Message of Abort Request for a particular STA. +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SAA_FSM_ABORT_T prSaaFsmAbortMsg; + P_STA_RECORD_T prStaRec; + + ASSERT(prMsgHdr); + + prSaaFsmAbortMsg = (P_MSG_SAA_FSM_ABORT_T) prMsgHdr; + prStaRec = prSaaFsmAbortMsg->prStaRec; + + ASSERT(prStaRec); + if (!prStaRec) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(SAA, LOUD, "EVENT-ABORT: Stop SAA FSM.\n"); + + cnmMemFree(prAdapter, prMsgHdr); + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* Cancel JOIN relative Timer */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { +#if DBG + DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %s.\n", + apucDebugAAState[prStaRec->eAuthAssocState]); +#else + DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %d.\n", prStaRec->eAuthAssocState); +#endif + } +#if 0 + /* For the Auth/Assoc State to IDLE */ + prStaRec->eAuthAssocState = AA_STATE_IDLE; +#else + /* Free this StaRec */ + cnmStaRecFree(prAdapter, prStaRec, FALSE); +#endif + +} /* end of saaFsmRunEventAbort() */ + +/* TODO(Kevin): following code will be modified and move to AIS FSM */ +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will send Join Timeout Event to JOIN FSM. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \retval WLAN_STATUS_FAILURE Fail because of Join Timeout +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS joinFsmRunEventJoinTimeOut(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("joinFsmRunEventJoinTimeOut"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + + DBGLOG(JOIN, EVENT, "JOIN EVENT: JOIN TIMEOUT\n"); + + /* Get a Station Record if possible, TA == BSSID for AP */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, prJoinInfo->prBssDesc->aucBSSID); + + /* We have renew this Sta Record when in JOIN_STATE_INIT */ + ASSERT(prStaRec); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_JOIN_TIMEOUT; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prJoinInfo->ucTxAuthAssocRetryCount = 0; + + /* Cancel other JOIN relative Timer */ + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rTxRequestTimer); + + ARB_CANCEL_TIMER(prAdapter, prJoinInfo->rRxResponseTimer); + + /* Restore original setting from current BSS_INFO_T */ + if (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED) + joinAdoptParametersFromCurrentBss(prAdapter); + + /* Pull back to IDLE */ + joinFsmSteps(prAdapter, JOIN_STATE_IDLE); + + return WLAN_STATUS_FAILURE; + +} /* end of joinFsmRunEventJoinTimeOut() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from Peer BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinAdoptParametersFromPeerBss(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + + DEBUGFUNC("joinAdoptParametersFromPeerBss"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + + /* 4 <1> Adopt Peer BSS' PHY TYPE */ + prAdapter->eCurrentPhyType = prBssDesc->ePhyType; + + DBGLOG(JOIN, INFO, "Target BSS[%s]'s PhyType = %s\n", + prBssDesc->aucSSID, (prBssDesc->ePhyType == PHY_TYPE_ERP_INDEX) ? "ERP" : "HR_DSSS"); + + /* 4 <2> Adopt Peer BSS' Frequency(Band/Channel) */ + DBGLOG(JOIN, INFO, "Target BSS's Channel = %d, Band = %d\n", prBssDesc->ucChannelNum, prBssDesc->eBand); + + nicSwitchChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, 10); + + prJoinInfo->fgIsParameterAdopted = TRUE; + +} /* end of joinAdoptParametersFromPeerBss() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will adopt the parameters from current associated BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinAdoptParametersFromCurrentBss(IN P_ADAPTER_T prAdapter) +{ + /* P_JOIN_INFO_T prJoinInfo = &prAdapter->rJoinInfo; */ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + prBssInfo = &prAdapter->rBssInfo; + + /* 4 <1> Adopt current BSS' PHY TYPE */ + prAdapter->eCurrentPhyType = prBssInfo->ePhyType; + + /* 4 <2> Adopt current BSS' Frequency(Band/Channel) */ + DBGLOG(JOIN, INFO, "Current BSS's Channel = %d, Band = %d\n", prBssInfo->ucChnl, prBssInfo->eBand); + + nicSwitchChannel(prAdapter, prBssInfo->eBand, prBssInfo->ucChnl, 10); +} /* end of joinAdoptParametersFromCurrentBss() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will update all the SW variables and HW MCR registers after +* the association with target BSS. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID joinComplete(IN P_ADAPTER_T prAdapter) +{ + P_JOIN_INFO_T prJoinInfo; + P_BSS_DESC_T prBssDesc; + P_PEER_BSS_INFO_T prPeerBssInfo; + P_BSS_INFO_T prBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_TX_CTRL_T prTxCtrl; +#if CFG_SUPPORT_802_11D + P_IE_COUNTRY_T prIECountry; +#endif + + DEBUGFUNC("joinComplete"); + + ASSERT(prAdapter); + prJoinInfo = &prAdapter->rJoinInfo; + prBssDesc = prJoinInfo->prBssDesc; + prPeerBssInfo = &prAdapter->rPeerBssInfo; + prBssInfo = &prAdapter->rBssInfo; + prConnSettings = &prAdapter->rConnSettings; + prTxCtrl = &prAdapter->rTxCtrl; + +/* 4 <1> Update Connecting & Connected Flag of BSS_DESC_T. */ + /* Remove previous AP's Connection Flags if have */ + scanRemoveConnectionFlagOfBssDescByBssid(prAdapter, prBssInfo->aucBSSID); + + prBssDesc->fgIsConnected = TRUE; /* Mask as Connected */ + + if (prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): This is for the case of Passive Scan and the target BSS didn't + * broadcast SSID on its Beacon Frame. + */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prAdapter->rConnSettings.aucSSID, prAdapter->rConnSettings.ucSSIDLen); + + if (prBssDesc->ucSSIDLen) + prBssDesc->fgIsHiddenSSID = FALSE; +#if DBG + else + ASSERT(0); +#endif /* DBG */ + + DBGLOG(JOIN, INFO, "Hidden SSID! - Update SSID : %s\n", prBssDesc->aucSSID); + } +/* 4 <2> Update BSS_INFO_T from BSS_DESC_T */ + /* 4 <2.A> PHY Type */ + prBssInfo->ePhyType = prBssDesc->ePhyType; + + /* 4 <2.B> BSS Type */ + prBssInfo->eBSSType = BSS_TYPE_INFRASTRUCTURE; + + /* 4 <2.C> BSSID */ + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID); + + DBGLOG(JOIN, INFO, "JOIN to BSSID: [%pM]\n", prBssDesc->aucBSSID); + + /* 4 <2.D> SSID */ + COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + + /* 4 <2.E> Channel / Band information. */ + prBssInfo->eBand = prBssDesc->eBand; + prBssInfo->ucChnl = prBssDesc->ucChannelNum; + + /* 4 <2.F> RSN/WPA information. */ + secFsmRunEventStart(prAdapter); + prBssInfo->u4RsnSelectedPairwiseCipher = prBssDesc->u4RsnSelectedPairwiseCipher; + prBssInfo->u4RsnSelectedGroupCipher = prBssDesc->u4RsnSelectedGroupCipher; + prBssInfo->u4RsnSelectedAKMSuite = prBssDesc->u4RsnSelectedAKMSuite; + + if (secRsnKeyHandshakeEnabled()) + prBssInfo->fgIsWPAorWPA2Enabled = TRUE; + else + prBssInfo->fgIsWPAorWPA2Enabled = FALSE; + + /* 4 <2.G> Beacon interval. */ + prBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + + /* 4 <2.H> DTIM period. */ + prBssInfo->ucDtimPeriod = prBssDesc->ucDTIMPeriod; + + /* 4 <2.I> ERP Information */ + if ((prBssInfo->ePhyType == PHY_TYPE_ERP_INDEX) && /* Our BSS's PHY_TYPE is ERP now. */ + (prBssDesc->fgIsERPPresent)) { + + prBssInfo->fgIsERPPresent = TRUE; + prBssInfo->ucERP = prBssDesc->ucERP; /* Save the ERP for later check */ + } else { /* Some AP, may send ProbeResp without ERP IE. Thus prBssDesc->fgIsERPPresent is FALSE. */ + prBssInfo->fgIsERPPresent = FALSE; + prBssInfo->ucERP = 0; + } + +#if CFG_SUPPORT_802_11D + /* 4 <2.J> Country inforamtion of the associated AP */ + if (prConnSettings->fgMultiDomainCapabilityEnabled) { + DOMAIN_INFO_ENTRY rDomainInfo; + + if (domainGetDomainInfoByScanResult(prAdapter, &rDomainInfo)) { + if (prBssDesc->prIECountry) { + prIECountry = prBssDesc->prIECountry; + + domainParseCountryInfoElem(prIECountry, &prBssInfo->rDomainInfo); + + /* use the domain get from the BSS info */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, prBssInfo->rDomainInfo.u2CountryCode, FALSE); + } else { + /* use the domain get from the scan result */ + prBssInfo->fgIsCountryInfoPresent = TRUE; + nicSetupOpChnlList(prAdapter, rDomainInfo.u2CountryCode, FALSE); + } + } + } +#endif + + /* 4 <2.K> Signal Power of the associated AP */ + prBssInfo->rRcpi = prBssDesc->rRcpi; + prBssInfo->rRssi = RCPI_TO_dBm(prBssInfo->rRcpi); + GET_CURRENT_SYSTIME(&prBssInfo->rRssiLastUpdateTime); + + /* 4 <2.L> Capability Field of the associated AP */ + prBssInfo->u2CapInfo = prBssDesc->u2CapInfo; + + DBGLOG(JOIN, INFO, "prBssInfo-> fgIsERPPresent = %d, ucERP = %02x, rRcpi = %d, rRssi = %ld\n", + prBssInfo->fgIsERPPresent, prBssInfo->ucERP, prBssInfo->rRcpi, prBssInfo->rRssi); + +/* 4 <3> Update BSS_INFO_T from PEER_BSS_INFO_T & NIC RATE FUNC */ + /* 4 <3.A> Association ID */ + prBssInfo->u2AssocId = prPeerBssInfo->u2AssocId; + + /* 4 <3.B> WMM Information */ + if (prAdapter->fgIsEnableWMM && (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_SUPPORT_WMM)) { + + prBssInfo->fgIsWmmAssoc = TRUE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC3; + + qosWmmInfoInit(&prBssInfo->rWmmInfo, (prBssInfo->ePhyType == PHY_TYPE_HR_DSSS_INDEX) ? TRUE : FALSE); + + if (prPeerBssInfo->rWmmInfo.ucWmmFlag & WMM_FLAG_AC_PARAM_PRESENT) { + kalMemCopy(&prBssInfo->rWmmInfo, &prPeerBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } else { + kalMemCopy(&prBssInfo->rWmmInfo, + &prPeerBssInfo->rWmmInfo, + sizeof(WMM_INFO_T) - sizeof(prPeerBssInfo->rWmmInfo.arWmmAcParams)); + } + } else { + prBssInfo->fgIsWmmAssoc = FALSE; + prTxCtrl->rTxQForVoipAccess = TXQ_AC1; + + kalMemZero(&prBssInfo->rWmmInfo, sizeof(WMM_INFO_T)); + } + + /* 4 <3.C> Operational Rate Set & BSS Basic Rate Set */ + prBssInfo->u2OperationalRateSet = prPeerBssInfo->u2OperationalRateSet; + prBssInfo->u2BSSBasicRateSet = prPeerBssInfo->u2BSSBasicRateSet; + + /* 4 <3.D> Short Preamble */ + if (prBssInfo->fgIsERPPresent) { + + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * TRUE FALSE TRUE FALSE + * FALSE FALSE FALSE FALSE(shouldn't have such case, use the AssocResp) + * FALSE FALSE TRUE FALSE + * TRUE TRUE FALSE TRUE(follow ERP) + * TRUE TRUE TRUE FALSE(follow ERP) + * FALSE TRUE FALSE FALSE(shouldn't have such case, and we should set to FALSE) + * FALSE TRUE TRUE FALSE(we should set to FALSE) + */ + if ((prPeerBssInfo->fgIsShortPreambleAllowed) && + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_SHORT) || + ((prConnSettings->ePreambleType == PREAMBLE_TYPE_AUTO) && + (prBssDesc->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + + prBssInfo->fgIsShortPreambleAllowed = TRUE; + + if (prBssInfo->ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) + prBssInfo->fgUseShortPreamble = FALSE; + else + prBssInfo->fgUseShortPreamble = TRUE; + } else { + prBssInfo->fgIsShortPreambleAllowed = FALSE; + prBssInfo->fgUseShortPreamble = FALSE; + } + } else { + /* NOTE(Kevin 2007/12/24): Truth Table. + * Short Preamble Bit in + * Final Driver Setting(Short) + * TRUE FALSE FALSE + * FALSE FALSE FALSE + * TRUE TRUE TRUE + * FALSE TRUE(status success) TRUE + * --> Honor the result of prPeerBssInfo. + */ + + prBssInfo->fgIsShortPreambleAllowed = prBssInfo->fgUseShortPreamble = + prPeerBssInfo->fgIsShortPreambleAllowed; + } + + DBGLOG(JOIN, INFO, "prBssInfo->fgIsShortPreambleAllowed = %d, prBssInfo->fgUseShortPreamble = %d\n", + prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortPreamble); + + /* 4 <3.E> Short Slot Time */ + prBssInfo->fgUseShortSlotTime = prPeerBssInfo->fgUseShortSlotTime; /* AP support Short Slot Time */ + + DBGLOG(JOIN, INFO, "prBssInfo->fgUseShortSlotTime = %d\n", prBssInfo->fgUseShortSlotTime); + + nicSetSlotTime(prAdapter, + prBssInfo->ePhyType, + ((prConnSettings->fgIsShortSlotTimeOptionEnable && + prBssInfo->fgUseShortSlotTime) ? TRUE : FALSE)); + + /* 4 <3.F> Update Tx Rate for Control Frame */ + bssUpdateTxRateForControlFrame(prAdapter); + + /* 4 <3.G> Save the available Auth Types during Roaming (Design for Fast BSS Transition). */ + /* if (prAdapter->fgIsEnableRoaming) */ /* NOTE(Kevin): Always prepare info for roaming */ + { + + if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_OPEN_SYSTEM) + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_OPEN_SYSTEM; + else if (prJoinInfo->ucCurrAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) + prJoinInfo->ucRoamingAuthTypes |= AUTH_TYPE_SHARED_KEY; + + prBssInfo->ucRoamingAuthTypes = prJoinInfo->ucRoamingAuthTypes; + + /* Set the stable time of the associated BSS. We won't do roaming decision + * during the stable time. + */ + SET_EXPIRATION_TIME(prBssInfo->rRoamingStableExpirationTime, + SEC_TO_SYSTIME(ROAMING_STABLE_TIMEOUT_SEC)); + } + + /* 4 <3.H> Update Parameter for TX Fragmentation Threshold */ +#if CFG_TX_FRAGMENT + txFragInfoUpdate(prAdapter); +#endif /* CFG_TX_FRAGMENT */ + +/* 4 <4> Update STA_RECORD_T */ + /* Get a Station Record if possible */ + prStaRec = staRecGetStaRecordByAddr(prAdapter, prBssDesc->aucBSSID); + + if (prStaRec) { + UINT_16 u2OperationalRateSet, u2DesiredRateSet; + + /* 4 <4.A> Desired Rate Set */ + u2OperationalRateSet = (rPhyAttributes[prBssInfo->ePhyType].u2SupportedRateSet & + prBssInfo->u2OperationalRateSet); + + u2DesiredRateSet = (u2OperationalRateSet & prConnSettings->u2DesiredRateSet); + if (u2DesiredRateSet) { + prStaRec->u2DesiredRateSet = u2DesiredRateSet; + } else { + /* For Error Handling - The Desired Rate Set is not covered in Operational Rate Set. */ + prStaRec->u2DesiredRateSet = u2OperationalRateSet; + } + + /* Try to set the best initial rate for this entry */ + if (!rateGetBestInitialRateIndex(prStaRec->u2DesiredRateSet, + prStaRec->rRcpi, &prStaRec->ucCurrRate1Index)) { + + if (!rateGetLowestRateIndexFromRateSet(prStaRec->u2DesiredRateSet, &prStaRec->ucCurrRate1Index)) + ASSERT(0); + } + + DBGLOG(JOIN, INFO, "prStaRec->ucCurrRate1Index = %d\n", prStaRec->ucCurrRate1Index); + + /* 4 <4.B> Preamble Mode */ + prStaRec->fgIsShortPreambleOptionEnable = prBssInfo->fgUseShortPreamble; + + /* 4 <4.C> QoS Flag */ + prStaRec->fgIsQoS = prBssInfo->fgIsWmmAssoc; + } +#if DBG + else + ASSERT(0); +#endif /* DBG */ + +/* 4 <5> Update NIC */ + /* 4 <5.A> Update BSSID & Operation Mode */ + nicSetupBSS(prAdapter, prBssInfo); + + /* 4 <5.B> Update WLAN Table. */ + if (nicSetHwBySta(prAdapter, prStaRec) == FALSE) + ASSERT(FALSE); + /* 4 <5.C> Update Desired Rate Set for BT. */ +#if CFG_TX_FRAGMENT + if (prConnSettings->fgIsEnableTxAutoFragmentForBT) + txRateSetInitForBT(prAdapter, prStaRec); +#endif /* CFG_TX_FRAGMENT */ + + /* 4 <5.D> TX AC Parameter and TX/RX Queue Control */ + if (prBssInfo->fgIsWmmAssoc) { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, FALSE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + qosUpdateWMMParametersAndAssignAllowedACI(prAdapter, &prBssInfo->rWmmInfo); + } else { + +#if CFG_TX_AGGREGATE_HW_FIFO + nicTxAggregateTXQ(prAdapter, TRUE); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxNonQoSAssignDefaultAdmittedTXQ(prAdapter); + + nicTxNonQoSUpdateTXQParameters(prAdapter, prBssInfo->ePhyType); + } + +#if CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN + { + prTxCtrl->fgBlockTxDuringJoin = FALSE; + +#if !CFG_TX_AGGREGATE_HW_FIFO /* TX FIFO AGGREGATE already do flush once */ + nicTxFlushStopQueues(prAdapter, (UINT_8) TXQ_DATA_MASK, (UINT_8) NULL); +#endif /* CFG_TX_AGGREGATE_HW_FIFO */ + + nicTxRetransmitOfSendWaitQue(prAdapter); + + if (prTxCtrl->fgIsPacketInOsSendQueue) + nicTxRetransmitOfOsSendQue(prAdapter); +#if CFG_SDIO_TX_ENHANCE + halTxLeftClusteredMpdu(prAdapter); +#endif /* CFG_SDIO_TX_ENHANCE */ + + } +#endif /* CFG_TX_STOP_WRITE_TX_FIFO_UNTIL_JOIN */ + +/* 4 <6> Setup CONNECTION flag. */ + prAdapter->eConnectionState = MEDIA_STATE_CONNECTED; + prAdapter->eConnectionStateIndicated = MEDIA_STATE_CONNECTED; + + if (prJoinInfo->fgIsReAssoc) + prAdapter->fgBypassPortCtrlForRoaming = TRUE; + else + prAdapter->fgBypassPortCtrlForRoaming = FALSE; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, (PVOID) NULL, 0); + +} /* end of joinComplete() */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c new file mode 100644 index 0000000000000..2c9ccbe82dd1b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan.c @@ -0,0 +1,3103 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan.c#3 +*/ + +/*! \file "scan.c" + \brief This file defines the scan profile and the processing function of + scan result for SCAN Module. + + The SCAN Profile selection is part of SCAN MODULE and responsible for defining + SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. + In this file we also define the process of SCAN Result including adding, searching + and removing SCAN record from the list. +*/ + +/* +** Log: scan.c +** +** 01 30 2013 yuche.tsai +** [ALPS00451578] [JB2][WFD][Case Fail][JE][MR1]?????????[Java (JE),660,-1361051648,99, +** /data/core/,0,system_server_crash,system_server]JE happens when try to connect WFD.(4/5) +** Fix possible old scan result indicate to supplicant after formation. +** +** 01 16 2013 yuche.tsai +** [ALPS00431980] [WFD]Aupus one ?play game 10 minitues?wfd connection automaticlly disconnect +** Fix possible FW assert issue. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 25 2012 cp.wu + * [WCXRP00001258] [MT6620][MT5931][MT6628][Driver] Do not use stale scan result for deciding connection target + * drop off scan result which is older than 5 seconds when choosing which BSS to join + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 16 2012 cp.wu + * [WCXRP00001169] [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band + * configuration with corresponding network configuration + * correct typo. + * + * 01 16 2012 cp.wu + * [MT6620 Wi-Fi][Driver] API and behavior modification for preferred band configuration + * with corresponding network configuration + * add wlanSetPreferBandByNetwork() for glue layer to invoke for setting preferred + * band configuration corresponding to network type. + * + * 12 05 2011 cp.wu + * [WCXRP00001131] [MT6620 Wi-Fi][Driver][AIS] Implement connect-by-BSSID path + * add CONNECT_BY_BSSID policy + * + * 11 23 2011 cp.wu + * [WCXRP00001123] [MT6620 Wi-Fi][Driver] Add option to disable beacon content change detection + * add compile option to disable beacon content change detection. + * + * 11 04 2011 cp.wu + * [WCXRP00001085] [MT6628 Wi-Fi][Driver] deprecate old BSS-DESC if timestamp + * is reset with received beacon/probe response frames + * deprecate old BSS-DESC when timestamp in received beacon/probe response frames showed a smaller value than before + * + * 10 11 2011 cm.chang + * [WCXRP00001031] [All Wi-Fi][Driver] Check HT IE length to avoid wrong SCO parameter + * Ignore HT OP IE if its length field is not valid + * + * 09 30 2011 cp.wu + * [WCXRP00001021] [MT5931][Driver] Correct scan result generation for conversion between BSS type and operation mode + * correct type casting issue. + * + * 08 23 2011 yuche.tsai + * NULL + * Fix multicast address list issue. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 08 10 2011 cp.wu + * [WCXRP00000922] [MT6620 Wi-Fi][Driver] traverse whole BSS-DESC list for removing + * traverse whole BSS-DESC list because BSSID is not unique anymore. + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * for multiple BSS descriptior detecting issue: + * 1) check BSSID for infrastructure network + * 2) check SSID for AdHoc network + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * check for BSSID for beacons used to update DTIM + * + * 07 12 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * do not check BSS descriptor for connected flag due to linksys's hidden + * SSID will use another BSS descriptor and never connected + * + * 07 11 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * just pass beacons with the same BSSID. + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define + * for make sure the value is initialize, for customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 28 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * Do not check for SSID as beacon content change due to the existence of + * single BSSID with multiple SSID AP configuration + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple + * SSID settings to work around some tricky AP which use space character as hidden SSID + * 1. correct logic + * 2. replace only BSS-DESC which doesn't have a valid SSID. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID + * settings to work around some tricky AP which use space character as hidden SSID + * remove unused temporal variable reference. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID + * settings to work around some tricky AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 06 02 2011 cp.wu + * [WCXRP00000757] [MT6620 Wi-Fi][Driver][SCN] take use of RLM API to filter out BSS in disallowed channels + * filter out BSS in disallowed channel by + * 1. do not add to scan result array if BSS is at disallowed channel + * 2. do not allow to search for BSS-DESC in disallowed channels + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Refine range of valid channel number + * + * 05 02 2011 cp.wu + * [MT6620 Wi-Fi][Driver] Take parsed result for channel information instead of + * hardware channel number passed from firmware domain + * take parsed result for generating scanning result with channel information. + * + * 05 02 2011 cm.chang + * [WCXRP00000691] [MT6620 Wi-Fi][Driver] Workaround about AP's wrong HT capability IE to have wrong channel number + * Check if channel is valided before record ing BSS channel + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 03 25 2011 yuche.tsai + * NULL + * Always update Bss Type, for Bss Type for P2P Network is changing every time. + * + * 03 23 2011 yuche.tsai + * NULL + * Fix concurrent issue when AIS scan result would overwrite p2p scan result. + * + * 03 14 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * filtering out other BSS coming from adjacent channels + * + * 03 11 2011 chinglan.wang + * [WCXRP00000537] [MT6620 Wi-Fi][Driver] Can not connect to 802.11b/g/n mixed AP with WEP security. + * . + * + * 03 11 2011 cp.wu + * [WCXRP00000535] [MT6620 Wi-Fi][Driver] Fixed channel operation when AIS and Tethering are operating concurrently + * When fixed channel operation is necessary, AIS-FSM would scan and only connect for BSS on the specific channel + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() + * won't sleep long enough for specified interval such as 500ms + * implement beacon change detection by checking SSID and supported rate. + * + * 02 22 2011 yuche.tsai + * [WCXRP00000480] [Volunteer Patch][MT6620][Driver] WCS IE format issue + * Fix WSC big endian issue. + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix scan channel extension issue when p2p module is not registered. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 21 2011 cp.wu + * [WCXRP00000380] [MT6620 Wi-Fi][Driver] SSID information should come from buffered + * BSS_DESC_T rather than using beacon-carried information + * SSID should come from buffered prBssDesc rather than beacon-carried information + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Fix compile error. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Memfree for P2P Descriptor & P2P Descriptor List. + * + * 01 14 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * Free P2P Descriptor List & Descriptor under BSS Descriptor. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc + * and vmalloc implementations to ease physically continuous memory demands + * 1) correct typo in scan.c + * 2) TX descriptors, RX descriptos and management buffer should use virtually + * continuous buffer instead of physically continuous one + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc + * and vmalloc implementations to ease physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * while being unloaded, clear all pending interrupt then set LP-own to firmware + * + * 12 21 2010 cp.wu + * [WCXRP00000280] [MT6620 Wi-Fi][Driver] Enable BSS selection with best RCPI policy in SCN module + * SCN: enable BEST RSSI selection policy support + * + * 11 29 2010 cp.wu + * [WCXRP00000210] [MT6620 Wi-Fi][Driver][FW] Set RCPI value in STA_REC + * for initial TX rate selection of auto-rate algorithm + * update ucRcpi of STA_RECORD_T for AIS when + * 1) Beacons for IBSS merge is received + * 2) Associate Response for a connecting peer is received + * + * 11 03 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Refine the HT rate disallow TKIP pairwise cipher . + * + * 10 12 2010 cp.wu + * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out + * beacons which is received on the folding frequency + * trust HT IE if available for 5GHz band + * + * 10 11 2010 cp.wu + * [WCXRP00000091] [MT6620 Wi-Fi][Driver] Add scanning logic to filter out + * beacons which is received on the folding frequency + * add timing and strenght constraint for filtering out beacons with same SSID/TA but received on different channels + * + * 10 08 2010 wh.su + * [WCXRP00000085] [MT6620 Wif-Fi] [Driver] update the modified p2p state machine + * update the frog's new p2p state machine. + * + * 10 01 2010 yuche.tsai + * NULL + * [MT6620 P2P] Fix Big Endian Issue when parse P2P device name TLV. + * + * 09 24 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate unused variables which lead gcc to argue + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * When indicate scan result, append IE buffer information in the scan result. + * + * 09 03 2010 yuche.tsai + * NULL + * 1. Update Beacon RX count when running SLT. + * 2. Ignore Beacon when running SLT, would not update information from Beacon. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 29 2010 yuche.tsai + * NULL + * 1. Fix P2P Descriptor List to be a link list, to avoid link corrupt after Bss Descriptor Free. + * 2.. Fix P2P Device Name Length BE issue. + * + * 08 23 2010 yuche.tsai + * NULL + * Add P2P Device Found Indication to supplicant + * + * 08 20 2010 cp.wu + * NULL + * reset BSS_DESC_T variables before parsing IE due to peer might have been reconfigured. + * + * 08 20 2010 yuche.tsai + * NULL + * Workaround for P2P Descriptor Infinite loop issue. + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 16 2010 yuche.tsai + * NULL + * Modify code of processing Probe Resonse frame for P2P. + * + * 08 12 2010 yuche.tsai + * NULL + * Add function to get P2P descriptor of BSS descriptor directly. + * + * 08 11 2010 yuche.tsai + * NULL + * Modify Scan result processing for P2P module. + * + * 08 05 2010 yuche.tsai + * NULL + * Update P2P Device Discovery result add function. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 26 2010 yuche.tsai + * + * Add support for Probe Request & Response parsing. + * + * 07 21 2010 cp.wu + * + * 1) change BG_SCAN to ONLINE_SCAN for consistent term + * 2) only clear scanning result when scan is permitted to do + * + * 07 21 2010 yuche.tsai + * + * Fix compile error for SCAN module while disabling P2P feature. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 wh.su + * + * update for security supporting. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, + * other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct BSS_DESC_T initialization after allocated. + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan uninitialization procedure + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * if beacon/probe-resp is received in 2.4GHz bands and there is ELEM_ID_DS_PARAM_SET IE available, + * trust IE instead of RMAC information + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 28 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * send MMPDU in basic rate. + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * modify Beacon/ProbeResp to complete parsing, + * because host software has looser memory usage restriction + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * integrate . + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 21 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Update P2P Function call. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * RSN/PRIVACY compilation flag awareness correction + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * specify correct value for management frames. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 18 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * migration from MT6620 firmware. + * + * 06 17 2010 yuche.tsai + * [WPD00003839][MT6620 5931][P2P] Feature migration + * Fix compile error when enable P2P function. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct when ADHOC support is turned on. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan.c. + * + * 06 04 2010 george.huang + * [BORA00000678][MT6620]WiFi LP integration + * [PM] Support U-APSD for STA mode + * + * 05 28 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * adding the TKIP disallow join a HT AP code. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add more chance of JOIN retry for BG_SCAN + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 04 29 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * adjsut the pre-authentication code. + * + * 04 27 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add Set Slot Time and Beacon Timeout Support for AdHoc Mode + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 19 2010 kevin.huang + * [BORA00000714][WIFISYS][New Feature]Beacon Timeout Support + * Add Beacon Timeout Support and will send Null frame to diagnose connection + * + * 04 13 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add new HW CH macro support + * + * 04 06 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the firmware return the broadcast frame at wrong tc. + * + * 03 29 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * let the rsn wapi IE always parsing. + * + * 03 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Not carry HT cap when being associated with b/g only AP + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Solve the compile warning for 'return non-void' function + * + * 03 16 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Add AdHoc Mode + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * + * * * * * * * * * * * * * * * * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Fix No PKT_INFO_T issue + * + * 02 26 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Update outgoing ProbeRequest Frame's TX data rate + * + * 02 23 2010 wh.su + * [BORA00000592][MT6620 Wi-Fi] Adding the security related code for driver + * refine the scan procedure, reduce the WPA and WAPI IE parsing, and move the parsing to the time for join. + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 02 04 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add AAA Module Support, Revise Net Type to Net Type Index for array lookup + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 22 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Support protection and bandwidth switch + * + * 01 20 2010 kevin.huang + * [BORA00000569][WIFISYS] Phase 2 Integration Test + * Add PHASE_2_INTEGRATION_WORK_AROUND and CFG_SUPPORT_BCM flags + * + * 01 11 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add Deauth and Disassoc Handler + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * + * Refine Beacon processing, add read RF channel from RX Status + * + * 01 04 2010 tehuang.liu + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * For working out the first connection Chariot-verified version + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 12 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Modify u2EstimatedExtraIELen for probe request + * + * Dec 9 2009 mtk01104 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add HT cap IE to probe request + * + * Dec 7 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix lint warning + * + * + * Dec 3 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update the process of SCAN Result by adding more Phy Attributes + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function and code for meet the new define + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Rename u4RSSI to i4RSSI + * + * Nov 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Report event of scan result to host + * + * Nov 26 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix SCAN Record update + * + * Nov 24 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Revise MGMT Handler with Retain Status and Integrate with TXM + * + * Nov 23 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add (Ext)Support Rate Set IE to ProbeReq + * + * Nov 20 2009 mtk02468 + * [BORA00000337] To check in codes for FPGA emulation + * Removed the use of SW_RFB->u2FrameLength + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix uninitial aucMacAddress[] for ProbeReq + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add scanSearchBssDescByPolicy() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Add Send Probe Request Frame + * + * Oct 30 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define REPLICATED_BEACON_TIME_THRESHOLD (3000) +#define REPLICATED_BEACON_FRESH_PERIOD (10000) +#define REPLICATED_BEACON_STRENGTH_THRESHOLD (32) + +#define ROAMING_NO_SWING_RCPI_STEP (10) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used by SCN to initialize its variables +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID scnInit(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBSSDesc; + PUINT_8 pucBSSBuff; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + pucBSSBuff = &prScanInfo->aucScanBuffer[0]; + + DBGLOG(SCN, INFO, "->scnInit()\n"); + + /* 4 <1> Reset STATE and Message List */ + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; + + LINK_INITIALIZE(&prScanInfo->rPendingMsgList); + + /* 4 <2> Reset link list of BSS_DESC_T */ + kalMemZero((PVOID) pucBSSBuff, SCN_MAX_BUFFER_SIZE); + + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); + + for (i = 0; i < CFG_MAX_NUM_BSS_LIST; i++) { + + prBSSDesc = (P_BSS_DESC_T) pucBSSBuff; + + LINK_INSERT_TAIL(&prScanInfo->rFreeBSSDescList, &prBSSDesc->rLinkEntry); + + pucBSSBuff += ALIGN_4(sizeof(BSS_DESC_T)); + } + /* Check if the memory allocation consist with this initialization function */ + ASSERT(((ULONG) pucBSSBuff - (ULONG)&prScanInfo->aucScanBuffer[0]) == SCN_MAX_BUFFER_SIZE); + + /* reset freest channel information */ + prScanInfo->fgIsSparseChannelValid = FALSE; + + /* reset NLO state */ + prScanInfo->fgNloScanning = FALSE; + prScanInfo->fgPscnOnnning = FALSE; + + prScanInfo->prPscnParam = kalMemAlloc(sizeof(PSCN_PARAM_T), VIR_MEM_TYPE); + if (prScanInfo->prPscnParam) + kalMemZero(prScanInfo->prPscnParam, sizeof(PSCN_PARAM_T)); + +} /* end of scnInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used by SCN to uninitialize its variables +* +* @param (none) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID scnUninit(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + DBGLOG(SCN, INFO, "->scnUninit()\n"); + + /* 4 <1> Reset STATE and Message List */ + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (OS_SYSTIME) 0; + + /* NOTE(Kevin): Check rPendingMsgList ? */ + + /* 4 <2> Reset link list of BSS_DESC_T */ + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); + + kalMemFree(prScanInfo->prPscnParam, VIR_MEM_TYPE, sizeof(PSCN_PARAM_T)); + +} /* end of scnUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given BSSID +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) +{ + return scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, FALSE, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given BSSID +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, + IN UINT_8 aucBSSID[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + if (fgCheckSsid == FALSE || prSsid == NULL) + return prBssDesc; + + if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { + return prBssDesc; + } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { + prDstBssDesc = prBssDesc; + } else { + /* 20120206 frog: Equal BSSID but not SSID, SSID not hidden, + * SSID must be updated. */ + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen); + return prBssDesc; + } + } + } + + return prDstBssDesc; + +} /* end of scanSearchBssDescByBssid() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucSrcAddr Given Source Address(TA). +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, IN UINT_8 aucSrcAddr[]) +{ + return scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, FALSE, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given Transmitter Address. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucSrcAddr Given Source Address(TA). +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, + IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucSrcAddr, aucSrcAddr)) { + if (fgCheckSsid == FALSE || prSsid == NULL) + return prBssDesc; + + if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prSsid->aucSsid, prSsid->u4SsidLen)) { + return prBssDesc; + } else if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == TRUE) { + prDstBssDesc = prBssDesc; + } + + } + } + + return prDstBssDesc; + +} /* end of scanSearchBssDescByTA() */ + +#if CFG_SUPPORT_HOTSPOT_2_0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to given BSSID +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByBssidAndLatestUpdateTime(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T) NULL; + OS_SYSTIME rLatestUpdateTime = 0; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + if (!rLatestUpdateTime || CHECK_FOR_EXPIRATION(prBssDesc->rUpdateTime, rLatestUpdateTime)) { + prDstBssDesc = prBssDesc; + COPY_SYSTIME(rLatestUpdateTime, prBssDesc->rUpdateTime); + } + } + } + + return prDstBssDesc; + +} /* end of scanSearchBssDescByBssid() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to +* given eBSSType, BSSID and Transmitter Address +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. +* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. +* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, IN UINT_8 aucBSSID[], IN UINT_8 aucSrcAddr[]) +{ + return scanSearchExistingBssDescWithSsid(prAdapter, eBSSType, aucBSSID, aucSrcAddr, FALSE, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Find the corresponding BSS Descriptor according to +* given eBSSType, BSSID and Transmitter Address +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. +* @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. +* @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. +* @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with single BSSID cases) +* @param[in] prSsid Specified SSID +* +* @return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN UINT_8 aucBSSID[], + IN UINT_8 aucSrcAddr[], IN BOOLEAN fgCheckSsid, IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBssDesc, prIBSSBssDesc; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + switch (eBSSType) { + case BSS_TYPE_P2P_DEVICE: + fgCheckSsid = FALSE; + case BSS_TYPE_INFRASTRUCTURE: + case BSS_TYPE_BOW_DEVICE: + { + prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); + + /* if (eBSSType == prBssDesc->eBSSType) */ + + return prBssDesc; + } + + case BSS_TYPE_IBSS: + { + prIBSSBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, fgCheckSsid, prSsid); + prBssDesc = scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, fgCheckSsid, prSsid); + + /* NOTE(Kevin): + * Rules to maintain the SCAN Result: + * For AdHoc - + * CASE I We have TA1(BSSID1), but it change its BSSID to BSSID2 + * -> Update TA1 entry's BSSID. + * CASE II We have TA1(BSSID1), and get TA1(BSSID1) again + * -> Update TA1 entry's contain. + * CASE III We have a SCAN result TA1(BSSID1), and TA2(BSSID2). Sooner or + * later, TA2 merge into TA1, we get TA2(BSSID1) + * -> Remove TA2 first and then replace TA1 entry's TA with TA2, + * Still have only one entry of BSSID. + * CASE IV We have a SCAN result TA1(BSSID1), and another TA2 also merge into BSSID1. + * -> Replace TA1 entry's TA with TA2, Still have only one entry. + * CASE V New IBSS + * -> Add this one to SCAN result. + */ + if (prBssDesc) { + if ((!prIBSSBssDesc) || /* CASE I */ + (prBssDesc == prIBSSBssDesc)) { /* CASE II */ + + return prBssDesc; + } /* CASE III */ + + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + return prIBSSBssDesc; + } + + if (prIBSSBssDesc) { /* CASE IV */ + + return prIBSSBssDesc; + } + /* CASE V */ + break; /* Return NULL; */ + } + + default: + break; + } + + return (P_BSS_DESC_T) NULL; + +} /* end of scanSearchExistingBssDesc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given Remove Policy. +* +* @param[in] u4RemovePolicy Remove Policy. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, IN UINT_32 u4RemovePolicy) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* DBGLOG(SCN, TRACE, ("Before Remove - Number Of SCAN Result = %ld\n", */ + /* prBSSDescList->u4NumElem)); */ + + if (u4RemovePolicy & SCN_RM_POLICY_TIMEOUT) { + P_BSS_DESC_T prBSSDescNext; + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { + + /* DBGLOG(SCN, TRACE, ("Remove TIMEOUT BSS DESC(%#x): + * MAC: %pM, Current Time = %08lx, Update Time = %08lx\n", */ + /* prBssDesc, prBssDesc->aucBSSID, rCurrentTime, prBssDesc->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + } else if (u4RemovePolicy & SCN_RM_POLICY_OLDEST_HIDDEN) { + P_BSS_DESC_T prBssDescOldest = (P_BSS_DESC_T) NULL; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if (!prBssDesc->fgIsHiddenSSID) + continue; + + if (!prBssDescOldest) { /* 1st element */ + prBssDescOldest = prBssDesc; + continue; + } + + if (TIME_BEFORE(prBssDesc->rUpdateTime, prBssDescOldest->rUpdateTime)) + prBssDescOldest = prBssDesc; + } + + if (prBssDescOldest) { + + /* DBGLOG(SCN, TRACE, ("Remove OLDEST HIDDEN BSS DESC(%#x): + * MAC: %pM, Update Time = %08lx\n", */ + /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescOldest); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescOldest->rLinkEntry); + } + } else if (u4RemovePolicy & SCN_RM_POLICY_SMART_WEAKEST) { + P_BSS_DESC_T prBssDescWeakest = (P_BSS_DESC_T) NULL; + P_BSS_DESC_T prBssDescWeakestSameSSID = (P_BSS_DESC_T) NULL; + UINT_32 u4SameSSIDCount = 0; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + if ((!prBssDesc->fgIsHiddenSSID) && + (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prConnSettings->aucSSID, prConnSettings->ucSSIDLen))) { + + u4SameSSIDCount++; + + if (!prBssDescWeakestSameSSID) + prBssDescWeakestSameSSID = prBssDesc; + else if (prBssDesc->ucRCPI < prBssDescWeakestSameSSID->ucRCPI) + prBssDescWeakestSameSSID = prBssDesc; + } + + if (!prBssDescWeakest) { /* 1st element */ + prBssDescWeakest = prBssDesc; + continue; + } + + if (prBssDesc->ucRCPI < prBssDescWeakest->ucRCPI) + prBssDescWeakest = prBssDesc; + + } + + if ((u4SameSSIDCount >= SCN_BSS_DESC_SAME_SSID_THRESHOLD) && (prBssDescWeakestSameSSID)) + prBssDescWeakest = prBssDescWeakestSameSSID; + + if (prBssDescWeakest) { + + /* DBGLOG(SCN, TRACE, ("Remove WEAKEST BSS DESC(%#x): MAC: %pM, Update Time = %08lx\n", */ + /* prBssDescOldest, prBssDescOldest->aucBSSID, prBssDescOldest->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescWeakest); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescWeakest->rLinkEntry); + } + } else if (u4RemovePolicy & SCN_RM_POLICY_ENTIRE) { + P_BSS_DESC_T prBSSDescNext; + + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are connected. */ + continue; + } + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + + } + + return; + +} /* end of scanRemoveBssDescsByPolicy() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given BSSID. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] aucBSSID Given BSSID. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + P_BSS_DESC_T prBSSDescNext; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + /* BSSID is not unique, so need to traverse whols link-list */ + } + } + +} /* end of scanRemoveBssDescByBssid() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Delete BSS Descriptors from current list according to given band configuration +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] eBand Given band +* @param[in] eNetTypeIndex AIS - Remove IBSS/Infrastructure BSS +* BOW - Remove BOW BSS +* P2P - Remove P2P BSS +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + P_BSS_DESC_T prBSSDescNext; + BOOLEAN fgToRemove; + + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(eNetTypeIndex <= NETWORK_TYPE_INDEX_NUM); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + if (eBand == BAND_NULL) + return; /* no need to do anything, keep all scan result */ + + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T) { + fgToRemove = FALSE; + + if (prBssDesc->eBand == eBand) { + switch (eNetTypeIndex) { + case NETWORK_TYPE_AIS_INDEX: + if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS)) { + fgToRemove = TRUE; + } + break; + + case NETWORK_TYPE_P2P_INDEX: + if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) + fgToRemove = TRUE; + break; + + case NETWORK_TYPE_BOW_INDEX: + if (prBssDesc->eBSSType == BSS_TYPE_BOW_DEVICE) + fgToRemove = TRUE; + break; + + default: + ASSERT(0); + break; + } + } + + if (fgToRemove == TRUE) { + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + +} /* end of scanRemoveBssDescByBand() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Clear the CONNECTION FLAG of a specified BSS Descriptor. +* +* @param[in] aucBSSID Given BSSID. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, IN UINT_8 aucBSSID[]) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + prBssDesc->fgIsConnected = FALSE; + prBssDesc->fgIsConnecting = FALSE; + + /* BSSID is not unique, so need to traverse whols link-list */ + } + } + + return; + +} /* end of scanRemoveConnectionFlagOfBssDescByBssid() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Allocate new BSS_DESC_T +* +* @param[in] prAdapter Pointer to the Adapter structure. +* +* @return Pointer to BSS Descriptor, if has free space. NULL, if has no space. +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + LINK_REMOVE_HEAD(prFreeBSSDescList, prBssDesc, P_BSS_DESC_T); + + if (prBssDesc) { + P_LINK_T prBSSDescList; + + kalMemZero(prBssDesc, sizeof(BSS_DESC_T)); + +#if CFG_ENABLE_WIFI_DIRECT + LINK_INITIALIZE(&(prBssDesc->rP2pDeviceList)); + prBssDesc->fgIsP2PPresent = FALSE; +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* NOTE(Kevin): In current design, this new empty BSS_DESC_T will be + * inserted to BSSDescList immediately. + */ + LINK_INSERT_TAIL(prBSSDescList, &prBssDesc->rLinkEntry); + } + + return prBssDesc; + +} /* end of scanAllocateBssDesc() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This API parses Beacon/ProbeResp frame and insert extracted BSS_DESC_T +* with IEs into prAdapter->rWifiVar.rScanInfo.aucScanBuffer +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prSwRfb Pointer to the receiving frame buffer. +* +* @return Pointer to BSS Descriptor +* NULL if the Beacon/ProbeResp frame is invalid +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_DESC_T prBssDesc = NULL; + UINT_16 u2CapInfo; + ENUM_BSS_TYPE_T eBSSType = BSS_TYPE_INFRASTRUCTURE; + + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset = 0; + + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T) NULL; + P_IE_SUPPORTED_RATE_T prIeSupportedRate = (P_IE_SUPPORTED_RATE_T) NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = (P_IE_EXT_SUPPORTED_RATE_T) NULL; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_8 ucHwChannelNum = 0; + UINT_8 ucIeDsChannelNum = 0; + UINT_8 ucIeHtChannelNum = 0; + BOOLEAN fgIsValidSsid = FALSE, fgEscape = FALSE; + PARAM_SSID_T rSsid; + UINT_64 u8Timestamp; + BOOLEAN fgIsNewBssDesc = FALSE; + + UINT_32 i; + UINT_8 ucSSIDChar; + + UINT_8 ucOuiType; + UINT_16 u2SubTypeVersion; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2CapInfo, &u2CapInfo); + WLAN_GET_FIELD_64(&prWlanBeaconFrame->au4Timestamp[0], &u8Timestamp); + + /* decide BSS type */ + switch (u2CapInfo & CAP_INFO_BSS_TYPE) { + case CAP_INFO_ESS: + /* It can also be Group Owner of P2P Group. */ + eBSSType = BSS_TYPE_INFRASTRUCTURE; + break; + + case CAP_INFO_IBSS: + eBSSType = BSS_TYPE_IBSS; + break; + case 0: + /* The P2P Device shall set the ESS bit of the Capabilities field + * in the Probe Response fame to 0 and IBSS bit to 0. (3.1.2.1.1) */ + eBSSType = BSS_TYPE_P2P_DEVICE; + break; + +#if CFG_ENABLE_BT_OVER_WIFI + /* @TODO: add rule to identify BOW beacons */ +#endif + + default: + DBGLOG(SCN, ERROR, "wrong bss type %d\n", (INT_32)(u2CapInfo & CAP_INFO_BSS_TYPE)); + return NULL; + } + + /* 4 <1.1> Pre-parse SSID IE */ + pucIE = prWlanBeaconFrame->aucInfoElem; + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + if (u2IELength > CFG_IE_BUFFER_SIZE) + u2IELength = CFG_IE_BUFFER_SIZE; + kalMemZero(&rSsid, sizeof(rSsid)); + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID) { + ucSSIDChar = '\0'; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) + fgIsValidSsid = FALSE; + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && + * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + + if (ucSSIDChar) + fgIsValidSsid = TRUE; + } + + /* Update SSID to BSS Descriptor only if SSID is not hidden. */ + if (fgIsValidSsid == TRUE) { + COPY_SSID(rSsid.aucSsid, + rSsid.u4SsidLen, SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); + } + } + fgEscape = TRUE; + break; + default: + break; + } + + if (fgEscape == TRUE) + break; + } + if (fgIsValidSsid) + DBGLOG(SCN, EVENT, "%s %pM channel %d\n", rSsid.aucSsid, prWlanBeaconFrame->aucBSSID, + HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); + else + DBGLOG(SCN, EVENT, "hidden ssid, %pM channel %d\n", prWlanBeaconFrame->aucBSSID, + HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr)); + /* 4 <1.2> Replace existing BSS_DESC_T or allocate a new one */ + prBssDesc = scanSearchExistingBssDescWithSsid(prAdapter, + eBSSType, + (PUINT_8) prWlanBeaconFrame->aucBSSID, + (PUINT_8) prWlanBeaconFrame->aucSrcAddr, + fgIsValidSsid, fgIsValidSsid == TRUE ? &rSsid : NULL); + + if (prBssDesc == (P_BSS_DESC_T) NULL) { + fgIsNewBssDesc = TRUE; + + do { + /* 4 <1.2.1> First trial of allocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) + break; + /* 4 <1.2.2> Hidden is useless, remove the oldest hidden ssid. (for passive scan) */ + scanRemoveBssDescsByPolicy(prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_OLDEST_HIDDEN)); + + /* 4 <1.2.3> Second tail of allocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) + break; + /* 4 <1.2.4> Remove the weakest one */ + /* If there are more than half of BSS which has the same ssid as connection + * setting, remove the weakest one from them. + * Else remove the weakest one. + */ + scanRemoveBssDescsByPolicy(prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_SMART_WEAKEST)); + + /* 4 <1.2.5> reallocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) + break; + /* 4 <1.2.6> no space, should not happen */ + DBGLOG(SCN, ERROR, "no bss desc available after remove policy\n"); + return NULL; + + } while (FALSE); + + } else { + OS_SYSTIME rCurrentTime; + + /* WCXRP00000091 */ + /* if the received strength is much weaker than the original one, */ + /* ignore it due to it might be received on the folding frequency */ + + GET_CURRENT_SYSTIME(&rCurrentTime); + + if (prBssDesc->eBSSType != eBSSType) { + prBssDesc->eBSSType = eBSSType; + } else if (HIF_RX_HDR_GET_CHNL_NUM(prSwRfb->prHifRxHdr) != prBssDesc->ucChannelNum && + prBssDesc->ucRCPI > prSwRfb->prHifRxHdr->ucRcpi) { + /* for signal strength is too much weaker and previous beacon is not stale */ + if ((prBssDesc->ucRCPI - prSwRfb->prHifRxHdr->ucRcpi) >= REPLICATED_BEACON_STRENGTH_THRESHOLD && + (rCurrentTime - prBssDesc->rUpdateTime) <= REPLICATED_BEACON_FRESH_PERIOD) { + DBGLOG(SCN, EVENT, "rssi is too much weaker and previous one is fresh\n"); + return prBssDesc; + } + /* for received beacons too close in time domain */ + else if (rCurrentTime - prBssDesc->rUpdateTime <= REPLICATED_BEACON_TIME_THRESHOLD) { + DBGLOG(SCN, EVENT, "receive beacon/probe reponses too close\n"); + return prBssDesc; + } + } + + /* if Timestamp has been reset, re-generate BSS DESC 'cause AP should have reset itself */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && u8Timestamp < prBssDesc->u8TimeStamp.QuadPart) { + BOOLEAN fgIsConnected, fgIsConnecting; + + /* set flag for indicating this is a new BSS-DESC */ + fgIsNewBssDesc = TRUE; + + /* backup 2 flags for APs which reset timestamp unexpectedly */ + fgIsConnected = prBssDesc->fgIsConnected; + fgIsConnecting = prBssDesc->fgIsConnecting; + scanRemoveBssDescByBssid(prAdapter, prBssDesc->aucBSSID); + + prBssDesc = scanAllocateBssDesc(prAdapter); + if (!prBssDesc) + return NULL; + + /* restore */ + prBssDesc->fgIsConnected = fgIsConnected; + prBssDesc->fgIsConnecting = fgIsConnecting; + } + } +#if 1 + + prBssDesc->u2RawLength = prSwRfb->u2PacketLen; + if (prBssDesc->u2RawLength > CFG_RAW_BUFFER_SIZE) + prBssDesc->u2RawLength = CFG_RAW_BUFFER_SIZE; + kalMemCopy(prBssDesc->aucRawBuf, prWlanBeaconFrame, prBssDesc->u2RawLength); +#endif + + /* NOTE: Keep consistency of Scan Record during JOIN process */ + if ((fgIsNewBssDesc == FALSE) && prBssDesc->fgIsConnecting) { + DBGLOG(SCN, INFO, "we're connecting this BSS(%pM) now, don't update it\n", + prBssDesc->aucBSSID); + return prBssDesc; + } + /* 4 <2> Get information from Fixed Fields */ + prBssDesc->eBSSType = eBSSType; /* Update the latest BSS type information. */ + + COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prWlanBeaconFrame->aucSrcAddr); + + COPY_MAC_ADDR(prBssDesc->aucBSSID, prWlanBeaconFrame->aucBSSID); + + prBssDesc->u8TimeStamp.QuadPart = u8Timestamp; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2BeaconInterval, &prBssDesc->u2BeaconInterval); + + prBssDesc->u2CapInfo = u2CapInfo; + + /* 4 <2.1> Retrieve IEs for later parsing */ + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16) OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + if (u2IELength > CFG_IE_BUFFER_SIZE) { + u2IELength = CFG_IE_BUFFER_SIZE; + prBssDesc->fgIsIEOverflow = TRUE; + } else { + prBssDesc->fgIsIEOverflow = FALSE; + } + prBssDesc->u2IELength = u2IELength; + + kalMemCopy(prBssDesc->aucIEBuf, prWlanBeaconFrame->aucInfoElem, u2IELength); + + /* 4 <2.2> reset prBssDesc variables in case that AP has been reconfigured */ + prBssDesc->fgIsERPPresent = FALSE; + prBssDesc->fgIsHTPresent = FALSE; + prBssDesc->eSco = CHNL_EXT_SCN; + prBssDesc->fgIEWAPI = FALSE; +#if CFG_RSN_MIGRATION + prBssDesc->fgIERSN = FALSE; +#endif +#if CFG_PRIVACY_MIGRATION + prBssDesc->fgIEWPA = FALSE; +#endif + + /* 4 <3.1> Full IE parsing on SW_RFB_T */ + pucIE = prWlanBeaconFrame->aucInfoElem; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): for Atheros IOT #1 */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + BOOLEAN fgIsHiddenSSID = FALSE; + + ucSSIDChar = '\0'; + + prIeSsid = (P_IE_SSID_T) pucIE; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) + fgIsHiddenSSID = TRUE; + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) && + * (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + + if (!ucSSIDChar) + fgIsHiddenSSID = TRUE; + } + + /* Update SSID to BSS Descriptor only if SSID is not hidden. */ + if (!fgIsHiddenSSID) { + COPY_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + SSID_IE(pucIE)->aucSSID, SSID_IE(pucIE)->ucLength); + } +#if 0 + /* + After we connect to a hidden SSID, prBssDesc->aucSSID[] will + not be empty and prBssDesc->ucSSIDLen will not be 0, + so maybe we need to empty prBssDesc->aucSSID[] and set + prBssDesc->ucSSIDLen to 0 in prBssDesc to avoid that + UI still displays hidden SSID AP in scan list after + we disconnect the hidden SSID AP. + */ + else { + prBssDesc->aucSSID[0] = '\0'; + prBssDesc->ucSSIDLen = 0; + } +#endif + + } + break; + + case ELEM_ID_SUP_RATES: + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8. + * IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B), + * 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + /* TP-LINK will set extra and incorrect ie with ELEM_ID_SUP_RATES */ + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM)) + prIeSupportedRate = SUP_RATES_IE(pucIE); + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) + ucIeDsChannelNum = DS_PARAM_IE(pucIE)->ucCurrChnl; + break; + + case ELEM_ID_TIM: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_TIM) + prBssDesc->ucDTIMPeriod = TIM_IE(pucIE)->ucDTIMPeriod; + break; + + case ELEM_ID_IBSS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_IBSS_PARAMETER_SET) + prBssDesc->u2ATIMWindow = IBSS_PARAM_IE(pucIE)->u2ATIMWindow; + break; + +#if 0 /* CFG_SUPPORT_802_11D */ + case ELEM_ID_COUNTRY_INFO: + prBssDesc->prIECountry = (P_IE_COUNTRY_T) pucIE; + break; +#endif + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_ERP) + prBssDesc->fgIsERPPresent = TRUE; + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + break; + +#if CFG_RSN_MIGRATION + case ELEM_ID_RSN: + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &prBssDesc->rRSNInfo)) { + prBssDesc->fgIERSN = TRUE; + prBssDesc->u2RsnCap = prBssDesc->rRSNInfo.u2RsnCap; + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) + rsnCheckPmkidCache(prAdapter, prBssDesc); + } + break; +#endif + + case ELEM_ID_HT_CAP: + prBssDesc->fgIsHTPresent = TRUE; + break; + + case ELEM_ID_HT_OP: + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) + break; + + if ((((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO) != CHNL_EXT_RES) { + prBssDesc->eSco = (ENUM_CHNL_EXT_T) + (((P_IE_HT_OP_T) pucIE)->ucInfo1 & HT_OP_INFO1_SCO); + } + ucIeHtChannelNum = ((P_IE_HT_OP_T) pucIE)->ucPrimaryChannel; + + break; + +#if CFG_SUPPORT_WAPI + case ELEM_ID_WAPI: + if (wapiParseWapiIE(WAPI_IE(pucIE), &prBssDesc->rIEWAPI)) + prBssDesc->fgIEWAPI = TRUE; + break; +#endif + + case ELEM_ID_VENDOR: /* ELEM_ID_P2P, ELEM_ID_WMM */ +#if CFG_PRIVACY_MIGRATION + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && (u2SubTypeVersion == VERSION_WPA)) { + + if (rsnParseWpaIE(prAdapter, WPA_IE(pucIE), &prBssDesc->rWPAInfo)) + prBssDesc->fgIEWPA = TRUE; + } + } +#endif + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, &ucOuiType)) { + if (ucOuiType == VENDOR_OUI_TYPE_P2P) + prBssDesc->fgIsP2PPresent = TRUE; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + break; + + /* no default */ + } + } + + /* 4 <3.2> Save information from IEs - SSID */ + /* Update Flag of Hidden SSID for used in SEARCH STATE. */ + + /* NOTE(Kevin): in current driver, the ucSSIDLen == 0 represent + * all cases of hidden SSID. + * If the fgIsHiddenSSID == TRUE, it means we didn't get the ProbeResp with + * valid SSID. + */ + if (prBssDesc->ucSSIDLen == 0) + prBssDesc->fgIsHiddenSSID = TRUE; + else + prBssDesc->fgIsHiddenSSID = FALSE; + + /* 4 <3.3> Check rate information in related IEs. */ + if (prIeSupportedRate || prIeExtSupportedRate) { + rateGetRateSetFromIEs(prIeSupportedRate, + prIeExtSupportedRate, + &prBssDesc->u2OperationalRateSet, + &prBssDesc->u2BSSBasicRateSet, &prBssDesc->fgIsUnknownBssBasicRate); + } + /* 4 <4> Update information from HIF RX Header */ + { + prHifRxHdr = prSwRfb->prHifRxHdr; + + ASSERT(prHifRxHdr); + + /* 4 <4.1> Get TSF comparison result */ + prBssDesc->fgIsLargerTSF = HIF_RX_HDR_GET_TCL_FLAG(prHifRxHdr); + + /* 4 <4.2> Get Band information */ + prBssDesc->eBand = HIF_RX_HDR_GET_RF_BAND(prHifRxHdr); + + /* 4 <4.2> Get channel and RCPI information */ + ucHwChannelNum = HIF_RX_HDR_GET_CHNL_NUM(prHifRxHdr); + + if (BAND_2G4 == prBssDesc->eBand) { + + /* Update RCPI if in right channel */ + if (ucIeDsChannelNum >= 1 && ucIeDsChannelNum <= 14) { + + /* Receive Beacon/ProbeResp frame from adjacent channel. */ + if ((ucIeDsChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeDsChannelNum; + } else if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum <= 14) { + /* Receive Beacon/ProbeResp frame from adjacent channel. */ + if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } else { + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + /* 5G Band */ + else { + if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum < 200) { + /* Receive Beacon/ProbeResp frame from adjacent channel. */ + if ((ucIeHtChannelNum == ucHwChannelNum) || (prHifRxHdr->ucRcpi > prBssDesc->ucRCPI)) + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } else { + /* Always update RCPI */ + prBssDesc->ucRCPI = prHifRxHdr->ucRcpi; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + } + + /* 4 <5> PHY type setting */ + prBssDesc->ucPhyTypeSet = 0; + + if (BAND_2G4 == prBssDesc->eBand) { + /* check if support 11n */ + if (prBssDesc->fgIsHTPresent) + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* check if support 11g */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || prBssDesc->fgIsERPPresent) + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + + /* if not 11g only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)) { + /* check if support 11b */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)) + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + } + } else { /* (BAND_5G == prBssDesc->eBande) */ + /* check if support 11n */ + if (prBssDesc->fgIsHTPresent) + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* Support 11a definitely */ + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + + ASSERT(!(prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)); + } + } + + /* 4 <6> Update BSS_DESC_T's Last Update TimeStamp. */ + GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); + + return prBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to scan result for query +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the host. +* @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) +{ + P_SCAN_INFO_T prScanInfo; + UINT_8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame; + PARAM_MAC_ADDRESS rMacAddr; + PARAM_SSID_T rSsid; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + UINT_8 ucRateLen = 0; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prBssDesc->eBand == BAND_2G4) { + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) + || prBssDesc->fgIsERPPresent) { + eNetworkType = PARAM_NETWORK_TYPE_OFDM24; + } else { + eNetworkType = PARAM_NETWORK_TYPE_DS; + } + } else { + ASSERT(prBssDesc->eBand == BAND_5G); + eNetworkType = PARAM_NETWORK_TYPE_OFDM5; + } + + if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + /* NOTE(Kevin): Not supported by WZC(TBD) */ + return WLAN_STATUS_FAILURE; + } + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; + COPY_MAC_ADDR(rMacAddr, prWlanBeaconFrame->aucBSSID); + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + + rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + rConfiguration.u4BeaconPeriod = (UINT_32) prWlanBeaconFrame->u2BeaconInterval; + rConfiguration.u4ATIMWindow = prBssDesc->u2ATIMWindow; + rConfiguration.u4DSConfig = nicChannelNum2Freq(prBssDesc->ucChannelNum); + rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + rateGetDataRatesFromRateSet(prBssDesc->u2OperationalRateSet, 0, aucRatesEx, &ucRateLen); + + /* NOTE(Kevin): Set unused entries, if any, at the end of the array to 0. + * from OID_802_11_BSSID_LIST + */ + for (i = ucRateLen; i < sizeof(aucRatesEx) / sizeof(aucRatesEx[0]); i++) + aucRatesEx[i] = 0; + + switch (prBssDesc->eBSSType) { + case BSS_TYPE_IBSS: + eOpMode = NET_TYPE_IBSS; + break; + + case BSS_TYPE_INFRASTRUCTURE: + case BSS_TYPE_P2P_DEVICE: + case BSS_TYPE_BOW_DEVICE: + default: + eOpMode = NET_TYPE_INFRA; + break; + } + + DBGLOG(SCN, TRACE, "ind %s %d\n", prBssDesc->aucSSID, prBssDesc->ucChannelNum); + +#if (CFG_SUPPORT_TDLS == 1) + { + if (flgTdlsTestExtCapElm == TRUE) { + /* only for RALINK AP */ + UINT8 *pucElm = (UINT8 *) (prSwRfb->pvHeader + prSwRfb->u2PacketLen); + + kalMemCopy(pucElm - 9, aucTdlsTestExtCapElm, 7); + prSwRfb->u2PacketLen -= 2; +/* prSwRfb->u2PacketLen += 7; */ + + DBGLOG(TDLS, INFO, + " %s: append ext cap element to %pM\n", + __func__, prBssDesc->aucBSSID); + } + } +#endif /* CFG_SUPPORT_TDLS */ + + if (prAdapter->rWifiVar.rScanInfo.fgNloScanning && + test_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag)) { + UINT_8 i = 0; + P_BSS_DESC_T *pprPendBssDesc = &prScanInfo->rNloParam.aprPendingBssDescToInd[0]; + + for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { + if (pprPendBssDesc[i]) + continue; + DBGLOG(SCN, INFO, + "indicate bss[%pM] before wiphy resume, need to indicate again after wiphy resume\n", + prBssDesc->aucBSSID); + pprPendBssDesc[i] = prBssDesc; + break; + } + } + + kalIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prSwRfb->pvHeader, + prSwRfb->u2PacketLen, prBssDesc->ucChannelNum, RCPI_TO_dBm(prBssDesc->ucRCPI)); + + nicAddScanResult(prAdapter, + rMacAddr, + &rSsid, + prWlanBeaconFrame->u2CapInfo & CAP_INFO_PRIVACY ? 1 : 0, + RCPI_TO_dBm(prBssDesc->ucRCPI), + eNetworkType, + &rConfiguration, + eOpMode, + aucRatesEx, + prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen, + (PUINT_8) ((ULONG) (prSwRfb->pvHeader) + WLAN_MAC_MGMT_HEADER_LEN)); + + return WLAN_STATUS_SUCCESS; + +} /* end of scanAddScanResult() */ + +#if 1 + +BOOLEAN scanCheckBssIsLegal(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) +{ + BOOLEAN fgAddToScanResult = FALSE; + ENUM_BAND_T eBand = 0; + UINT_8 ucChannel = 0; + + ASSERT(prAdapter); + /* check the channel is in the legal doamin */ + if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == TRUE) { + /* check ucChannelNum/eBand for adjacement channel filtering */ + if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == TRUE && + (eBand != prBssDesc->eBand || ucChannel != prBssDesc->ucChannelNum)) { + fgAddToScanResult = FALSE; + } else { + fgAddToScanResult = TRUE; + } + } + return fgAddToScanResult; + +} + +VOID scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, IN P_BSS_DESC_T SpecificprBssDesc) +{ + P_SCAN_INFO_T prScanInfo = (P_SCAN_INFO_T) NULL; + P_LINK_T prBSSDescList = (P_LINK_T) NULL; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + RF_CHANNEL_INFO_T rChannelInfo; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + DBGLOG(SCN, TRACE, "scanReportBss2Cfg80211\n"); + + if (SpecificprBssDesc) { + { + /* check BSSID is legal channel */ + if (!scanCheckBssIsLegal(prAdapter, SpecificprBssDesc)) { + DBGLOG(SCN, TRACE, "Remove specific SSID[%s %d]\n", + SpecificprBssDesc->aucSSID, SpecificprBssDesc->ucChannelNum); + return; + } + + DBGLOG(SCN, TRACE, "Report Specific SSID[%s]\n", SpecificprBssDesc->aucSSID); + if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { + + kalIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) SpecificprBssDesc->aucRawBuf, + SpecificprBssDesc->u2RawLength, + SpecificprBssDesc->ucChannelNum, + RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); + } else { + + rChannelInfo.ucChannelNum = SpecificprBssDesc->ucChannelNum; + rChannelInfo.eBand = SpecificprBssDesc->eBand; + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) SpecificprBssDesc->aucRawBuf, + SpecificprBssDesc->u2RawLength, + &rChannelInfo, RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); + + } + +#if CFG_ENABLE_WIFI_DIRECT + SpecificprBssDesc->fgIsP2PReport = FALSE; +#endif + } + } else { + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + /* 4 Auto Channel Selection:Record the AP Number */ + P_PARAM_CHN_LOAD_INFO prChnLoad; + UINT_8 ucIdx = 0; + + if (((prBssDesc->ucChannelNum > 0) && (prBssDesc->ucChannelNum <= 48)) + || (prBssDesc->ucChannelNum >= 147) /*non-DFS Channel */) { + if (prBssDesc->ucChannelNum <= HW_CHNL_NUM_MAX_2G4) { + ucIdx = prBssDesc->ucChannelNum - 1; + } else if (prBssDesc->ucChannelNum <= 48) { + ucIdx = (UINT_8) (HW_CHNL_NUM_MAX_2G4 + (prBssDesc->ucChannelNum - 34) / 4); + } else { + ucIdx = + (UINT_8) (HW_CHNL_NUM_MAX_2G4 + 4 + (prBssDesc->ucChannelNum - 149) / 4); + } + + if (ucIdx < MAX_AUTO_CHAL_NUM) { + prChnLoad = (P_PARAM_CHN_LOAD_INFO) & + (prAdapter->rWifiVar.rChnLoadInfo.rEachChnLoad[ucIdx]); + prChnLoad->ucChannel = prBssDesc->ucChannelNum; + prChnLoad->u2APNum++; + } else { + DBGLOG(SCN, WARN, "ACS: ChIdx > MAX_AUTO_CHAL_NUM\n"); + } + + } +#endif + /* check BSSID is legal channel */ + if (!scanCheckBssIsLegal(prAdapter, prBssDesc)) { + DBGLOG(SCN, TRACE, "Remove SSID[%s %d]\n", + prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + continue; + } + + if ((prBssDesc->eBSSType == eBSSType) +#if CFG_ENABLE_WIFI_DIRECT + || ((eBSSType == BSS_TYPE_P2P_DEVICE) && (prBssDesc->fgIsP2PReport == TRUE)) +#endif + ) { + + DBGLOG(SCN, TRACE, "Report ALL SSID[%s %d]\n", + prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { + if (prBssDesc->u2RawLength != 0) { + kalIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prBssDesc->aucRawBuf, + prBssDesc->u2RawLength, + prBssDesc->ucChannelNum, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); + prBssDesc->u2RawLength = 0; + +#if CFG_ENABLE_WIFI_DIRECT + prBssDesc->fgIsP2PReport = FALSE; +#endif + } + } else { +#if CFG_ENABLE_WIFI_DIRECT + if (prBssDesc->fgIsP2PReport == TRUE) { +#endif + rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; + rChannelInfo.eBand = prBssDesc->eBand; + + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (PUINT_8) prBssDesc->aucRawBuf, + prBssDesc->u2RawLength, + &rChannelInfo, RCPI_TO_dBm(prBssDesc->ucRCPI)); + + /* do not clear it then we can pass the bss in Specific report */ + /* kalMemZero(prBssDesc->aucRawBuf,CFG_RAW_BUFFER_SIZE); */ + + /* + the BSS entry will not be cleared after scan done. + So if we dont receive the BSS in next scan, we cannot + pass it. We use u2RawLength for the purpose. + */ + /* prBssDesc->u2RawLength=0; */ +#if CFG_ENABLE_WIFI_DIRECT + prBssDesc->fgIsP2PReport = FALSE; + } +#endif + } + } + + } +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = TRUE; +#endif + + } + +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Parse the content of given Beacon or ProbeResp Frame. +* +* @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. +* +* @retval WLAN_STATUS_SUCCESS if not report this SW_RFB_T to host +* @retval WLAN_STATUS_PENDING if report this SW_RFB_T to host as scan result +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_BSS_INFO_T prAisBssInfo; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) NULL; +#if CFG_SLT_SUPPORT + P_SLT_INFO_T prSltInfo = (P_SLT_INFO_T) NULL; +#endif + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + /* 4 <0> Ignore invalid Beacon Frame */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN)) { + /* to debug beacon length too small issue */ + UINT_32 u4MailBox0; + + nicGetMailbox(prAdapter, 0, &u4MailBox0); + DBGLOG(SCN, WARN, "if conn sys also get less length (0x5a means yes) %x\n", (UINT_32) u4MailBox0); + DBGLOG(SCN, WARN, "u2PacketLen %d, u2HeaderLen %d, payloadLen %d\n", + prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen, + prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); + /* dumpMemory8(prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ + +#ifndef _lint + ASSERT(0); +#endif /* _lint */ + return rStatus; + } +#if CFG_SLT_SUPPORT + prSltInfo = &prAdapter->rWifiVar.rSltInfo; + + if (prSltInfo->fgIsDUT) { + DBGLOG(SCN, INFO, "\n\rBCN: RX\n"); + prSltInfo->u4BeaconReceiveCnt++; + return WLAN_STATUS_SUCCESS; + } else { + return WLAN_STATUS_SUCCESS; + } +#endif + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T) prSwRfb->pvHeader; + + /*ALPS01475157: don't show SSID on scan list for multicast MAC AP */ + if (IS_BMCAST_MAC_ADDR(prWlanBeaconFrame->aucSrcAddr)) { + DBGLOG(SCN, WARN, "received beacon/probe response from multicast AP\n"); + return rStatus; + } + + /* 4 <1> Parse and add into BSS_DESC_T */ + prBssDesc = scanAddToBssDesc(prAdapter, prSwRfb); + + if (prBssDesc) { + /* 4 <1.1> Beacon Change Detection for Connected BSS */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED && + ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA)) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && + EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen)) { + BOOLEAN fgNeedDisconnect = FALSE; + +#if CFG_SUPPORT_BEACON_CHANGE_DETECTION + /* <1.1.2> check if supported rate differs */ + if (prAisBssInfo->u2OperationalRateSet != prBssDesc->u2OperationalRateSet) + fgNeedDisconnect = TRUE; +#endif +#if CFG_SUPPORT_DETECT_SECURITY_MODE_CHANGE + if ( +#if CFG_SUPPORT_WAPI + (prAdapter->rWifiVar.rConnSettings.fgWapiMode == TRUE && + !wapiPerformPolicySelection(prAdapter, prBssDesc)) || +#endif + rsnCheckSecurityModeChanged(prAdapter, prAisBssInfo, prBssDesc)) { + DBGLOG(SCN, INFO, "Beacon security mode change detected\n"); + fgNeedDisconnect = FALSE; + aisBssSecurityChanged(prAdapter); + } +#endif + + /* <1.1.3> beacon content change detected, disconnect immediately */ + if (fgNeedDisconnect == TRUE) + aisBssBeaconTimeout(prAdapter); + } + /* 4 <1.1> Update AIS_BSS_INFO */ + if (((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && prConnSettings->eOPMode != NET_TYPE_IBSS) + || (prBssDesc->eBSSType == BSS_TYPE_IBSS && prConnSettings->eOPMode != NET_TYPE_INFRA))) { + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* *not* checking prBssDesc->fgIsConnected anymore, + * due to Linksys AP uses " " as hidden SSID, and would have different BSS descriptor */ + if ((!prAisBssInfo->ucDTIMPeriod) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && + (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_BEACON)) { + + prAisBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + + /* sync with firmware for beacon information */ + nicPmIndicateBssConnected(prAdapter, NETWORK_TYPE_AIS_INDEX); + } + } +#if CFG_SUPPORT_ADHOC + if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen) && + (prBssDesc->eBSSType == BSS_TYPE_IBSS) && (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { + ibssProcessMatchedBeacon(prAdapter, prAisBssInfo, prBssDesc, + prSwRfb->prHifRxHdr->ucRcpi); + } +#endif /* CFG_SUPPORT_ADHOC */ + } + + rlmProcessBcn(prAdapter, + prSwRfb, + ((P_WLAN_BEACON_FRAME_T) (prSwRfb->pvHeader))->aucInfoElem, + (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (UINT_16) (OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); + + /* 4 <3> Send SW_RFB_T to HIF when we perform SCAN for HOST */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE || prBssDesc->eBSSType == BSS_TYPE_IBSS) { + /* for AIS, send to host */ + if (prConnSettings->fgIsScanReqIssued || prAdapter->rWifiVar.rScanInfo.fgNloScanning) { + BOOLEAN fgAddToScanResult; + + fgAddToScanResult = scanCheckBssIsLegal(prAdapter, prBssDesc); + + if (fgAddToScanResult == TRUE) + rStatus = scanAddScanResult(prAdapter, prBssDesc, prSwRfb); + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + scanP2pProcessBeaconAndProbeResp(prAdapter, prSwRfb, &rStatus, prBssDesc, prWlanBeaconFrame); +#endif + } + + return rStatus; + +} /* end of scanProcessBeaconAndProbeResp() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Search the Candidate of BSS Descriptor for JOIN(Infrastructure) or +* MERGE(AdHoc) according to current Connection Policy. +* +* \return Pointer to BSS Descriptor, if found. NULL, if not found +*/ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_SCAN_INFO_T prScanInfo; + + P_LINK_T prBSSDescList; + + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T) NULL; + P_BSS_DESC_T prPrimaryBssDesc = (P_BSS_DESC_T) NULL; + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T) NULL; + + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + P_STA_RECORD_T prPrimaryStaRec; + P_STA_RECORD_T prCandidateStaRec = (P_STA_RECORD_T) NULL; + + OS_SYSTIME rCurrentTime; + + /* The first one reach the check point will be our candidate */ + BOOLEAN fgIsFindFirst = (BOOLEAN) FALSE; + + BOOLEAN fgIsFindBestRSSI = (BOOLEAN) FALSE; + BOOLEAN fgIsFindBestEncryptionLevel = (BOOLEAN) FALSE; + /* BOOLEAN fgIsFindMinChannelLoad = (BOOLEAN)FALSE; */ + + /* TODO(Kevin): Support Min Channel Load */ + /* UINT_8 aucChannelLoad[CHANNEL_NUM] = {0}; */ + + BOOLEAN fgIsFixedChannel; + ENUM_BAND_T eBand = 0; + UINT_8 ucChannel = 0; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetTypeIndex]); + + prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* check for fixed channel operation */ + if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { +#if CFG_P2P_LEGACY_COEX_REVISE + fgIsFixedChannel = cnmAisDetectP2PChannel(prAdapter, &eBand, &ucChannel); +#else + fgIsFixedChannel = cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel); +#endif + } else { + fgIsFixedChannel = FALSE; + } + +#if DBG + if (prConnSettings->ucSSIDLen < ELEM_MAX_LEN_SSID) + prConnSettings->aucSSID[prConnSettings->ucSSIDLen] = '\0'; +#endif + + DBGLOG(SCN, INFO, "SEARCH: Bss Num: %d, Look for SSID: %s, %pM Band=%d, channel=%d\n", + (UINT_32) prBSSDescList->u4NumElem, prConnSettings->aucSSID, + (prConnSettings->aucBSSID), eBand, ucChannel); + + /* 4 <1> The outer loop to search for a candidate. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + + /* TODO(Kevin): Update Minimum Channel Load Information here */ + + DBGLOG(SCN, TRACE, "SEARCH: [ %pM ], SSID:%s\n", + prBssDesc->aucBSSID, prBssDesc->aucSSID); + + /* 4 <2> Check PHY Type and attributes */ + /* 4 <2.1> Check Unsupported BSS PHY Type */ + if (!(prBssDesc->ucPhyTypeSet & (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + DBGLOG(SCN, TRACE, "SEARCH: Ignore unsupported ucPhyTypeSet = %x\n", prBssDesc->ucPhyTypeSet); + continue; + } + /* 4 <2.2> Check if has unknown NonHT BSS Basic Rate Set. */ + if (prBssDesc->fgIsUnknownBssBasicRate) + continue; + /* 4 <2.3> Check if fixed operation cases should be aware */ + if (fgIsFixedChannel == TRUE && (prBssDesc->eBand != eBand || prBssDesc->ucChannelNum != ucChannel)) + continue; + /* 4 <2.4> Check if the channel is legal under regulatory domain */ + if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum) == FALSE) + continue; + /* 4 <2.5> Check if this BSS_DESC_T is stale */ + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { + + BOOLEAN fgIsNeedToCheckTimeout = TRUE; + +#if CFG_SUPPORT_ROAMING + P_ROAMING_INFO_T prRoamingFsmInfo; + + prRoamingFsmInfo = (P_ROAMING_INFO_T) &(prAdapter->rWifiVar.rRoamingInfo); + if ((prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) || + (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) { + if (++prRoamingFsmInfo->RoamingEntryTimeoutSkipCount < + ROAMING_ENTRY_TIMEOUT_SKIP_COUNT_MAX) { + fgIsNeedToCheckTimeout = FALSE; + DBGLOG(SCN, INFO, "SEARCH: Romaing skip SCN_BSS_DESC_REMOVE_TIMEOUT_SEC\n"); + } + } +#endif + + if (fgIsNeedToCheckTimeout == TRUE) { + DBGLOG(SCN, TRACE, "Ignore stale bss %pM\n", prBssDesc->aucBSSID); + continue; + } + } + /* 4 <3> Check if reach the excessive join retry limit */ + /* NOTE(Kevin): STA_RECORD_T is recorded by TA. */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) eNetTypeIndex, prBssDesc->aucSrcAddr); + + if (prStaRec) { + /* NOTE(Kevin): + * The Status Code is the result of a Previous Connection Request, + * we use this as SCORE for choosing a proper + * candidate (Also used for compare see <6>) + * The Reason Code is an indication of the reason why AP reject us, + * we use this Code for "Reject" + * a SCAN result to become our candidate(Like a blacklist). + */ +#if 0 /* TODO(Kevin): */ + if (prStaRec->u2ReasonCode != REASON_CODE_RESERVED) { + DBGLOG(SCN, INFO, "SEARCH: Ignore BSS with previous Reason Code = %d\n", + prStaRec->u2ReasonCode); + continue; + } else +#endif + if (prStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + /* NOTE(Kevin): greedy association - after timeout, we'll still + * try to associate to the AP whose STATUS of conection attempt + * was not success. + * We may also use (ucJoinFailureCount x JOIN_RETRY_INTERVAL_SEC) for + * time bound. + */ + if ((prStaRec->ucJoinFailureCount < JOIN_MAX_RETRY_FAILURE_COUNT) || + (CHECK_FOR_TIMEOUT(rCurrentTime, + prStaRec->rLastJoinTime, + SEC_TO_SYSTIME(JOIN_RETRY_INTERVAL_SEC)))) { + + /* NOTE(Kevin): Every JOIN_RETRY_INTERVAL_SEC interval, we can retry + * JOIN_MAX_RETRY_FAILURE_COUNT times. + */ + if (prStaRec->ucJoinFailureCount >= JOIN_MAX_RETRY_FAILURE_COUNT) + prStaRec->ucJoinFailureCount = 0; + DBGLOG(SCN, INFO, + "SEARCH: Try to join BSS again,Status Code=%d (Curr=%u/Last Join=%u)\n", + prStaRec->u2StatusCode, rCurrentTime, prStaRec->rLastJoinTime); + } else { + DBGLOG(SCN, INFO, + "SEARCH: Ignore BSS which reach maximum Join Retry Count = %d\n", + JOIN_MAX_RETRY_FAILURE_COUNT); + continue; + } + + } + } + /* 4 <4> Check for various NETWORK conditions */ + if (eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + + /* 4 <4.1> Check BSS Type for the corresponding Operation Mode in Connection Setting */ + /* NOTE(Kevin): For NET_TYPE_AUTO_SWITCH, we will always pass following check. */ + if (((prConnSettings->eOPMode == NET_TYPE_INFRA) && + (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE)) +#if CFG_SUPPORT_ADHOC + || ((prConnSettings->eOPMode == NET_TYPE_IBSS + || prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) + && (prBssDesc->eBSSType != BSS_TYPE_IBSS)) +#endif + ) { + + DBGLOG(SCN, TRACE, "Cur OPMode %d, Ignore eBSSType = %d\n", + prConnSettings->eOPMode, prBssDesc->eBSSType); + continue; + } + /* 4 <4.2> Check AP's BSSID if OID_802_11_BSSID has been set. */ + if ((prConnSettings->fgIsConnByBssidIssued) && + (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE)) { + + if (UNEQUAL_MAC_ADDR(prConnSettings->aucBSSID, prBssDesc->aucBSSID)) { + + DBGLOG(SCN, TRACE, "SEARCH: Ignore due to BSSID was not matched!\n"); + continue; + } + } +#if CFG_SUPPORT_ADHOC + /* 4 <4.3> Check for AdHoc Mode */ + if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + OS_SYSTIME rCurrentTime; + + /* 4 <4.3.1> Check if this SCAN record has been updated recently for IBSS. */ + /* NOTE(Kevin): Because some STA may change its BSSID frequently after it + * create the IBSS - e.g. IPN2220, so we need to make sure we get the new one. + * For BSS, if the old record was matched, however it won't be able to pass + * the Join Process later. + */ + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_ADHOC_BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCN, LOUD, + "SEARCH: Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", + prBssDesc->aucBSSID); + continue; + } + /* 4 <4.3.2> Check Peer's capability */ + if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == WLAN_STATUS_FAILURE) { + + if (prPrimaryBssDesc) + DBGLOG(SCN, INFO, + "SEARCH: BSS DESC MAC: %pM, not supported AdHoc Mode.\n", + prPrimaryBssDesc->aucBSSID); + + continue; + } + /* 4 <4.3.3> Compare TSF */ + if (prBssInfo->fgIsBeaconActivated && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID)) { + + DBGLOG(SCN, LOUD, + "SEARCH: prBssDesc->fgIsLargerTSF = %d\n", prBssDesc->fgIsLargerTSF); + + if (!prBssDesc->fgIsLargerTSF) { + DBGLOG(SCN, INFO, + "SEARCH: Ignore BSS DESC MAC: [ %pM ], Smaller TSF\n", + prBssDesc->aucBSSID); + continue; + } + } + } +#endif /* CFG_SUPPORT_ADHOC */ + + } +#if 0 /* TODO(Kevin): For IBSS */ + /* 4 <2.c> Check if this SCAN record has been updated recently for IBSS. */ + /* NOTE(Kevin): Because some STA may change its BSSID frequently after it + * create the IBSS, so we need to make sure we get the new one. + * For BSS, if the old record was matched, however it won't be able to pass + * the Join Process later. + */ + if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", + prBssDesc->aucBSSID); + continue; + } + } + + if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) && + (prAdapter->eConnectionState == MEDIA_STATE_CONNECTED)) { + OS_SYSTIME rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(BSS_DESC_TIMEOUT_SEC))) { + DBGLOG(SCAN, TRACE, "Skip old record of BSS Descriptor - BSSID:[%pM]\n\n", + (prBssDesc->aucBSSID)); + continue; + } + } + /* 4 <4B> Check for IBSS AdHoc Mode. */ + /* Skip if one or more BSS Basic Rate are not supported by current AdHocMode */ + if (prPrimaryBssDesc->eBSSType == BSS_TYPE_IBSS) { + /* 4 <4B.1> Check if match the Capability of current IBSS AdHoc Mode. */ + if (ibssCheckCapabilityForAdHocMode(prAdapter, prPrimaryBssDesc) == WLAN_STATUS_FAILURE) { + + DBGLOG(SCAN, TRACE, + "Ignore BSS DESC MAC: %pM, Capability not supported for AdHoc Mode.\n", + prPrimaryBssDesc->aucBSSID); + + continue; + } + /* 4 <4B.2> IBSS Merge Decision Flow for SEARCH STATE. */ + if (prAdapter->fgIsIBSSActive && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prPrimaryBssDesc->aucBSSID)) { + + if (!fgIsLocalTSFRead) { + NIC_GET_CURRENT_TSF(prAdapter, &rCurrentTsf); + + DBGLOG(SCAN, TRACE, + "\n\nCurrent TSF : %08lx-%08lx\n\n", + rCurrentTsf.u.HighPart, rCurrentTsf.u.LowPart); + } + + if (rCurrentTsf.QuadPart > prPrimaryBssDesc->u8TimeStamp.QuadPart) { + DBGLOG(SCAN, TRACE, + "Ignore BSS DESC MAC: [%pM], Current BSSID: [%pM].\n", + prPrimaryBssDesc->aucBSSID, prBssInfo->aucBSSID); + + DBGLOG(SCAN, TRACE, + "\n\nBSS's TSF : %08lx-%08lx\n\n", + prPrimaryBssDesc->u8TimeStamp.u.HighPart, + prPrimaryBssDesc->u8TimeStamp.u.LowPart); + + prPrimaryBssDesc->fgIsLargerTSF = FALSE; + continue; + } else { + prPrimaryBssDesc->fgIsLargerTSF = TRUE; + } + + } + } + /* 4 <5> Check the Encryption Status. */ + if (rsnPerformPolicySelection(prPrimaryBssDesc)) { + + if (prPrimaryBssDesc->ucEncLevel > 0) { + fgIsFindBestEncryptionLevel = TRUE; + + fgIsFindFirst = FALSE; + } + } else { + /* Can't pass the Encryption Status Check, get next one */ + continue; + } + + /* For RSN Pre-authentication, update the PMKID canidate list for + same SSID and encrypt status */ + /* Update PMKID candicate list. */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnUpdatePmkidCandidateList(prPrimaryBssDesc); + if (prAdapter->rWifiVar.rAisBssInfo.u4PmkidCandicateCount) + prAdapter->rWifiVar.rAisBssInfo.fgIndicatePMKID = rsnCheckPmkidCandicate(); + } +#endif + + prPrimaryBssDesc = (P_BSS_DESC_T) NULL; + + /* 4 <6> Check current Connection Policy. */ + switch (prConnSettings->eConnectionPolicy) { + case CONNECT_BY_SSID_BEST_RSSI: + /* Choose Hidden SSID to join only if the `fgIsEnableJoin...` is TRUE */ + if (prAdapter->rWifiVar.fgEnableJoinToHiddenSSID && prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): following if () statement means that + * If Target is hidden, then we won't connect when user specify SSID_ANY policy. + */ + if (prConnSettings->ucSSIDLen) { + prPrimaryBssDesc = prBssDesc; + fgIsFindBestRSSI = TRUE; + } + + } else if (EQUAL_SSID(prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + prPrimaryBssDesc = prBssDesc; + fgIsFindBestRSSI = TRUE; + + DBGLOG(SCN, TRACE, "SEARCH: fgIsFindBestRSSI=TRUE, %d, prPrimaryBssDesc=[ %pM ]\n", + prBssDesc->ucRCPI, prPrimaryBssDesc->aucBSSID); + } + break; + + case CONNECT_BY_SSID_ANY: + /* NOTE(Kevin): In this policy, we don't know the desired + * SSID from user, so we should exclude the Hidden SSID from scan list. + * And because we refuse to connect to Hidden SSID node at the beginning, so + * when the JOIN Module deal with a BSS_DESC_T which has fgIsHiddenSSID == TRUE, + * then the Connection Settings must be valid without doubt. + */ + if (!prBssDesc->fgIsHiddenSSID) { + prPrimaryBssDesc = prBssDesc; + fgIsFindFirst = TRUE; + } + break; + + case CONNECT_BY_BSSID: + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnSettings->aucBSSID)) + prPrimaryBssDesc = prBssDesc; + break; + + default: + break; + } + + /* Primary Candidate was not found */ + if (prPrimaryBssDesc == NULL) + continue; + /* 4 <7> Check the Encryption Status. */ + if (prPrimaryBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { +#if CFG_SUPPORT_WAPI + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) { + DBGLOG(SCN, TRACE, "SEARCH: fgWapiMode == 1\n"); + + if (wapiPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { + fgIsFindFirst = TRUE; + } else { + /* Can't pass the Encryption Status Check, get next one */ + DBGLOG(SCN, TRACE, "SEARCH: WAPI cannot pass the Encryption Status Check!\n"); + continue; + } + } else +#endif +#if CFG_RSN_MIGRATION + if (rsnPerformPolicySelection(prAdapter, prPrimaryBssDesc)) { + if (prAisSpecBssInfo->fgCounterMeasure) { + DBGLOG(RSN, INFO, "Skip while at counter measure period!!!\n"); + continue; + } + + if (prPrimaryBssDesc->ucEncLevel > 0) { + fgIsFindBestEncryptionLevel = TRUE; + fgIsFindFirst = FALSE; + } +#if 0 + /* Update PMKID candicate list. */ + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnUpdatePmkidCandidateList(prPrimaryBssDesc); + if (prAisSpecBssInfo->u4PmkidCandicateCount) { + if (rsnCheckPmkidCandicate()) { + DBGLOG(RSN, WARN, + "Prepare a timer to indicate candidate %pM\n", + (prAisSpecBssInfo->arPmkidCache + [prAisSpecBssInfo->u4PmkidCacheCount]. + rBssidInfo.aucBssid))); + cnmTimerStopTimer(&prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(&prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC + (WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } + } +#endif + } else { + /* Can't pass the Encryption Status Check, get next one */ + continue; + } +#endif + } else { + /* Todo:: P2P and BOW Policy Selection */ + } + + prPrimaryStaRec = prStaRec; + + /* 4 <8> Compare the Candidate and the Primary Scan Record. */ + if (!prCandidateBssDesc) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + + /* 4 <8.1> Condition - Get the first matched one. */ + if (fgIsFindFirst) + break; + } else { +#if 0 /* TODO(Kevin): For security(TBD) */ + /* 4 <6B> Condition - Choose the one with best Encryption Score. */ + if (fgIsFindBestEncryptionLevel) { + if (prCandidateBssDesc->ucEncLevel < prPrimaryBssDesc->ucEncLevel) { + + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + + /* If reach here, that means they have the same Encryption Score. + */ + + /* 4 <6C> Condition - Give opportunity to the one we didn't connect before. */ + /* For roaming, only compare the candidates other than current associated BSSID. */ + if (!prCandidateBssDesc->fgIsConnected && !prPrimaryBssDesc->fgIsConnected) { + if ((prCandidateStaRec != (P_STA_RECORD_T) NULL) && + (prCandidateStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { + + DBGLOG(SCAN, TRACE, + "So far -BSS DESC MAC: %pM has nonzero Status Code = %d\n", + prCandidateBssDesc->aucBSSID, + prCandidateStaRec->u2StatusCode); + + if (prPrimaryStaRec != (P_STA_RECORD_T) NULL) { + if (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + + /* Give opportunity to the one with smaller rLastJoinTime */ + if (TIME_BEFORE(prCandidateStaRec->rLastJoinTime, + prPrimaryStaRec->rLastJoinTime)) { + continue; + } + /* We've connect to CANDIDATE recently, + * let us try PRIMARY now */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + /* PRIMARY's u2StatusCode = 0 */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + /* PRIMARY has no StaRec - We didn't connet to PRIMARY before */ + else { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else { + if ((prPrimaryStaRec != (P_STA_RECORD_T) NULL) && + (prPrimaryStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL)) { + continue; + } + } + } +#endif + + /* 4 <6D> Condition - Visible SSID win Hidden SSID. */ + if (prCandidateBssDesc->fgIsHiddenSSID) { + if (!prPrimaryBssDesc->fgIsHiddenSSID) { + prCandidateBssDesc = prPrimaryBssDesc; /* The non Hidden SSID win. */ + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else { + if (prPrimaryBssDesc->fgIsHiddenSSID) + continue; + } + + /* 4 <6E> Condition - Choose the one with better RCPI(RSSI). */ + if (fgIsFindBestRSSI) { + /* TODO(Kevin): We shouldn't compare the actual value, we should + * allow some acceptable tolerance of some RSSI percentage here. + */ + DBGLOG(SCN, TRACE, + "Candidate [%pM]: RCPI = %d, joinFailCnt=%d, Primary [%pM]: RCPI = %d, joinFailCnt=%d\n", + prCandidateBssDesc->aucBSSID, + prCandidateBssDesc->ucRCPI, prCandidateBssDesc->ucJoinFailureCount, + prPrimaryBssDesc->aucBSSID, + prPrimaryBssDesc->ucRCPI, prPrimaryBssDesc->ucJoinFailureCount); + + ASSERT(!(prCandidateBssDesc->fgIsConnected && prPrimaryBssDesc->fgIsConnected)); + if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) { + /* give a chance to do join if join fail before + * SCN_BSS_DECRASE_JOIN_FAIL_CNT_SEC seconds + */ + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rJoinFailTime, + SEC_TO_SYSTIME(SCN_BSS_JOIN_FAIL_CNT_RESET_SEC))) { + prBssDesc->ucJoinFailureCount = SCN_BSS_JOIN_FAIL_THRESOLD - + SCN_BSS_JOIN_FAIL_RESET_STEP; + DBGLOG(SCN, INFO, + "decrease join fail count for Bss %pM to %u, timeout second %d\n", + prBssDesc->aucBSSID, prBssDesc->ucJoinFailureCount, + SCN_BSS_JOIN_FAIL_CNT_RESET_SEC); + } + } + + /* NOTE: To prevent SWING, + * we do roaming only if target AP has at least 5dBm larger than us. */ + if (prCandidateBssDesc->fgIsConnected) { + if (prCandidateBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP <= + prPrimaryBssDesc->ucRCPI && + prPrimaryBssDesc->ucJoinFailureCount < SCN_BSS_JOIN_FAIL_THRESOLD) { + + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else if (prPrimaryBssDesc->fgIsConnected) { + if (prCandidateBssDesc->ucRCPI < + (prPrimaryBssDesc->ucRCPI + ROAMING_NO_SWING_RCPI_STEP) || + (prCandidateBssDesc->ucJoinFailureCount >= + SCN_BSS_JOIN_FAIL_THRESOLD)) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else if (prPrimaryBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD) + continue; + else if (prCandidateBssDesc->ucJoinFailureCount >= SCN_BSS_JOIN_FAIL_THRESOLD || + prCandidateBssDesc->ucRCPI < prPrimaryBssDesc->ucRCPI) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } +#if 0 + /* If reach here, that means they have the same Encryption Score, and + * both RSSI value are close too. + */ + /* 4 <6F> Seek the minimum Channel Load for less interference. */ + if (fgIsFindMinChannelLoad) { + /* Do nothing */ + /* TODO(Kevin): Check which one has minimum channel load in its channel */ + } +#endif + } + } + + + if (prCandidateBssDesc != NULL) { + DBGLOG(SCN, INFO, + "SEARCH: Candidate BSS: %pM\n", prCandidateBssDesc->aucBSSID); + } + + return prCandidateBssDesc; + +} /* end of scanSearchBssDescByPolicy() */ + +#if CFG_SUPPORT_AGPS_ASSIST +VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter) +{ + P_LINK_T prBSSDescList = &prAdapter->rWifiVar.rScanInfo.rBSSDescList; + P_BSS_DESC_T prBssDesc = NULL; + P_AGPS_AP_LIST_T prAgpsApList; + P_AGPS_AP_INFO_T prAgpsInfo; + P_SCAN_INFO_T prScanInfo = &prAdapter->rWifiVar.rScanInfo; + UINT_8 ucIndex = 0; + + prAgpsApList = kalMemAlloc(sizeof(AGPS_AP_LIST_T), VIR_MEM_TYPE); + if (!prAgpsApList) + return; + + prAgpsInfo = &prAgpsApList->arApInfo[0]; + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + if (prBssDesc->rUpdateTime < prScanInfo->rLastScanCompletedTime) + continue; + COPY_MAC_ADDR(prAgpsInfo->aucBSSID, prBssDesc->aucBSSID); + prAgpsInfo->ePhyType = AGPS_PHY_G; + prAgpsInfo->u2Channel = prBssDesc->ucChannelNum; + prAgpsInfo->i2ApRssi = RCPI_TO_dBm(prBssDesc->ucRCPI); + prAgpsInfo++; + ucIndex++; + if (ucIndex == 32) + break; + } + prAgpsApList->ucNum = ucIndex; + GET_CURRENT_SYSTIME(&prScanInfo->rLastScanCompletedTime); + /* DBGLOG(SCN, INFO, ("num of scan list:%d\n", ucIndex)); */ + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_AP_LIST, (PUINT_8) prAgpsApList, sizeof(AGPS_AP_LIST_T)); + kalMemFree(prAgpsApList, VIR_MEM_TYPE, sizeof(AGPS_AP_LIST_T)); +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c new file mode 100644 index 0000000000000..fac9f94428dd9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/scan_fsm.c @@ -0,0 +1,2136 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/scan_fsm.c#1 +*/ + +/*! \file "scan_fsm.c" + \brief This file defines the state transition function for SCAN FSM. + + The SCAN FSM is part of SCAN MODULE and responsible for performing basic SCAN + behavior as metioned in IEEE 802.11 2007 11.1.3.1 & 11.1.3.2 . +*/ + +/* +** Log: scan_fsm.c + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 14 2011 yuche.tsai + * [WCXRP00001095] [Volunteer Patch][Driver] Always Scan before enable Hot-Spot. + * Fix bug when unregister P2P network.. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search + * for more than one SSID in a single scanning request + * free mailbox message afte parsing is completed. + * + * 07 18 2011 cp.wu + * [WCXRP00000858] [MT5931][Driver][Firmware] Add support for scan to search + * for more than one SSID in a single scanning request + * add framework in driver domain for supporting new SCAN_REQ_V2 for more than 1 SSID support + * as well as uProbeDelay in NDIS 6.x driver model + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 29 2011 cp.wu + * [WCXRP00000604] [MT6620 Wi-Fi][Driver] Surpress Klockwork Warning + * surpress klock warning with code path rewritten + * + * 03 18 2011 cm.chang + * [WCXRP00000576] [MT6620 Wi-Fi][Driver][FW] Remove P2P compile option in scan req/cancel command + * As CR title + * + * 02 18 2011 yuche.tsai + * [WCXRP00000478] [Volunteer Patch][MT6620][Driver] Probe request frame + * during search phase do not contain P2P wildcard SSID. + * Take P2P wildcard SSID into consideration. + * + * 01 27 2011 yuche.tsai + * [WCXRP00000399] [Volunteer Patch][MT6620/MT5931][Driver] Fix scan side effect after P2P module separate. + * Fix scan channel extension issue when p2p module is not registered. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * add interface for RLM to trigger OBSS-SCAN. + * + * 08 16 2010 yuche.tsai + * NULL + * Fix bug for processing queued scan request. + * + * 08 11 2010 yuche.tsai + * NULL + * Add a function for returning channel. + * + * 08 05 2010 yuche.tsai + * NULL + * Update SCAN FSM for support P2P Device discovery scan. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 07 26 2010 yuche.tsai + * + * Add option of channel extension while cancelling scan request. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 20 2010 cp.wu + * + * pass band information for scan in an efficient way by mapping ENUM_BAND_T into UINT_8.. + * + * 07 19 2010 cp.wu + * + * due to FW/DRV won't be sync. precisely, some strict assertions should be eased. + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * SCN module is now able to handle multiple concurrent scanning requests + * + * 07 16 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * bugfix for SCN migration + * 1) modify QUEUE_CONCATENATE_QUEUES() so it could be used to concatence with an empty queue + * 2) before AIS issues scan request, network(BSS) needs to be activated first + * 3) only invoke COPY_SSID when using specified SSID for scan + * + * 07 15 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * driver no longer generates probe request frames + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * pass band with channel number information as scan parameter + * + * 07 14 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * remove timer in DRV-SCN. + * + * 07 09 2010 cp.wu + * + * 1) separate AIS_FSM state for two kinds of scanning. (OID triggered scan, and scan-for-connection) + * 2) eliminate PRE_BSS_DESC_T, Beacon/PrebResp is now parsed in single pass + * 3) implment DRV-SCN module, currently only accepts single scan request, + * other request will be directly dropped by returning BUSY + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * take use of RLM module for parsing/generating HT IEs for 11n capability + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * when returning to SCAN_IDLE state, send a correct message to source FSM. + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * comment out RLM APIs by CFG_RLM_MIGRATION. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add scan_fsm into building. + * + * 05 14 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine the order of Stop TX Queue and Switch Channel + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Update pause/resume/flush API to new Bitmap API + * + * 05 12 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Add Power Management - Legacy PS-POLL support. + * + * 03 18 2010 kevin.huang + * [BORA00000663][WIFISYS][New Feature] AdHoc Mode Support + * Ignore the PROBE_DELAY state if the value of Probe Delay == 0 + * + * 03 10 2010 kevin.huang + * [BORA00000654][WIFISYS][New Feature] CNM Module - Ch Manager Support + * Add Channel Manager for arbitration of JOIN and SCAN Req + * + * 02 23 2010 kevin.huang + * [BORA00000603][WIFISYS] [New Feature] AAA Module Support + * Add support scan channel 1~14 and update scan result's frequency infou1rwduu`wvpghlqg|n`slk+mpdkb + * + * 01 08 2010 kevin.huang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * Add set RX Filter to receive BCN from different BSSID during SCAN + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Nov 25 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Remove flag of CFG_TEST_MGMT_FSM + * + * Nov 20 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Change parameter of scanSendProbeReqFrames() + * + * Nov 16 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Update scnFsmSteps() + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * Fix typo + * + * Nov 5 2009 mtk01461 + * [BORA00000018] Integrate WIFI part into BORA for the 1st time + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugScanState[SCAN_STATE_NUM] = { + (PUINT_8) DISP_STRING("SCAN_STATE_IDLE"), + (PUINT_8) DISP_STRING("SCAN_STATE_SCANNING"), +}; + +/*lint -restore */ +#endif /* DBG */ + +#define CURRENT_PSCN_VERSION 1 +#define RSSI_MARGIN_DEFAULT 5 +#define MAX_PERIOD 200000 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prMsgHdr; + + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + do { + +#if DBG + DBGLOG(SCN, STATE, "TRANSITION: [%s] -> [%s]\n", + apucDebugScanState[prScanInfo->eCurrentState], apucDebugScanState[eNextState]); +#else + DBGLOG(SCN, STATE, "[%d] TRANSITION: [%d] -> [%d]\n", + DBG_SCN_IDX, prScanInfo->eCurrentState, eNextState); +#endif + + /* NOTE(Kevin): This is the only place to change the eCurrentState(except initial) */ + prScanInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN) FALSE; + + switch (prScanInfo->eCurrentState) { + case SCAN_STATE_IDLE: + /* check for pending scanning requests */ + if (!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { + /* load next message from pending list as scan parameters */ + LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, P_MSG_HDR_T); + + if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); + } else { + scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); + } + + /* switch to next state */ + eNextState = SCAN_STATE_SCANNING; + fgIsTransition = TRUE; + + cnmMemFree(prAdapter, prMsgHdr); + } + break; + + case SCAN_STATE_SCANNING: + if (prScanParam->fgIsScanV2 == FALSE) + scnSendScanReq(prAdapter); + else + scnSendScanReqV2(prAdapter); + break; + + default: + ASSERT(0); + break; + + } + } while (fgIsTransition); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnSendScanReqExtCh(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + /*CMD_SCAN_REQ_EXT_CH rCmdScanReq;*/ + P_CMD_SCAN_REQ_EXT_CH prCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_EXT_CH), VIR_MEM_TYPE); + if (prCmdScanReq == NULL) + return; + + /* send command packet for scan */ + kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_EXT_CH)); + + prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; + prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; + prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; + prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; + + if (prScanParam->ucSSIDNum == 1) { + COPY_SSID(prCmdScanReq->aucSSID, + prCmdScanReq->ucSSIDLength, + prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); + } + + prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) + */ + prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { + prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + prCmdScanReq->arChannelList[i].ucChannelNum = + (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; +#endif + + if (prScanParam->u2IELen <= MAX_IE_LENGTH) + prCmdScanReq->u2IELen = prScanParam->u2IELen; + else + prCmdScanReq->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ_EXT_CH, aucIE) + prCmdScanReq->u2IELen, + (PUINT_8) prCmdScanReq, NULL, 0); + /* sanity check for some scan parameters */ + if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) + kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); + else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) + kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); + else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && + prCmdScanReq->ucChannelListNum != 0) + kalSendAeeWarning("wlan", + "channel list is not NULL but channel type is not specified"); + else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) + kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); + else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ + kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); + else if (prCmdScanReq->ucSSIDLength > 32) + kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); + + kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_EXT_CH)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnSendScanReq(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + /*CMD_SCAN_REQ rCmdScanReq;*/ + P_CMD_SCAN_REQ prCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanParam->ucChannelListNum > 32) { + scnSendScanReqExtCh(prAdapter); + } else { + prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ), VIR_MEM_TYPE); + if (prCmdScanReq == NULL) { + DBGLOG(SCN, INFO, "alloc CmdScanReq fail"); + return; + } + /* send command packet for scan */ + kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ)); + + prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; + prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; + prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; + prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; + + if (prScanParam->ucSSIDNum == 1) { + COPY_SSID(prCmdScanReq->aucSSID, + prCmdScanReq->ucSSIDLength, + prScanParam->aucSpecifiedSSID[0], prScanParam->ucSpecifiedSSIDLen[0]); + } + + prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. + * (Target != NULL) + */ + prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { + prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + prCmdScanReq->arChannelList[i].ucChannelNum = + (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; +#endif +#if CFG_ENABLE_FAST_SCAN + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_AIS_INDEX) + prCmdScanReq->u2ChannelDwellTime = CFG_FAST_SCAN_DWELL_TIME; +#endif + if (prScanParam->u2IELen <= MAX_IE_LENGTH) + prCmdScanReq->u2IELen = prScanParam->u2IELen; + else + prCmdScanReq->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ, aucIE) + prCmdScanReq->u2IELen, + (PUINT_8) prCmdScanReq, NULL, 0); + /* sanity check for some scan parameters */ + if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) + kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); + else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) + kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); + else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && + prCmdScanReq->ucChannelListNum != 0) + kalSendAeeWarning("wlan", + "channel list is not NULL but channel type is not specified"); + else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) + kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); + else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ + kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); + else if (prCmdScanReq->ucSSIDLength > 32) + kalSendAeeWarning("wlan", "wrong ssid length %d", prCmdScanReq->ucSSIDLength); + + kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ_V2 command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnSendScanReqV2ExtCh(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + /*CMD_SCAN_REQ_V2_EXT_CH rCmdScanReq;*/ + P_CMD_SCAN_REQ_V2_EXT_CH prCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2_EXT_CH), VIR_MEM_TYPE); + if (prCmdScanReq == NULL) + return; + + /* send command packet for scan */ + kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); + + prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; + prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; + prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; + prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; + + for (i = 0; i < prScanParam->ucSSIDNum; i++) { + COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, + prCmdScanReq->arSSID[i].u4SsidLen, + prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); + } + + prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; + prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. (Target != NULL) + */ + prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { + prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + prCmdScanReq->arChannelList[i].ucChannelNum = + (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; +#endif + + if (prScanParam->u2IELen <= MAX_IE_LENGTH) + prCmdScanReq->u2IELen = prScanParam->u2IELen; + else + prCmdScanReq->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ_V2, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ_V2_EXT_CH, aucIE) + prCmdScanReq->u2IELen, + (PUINT_8) prCmdScanReq, NULL, 0); + /* sanity check for some scan parameters */ + if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) + kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); + else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) + kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); + else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && + prCmdScanReq->ucChannelListNum != 0) + kalSendAeeWarning("wlan", + "channel list is not NULL but channel type is not specified"); + else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) + kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); + else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ + kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); + + kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2_EXT_CH)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Generate CMD_ID_SCAN_REQ_V2 command +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnSendScanReqV2(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + /*CMD_SCAN_REQ_V2 rCmdScanReq;*/ + P_CMD_SCAN_REQ_V2 prCmdScanReq; + UINT_32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanParam->ucChannelListNum > 32) { + scnSendScanReqV2ExtCh(prAdapter); + } else { + prCmdScanReq = kalMemAlloc(sizeof(CMD_SCAN_REQ_V2), VIR_MEM_TYPE); + if (prCmdScanReq == NULL) { + DBGLOG(SCN, INFO, "alloc CmdScanReq v2 fail"); + return; + } + /* send command packet for scan */ + kalMemZero(prCmdScanReq, sizeof(CMD_SCAN_REQ_V2)); + + prCmdScanReq->ucSeqNum = prScanParam->ucSeqNum; + prCmdScanReq->ucNetworkType = (UINT_8) prScanParam->eNetTypeIndex; + prCmdScanReq->ucScanType = (UINT_8) prScanParam->eScanType; + prCmdScanReq->ucSSIDType = prScanParam->ucSSIDType; + + for (i = 0; i < prScanParam->ucSSIDNum; i++) { + COPY_SSID(prCmdScanReq->arSSID[i].aucSsid, + prCmdScanReq->arSSID[i].u4SsidLen, + prScanParam->aucSpecifiedSSID[i], prScanParam->ucSpecifiedSSIDLen[i]); + } + + prCmdScanReq->u2ProbeDelayTime = (UINT_8) prScanParam->u2ProbeDelayTime; + prCmdScanReq->ucChannelType = (UINT_8) prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan for SEARCH state. + * (Target != NULL) + */ + prCmdScanReq->ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < prCmdScanReq->ucChannelListNum; i++) { + prCmdScanReq->arChannelList[i].ucBand = (UINT_8) prScanParam->arChnlInfoList[i].eBand; + + prCmdScanReq->arChannelList[i].ucChannelNum = + (UINT_8) prScanParam->arChnlInfoList[i].ucChannelNum; + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prCmdScanReq->u2ChannelDwellTime = prScanParam->u2PassiveListenInterval; +#endif + if (prScanParam->u2IELen <= MAX_IE_LENGTH) + prCmdScanReq->u2IELen = prScanParam->u2IELen; + else + prCmdScanReq->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prCmdScanReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdScanReq->u2IELen); + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_REQ_V2, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ_V2, aucIE) + prCmdScanReq->u2IELen, + (PUINT_8) prCmdScanReq, NULL, 0); + /* sanity check for some scan parameters */ + if (prCmdScanReq->ucScanType >= SCAN_TYPE_NUM) + kalSendAeeWarning("wlan", "wrong scan type %d", prCmdScanReq->ucScanType); + else if (prCmdScanReq->ucChannelType >= SCAN_CHANNEL_NUM) + kalSendAeeWarning("wlan", "wrong channel type %d", prCmdScanReq->ucChannelType); + else if (prCmdScanReq->ucChannelType != SCAN_CHANNEL_SPECIFIED && + prCmdScanReq->ucChannelListNum != 0) + kalSendAeeWarning("wlan", + "channel list is not NULL but channel type is not specified"); + else if (prCmdScanReq->ucNetworkType >= NETWORK_TYPE_INDEX_NUM) + kalSendAeeWarning("wlan", "wrong network type %d", prCmdScanReq->ucNetworkType); + else if (prCmdScanReq->ucSSIDType >= BIT(4)) /* ssid type is wrong */ + kalSendAeeWarning("wlan", "wrong ssid type %d", prCmdScanReq->ucSSIDType); + + kalMemFree(prCmdScanReq, VIR_MEM_TYPE, sizeof(CMD_SCAN_REQ_V2)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + + ASSERT(prMsgHdr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanInfo->eCurrentState == SCAN_STATE_IDLE) { + if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ) prMsgHdr); + } else if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 + || prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2) prMsgHdr); + } else { + /* should not deliver to this function */ + ASSERT(0); + } + + cnmMemFree(prAdapter, prMsgHdr); + scnFsmSteps(prAdapter, SCAN_STATE_SCANNING); + } else { + LINK_INSERT_TAIL(&prScanInfo->rPendingMsgList, &prMsgHdr->rLinkEntry); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancel; + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_CANCEL rCmdScanCancel; + + ASSERT(prMsgHdr); + + prScanCancel = (P_MSG_SCN_SCAN_CANCEL) prMsgHdr; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanInfo->eCurrentState != SCAN_STATE_IDLE) { + if (prScanCancel->ucSeqNum == prScanParam->ucSeqNum && + prScanCancel->ucNetTypeIndex == (UINT_8) prScanParam->eNetTypeIndex) { + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = prScanParam->ucSeqNum; + +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + rCmdScanCancel.ucIsExtChannel = (UINT_8) prScanCancel->fgIsChannelExt; + else + rCmdScanCancel.ucIsExtChannel = (UINT_8) FALSE; +#endif + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SCAN_CANCEL, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_SCAN_CANCEL), (PUINT_8) &rCmdScanCancel, NULL, 0); + + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, + prScanParam->ucSeqNum, + (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_CANCELLED); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } else { + scnFsmRemovePendingMsg(prAdapter, prScanCancel->ucSeqNum, prScanCancel->ucNetTypeIndex); + } + } + + cnmMemFree(prAdapter, prMsgHdr); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Scan Message Parsing (Legacy) +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ prScanReqMsg) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + if (prScanParam->ucSSIDType & (SCAN_REQ_SSID_SPECIFIED | SCAN_REQ_SSID_P2P_WILDCARD)) { + prScanParam->ucSSIDNum = 1; + + COPY_SSID(prScanParam->aucSpecifiedSSID[0], + prScanParam->ucSpecifiedSSIDLen[0], prScanReqMsg->aucSSID, prScanReqMsg->ucSSIDLength); + + /* reset SSID length to zero for rest array entries */ + for (i = 1; i < SCN_SSID_MAX_NUM; i++) + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } else { + prScanParam->ucSSIDNum = 0; + + for (i = 0; i < SCN_SSID_MAX_NUM; i++) + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } + + prScanParam->u2ProbeDelayTime = 0; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + else + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + + kalMemCopy(prScanParam->arChnlInfoList, + prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) + prScanParam->u2IELen = prScanReqMsg->u2IELen; + else + prScanParam->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; +#endif + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) + prScanParam->fgIsObssScan = TRUE; + else + prScanParam->fgIsObssScan = FALSE; + + prScanParam->fgIsScanV2 = FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Scan Message Parsing - V2 with multiple SSID support +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + UINT_32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + ASSERT(prScanReqMsg->ucSSIDNum <= SCN_SSID_MAX_NUM); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->eNetTypeIndex = (ENUM_NETWORK_TYPE_INDEX_T) prScanReqMsg->ucNetTypeIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + prScanParam->ucSSIDNum = prScanReqMsg->ucSSIDNum; + + for (i = 0; i < prScanReqMsg->ucSSIDNum; i++) { + COPY_SSID(prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i], + prScanReqMsg->prSsid[i].aucSsid, (UINT_8) prScanReqMsg->prSsid[i].u4SsidLen); + } + + prScanParam->u2ProbeDelayTime = prScanReqMsg->u2ProbeDelay; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + else + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + + kalMemCopy(prScanParam->arChnlInfoList, + prScanReqMsg->arChnlInfoList, sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) + prScanParam->u2IELen = prScanReqMsg->u2IELen; + else + prScanParam->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, prScanParam->u2IELen); +#if CFG_ENABLE_WIFI_DIRECT + if (prScanParam->eNetTypeIndex == NETWORK_TYPE_P2P_INDEX) + prScanParam->u2PassiveListenInterval = prScanReqMsg->u2ChannelDwellTime; +#endif + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) + prScanParam->fgIsObssScan = TRUE; + else + prScanParam->fgIsObssScan = FALSE; + + prScanParam->fgIsScanV2 = TRUE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Remove pending scan request +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prPendingMsgHdr, prPendingMsgHdrNext, prRemoveMsgHdr = NULL; + P_LINK_ENTRY_T prRemoveLinkEntry = NULL; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* traverse through rPendingMsgList for removal */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingMsgHdr, + prPendingMsgHdrNext, &(prScanInfo->rPendingMsgList), rLinkEntry, MSG_HDR_T) { + if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ + || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + P_MSG_SCN_SCAN_REQ prScanReqMsg = (P_MSG_SCN_SCAN_REQ) prPendingMsgHdr; + + if (ucSeqNum == prScanReqMsg->ucSeqNum && ucNetTypeIndex == prScanReqMsg->ucNetTypeIndex) { + prRemoveLinkEntry = &(prScanReqMsg->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + } + } else if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 + || prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + P_MSG_SCN_SCAN_REQ_V2 prScanReqMsgV2 = (P_MSG_SCN_SCAN_REQ_V2) prPendingMsgHdr; + + if (ucSeqNum == prScanReqMsgV2->ucSeqNum && ucNetTypeIndex == prScanReqMsgV2->ucNetTypeIndex) { + prRemoveLinkEntry = &(prScanReqMsgV2->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + } + } + + if (prRemoveLinkEntry) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, ucSeqNum, ucNetTypeIndex, SCAN_STATUS_CANCELLED); + + /* remove from pending list */ + LINK_REMOVE_KNOWN_ENTRY(&(prScanInfo->rPendingMsgList), prRemoveLinkEntry); + cnmMemFree(prAdapter, prRemoveMsgHdr); + + break; + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* buffer empty channel information */ + if (prScanParam->eScanChannel == SCAN_CHANNEL_FULL || prScanParam->eScanChannel == SCAN_CHANNEL_2G4) { + if (prScanDone->ucSparseChannelValid) { + prScanInfo->fgIsSparseChannelValid = TRUE; + prScanInfo->rSparseChannel.eBand = (ENUM_BAND_T) prScanDone->rSparseChannel.ucBand; + prScanInfo->rSparseChannel.ucChannelNum = prScanDone->rSparseChannel.ucChannelNum; + } else { + prScanInfo->fgIsSparseChannelValid = FALSE; + } + } + + if (prScanInfo->eCurrentState == SCAN_STATE_SCANNING && prScanDone->ucSeqNum == prScanParam->ucSeqNum) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, + prScanParam->ucSeqNum, (UINT_8) prScanParam->eNetTypeIndex, SCAN_STATUS_DONE); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } else { + DBGLOG(SCN, WARN, "Unexpected SCAN-DONE event: SeqNum = %d, Current State = %d\n", + prScanDone->ucSeqNum, prScanInfo->eCurrentState); + } + +} /* end of scnEventScanDone */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSeqNum, IN UINT_8 ucNetTypeIndex, IN ENUM_SCAN_STATUS eScanStatus) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + DBGLOG(SCN, INFO, "Rcv Scan Done, NetIdx %d, Obss %d, Status %d, Seq %d\n", + ucNetTypeIndex, prScanParam->fgIsObssScan, eScanStatus, ucSeqNum); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_DONE)); + if (!prScanDoneMsg) { + ASSERT(0); /* Can't indicate SCAN FSM Complete */ + return; + } + + if (prScanParam->fgIsObssScan == TRUE) { + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_RLM_SCAN_DONE; + } else { + switch ((ENUM_NETWORK_TYPE_INDEX_T) ucNetTypeIndex) { + case NETWORK_TYPE_AIS_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_AIS_SCAN_DONE; + break; + +#if CFG_ENABLE_WIFI_DIRECT + case NETWORK_TYPE_P2P_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_P2P_SCAN_DONE; + break; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + case NETWORK_TYPE_BOW_INDEX: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_BOW_SCAN_DONE; + break; +#endif + + default: + ASSERT(0); + break; + } + } + + prScanDoneMsg->ucSeqNum = ucSeqNum; + prScanDoneMsg->ucNetTypeIndex = ucNetTypeIndex; + prScanDoneMsg->eScanStatus = eScanStatus; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prScanDoneMsg, MSG_SEND_METHOD_BUF); + +} /* end of scnFsmGenerateScanDoneMsg() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Query for most sparse channel +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, PUINT_8 pucSparseChannel) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prScanInfo->fgIsSparseChannelValid == TRUE) { + if (prSparseBand) + *prSparseBand = prScanInfo->rSparseChannel.eBand; + + if (pucSparseChannel) + *pucSparseChannel = prScanInfo->rSparseChannel.ucChannelNum; + + return TRUE; + } else { + return FALSE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Event handler for NLO done event +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + if (prScanInfo->fgNloScanning == TRUE) { + DBGLOG(SCN, INFO, "scnEventNloDone Current State = %d\n", prScanInfo->eCurrentState); + + kalSchedScanResults(prAdapter->prGlueInfo); + + if (prNloParam->fgStopAfterIndication == TRUE) + prScanInfo->fgNloScanning = FALSE; + + kalMemZero(&prNloParam->aprPendingBssDescToInd[0], + CFG_SCAN_SSID_MATCH_MAX_NUM * sizeof(P_BSS_DESC_T)); + } else { + DBGLOG(SCN, INFO, "Unexpected NLO-DONE event\n"); + } + +} + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for starting scheduled scan +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, IN UINT_32 u4IeLength, IN PUINT_8 pucIe, IN UINT_16 u2Interval) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + P_CMD_NLO_REQ prCmdNloReq; + UINT_32 i, j; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + if (prScanInfo->fgNloScanning) { + DBGLOG(SCN, INFO, "prScanInfo->fgNloScanning == TRUE already scanning\n"); + return TRUE; + } + + prScanInfo->fgNloScanning = TRUE; + + /* 1. load parameters */ + prScanParam->ucSeqNum++; + /* prScanParam->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; */ + + prNloParam->fgStopAfterIndication = TRUE; + prNloParam->ucFastScanIteration = 0; + prNloParam->u2FastScanPeriod = u2Interval; + prNloParam->u2SlowScanPeriod = u2Interval; + + if (prScanParam->ucSSIDNum > CFG_SCAN_SSID_MAX_NUM) + prScanParam->ucSSIDNum = CFG_SCAN_SSID_MAX_NUM; + else + prScanParam->ucSSIDNum = ucSsidNum; + + if (prNloParam->ucMatchSSIDNum > CFG_SCAN_SSID_MATCH_MAX_NUM) + prNloParam->ucMatchSSIDNum = CFG_SCAN_SSID_MATCH_MAX_NUM; + else + prNloParam->ucMatchSSIDNum = ucSsidNum; + + for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { + if (i < CFG_SCAN_SSID_MAX_NUM) { + COPY_SSID(prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); + } + + COPY_SSID(prNloParam->aucMatchSSID[i], + prNloParam->ucMatchSSIDLen[i], prSsid[i].aucSsid, (UINT_8) prSsid[i].u4SsidLen); + + prNloParam->aucCipherAlgo[i] = 0; + prNloParam->au2AuthAlgo[i] = 0; + + for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) + prNloParam->aucChannelHint[i][j] = 0; + } + + /* 2. prepare command for sending */ + prCmdNloReq = (P_CMD_NLO_REQ) cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_NLO_REQ) + prScanParam->u2IELen); + + if (!prCmdNloReq) { + ASSERT(0); /* Can't initiate NLO operation */ + return FALSE; + } + + /* 3. send command packet for NLO operation */ + kalMemZero(prCmdNloReq, sizeof(CMD_NLO_REQ)); + + prCmdNloReq->ucSeqNum = prScanParam->ucSeqNum; + /* prCmdNloReq->ucBssIndex = prScanParam->ucBssIndex; */ + + prCmdNloReq->ucNetworkType = prScanParam->eNetTypeIndex; + prCmdNloReq->ucScanType = (UINT_8) prScanParam->eScanType; + + prCmdNloReq->fgStopAfterIndication = prNloParam->fgStopAfterIndication; + prCmdNloReq->ucFastScanIteration = prNloParam->ucFastScanIteration; + prCmdNloReq->u2FastScanPeriod = prNloParam->u2FastScanPeriod; + prCmdNloReq->u2SlowScanPeriod = prNloParam->u2SlowScanPeriod; + prCmdNloReq->ucEntryNum = prNloParam->ucMatchSSIDNum; + for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { + COPY_SSID(prCmdNloReq->arNetworkList[i].aucSSID, + prCmdNloReq->arNetworkList[i].ucSSIDLength, + prNloParam->aucMatchSSID[i], prNloParam->ucMatchSSIDLen[i]); + + prCmdNloReq->arNetworkList[i].ucCipherAlgo = prNloParam->aucCipherAlgo[i]; + prCmdNloReq->arNetworkList[i].u2AuthAlgo = prNloParam->au2AuthAlgo[i]; + + for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) + prCmdNloReq->arNetworkList[i].ucNumChannelHint[j] = prNloParam->aucChannelHint[i][j]; + } + + if (prScanParam->u2IELen <= MAX_IE_LENGTH) + prCmdNloReq->u2IELen = prScanParam->u2IELen; + else + prCmdNloReq->u2IELen = MAX_IE_LENGTH; + + if (prScanParam->u2IELen) + kalMemCopy(prCmdNloReq->aucIE, prScanParam->aucIE, sizeof(UINT_8) * prCmdNloReq->u2IELen); +#if !CFG_SUPPORT_GSCN + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NLO_REQ, + TRUE, + FALSE, + TRUE, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_NLO_REQ) + prCmdNloReq->u2IELen, (PUINT_8) prCmdNloReq, NULL, 0); + +#else + scnPSCNFsm(prAdapter, PSCN_RESET, prCmdNloReq, NULL, NULL, NULL, FALSE, FALSE, FALSE, FALSE); +#endif + cnmMemFree(prAdapter, (PVOID) prCmdNloReq); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for stopping scheduled scan +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + CMD_NLO_CANCEL rCmdNloCancel; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + /* send cancel message to firmware domain */ + rCmdNloCancel.ucSeqNum = prScanParam->ucSeqNum; + +#if !CFG_SUPPORT_GSCN + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_NLO_CANCEL, + TRUE, + FALSE, + TRUE, + nicCmdEventSetStopSchedScan, + nicOidCmdTimeoutCommon, sizeof(CMD_NLO_CANCEL), (PUINT_8)(&rCmdNloCancel), NULL, 0); +#else + + scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, NULL, TRUE, FALSE, FALSE, FALSE); +#endif + + prScanInfo->fgNloScanning = FALSE; + + return TRUE; +} + +#if CFG_SUPPORT_GSCN + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set PSCN action +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmPSCNAction(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPscanAct) +{ + CMD_SET_PSCAN_ENABLE rCmdPscnAction; + P_SCAN_INFO_T prScanInfo; + + DBGLOG(SCN, TRACE, "scnFsmPSCNAction Act = %d\n", ucPscanAct); + + rCmdPscnAction.ucPscanAct = ucPscanAct; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (ucPscanAct == DISABLE) + prScanInfo->fgPscnOnnning = FALSE; + if (ucPscanAct == ENABLE) + prScanInfo->fgPscnOnnning = TRUE; + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PSCN_ENABLE, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_ENABLE), (PUINT_8) &rCmdPscnAction, NULL, 0); + + DBGLOG(SCN, INFO, "scnFsmPSCNAction Act = %d is Set to FW\n", ucPscanAct); + return TRUE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set PSCN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmPSCNSetParam(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) +{ + UINT_8 i, j; + + i = 0; + j = 0; + + ASSERT(prAdapter); + /*prCmdPscnParam->u4BasePeriod = prCmdPscnParam->u4BasePeriod;*/ +#if 0 + DBGLOG(SCN, TRACE, + "rCmdPscnParam: Period[%u],NumCache[%u],Threshold[%u],NumBkts[%u],fgGSCN[%d] fgNLO[%d] fgBatch[%d]\n", + prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, + prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, + prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, prCmdPscnParam->fgBatchScnEnable)); + + for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { + DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); + DBGLOG(SCN, TRACE, + "band[%u], Index[%u] NumChannels[%u], ucBktFreqMultiple[%u] Flag[%u]\n", + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); + for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) + DBGLOG(SCN, TRACE, + " %d, ", prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); + DBGLOG(SCN, TRACE, "\n"); + } +#endif + + if (1 /*prScanInfo->fgPscnOnnning == FALSE */) { + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PSCAN_PARAM, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SET_PSCAN_PARAM), (PUINT_8) prCmdPscnParam, NULL, 0); + + DBGLOG(SCN, TRACE, "CMD_ID_SET_PSCAN_PARAM is set to FW !!!!!!!!!!\n"); + return TRUE; + } + return FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set hotlist +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmPSCNSetHotlist(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_HOTLIST_BSSID prCmdPscnAddHotlist) +{ + CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + memcpy(&rCmdPscnAddHotlist.aucMacAddr, &(prCmdPscnAddHotlist->aucMacAddr), sizeof(MAC_ADDR_LEN)); + + /* rCmdPscnAddHotlist.aucMacAddr = prCmdPscnAddHotlist->aucMacAddr; */ + rCmdPscnAddHotlist.ucFlags = prCmdPscnAddHotlist->ucFlags; + + if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PSCN_ADD_HOTLIST_BSSID, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_SET_PSCAN_ADD_HOTLIST_BSSID), (PUINT_8) &rCmdPscnAddHotlist, NULL, 0); + return TRUE; + } + /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ + return FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set CMD_ID_SET_PSCN_ADD_SW_BSSID +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmPSCNAddSWCBssId(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_ADD_SWC_BSSID prCmdPscnAddSWCBssId) +{ + CMD_SET_PSCAN_ADD_SWC_BSSID rCmdPscnAddSWCBssId; + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + memcpy(&rCmdPscnAddSWCBssId.aucMacAddr, &(prCmdPscnAddSWCBssId->aucMacAddr), sizeof(MAC_ADDR_LEN)); + + /* rCmdPscnAddSWCBssId.aucMacAddr = prCmdPscnAddSWCBssId->aucMacAddr; */ + rCmdPscnAddSWCBssId.i4RssiHighThreshold = prCmdPscnAddSWCBssId->i4RssiHighThreshold; + rCmdPscnAddSWCBssId.i4RssiLowThreshold = prCmdPscnAddSWCBssId->i4RssiLowThreshold; + + if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PSCN_ADD_SW_BSSID, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_SET_PSCAN_ADD_SWC_BSSID), (PUINT_8) &rCmdPscnAddSWCBssId, NULL, 0); + return TRUE; + } + /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ + return FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmPSCNSetMacAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_SET_PSCAN_MAC_ADDR prCmdPscnSetMacAddr) +{ + CMD_SET_PSCAN_MAC_ADDR rCmdPscnSetMacAddr; + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + /* rCmdPscnSetMacAddr.aucMacAddr = prCmdPscnSetMacAddr->aucMacAddr; */ + memcpy(&rCmdPscnSetMacAddr.aucMacAddr, &(prCmdPscnSetMacAddr->aucMacAddr), sizeof(MAC_ADDR_LEN)); + + rCmdPscnSetMacAddr.ucFlags = prCmdPscnSetMacAddr->ucFlags; + rCmdPscnSetMacAddr.ucVersion = prCmdPscnSetMacAddr->ucVersion; + + if (1 /* (prScanInfo->fgPscnOnnning == TRUE */) { + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PSCN_MAC_ADDR, + TRUE, + FALSE, + FALSE, + NULL, + NULL, sizeof(CMD_SET_PSCAN_MAC_ADDR), (PUINT_8) &rCmdPscnSetMacAddr, NULL, 0); + return TRUE; + } + /* debug msg, No PSCN, Sched SCAN no need to add the hotlist ??? */ + return FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set GSCN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnSetGSCNParam(IN P_ADAPTER_T prAdapter, IN P_PARAM_WIFI_GSCAN_CMD_PARAMS prCmdGscnParam) +{ + /*CMD_GSCN_REQ_T rCmdGscnParam;*/ + P_CMD_GSCN_REQ_T rCmdGscnParamp; + P_SCAN_INFO_T prScanInfo; + UINT_8 ucChannelBuckIndex; + UINT_8 i; + + ASSERT(prAdapter); + rCmdGscnParamp = kalMemAlloc(sizeof(CMD_GSCN_REQ_T), VIR_MEM_TYPE); + if (rCmdGscnParamp == NULL) { + DBGLOG(SCN, INFO, "alloc CmdGscnParam fail\n"); + return TRUE; + } + kalMemZero(rCmdGscnParamp, sizeof(CMD_GSCN_REQ_T)); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + rCmdGscnParamp->u4NumBuckets = prCmdGscnParam->num_buckets; + rCmdGscnParamp->u4BasePeriod = prCmdGscnParam->base_period; + DBGLOG(SCN, INFO, + "u4BasePeriod[%d], u4NumBuckets[%d]\n", rCmdGscnParamp->u4BasePeriod, rCmdGscnParamp->u4NumBuckets); + for (ucChannelBuckIndex = 0; ucChannelBuckIndex < prCmdGscnParam->num_buckets; ucChannelBuckIndex++) { + DBGLOG(SCN, TRACE, "assign channels to bucket[%d]\n", ucChannelBuckIndex); + for (i = 0; i < prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; i++) { + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel = + (UINT_8) nicFreq2ChannelNum(prCmdGscnParam->buckets[ucChannelBuckIndex]. + channels[i].channel * 1000); + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive = + (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].passive; + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs = + (UINT_8) prCmdGscnParam->buckets[ucChannelBuckIndex].channels[i].dwellTimeMs; + + DBGLOG(SCN, TRACE, "[ucChannel %d, ucPassive %d, u4DwellTimeMs %d\n", + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucChannel, + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].ucPassive, + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].arChannelList[i].u4DwellTimeMs); + + } + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].u2BucketIndex = + (UINT_16) prCmdGscnParam->buckets[ucChannelBuckIndex].bucket; + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].eBand = + prCmdGscnParam->buckets[ucChannelBuckIndex].band; + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucBucketFreqMultiple = + (prCmdGscnParam->buckets[ucChannelBuckIndex].period / prCmdGscnParam->base_period); + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucNumChannels = + prCmdGscnParam->buckets[ucChannelBuckIndex].num_channels; + rCmdGscnParamp->arChannelBucket[ucChannelBuckIndex].ucReportFlag = + prCmdGscnParam->buckets[ucChannelBuckIndex].report_events; + + /* printk("\n"); */ + } + + DBGLOG(SCN, INFO, "scnSetGSCNParam ---> scnPSCNFsm PSCN_RESET\n"); + + scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, rCmdGscnParamp, NULL, FALSE, FALSE, FALSE, FALSE); + kalMemFree(rCmdGscnParamp, VIR_MEM_TYPE, sizeof(CMD_GSCN_REQ_T)); + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Combine PNO Scan params into PSCAN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +scnSubCombineNLOtoPSCN(IN P_ADAPTER_T prAdapter, + IN P_CMD_NLO_REQ prNewCmdNloReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prNewCmdNloReq) { + prCmdPscnParam->fgNLOScnEnable = TRUE; + memcpy(&prCmdPscnParam->rCmdNloReq, prNewCmdNloReq, sizeof(CMD_NLO_REQ)); + } else if (prScanInfo->prPscnParam->fgNLOScnEnable) { + memcpy(&prCmdPscnParam->rCmdNloReq, &prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); + } else + prCmdPscnParam->fgNLOScnEnable = FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Combine Batcht Scan params into PSCAN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +scnSubCombineBatchSCNtoPSCN(IN P_ADAPTER_T prAdapter, + IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prNewCmdBatchReq) { + prCmdPscnParam->fgBatchScnEnable = TRUE; + memcpy(&prCmdPscnParam->rCmdBatchReq, prNewCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); + } else if (prScanInfo->prPscnParam->fgBatchScnEnable) { + memcpy(&prCmdPscnParam->rCmdBatchReq, &prScanInfo->prPscnParam->rCurrentCmdBatchReq, + sizeof(CMD_BATCH_REQ_T)); + } else + prCmdPscnParam->fgBatchScnEnable = FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Combine GSCN Scan params into PSCAN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +scnSubCombineGSCNtoPSCN(IN P_ADAPTER_T prAdapter, + IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, + IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) +{ + P_SCAN_INFO_T prScanInfo; + UINT_32 ucPeriodMin = MAX_PERIOD; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prCmdPscnParam->fgGScnEnable = FALSE; + + DBGLOG(SCN, TRACE, "scnSubCombineGSCNtoPSCN fgGScnParamSet %d fgGScnConfigSet %d\n", + prScanInfo->fgGScnParamSet, prScanInfo->fgGScnConfigSet); + + if (prNewCmdGscnReq) { + DBGLOG(SCN, INFO, "setup prNewCmdGscnReq\n"); + prScanInfo->fgGScnParamSet = TRUE; + memcpy(&prCmdPscnParam->rCmdGscnReq, prNewCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); + if (ucPeriodMin > prNewCmdGscnReq->u4BasePeriod) + prCmdPscnParam->u4BasePeriod = prNewCmdGscnReq->u4BasePeriod; + } else if (prScanInfo->fgGScnParamSet) { + DBGLOG(SCN, INFO, "no new prNewCmdGscnReq but there is a old one\n"); + memcpy(&prCmdPscnParam->rCmdGscnReq, &prScanInfo->prPscnParam->rCurrentCmdGscnReq, + sizeof(CMD_GSCN_REQ_T)); + prCmdPscnParam->u4BasePeriod = prScanInfo->prPscnParam->u4BasePeriod; + } else + prScanInfo->fgGScnParamSet = FALSE; + + if (prNewCmdGscnConfig) { + DBGLOG(SCN, INFO, "set up prNewCmdGscnConfig\n"); + memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + prScanInfo->fgGScnConfigSet = TRUE; + prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = prNewCmdGscnConfig->u4BufferThreshold; + prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = (UINT_8) prNewCmdGscnConfig->u4NumScnToCache; + } else if (prScanInfo->fgGScnConfigSet) { + DBGLOG(SCN, INFO, "no new prNewCmdGscnConfig but there is a old one\n"); + memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + prCmdPscnParam->rCmdGscnReq.u4BufferThreshold = + prScanInfo->prPscnParam->rCurrentCmdGscnReq.u4BufferThreshold; + prCmdPscnParam->rCmdGscnReq.ucNumScnToCache = + (UINT_8) prScanInfo->prPscnParam->rCurrentCmdGscnReq.ucNumScnToCache; + } else + prScanInfo->fgGScnConfigSet = FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Combine GSCN Scan params into PSCAN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +VOID +scnRemoveFromPSCN(IN P_ADAPTER_T prAdapter, + IN BOOLEAN fgRemoveNLOfromPSCN, + IN BOOLEAN fgRemoveBatchSCNfromPSCN, + IN BOOLEAN fgRemoveGSCNfromPSCN, IN P_CMD_SET_PSCAN_PARAM prCmdPscnParam) +{ + P_SCAN_INFO_T prScanInfo; + UINT_8 ucPscanAct = DISABLE; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + { + DBGLOG(SCN, INFO, "remove NLO or Batch or GSCN from PSCN--->NLO=%d, BSN=%d, GSN=%d\n", + fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); + + if (fgRemoveNLOfromPSCN) { + memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + prCmdPscnParam->fgNLOScnEnable = FALSE; + kalMemZero(&prCmdPscnParam->rCmdNloReq, sizeof(CMD_NLO_REQ)); + kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdNloReq, sizeof(CMD_NLO_REQ)); + } + if (fgRemoveBatchSCNfromPSCN) { + memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + prCmdPscnParam->fgBatchScnEnable = FALSE; + kalMemZero(&prCmdPscnParam->rCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); + kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); + } + if (fgRemoveGSCNfromPSCN) { + memcpy(prCmdPscnParam, prScanInfo->prPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + prCmdPscnParam->fgGScnEnable = FALSE; + prScanInfo->fgGScnParamSet = FALSE; + kalMemZero(&prCmdPscnParam->rCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); + kalMemZero(&prScanInfo->prPscnParam->rCurrentCmdGscnReq, sizeof(CMD_GSCN_REQ_T)); + } + + if (!fgRemoveNLOfromPSCN && !fgRemoveBatchSCNfromPSCN && !fgRemoveGSCNfromPSCN) { + /* prCmdPscnParam->fgIsPeriodicallyScn = FALSE; */ + prScanInfo->fgPscnOnnning = FALSE; + scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); + scnFsmPSCNAction(prAdapter, ucPscanAct); + } else { + /* prCmdPscnParam->fgIsPeriodicallyScn = TRUE; */ + scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); + DBGLOG(SCN, INFO, " disable NLO or GSCN or Batch but fgIsPeriodicallyScn = TRUE <-----\n"); + } + } + +} + +#if 1 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Combine GSCN , Batch, PNO Scan params into PSCAN param +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ + +BOOLEAN +scnCombineParamsIntoPSCN(IN P_ADAPTER_T prAdapter, + IN P_CMD_NLO_REQ prNewCmdNloReq, + IN P_CMD_BATCH_REQ_T prNewCmdBatchReq, + IN P_CMD_GSCN_REQ_T prNewCmdGscnReq, + IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, + IN BOOLEAN fgRemoveNLOfromPSCN, + IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN) +{ + P_SCAN_INFO_T prScanInfo; + /* CMD_SET_PSCAN_PARAM rCmdPscnParam; */ + P_CMD_SET_PSCAN_PARAM prCmdPscnParam; + /* UINT_8 i, j = 0; */ + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prCmdPscnParam = (P_CMD_SET_PSCAN_PARAM) kalMemAlloc(sizeof(CMD_SET_PSCAN_PARAM), VIR_MEM_TYPE); + if (!prCmdPscnParam) { + DBGLOG(SCN, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); + return -ENOMEM; + } + kalMemZero(prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + + prCmdPscnParam->ucVersion = CURRENT_PSCN_VERSION; + + if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { + scnRemoveFromPSCN(prAdapter, + fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN, prCmdPscnParam); + } else { + DBGLOG(SCN, INFO, "combine GSCN or Batch or NLO to PSCN --->\n"); + + scnSubCombineNLOtoPSCN(prAdapter, prNewCmdNloReq, prCmdPscnParam); + scnSubCombineBatchSCNtoPSCN(prAdapter, prNewCmdBatchReq, prCmdPscnParam); + if (prNewCmdGscnReq) + scnSubCombineGSCNtoPSCN(prAdapter, prNewCmdGscnReq, NULL, prCmdPscnParam); + if (prNewCmdGscnConfig) + scnSubCombineGSCNtoPSCN(prAdapter, NULL, prNewCmdGscnConfig, prCmdPscnParam); + /* scnFsmPSCNSetParam(prAdapter, prCmdPscnParam); */ + +#if 0 + DBGLOG(SCN, TRACE, "combine GSCN or Batch or NLO to PSCN <--- rCmdPscnParam\n"); + DBGLOG(SCN, TRACE, + "Period[%u], NumCache[%u], Threshold[%u], NumBuckets[%u],GSCNEn[%d] NLOEn[%d] BatchEn[%d]\n", + prCmdPscnParam->rCmdGscnReq.u4BasePeriod, prCmdPscnParam->rCmdGscnReq.ucNumScnToCache, + prCmdPscnParam->rCmdGscnReq.u4BufferThreshold, prCmdPscnParam->rCmdGscnReq.u4NumBuckets, + prCmdPscnParam->fgGScnEnable, prCmdPscnParam->fgNLOScnEnable, + prCmdPscnParam->fgBatchScnEnable)); + + for (i = 0; i < prCmdPscnParam->rCmdGscnReq.u4NumBuckets; i++) { + DBGLOG(SCN, TRACE, "rCmdPscnParam.rCmdGscnParam.arChannelBucket[%d] has channel: ", i); + DBGLOG(SCN, TRACE, + "band[%u], ChnBkt[%u] NumChns[%u], BktFreqMltpl[%u] Flag[%u]\n", + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].eBand, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].u2BucketIndex, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucBucketFreqMultiple, + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucReportFlag)); + for (j = 0; j < prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].ucNumChannels; j++) { + DBGLOG(SCN, TRACE, " %d, ", + prCmdPscnParam->rCmdGscnReq.arChannelBucket[i].arChannelList[j].ucChannel); + } + DBGLOG(SCN, TRACE, "\n"); + } +#endif + } + + memcpy(prScanInfo->prPscnParam, prCmdPscnParam, sizeof(CMD_SET_PSCAN_PARAM)); + kalMemFree(prCmdPscnParam, VIR_MEM_TYPE, sizeof(CMD_SET_PSCAN_PARAM)); + return TRUE; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmSetGSCNConfig(IN P_ADAPTER_T prAdapter, IN P_CMD_GSCN_SCN_COFIG_T prCmdGscnScnConfig) +{ + CMD_GSCN_SCN_COFIG_T rCmdGscnScnConfig; + + ASSERT(prAdapter); + memcpy(&rCmdGscnScnConfig, prCmdGscnScnConfig, sizeof(CMD_GSCN_SCN_COFIG_T)); + DBGLOG(SCN, TRACE, "rCmdGscnScnConfig: u4BufferThreshold; [%d] ucNumApPerScn [%d] ucNumScnToCache [%d]\n", + rCmdGscnScnConfig.u4BufferThreshold, + rCmdGscnScnConfig.ucNumApPerScn, + rCmdGscnScnConfig.u4NumScnToCache); + + scnPSCNFsm(prAdapter, PSCN_RESET, NULL, NULL, NULL, &rCmdGscnScnConfig, FALSE, FALSE, FALSE, FALSE); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief handler for Set CMD_ID_SET_PSCN_MAC_ADDR +* +* \param[in] +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN scnFsmGetGSCNResult(IN P_ADAPTER_T prAdapter, IN P_CMD_GET_GSCAN_RESULT_T prGetGscnScnResultCmd) +{ + CMD_GET_GSCAN_RESULT_T rGetGscnScnResultCmd; + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + memcpy(&rGetGscnScnResultCmd, prGetGscnScnResultCmd, sizeof(CMD_GET_GSCAN_RESULT_T)); + DBGLOG(SCN, INFO, "rGetGscnScnResultCmd: ucGetNum [%d] fgFlush [%d]\n", + rGetGscnScnResultCmd.u4Num, rGetGscnScnResultCmd.ucFlush); + + if (prScanInfo->fgPscnOnnning && prScanInfo->prPscnParam->fgGScnEnable) { + wlanSendSetQueryCmd(prAdapter, + CMD_ID_GET_GSCN_SCN_RESULT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, sizeof(CMD_GET_GSCAN_RESULT_T), (PUINT_8) &rGetGscnScnResultCmd, NULL, 0); + return TRUE; + } + /* debug msg, No PSCN, Sched SCAN GSCN ongoing ??? */ + return FALSE; + +} + +VOID +scnPSCNFsm(IN P_ADAPTER_T prAdapter, + ENUM_PSCAN_STATE_T eNextPSCNState, + IN P_CMD_NLO_REQ prCmdNloReq, + IN P_CMD_BATCH_REQ_T prCmdBatchReq, + IN P_CMD_GSCN_REQ_T prCmdGscnReq, + IN P_CMD_GSCN_SCN_COFIG_T prNewCmdGscnConfig, + IN BOOLEAN fgRemoveNLOfromPSCN, + IN BOOLEAN fgRemoveBatchSCNfromPSCN, IN BOOLEAN fgRemoveGSCNfromPSCN, IN BOOLEAN fgEnableGSCN) +{ + P_SCAN_INFO_T prScanInfo; + BOOLEAN fgTransitionState = FALSE; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + do { + fgTransitionState = FALSE; + + DBGLOG(SCN, STATE, "eCurrentPSCNState=%d, eNextPSCNState=%d\n", + prScanInfo->eCurrentPSCNState, eNextPSCNState); + + switch (prScanInfo->eCurrentPSCNState) { + case PSCN_IDLE: + if (eNextPSCNState == PSCN_RESET) { + if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { + DBGLOG(SCN, TRACE, "Unexpected remove NLO/BATCH/GSCN request\n"); + eNextPSCNState = PSCN_IDLE; + break; + } + + if (prCmdNloReq || prCmdBatchReq) { + DBGLOG(SCN, TRACE, "PSCN_IDLE->PSCN_RESET,.... scnFsmPSCNActionDISABLE\n"); + /*TBD check PSCAN is ongoing */ + scnFsmPSCNAction(prAdapter, DISABLE); + break; + } + + } else if (eNextPSCNState == PSCN_SCANNING) { + if (fgEnableGSCN) { + if (prScanInfo->fgPscnOnnning) + scnFsmPSCNAction(prAdapter, DISABLE); + if (prScanInfo->fgGScnParamSet) { + DBGLOG(SCN, TRACE, + "PSCN_IDLE->PSCN_SCANNING,.... scnFsmPSCNActionENABLE\n"); + prScanInfo->prPscnParam->fgGScnEnable = TRUE; + scnFsmPSCNSetParam(prAdapter, + (P_CMD_SET_PSCAN_PARAM)prScanInfo->prPscnParam); + scnFsmPSCNAction(prAdapter, ENABLE); + eNextPSCNState = PSCN_SCANNING; + } + } + } + break; + + case PSCN_RESET: + scnCombineParamsIntoPSCN(prAdapter, + prCmdNloReq, + prCmdBatchReq, + prCmdGscnReq, + prNewCmdGscnConfig, + fgRemoveNLOfromPSCN, fgRemoveBatchSCNfromPSCN, fgRemoveGSCNfromPSCN); + + if (!prScanInfo->prPscnParam->fgNLOScnEnable && !prScanInfo->prPscnParam->fgBatchScnEnable + && !prScanInfo->prPscnParam->fgGScnEnable) { + DBGLOG(SCN, TRACE, + "PSCN_RESET->PSCN_IDLE,.... fgNLOScnEnable/fgBatchScnEnable/fgGScnEnable false\n"); + eNextPSCNState = PSCN_IDLE; + } else { + if (prScanInfo->prPscnParam->fgNLOScnEnable + || prScanInfo->prPscnParam->fgBatchScnEnable) { + scnFsmPSCNSetParam(prAdapter, (P_CMD_SET_PSCAN_PARAM) prScanInfo->prPscnParam); + scnFsmPSCNAction(prAdapter, ENABLE); + eNextPSCNState = PSCN_SCANNING; + DBGLOG(SCN, TRACE, + "PSCN_RESET->PSCN_SCANNING,.... fgNLOScnEnable/fgBatchScnEnable ENABLE\n"); + } + } + break; + + case PSCN_SCANNING: + if (eNextPSCNState == PSCN_RESET) { + if (fgRemoveNLOfromPSCN || fgRemoveBatchSCNfromPSCN || fgRemoveGSCNfromPSCN) { + DBGLOG(SCN, TRACE, + "PSCN_SCANNING->PSCN_RESET,.... fgRemoveNLOfromPSCN/fgRemoveBatchSCNfromPSCN/fgRemoveGSCNfromPSCN\n"); + scnFsmPSCNAction(prAdapter, DISABLE); + break; + } + + if (prCmdNloReq || prCmdBatchReq || prCmdGscnReq || prNewCmdGscnConfig) { + DBGLOG(SCN, TRACE, + "PSCN_SCANNING->PSCN_RESET,.... prCmdNloReq/prCmdBatchReq/prCmdGscnReq/prNewCmdGscnConfig\n"); + scnFsmPSCNAction(prAdapter, DISABLE); + break; + } + + } else if (eNextPSCNState == PSCN_SCANNING) { + if (fgEnableGSCN) { + if (prScanInfo->prPscnParam->fgGScnEnable && (!prScanInfo->fgPscnOnnning)) { + DBGLOG(SCN, TRACE, + "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); + /* scnFsmPSCNAction(prAdapter, ENABLE); */ + eNextPSCNState = PSCN_SCANNING; + } else { + + DBGLOG(SCN, TRACE, + "PSCN_SCANNING->PSCN_SCANNING,.... fgGScnEnable/!fgPscnOnnning\n"); + } + } + } + eNextPSCNState = PSCN_SCANNING; + break; + + default: + DBGLOG(SCN, WARN, "Unexpected state\n"); + ASSERT(0); + break; + } + + DBGLOG(SCN, STATE, "eCurrentState %d , eNextPSCNState %d\n", + prScanInfo->eCurrentPSCNState, eNextPSCNState); + if (prScanInfo->eCurrentPSCNState != eNextPSCNState) + fgTransitionState = TRUE; + + prScanInfo->eCurrentPSCNState = eNextPSCNState; + } while (fgTransitionState); + +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c new file mode 100644 index 0000000000000..29eb8d4e7d92f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/sec_fsm.c @@ -0,0 +1,1112 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/sec_fsm.c#1 +*/ + +/*! \file "sec_fsm.c" + \brief This is the file implement security check state machine. + + In security module, do the port control check after success join to an AP, + and the path to NORMAL TR, the state machine handle these state transition. +*/ + +/* +** Log: sec_fsm.c + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Adjust code for DBG and CONFIG_XLOG. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 03 29 2011 wh.su + * [WCXRP00000248] [MT6620 Wi-Fi][FW]Fixed the Klockwork error + * fixed the kclocwork error. + * + * 01 26 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * . + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Fix Compile Error when DBG is disabled. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 24 2010 wh.su + * NULL + * [WCXRP00005002][MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 19 2010 wh.su + * NULL + * adding the tx pkt call back handle for countermeasure. + * + * 07 19 2010 wh.su + * + * fixed the compilng error at debug mode. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * modify some code for concurrent network. + * + * 06 19 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * consdier the concurrent network setting. + * + * 05 28 2010 wh.su + * [BORA00000626][MT6620] Refine the remove key flow for WHQL testing + * fixed the ad-hoc wpa-none send non-encrypted frame issue. + * + * 05 24 2010 kevin.huang + * [BORA00000794][WIFISYS][New Feature]Power Management Support + * Refine authSendAuthFrame() for NULL STA_RECORD_T case and minimum deauth interval. + * + * 04 24 2010 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * g_aprBssInfo[] depends on CFG_SUPPORT_P2P and CFG_SUPPORT_BOW + * + * 04 13 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the Klocwork error and refine the class error message. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * Fixed the pre-authentication timer not correctly init issue, + * and modify the security related callback function prototype. + * + * 03 01 2010 wh.su + * [BORA00000605][WIFISYS] Phase3 Integration + * Refine the variable and parameter for security. + * + * 01 27 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * add and fixed some security function. + * + * 01 13 2010 wh.su + * [BORA00000476][Wi-Fi][firmware] Add the security module initialize code + * fixed the compiling warning + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine some code + * + * Dec 4 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * refine the code + * + * Dec 1 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * code refine + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the function name + * + * Nov 19 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adjust the state machine, to meet the firmware security design v1.1 + * + * Nov 18 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_RSN_MIGRATION + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if DBG +/*lint -save -e64 Type mismatch */ +static PUINT_8 apucDebugSecState[SEC_STATE_NUM] = { + (PUINT_8) DISP_STRING("SEC_STATE_INIT"), + (PUINT_8) DISP_STRING("SEC_STATE_INITIATOR_PORT_BLOCKED"), + (PUINT_8) DISP_STRING("SEC_STATE_RESPONDER_PORT_BLOCKED"), + (PUINT_8) DISP_STRING("SEC_STATE_CHECK_OK"), + (PUINT_8) DISP_STRING("SEC_STATE_SEND_EAPOL"), + (PUINT_8) DISP_STRING("SEC_STATE_SEND_DEAUTH"), + (PUINT_8) DISP_STRING("SEC_STATE_COUNTERMEASURE"), +}; + +/*lint -restore */ +#endif /* DBG */ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do initialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the STA record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + +#if 1 /* MT6620 */ + /* At MT5921, is ok, but at MT6620, firmware base ASIC, the firmware */ + /* will lost these data, thus, driver have to keep the wep material and */ + /* setting to firmware while awake from D3. */ +#endif + + prSecInfo->eCurrentState = SEC_STATE_INIT; + + prSecInfo->fg2nd1xSend = FALSE; + prSecInfo->fgKeyStored = FALSE; + + if (IS_STA_IN_AIS(prSta)) { + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + prAisSpecBssInfo->u4RsnaLastMICFailTime = 0; + prAisSpecBssInfo->fgCheckEAPoLTxDone = FALSE; + + cnmTimerInitTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEapolTxTimeout, (ULONG) prSta); + + cnmTimerInitTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, + (PFN_MGMT_TIMEOUT_FUNC) secFsmEventEndOfCounterMeasure, (ULONG) prSta); + + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do uninitialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the STA record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID /* whsu:Todo: */ +secFsmUnInit(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + + prSecInfo->fg2nd1xSend = FALSE; + prSecInfo->fgKeyStored = FALSE; + + /* nicPrivacyRemoveWlanTable(prSta->ucWTEntry); */ + + if (IS_STA_IN_AIS(prSta)) { + cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); + cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* STANDBY to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_INIT_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INIT to INITIATOR_PORT_BLOCKED. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_INIT_to_INITIATOR_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INIT to RESPONDER_PORT_BLOCKED. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_INIT_to_RESPONDER_PORT_BLOCKED(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* INITIATOR_PORT_BLOCKED to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_INITIATOR_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* RESPONDER_PORT_BLOCKED to CHECK_OK. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_RESPONDER_PORT_BLOCKED_to_CHECK_OK(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + secSetPortBlocked(prAdapter, prSta, FALSE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* CHECK_OK to SEND_EAPOL +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_CHECK_OK_to_SEND_EAPOL(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + + P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + ASSERT(prSta); + + prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + ASSERT(prAisBssInfo); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + prAisBssInfo->fgCheckEAPoLTxDone = TRUE; + + /* cnmTimerStartTimer(prAdapter, */ + /* &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer, */ + /* SEC_TO_MSEC(EAPOL_REPORT_SEND_TIMEOUT_INTERVAL_SEC)); */ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_EAPOL to SEND_DEAUTH. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - none +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_SEND_EAPOL_to_SEND_DEAUTH(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + /* Compose deauth frame to AP, a call back function for tx done */ + if (authSendDeauthFrame(prAdapter, + prSta, + (P_SW_RFB_T) NULL, + REASON_CODE_MIC_FAILURE, + (PFN_TX_DONE_HANDLER) secFsmEventDeauthTxDone) != WLAN_STATUS_SUCCESS) { + ASSERT(FALSE); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_DEAUTH to COUNTERMEASURE. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_SEND_DEAUTH_to_COUNTERMEASURE(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + ASSERT(prAdapter); + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + /* Start the 60 sec timer */ + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rAisSpecificBssInfo.rRsnaBlockTrafficTimer, + SEC_TO_MSEC(COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do action part while in STATE transition of +* SEND_DEAUTH to COUNTERMEASURE. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +static inline VOID secFsmTrans_COUNTERMEASURE_to_INIT(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + + /* Clear the counter measure flag */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The Core FSM engine of security module. +* +* \param[in] prSta Pointer to the Sta record +* \param[in] eNextState Enum value of next sec STATE +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmSteps(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN ENUM_SEC_STATE_T eNextState) +{ + P_SEC_INFO_T prSecInfo; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + ASSERT(prSecInfo); + + DEBUGFUNC("secFsmSteps"); + do { + /* Do entering Next State */ + prSecInfo->ePreviousState = prSecInfo->eCurrentState; + + /* Do entering Next State */ +#if DBG + DBGLOG(RSN, STATE, "\n %pM TRANSITION: [%s] -> [%s]\n\n", + prSta->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState], apucDebugSecState[eNextState]); +#else + DBGLOG(RSN, STATE, "\n %pM [%d] TRANSITION: [%d] -> [%d]\n\n", + prSta->aucMacAddr, DBG_RSN_IDX, prSecInfo->eCurrentState, eNextState); +#endif + prSecInfo->eCurrentState = eNextState; + + fgIsTransition = (BOOLEAN) FALSE; +#if 0 + /* Do tasks of the State that we just entered */ + switch (prSecInfo->eCurrentState) { + case SEC_STATE_INIT: + break; + case SEC_STATE_INITIATOR_PORT_BLOCKED: + break; + case SEC_STATE_RESPONDER_PORT_BLOCKED: + break; + case SEC_STATE_CHECK_OK: + break; + case SEC_STATE_SEND_EAPOL: + break; + case SEC_STATE_SEND_DEAUTH: + break; + case SEC_STATE_COUNTERMEASURE: + break; + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + break; + } +#endif + } while (fgIsTransition); + + return; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do initialization of Security FSM and all variables in +* SEC_INFO_T. +* +* \param[in] prSta Pointer to the Sta record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEventStart(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + ENUM_SEC_STATE_T eNextState; + + DBGLOG(RSN, TRACE, "secFsmRunEventStart\n"); + + ASSERT(prSta); + + if (!prSta) + return; + + if (!IS_STA_IN_AIS(prSta)) + return; + + DBGLOG(RSN, TRACE, "secFsmRunEventStart for sta %pM network %d\n", + prSta->aucMacAddr, prSta->ucNetTypeIndex); + + prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; + + eNextState = prSecInfo->eCurrentState; + + secSetPortBlocked(prAdapter, prSta, TRUE); + + /* prSta->fgTransmitKeyExist = FALSE; */ + /* whsu:: nicPrivacySetStaDefaultWTIdx(prSta); */ + +#if 1 /* Since the 1x and key can set to firmware in order, always enter the check ok state */ + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); +#else + if (IS_STA_IN_AIS(prSta->eStaType)) { + if (secRsnKeyHandshakeEnabled(prAdapter) == TRUE +#if CFG_SUPPORT_WAPI + || (prAdapter->rWifiVar.rConnSettings.fgWapiMode) +#endif + ) { + prSta->fgTransmitKeyExist = FALSE; + /* nicPrivacyInitialize(prSta->ucNetTypeIndex); */ + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); + } else { + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, CHECK_OK); + } + } +#if CFG_ENABLE_WIFI_DIRECT || CFG_ENABLE_BT_OVER_WIFI +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_BT_OVER_WIFI + else if ((prSta->eStaType == STA_TYPE_BOW_CLIENT) || (prSta->eStaType == STA_TYPE_P2P_GC)) { +#elif CFG_ENABLE_WIFI_DIRECT + else if (prSta->eStaType == STA_TYPE_P2P_GC) { +#elif CFG_ENABLE_BT_OVER_WIFI + else if (prSta->eStaType == STA_TYPE_BOW_CLIENT) { +#endif + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, RESPONDER_PORT_BLOCKED); + } +#endif + else + SEC_STATE_TRANSITION(prAdapter, prSta, INIT, INITIATOR_PORT_BLOCKED); +#endif + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + +} /* secFsmRunEventStart */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function called by reset procedure to force the sec fsm enter +* idle state +* +* \param[in] ucNetTypeIdx The Specific Network type index +* \param[in] prSta Pointer to the Sta record +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEventAbort(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + + DBGLOG(RSN, TRACE, "secFsmEventAbort for sta %pM network %d\n", + prSta->aucMacAddr, prSta->ucNetTypeIndex); + + ASSERT(prSta); + + if (!prSta) + return; + + if (!IS_STA_IN_AIS(prSta)) + return; + + prSecInfo = (P_SEC_INFO_T) &prSta->rSecInfo; + + prSta->fgTransmitKeyExist = FALSE; + + secSetPortBlocked(prAdapter, prSta, TRUE); + + if (prSecInfo == NULL) + return; + + if (IS_STA_IN_AIS(prSta)) { + + prAdapter->rWifiVar.rAisSpecificBssInfo.fgTransmitKeyExist = FALSE; + + if (prSecInfo->eCurrentState == SEC_STATE_SEND_EAPOL) { + if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCheckEAPoLTxDone == FALSE) { + DBGLOG(RSN, TRACE, "EAPOL STATE not match the flag\n"); + /* cnmTimerStopTimer(prAdapter, &prAdapter->rWifiVar. + * rAisSpecificBssInfo.rRsnaEAPoLReportTimeoutTimer); */ + } + } + } + prSecInfo->eCurrentState = SEC_STATE_INIT; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "2nd EAPoL Tx is sending" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEvent2ndEapolTx(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + /* BOOLEAN fgIsTransition = (BOOLEAN)FALSE; */ + + DEBUGFUNC("secFsmRunEvent2ndEapolTx"); + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); +#endif + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_INITIATOR_PORT_BLOCKED: + case SEC_STATE_CHECK_OK: + prSecInfo->fg2nd1xSend = TRUE; + break; + default: +#if DBG + DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, WARN, "Rcv 2nd EAPoL at [%d]\n", prSecInfo->eCurrentState); +#endif + break; + } + + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + + return; + +} /* secFsmRunEvent2ndEapolTx */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "4th EAPoL Tx is Tx done" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEvent4ndEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + P_CMD_802_11_KEY prStoredKey; + + DEBUGFUNC("secFsmRunEvent4ndEapolTx"); + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); +#endif + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_INITIATOR_PORT_BLOCKED: + case SEC_STATE_CHECK_OK: + prSecInfo->fg2nd1xSend = FALSE; + if (prSecInfo->fgKeyStored) { + prStoredKey = (P_CMD_802_11_KEY) prSecInfo->aucStoredKey; + + /* prSta = rxmLookupStaRecIndexFromTA(prStoredKey->aucPeerAddr); */ + /* if (nicPrivacySetKeyEntry(prStoredKey, prSta->ucWTEntry) == FALSE) */ + /* DBGLOG(RSN, WARN, ("nicPrivacySetKeyEntry() fail,..\n")); */ + + /* key update */ + prSecInfo->fgKeyStored = FALSE; + prSta->fgTransmitKeyExist = TRUE; + } + if (prSecInfo->eCurrentState == SEC_STATE_INITIATOR_PORT_BLOCKED) + SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); + break; + default: + +#if DBG + DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at %s\n", apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, WARN, "Rcv thh EAPoL Tx done at [%d]\n", prSecInfo->eCurrentState); +#endif + break; + } + + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + + return; + +} /* secFsmRunEvent4ndEapolTx */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Pairwise key installed" to SEC FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \retval TRUE The key can be installed to HW +* \retval FALSE The kay conflict with the current key, abort it +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN secFsmEventPTKInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgStatus = TRUE; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + ASSERT(prSta); + + prSecInfo = &prSta->rSecInfo; + if (prSecInfo == NULL) + return TRUE; /* Not PTK */ + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAdd), + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); +#endif + + eNextState = prSecInfo->eCurrentState; + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_INIT: + /* Legacy wep, wpa-none */ + break; + + case SEC_STATE_INITIATOR_PORT_BLOCKED: + if (prSecInfo->fg2nd1xSend) + ; + else + SEC_STATE_TRANSITION(prAdapter, prSta, INITIATOR_PORT_BLOCKED, CHECK_OK); + break; + + case SEC_STATE_RESPONDER_PORT_BLOCKED: + SEC_STATE_TRANSITION(prAdapter, prSta, RESPONDER_PORT_BLOCKED, CHECK_OK); + break; + + case SEC_STATE_CHECK_OK: + break; + + default: + fgStatus = FALSE; + break; + } + + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + + return fgStatus; + +} /* end of secFsmRunEventPTKInstalled() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Counter Measure" to SEC FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEventStartCounterMeasure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + DEBUGFUNC("secFsmRunEventStartCounterMeasure"); + + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + prSecInfo = &prSta->rSecInfo; + + eNextState = prSecInfo->eCurrentState; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); +#endif + + prAdapter->rWifiVar.rAisSpecificBssInfo.u4RsnaLastMICFailTime = 0; + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_CHECK_OK: + { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = TRUE; + + /* dls port control */ + SEC_STATE_TRANSITION(prAdapter, prSta, CHECK_OK, SEND_EAPOL); + } + break; + + default: + break; + } + + /* Call arbFsmSteps() when we are going to change ARB STATE */ + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + + return; + +} /* secFsmRunEventStartCounterMeasure */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "802.1x EAPoL Tx Done" to Sec FSM. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventEapolTxDone(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + P_AIS_SPECIFIC_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("secFsmRunEventEapolTxDone"); + + ASSERT(prStaRec); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(RSN, INFO, "Error EAPoL fram fail to send!!\n"); + /* ASSERT(0); */ + return; + } + + if (!IS_STA_IN_AIS(prStaRec)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + prAisBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + ASSERT(prAisBssInfo); + + prSecInfo = &prStaRec->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); +#endif + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_SEND_EAPOL: + if (prAisBssInfo->fgCheckEAPoLTxDone == FALSE) + ASSERT(0); + + prAisBssInfo->fgCheckEAPoLTxDone = FALSE; + /* cnmTimerStopTimer(prAdapter, &prAisBssInfo->rRsnaEAPoLReportTimeoutTimer); */ + + SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_EAPOL, SEND_DEAUTH); + break; + default: + break; + } + + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prStaRec, eNextState); + + return; + +} /* secFsmRunEventEapolTxDone */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will indicate an Event of "Deauth frame Tx Done" to Sec FSM. +* +* \param[in] pMsduInfo Pointer to the Msdu Info +* \param[in] rStatus The Tx done status +* +* \return - +* +* \note after receive deauth frame, callback function call this +*/ +/*----------------------------------------------------------------------------*/ +VOID +secFsmEventDeauthTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec; + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + DEBUGFUNC("secFsmRunEventDeauthTxDone"); + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + ASSERT(prStaRec); + + if (!prStaRec) + return; + + if (!IS_STA_IN_AIS(prStaRec)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + prSecInfo = (P_SEC_INFO_T) &prStaRec->rSecInfo; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prStaRec->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prStaRec->aucMacAddr, prSecInfo->eCurrentState); +#endif + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_SEND_DEAUTH: + + DBGLOG(RSN, TRACE, "Set timer %d\n", COUNTER_MEASURE_TIMEOUT_INTERVAL_SEC); + + SEC_STATE_TRANSITION(prAdapter, prStaRec, SEND_DEAUTH, COUNTERMEASURE); + + break; + + default: + ASSERT(0); + break; + } + +} /* secFsmRunEventDeauthTxDone */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will check the eapol error frame fail to send issue. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEventEapolTxTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParm) +{ + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("secFsmRunEventEapolTxTimeout"); + + prStaRec = (P_STA_RECORD_T) ulParm; + + ASSERT(prStaRec); + + /* Todo:: How to handle the Eapol Error fail to send case? */ + ASSERT(0); + + return; + +} /* secFsmEventEapolTxTimeout */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will stop the counterMeasure duration. +* +* \param[in] prSta Pointer to the Sta record +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID secFsmEventEndOfCounterMeasure(IN P_ADAPTER_T prAdapter, ULONG ulParm) +{ + P_STA_RECORD_T prSta; + P_SEC_INFO_T prSecInfo; + ENUM_SEC_STATE_T eNextState; + BOOLEAN fgIsTransition = (BOOLEAN) FALSE; + + DEBUGFUNC("secFsmRunEventEndOfCounterMeasure"); + + prSta = (P_STA_RECORD_T) ulParm; + + ASSERT(prSta); + + if (!IS_STA_IN_AIS(prSta)) { + DBGLOG(RSN, INFO, "Counter Measure should occur at AIS network!!\n"); + /* ASSERT(0); */ + return; + } + + prSecInfo = &prSta->rSecInfo; + eNextState = prSecInfo->eCurrentState; + +#if DBG + DBGLOG(RSN, TRACE, "%pM Sec state %s\n", prSta->aucMacAddr, + apucDebugSecState[prSecInfo->eCurrentState]); +#else + DBGLOG(RSN, TRACE, "%pM Sec state [%d]\n", prSta->aucMacAddr, prSecInfo->eCurrentState); +#endif + + switch (prSecInfo->eCurrentState) { + case SEC_STATE_SEND_DEAUTH: + { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure = FALSE; + + SEC_STATE_TRANSITION(prAdapter, prSta, COUNTERMEASURE, INIT); + } + break; + + default: + ASSERT(0); + } + + /* Call arbFsmSteps() when we are going to change ARB STATE */ + if (prSecInfo->eCurrentState != eNextState) + secFsmSteps(prAdapter, prSta, eNextState); + +} /* end of secFsmRunEventEndOfCounterMeasure */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c new file mode 100644 index 0000000000000..ab3fcc028375b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/stats.c @@ -0,0 +1,1342 @@ +/* +** Id: stats.c#1 +*/ + +/*! \file stats.c + \brief This file includes statistics support. +*/ + +/* +** Log: stats.c + * + * 07 17 2014 samp.lin + * NULL + * Initial version. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************** + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************** + */ +#include "precomp.h" + +enum EVENT_TYPE { + EVENT_RX, + EVENT_TX, + EVENT_TX_DONE +}; +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); + +static WLAN_STATUS +statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +UINT_64 u8DrvOwnStart, u8DrvOwnEnd; +UINT32 u4DrvOwnMax = 0; +#define CFG_USER_LOAD 0 +static UINT_16 su2TxDoneCfg = CFG_DHCP | CFG_ICMP | CFG_EAPOL; +/******************************************************************************* +* P R I V A T E F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display all environment log. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + P_ADAPTER_T prAdapter; + STA_RECORD_T *prStaRec; + UINT32 u4NumOfInfo, u4InfoId; + UINT32 u4RxErrBitmap; + STATS_INFO_ENV_T *prInfo; + UINT32 u4Total, u4RateId; + +/* +[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. +[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event +[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 +[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: + +[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) + TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, + bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) + RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) + BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) + OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) + ERR (1st: total number of tx err, 2nd ~ 7st: total number of + WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, + WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) + +[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) + TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) + +[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) + RX (1st: latest RCPI, 2nd: chan num) + BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) + OK (number of rx packets without error, number of rx packets to OS) + ERR (number of rx packets with error) + +[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + CCK MODE (1 2 5.5 11M) +[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) +[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) + MIXED MODE (number of rx packets with MCS0 ~ MCS15) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) + delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) + delay from MAC start TX to MAC TX done + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) + delay from HIF to MAC TX done (min, avg, max_system time for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) + delay from driver to MAC TX done (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) + delay from MAC to HIF (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) + delay from HIF to Driver OS (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) + delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) + delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) + delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) + Channel idle time, scan count, channel change count, empty tx quota count, + power save change count from active to PS, maximum delay from PS to active +*/ + + /* init */ + prAdapter = prGlueInfo->prAdapter; + /*prInfo = &rStatsInfoEnv;*/ + prInfo = kalMemAlloc(sizeof(STATS_INFO_ENV_T), VIR_MEM_TYPE); + if (prInfo == NULL) { + DBGLOG(RX, INFO, "prInfo alloc fail"); + return; + } + + kalMemZero(prInfo, sizeof(STATS_INFO_ENV_T)); + + if (u4InBufLen > sizeof(STATS_INFO_ENV_T)) + u4InBufLen = sizeof(STATS_INFO_ENV_T); + + /* parse */ + u4NumOfInfo = *(UINT32 *) prInBuf; + u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); + + /* print */ + for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { + /* + use u4InBufLen, not sizeof(rStatsInfoEnv) + because the firmware version maybe not equal to driver version + */ + kalMemCopy(prInfo, prInBuf + 8, u4InBufLen); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prInfo->ucStaRecIdx); + if (prStaRec == NULL) + continue; + + DBGLOG(RX, INFO, " Display stats for [%pM]: %uB\n", + prStaRec->aucMacAddr, (UINT32) sizeof(STATS_INFO_ENV_T)); + + if (prStaRec->ucStatsGenDisplayCnt++ > 10) { + /* display general statistics information every 10 * (5 or 10s) */ + DBGLOG(RX, INFO, " TBA(0x%x %u) RBA(0x%x %u)\n", + prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, + prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize); + prStaRec->ucStatsGenDisplayCnt = 0; + } + + if (prInfo->u4TxDataCntErr == 0) { + DBGLOG(RX, INFO, " TOS(%u) OK(%u %u)\n", + (UINT32) prGlueInfo->rNetDevStats.tx_packets, + prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK); + } else { + DBGLOG(RX, INFO, " TOS(%u) OK(%u %u) ERR(%u)\n", + (UINT32) prGlueInfo->rNetDevStats.tx_packets, + prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, prInfo->u4TxDataCntErr); + DBGLOG(RX, INFO, " ERR type(%u %u %u %u %u %u)\n", + prInfo->u4TxDataCntErrType[0], prInfo->u4TxDataCntErrType[1], + prInfo->u4TxDataCntErrType[2], prInfo->u4TxDataCntErrType[3], + prInfo->u4TxDataCntErrType[4], prInfo->u4TxDataCntErrType[5]); + } + + for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4TxRateCntNonHT[u4RateId]; + if (u4Total > 0) { + DBGLOG(RX, INFO, " non-HT TRATE (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", + prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], + prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], + prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], + prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], + prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], + prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], + prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], + prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15]); + } + if (prInfo->u4TxRateCntNonHT[0] > 0) { + DBGLOG(RX, INFO, " HT TRATE (1M %u) (%u %u %u %u %u %u %u %u)\n", + prInfo->u4TxRateCntNonHT[0], + prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], + prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], + prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], + prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); + } else { + DBGLOG(RX, INFO, " HT TRATE (%u %u %u %u %u %u %u %u)\n", + prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], + prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], + prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], + prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7]); + } + + if ((prStaRec->u4RxReorderFallAheadCnt != 0) || + (prStaRec->u4RxReorderFallBehindCnt != 0) || (prStaRec->u4RxReorderHoleCnt != 0)) { + DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", + prStaRec->u4RxReorderFallAheadCnt, + prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); + } + + if (prInfo->u4RxDataCntErr == 0) { + DBGLOG(RX, INFO, " ROK(%u %u)\n", + prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt); + } else { + DBGLOG(RX, INFO, " ROK(%u %u) ERR(%u)\n", + prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, + prInfo->u4RxDataCntErr); + } + + for (u4RateId = 1, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateCnt[0][u4RateId] + prInfo->u4RxRateRetryCnt[0][u4RateId]; + if (u4Total > 0) { + for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateRetryCnt[0][u4RateId]; + if (u4Total > 0) { + DBGLOG(RX, INFO, + " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" + "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], + prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], + prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], + prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], + prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], + prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], + prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], + prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], + prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], + prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], + prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], + prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], + prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], + prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], + prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], + prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15]); + } else { + DBGLOG(RX, INFO, " RCCK (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", + prInfo->u4RxRateCnt[0][0], + prInfo->u4RxRateCnt[0][1], + prInfo->u4RxRateCnt[0][2], + prInfo->u4RxRateCnt[0][3], + prInfo->u4RxRateCnt[0][4], + prInfo->u4RxRateCnt[0][5], + prInfo->u4RxRateCnt[0][6], + prInfo->u4RxRateCnt[0][7], + prInfo->u4RxRateCnt[0][8], + prInfo->u4RxRateCnt[0][9], + prInfo->u4RxRateCnt[0][10], + prInfo->u4RxRateCnt[0][11], + prInfo->u4RxRateCnt[0][12], + prInfo->u4RxRateCnt[0][13], + prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateCnt[0][15]); + } + } else { + if ((prInfo->u4RxRateCnt[0][0] + prInfo->u4RxRateRetryCnt[0][0]) > 0) { + DBGLOG(RX, INFO, " RCCK (%u %u)\n", + prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0]); + } + } + + for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateCnt[1][u4RateId] + prInfo->u4RxRateRetryCnt[1][u4RateId]; + if (u4Total > 0) { + for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateRetryCnt[1][u4RateId]; + if (u4Total > 0) { + DBGLOG(RX, INFO, + " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" + "(%u %u)(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], + prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], + prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], + prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], + prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], + prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], + prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], + prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], + prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], + prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], + prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], + prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], + prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], + prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], + prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], + prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15]); + } else { + DBGLOG(RX, INFO, " ROFDM (%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", + prInfo->u4RxRateCnt[1][0], + prInfo->u4RxRateCnt[1][1], + prInfo->u4RxRateCnt[1][2], + prInfo->u4RxRateCnt[1][3], + prInfo->u4RxRateCnt[1][4], + prInfo->u4RxRateCnt[1][5], + prInfo->u4RxRateCnt[1][6], + prInfo->u4RxRateCnt[1][7], + prInfo->u4RxRateCnt[1][8], + prInfo->u4RxRateCnt[1][9], + prInfo->u4RxRateCnt[1][10], + prInfo->u4RxRateCnt[1][11], + prInfo->u4RxRateCnt[1][12], + prInfo->u4RxRateCnt[1][13], + prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateCnt[1][15]); + } + } + + for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateCnt[2][u4RateId] + prInfo->u4RxRateRetryCnt[2][u4RateId]; + if (u4Total > 0) { + for (u4RateId = 0, u4Total = 0; u4RateId < 16; u4RateId++) + u4Total += prInfo->u4RxRateRetryCnt[2][u4RateId]; + if (u4Total > 0) { + DBGLOG(RX, INFO, " RHT\n" + "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], + prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], + prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], + prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], + prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], + prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], + prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], + prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7]); + } else { + DBGLOG(RX, INFO, " RHT (%u %u %u %u %u %u %u %u)\n", + prInfo->u4RxRateCnt[2][0], + prInfo->u4RxRateCnt[2][1], + prInfo->u4RxRateCnt[2][2], + prInfo->u4RxRateCnt[2][3], + prInfo->u4RxRateCnt[2][4], + prInfo->u4RxRateCnt[2][5], + prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateCnt[2][7]); + } + } + + /* RX drop counts */ + for (u4RateId = 0, u4Total = 0; u4RateId < 20; u4RateId++) + u4Total += prInfo->u4NumOfRxDrop[u4RateId]; + if (u4Total > 0) { + DBGLOG(RX, INFO, " RX Drop Count: (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n" + " (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", + prInfo->u4NumOfRxDrop[0], prInfo->u4NumOfRxDrop[1], + prInfo->u4NumOfRxDrop[2], prInfo->u4NumOfRxDrop[3], + prInfo->u4NumOfRxDrop[4], prInfo->u4NumOfRxDrop[5], + prInfo->u4NumOfRxDrop[6], prInfo->u4NumOfRxDrop[7], + prInfo->u4NumOfRxDrop[8], prInfo->u4NumOfRxDrop[9], + prInfo->u4NumOfRxDrop[10], prInfo->u4NumOfRxDrop[11], + prInfo->u4NumOfRxDrop[12], prInfo->u4NumOfRxDrop[13], + prInfo->u4NumOfRxDrop[14], prInfo->u4NumOfRxDrop[15], + prInfo->u4NumOfRxDrop[16], prInfo->u4NumOfRxDrop[17], + prInfo->u4NumOfRxDrop[18], prInfo->u4NumOfRxDrop[19]); + } + + /* delay from HIF RX to HIF RX Done */ + if (((prInfo->u4StayIntMinHR2HRD[1] + prInfo->u4StayIntAvgHR2HRD[1] + + prInfo->u4StayIntMaxHR2HRD[1]) > 0) || + ((prInfo->u4StayIntMinHR2HRD[2] + prInfo->u4StayIntAvgHR2HRD[2] + + prInfo->u4StayIntMaxHR2HRD[2]) > 0)) { + DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], + prInfo->u4StayIntMaxHR2HRD[0], + prInfo->u4StayIntMinHR2HRD[1], prInfo->u4StayIntAvgHR2HRD[1], + prInfo->u4StayIntMaxHR2HRD[1], + prInfo->u4StayIntMinHR2HRD[2], prInfo->u4StayIntAvgHR2HRD[2], + prInfo->u4StayIntMaxHR2HRD[2]); + } else { + DBGLOG(RX, INFO, " StayIntR_HR2HRD us (%u %u %u)\n", + prInfo->u4StayIntMinHR2HRD[0], prInfo->u4StayIntAvgHR2HRD[0], + prInfo->u4StayIntMaxHR2HRD[0]); + } + + /* others */ + DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%x)\n", + prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, + prInfo->u4NumOfChanChange, prInfo->u4CurrChnlInfo); +#if CFG_SUPPORT_THERMO_THROTTLING + prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; +#endif + /* reset */ + kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); + kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); + kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); + prStaRec->u4StatsRxPassToOsCnt = 0; + prStaRec->u4RxReorderFallAheadCnt = 0; + prStaRec->u4RxReorderFallBehindCnt = 0; + prStaRec->u4RxReorderHoleCnt = 0; + } + + STATS_DRIVER_OWN_RESET(); + kalMemFree(prInfo, VIR_MEM_TYPE, sizeof(STATS_INFO_ENV_T)); +} + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display all environment log. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void statsInfoEnvDisplay(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + P_ADAPTER_T prAdapter; + STA_RECORD_T *prStaRec; + UINT32 u4NumOfInfo, u4InfoId; + UINT32 u4RxErrBitmap; + STATS_INFO_ENV_T rStatsInfoEnv, *prInfo; + +/* +[wlan] statsInfoEnvRequest: (INIT INFO) statsInfoEnvRequest cmd ok. +[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event +[wlan] statsEventHandle: (INIT INFO) statsEventHandle: Rcv a event: 0 +[wlan] statsInfoEnvDisplay: (INIT INFO) Display stats for [00:0c:43:31:35:97]: + +[wlan] statsInfoEnvDisplay: (INIT INFO) TPAM(0x0) RTS(0 0) BA(0x1 0) OK(9 9 xxx) ERR(0 0 0 0 0 0 0) + TPAM (bit0: enable 40M, bit1: enable 20 short GI, bit2: enable 40 short GI, + bit3: use 40M TX, bit4: use short GI TX, bit5: use no ack) + RTS (1st: current use RTS/CTS, 2nd: ever use RTS/CTS) + BA (1st: TX session BA bitmap for TID0 ~ TID7, 2nd: peer receive maximum agg number) + OK (1st: total number of tx packet from host, 2nd: total number of tx ok, system time last TX OK) + ERR (1st: total number of tx err, 2nd ~ 7st: total number of + WLAN_STATUS_BUFFER_RETAINED, WLAN_STATUS_PACKET_FLUSHED, WLAN_STATUS_PACKET_AGING_TIMEOUT, + WLAN_STATUS_PACKET_MPDU_ERROR, WLAN_STATUS_PACKET_RTS_ERROR, WLAN_STATUS_PACKET_LIFETIME_ERROR) + +[wlan] statsInfoEnvDisplay: (INIT INFO) TRATE (6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 3) + TX rate count (1M 2 5.5 11 NA NA NA NA 48 24 12 6 54 36 18 9) (MCS0 ~ MCS7) + +[wlan] statsInfoEnvDisplay: (INIT INFO) RX(148 1 0) BA(0x1 64) OK(2 2) ERR(0) + RX (1st: latest RCPI, 2nd: chan num) + BA (1st: RX session BA bitmap for TID0 ~ TID7, 2nd: our receive maximum agg number) + OK (number of rx packets without error, number of rx packets to OS) + ERR (number of rx packets with error) + +[wlan] statsInfoEnvDisplay: (INIT INFO) RCCK (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + CCK MODE (1 2 5.5 11M) +[wlan] statsInfoEnvDisplay: (INIT INFO) ROFDM (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) + OFDM MODE (NA NA NA NA 6 9 12 18 24 36 48 54M) +[wlan] statsInfoEnvDisplay: (INIT INFO) RHT (0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0) + MIXED MODE (number of rx packets with MCS0 ~ MCS15) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntH2M us (29 29 32) (0 0 0) (0 0 0) + delay from HIF to MAC own bit=1 (min, avg, max for 500B) (min, avg, max for 1000B) (min, avg, max for others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) AirTime us (608 864 4480) (0 0 0) (0 0 0) + delay from MAC start TX to MAC TX done + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayInt us (795 1052 4644_4504) (0 0 0_0) (0 0 0_0) + delay from HIF to MAC TX done (min, avg, max_system time for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntD2T us (795 1052 4644) (0 0 0) (0 0 0) + delay from driver to MAC TX done (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_M2H us (37 40 58) (0 0 0) (0 0 0) + delay from MAC to HIF (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayIntR_H2D us (0 0 0) (0 0 0) (0 0 0) + delay from HIF to Driver OS (min, avg, max for 500B) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCntD2H unit:10ms (10 0 0 0) + delay count from Driver to HIF (count in 0~10ms, 10~20ms, 20~30ms, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt unit:1ms (6 3 0 1) + delay count from HIF to TX DONE (count in 0~1ms, 1~5ms, 5~10ms, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) StayCnt (0~1161:7) (1161~2322:2) (2322~3483:0) (3483~4644:0) (4644~:1) + delay count from HIF to TX DONE (count in 0~1161 ticks, 1161~2322, 2322~3483, 3483~4644, others) + +[wlan] statsInfoEnvDisplay: (INIT INFO) OTHER (61877) (0) (38) (0) (0) (0ms) + Channel idle time, scan count, channel change count, empty tx quota count, + power save change count from active to PS, maximum delay from PS to active +*/ + + /* init */ + prAdapter = prGlueInfo->prAdapter; + prInfo = &rStatsInfoEnv; + kalMemZero(&rStatsInfoEnv, sizeof(rStatsInfoEnv)); + + if (u4InBufLen > sizeof(rStatsInfoEnv)) + u4InBufLen = sizeof(rStatsInfoEnv); + + /* parse */ + u4NumOfInfo = *(UINT32 *) prInBuf; + u4RxErrBitmap = *(UINT32 *) (prInBuf + 4); + + /* print */ + for (u4InfoId = 0; u4InfoId < u4NumOfInfo; u4InfoId++) { + /* + use u4InBufLen, not sizeof(rStatsInfoEnv) + because the firmware version maybe not equal to driver version + */ + kalMemCopy(&rStatsInfoEnv, prInBuf + 8, u4InBufLen); + + prStaRec = cnmGetStaRecByIndex(prAdapter, rStatsInfoEnv.ucStaRecIdx); + if (prStaRec == NULL) + continue; + + DBGLOG(RX, INFO, " Display stats V%d.%d for [%pM]: %uB %ums\n", + prInfo->ucFwVer[0], prInfo->ucFwVer[1], + (prStaRec->aucMacAddr), (UINT32) sizeof(STATS_INFO_ENV_T), + prInfo->u4ReportSysTime); + DBGLOG(RX, INFO, "TPAM(0x%x)RTS(%u %u)BA(0x%x %u)OS(%u)OK(%u %u)ERR(%u %u %u %u %u %u %u)\n", + prInfo->ucTxParam, + prInfo->fgTxIsRtsUsed, prInfo->fgTxIsRtsEverUsed, + prInfo->ucTxAggBitmap, prInfo->ucTxPeerAggMaxSize, + (UINT32) prGlueInfo->rNetDevStats.tx_packets, + prInfo->u4TxDataCntAll, prInfo->u4TxDataCntOK, + prInfo->u4TxDataCntErr, prInfo->u4TxDataCntErrType[0], + prInfo->u4TxDataCntErrType[1], prInfo->u4TxDataCntErrType[2], + prInfo->u4TxDataCntErrType[3], prInfo->u4TxDataCntErrType[4], + prInfo->u4TxDataCntErrType[5])); + + DBGLOG(RX, INFO, "TRATE(%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u)\n", + prInfo->u4TxRateCntNonHT[0], prInfo->u4TxRateCntNonHT[1], + prInfo->u4TxRateCntNonHT[2], prInfo->u4TxRateCntNonHT[3], + prInfo->u4TxRateCntNonHT[4], prInfo->u4TxRateCntNonHT[5], + prInfo->u4TxRateCntNonHT[6], prInfo->u4TxRateCntNonHT[7], + prInfo->u4TxRateCntNonHT[8], prInfo->u4TxRateCntNonHT[9], + prInfo->u4TxRateCntNonHT[10], prInfo->u4TxRateCntNonHT[11], + prInfo->u4TxRateCntNonHT[12], prInfo->u4TxRateCntNonHT[13], + prInfo->u4TxRateCntNonHT[14], prInfo->u4TxRateCntNonHT[15], + prInfo->u4TxRateCntHT[0], prInfo->u4TxRateCntHT[1], + prInfo->u4TxRateCntHT[2], prInfo->u4TxRateCntHT[3], + prInfo->u4TxRateCntHT[4], prInfo->u4TxRateCntHT[5], + prInfo->u4TxRateCntHT[6], prInfo->u4TxRateCntHT[7])); + + DBGLOG(RX, INFO, " TREORDER (%u %u %u)\n", + prStaRec->u4RxReorderFallAheadCnt, + prStaRec->u4RxReorderFallBehindCnt, prStaRec->u4RxReorderHoleCnt); + + DBGLOG(RX, INFO, " RX(%u %u %u) BA(0x%x %u) OK(%u %u) ERR(%u)\n", + prInfo->ucRcvRcpi, prInfo->ucHwChanNum, prInfo->fgRxIsShortGI, + prInfo->ucRxAggBitmap, prInfo->ucRxAggMaxSize, + prInfo->u4RxDataCntAll, prStaRec->u4StatsRxPassToOsCnt, prInfo->u4RxDataCntErr); + + DBGLOG(RX, INFO, " RX Free MAC DESC(%u %u %u %u %u %u) Free HIF DESC(%u %u %u %u %u %u)\n", + prInfo->u4RxMacFreeDescCnt[0], prInfo->u4RxMacFreeDescCnt[1], + prInfo->u4RxMacFreeDescCnt[2], prInfo->u4RxMacFreeDescCnt[3], + prInfo->u4RxMacFreeDescCnt[4], prInfo->u4RxMacFreeDescCnt[5], + prInfo->u4RxHifFreeDescCnt[0], prInfo->u4RxHifFreeDescCnt[1], + prInfo->u4RxHifFreeDescCnt[2], prInfo->u4RxHifFreeDescCnt[3], + prInfo->u4RxHifFreeDescCnt[4], prInfo->u4RxHifFreeDescCnt[5])); + + DBGLOG(RX, INFO, " RCCK (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" + "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[0][0], prInfo->u4RxRateRetryCnt[0][0], + prInfo->u4RxRateCnt[0][1], prInfo->u4RxRateRetryCnt[0][1], + prInfo->u4RxRateCnt[0][2], prInfo->u4RxRateRetryCnt[0][2], + prInfo->u4RxRateCnt[0][3], prInfo->u4RxRateRetryCnt[0][3], + prInfo->u4RxRateCnt[0][4], prInfo->u4RxRateRetryCnt[0][4], + prInfo->u4RxRateCnt[0][5], prInfo->u4RxRateRetryCnt[0][5], + prInfo->u4RxRateCnt[0][6], prInfo->u4RxRateRetryCnt[0][6], + prInfo->u4RxRateCnt[0][7], prInfo->u4RxRateRetryCnt[0][7], + prInfo->u4RxRateCnt[0][8], prInfo->u4RxRateRetryCnt[0][8], + prInfo->u4RxRateCnt[0][9], prInfo->u4RxRateRetryCnt[0][9], + prInfo->u4RxRateCnt[0][10], prInfo->u4RxRateRetryCnt[0][10], + prInfo->u4RxRateCnt[0][11], prInfo->u4RxRateRetryCnt[0][11], + prInfo->u4RxRateCnt[0][12], prInfo->u4RxRateRetryCnt[0][12], + prInfo->u4RxRateCnt[0][13], prInfo->u4RxRateRetryCnt[0][13], + prInfo->u4RxRateCnt[0][14], prInfo->u4RxRateRetryCnt[0][14], + prInfo->u4RxRateCnt[0][15], prInfo->u4RxRateRetryCnt[0][15])); + DBGLOG(RX, INFO, " ROFDM (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" + "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[1][0], prInfo->u4RxRateRetryCnt[1][0], + prInfo->u4RxRateCnt[1][1], prInfo->u4RxRateRetryCnt[1][1], + prInfo->u4RxRateCnt[1][2], prInfo->u4RxRateRetryCnt[1][2], + prInfo->u4RxRateCnt[1][3], prInfo->u4RxRateRetryCnt[1][3], + prInfo->u4RxRateCnt[1][4], prInfo->u4RxRateRetryCnt[1][4], + prInfo->u4RxRateCnt[1][5], prInfo->u4RxRateRetryCnt[1][5], + prInfo->u4RxRateCnt[1][6], prInfo->u4RxRateRetryCnt[1][6], + prInfo->u4RxRateCnt[1][7], prInfo->u4RxRateRetryCnt[1][7], + prInfo->u4RxRateCnt[1][8], prInfo->u4RxRateRetryCnt[1][8], + prInfo->u4RxRateCnt[1][9], prInfo->u4RxRateRetryCnt[1][9], + prInfo->u4RxRateCnt[1][10], prInfo->u4RxRateRetryCnt[1][10], + prInfo->u4RxRateCnt[1][11], prInfo->u4RxRateRetryCnt[1][11], + prInfo->u4RxRateCnt[1][12], prInfo->u4RxRateRetryCnt[1][12], + prInfo->u4RxRateCnt[1][13], prInfo->u4RxRateRetryCnt[1][13], + prInfo->u4RxRateCnt[1][14], prInfo->u4RxRateRetryCnt[1][14], + prInfo->u4RxRateCnt[1][15], prInfo->u4RxRateRetryCnt[1][15])); + DBGLOG(RX, INFO, " RHT (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n" + "(%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u) (%u %u)\n", + prInfo->u4RxRateCnt[2][0], prInfo->u4RxRateRetryCnt[2][0], + prInfo->u4RxRateCnt[2][1], prInfo->u4RxRateRetryCnt[2][1], + prInfo->u4RxRateCnt[2][2], prInfo->u4RxRateRetryCnt[2][2], + prInfo->u4RxRateCnt[2][3], prInfo->u4RxRateRetryCnt[2][3], + prInfo->u4RxRateCnt[2][4], prInfo->u4RxRateRetryCnt[2][4], + prInfo->u4RxRateCnt[2][5], prInfo->u4RxRateRetryCnt[2][5], + prInfo->u4RxRateCnt[2][6], prInfo->u4RxRateRetryCnt[2][6], + prInfo->u4RxRateCnt[2][7], prInfo->u4RxRateRetryCnt[2][7], + prInfo->u4RxRateCnt[2][8], prInfo->u4RxRateRetryCnt[2][8], + prInfo->u4RxRateCnt[2][9], prInfo->u4RxRateRetryCnt[2][9], + prInfo->u4RxRateCnt[2][10], prInfo->u4RxRateRetryCnt[2][10], + prInfo->u4RxRateCnt[2][11], prInfo->u4RxRateRetryCnt[2][11], + prInfo->u4RxRateCnt[2][12], prInfo->u4RxRateRetryCnt[2][12], + prInfo->u4RxRateCnt[2][13], prInfo->u4RxRateRetryCnt[2][13], + prInfo->u4RxRateCnt[2][14], prInfo->u4RxRateRetryCnt[2][14], + prInfo->u4RxRateCnt[2][15], prInfo->u4RxRateRetryCnt[2][15])); + + /* delay from HIF to MAC */ + DBGLOG(RX, INFO, " StayIntH2M us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prInfo->u4StayIntMinH2M[0], prInfo->u4StayIntAvgH2M[0], + prInfo->u4StayIntMaxH2M[0], + prInfo->u4StayIntMinH2M[1], prInfo->u4StayIntAvgH2M[1], + prInfo->u4StayIntMaxH2M[1], + prInfo->u4StayIntMinH2M[2], prInfo->u4StayIntAvgH2M[2], + prInfo->u4StayIntMaxH2M[2])); + /* delay from MAC to TXDONE */ + DBGLOG(RX, INFO, " AirTime us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prInfo->u4AirDelayMin[0] << 5, prInfo->u4AirDelayAvg[0] << 5, + prInfo->u4AirDelayMax[0] << 5, + prInfo->u4AirDelayMin[1] << 5, prInfo->u4AirDelayAvg[1] << 5, + prInfo->u4AirDelayMax[1] << 5, + prInfo->u4TxDataCntAll, (prInfo->u4AirDelayAvg[2] << 5) / (prInfo->u4TxDataCntAll), + (prInfo->u4AirDelayAvg[2] << 5) / 400000)); + prAdapter->u4AirDelayTotal = (prInfo->u4AirDelayTotal << 5) / 400000; + /* delay from HIF to TXDONE */ + DBGLOG(RX, INFO, " StayInt us (%u %u %u_%u) (%u %u %u_%u) (%u %u %u_%u)\n", + prInfo->u4StayIntMin[0], prInfo->u4StayIntAvg[0], + prInfo->u4StayIntMax[0], prInfo->u4StayIntMaxSysTime[0], + prInfo->u4StayIntMin[1], prInfo->u4StayIntAvg[1], + prInfo->u4StayIntMax[1], prInfo->u4StayIntMaxSysTime[1], + prInfo->u4StayIntMin[2], prInfo->u4StayIntAvg[2], + prInfo->u4StayIntMax[2], prInfo->u4StayIntMaxSysTime[2])); + /* delay from Driver to TXDONE */ + DBGLOG(RX, INFO, " StayIntD2T us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prInfo->u4StayIntMinD2T[0], prInfo->u4StayIntAvgD2T[0], + prInfo->u4StayIntMaxD2T[0], + prInfo->u4StayIntMinD2T[1], prInfo->u4StayIntAvgD2T[1], + prInfo->u4StayIntMaxD2T[1], + prInfo->u4StayIntMinD2T[2], prInfo->u4StayIntAvgD2T[2], + prInfo->u4StayIntMaxD2T[2])); + + /* delay from RXDONE to HIF */ + DBGLOG(RX, INFO, " StayIntR_M2H us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prInfo->u4StayIntMinRx[0], prInfo->u4StayIntAvgRx[0], + prInfo->u4StayIntMaxRx[0], + prInfo->u4StayIntMinRx[1], prInfo->u4StayIntAvgRx[1], + prInfo->u4StayIntMaxRx[1], + prInfo->u4StayIntMinRx[2], prInfo->u4StayIntAvgRx[2], prInfo->u4StayIntMaxRx[2])); + /* delay from HIF to OS */ + DBGLOG(RX, INFO, " StayIntR_H2D us (%u %u %u) (%u %u %u) (%u %u %u)\n", + prStaRec->u4StayIntMinRx[0], prStaRec->u4StayIntAvgRx[0], + prStaRec->u4StayIntMaxRx[0], + prStaRec->u4StayIntMinRx[1], prStaRec->u4StayIntAvgRx[1], + prStaRec->u4StayIntMaxRx[1], + prStaRec->u4StayIntMinRx[2], prStaRec->u4StayIntAvgRx[2], + prStaRec->u4StayIntMaxRx[2])); + + /* count based on delay from OS to HIF */ + DBGLOG(RX, INFO, " StayCntD2H unit:%dms (%d %d %d %d)\n", + STATS_STAY_INT_D2H_CONST, + prInfo->u4StayIntD2HByConst[0], prInfo->u4StayIntD2HByConst[1], + prInfo->u4StayIntD2HByConst[2], prInfo->u4StayIntD2HByConst[3]); + + /* count based on different delay from HIF to TX DONE */ + DBGLOG(RX, INFO, " StayCnt unit:%dms (%d %d %d %d)\n", + STATS_STAY_INT_CONST, + prInfo->u4StayIntByConst[0], prInfo->u4StayIntByConst[1], + prInfo->u4StayIntByConst[2], prInfo->u4StayIntByConst[3]); + DBGLOG(RX, INFO, " StayCnt (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~%d:%d) (%d~:%d)\n", + 0, prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntCnt[0], + prInfo->u4StayIntMaxPast / 4, prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntCnt[1], + prInfo->u4StayIntMaxPast / 2, prInfo->u4StayIntMaxPast * 3 / 4, + prInfo->u4StayIntCnt[2], prInfo->u4StayIntMaxPast * 3 / 4, prInfo->u4StayIntMaxPast, + prInfo->u4StayIntCnt[3], prInfo->u4StayIntMaxPast, prInfo->u4StayIntCnt[4])); + + /* channel idle time */ + DBGLOG(RX, INFO, " Idle Time (slot): (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u) (%u)\n", + prInfo->au4ChanIdleCnt[0], prInfo->au4ChanIdleCnt[1], + prInfo->au4ChanIdleCnt[2], prInfo->au4ChanIdleCnt[3], + prInfo->au4ChanIdleCnt[4], prInfo->au4ChanIdleCnt[5], + prInfo->au4ChanIdleCnt[6], prInfo->au4ChanIdleCnt[7], + prInfo->au4ChanIdleCnt[8], prInfo->au4ChanIdleCnt[9])); + + /* BT coex */ + DBGLOG(RX, INFO, " BT coex (0x%x)\n", prInfo->u4BtContUseTime); + + /* others */ + DBGLOG(RX, INFO, " OTHER (%u) (%u) (%u) (%u) (%u) (%ums) (%uus)\n", + prInfo->u4RxFifoFullCnt, prAdapter->ucScanTime, + prInfo->u4NumOfChanChange, prStaRec->u4NumOfNoTxQuota, + prInfo->ucNumOfPsChange, prInfo->u4PsIntMax, u4DrvOwnMax / 1000); + + /* reset */ + kalMemZero(prStaRec->u4StayIntMinRx, sizeof(prStaRec->u4StayIntMinRx)); + kalMemZero(prStaRec->u4StayIntAvgRx, sizeof(prStaRec->u4StayIntAvgRx)); + kalMemZero(prStaRec->u4StayIntMaxRx, sizeof(prStaRec->u4StayIntMaxRx)); + prStaRec->u4StatsRxPassToOsCnt = 0; + prStaRec->u4RxReorderFallAheadCnt = 0; + prStaRec->u4RxReorderFallBehindCnt = 0; + prStaRec->u4RxReorderHoleCnt = 0; + } + + STATS_DRIVER_OWN_RESET(); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to request firmware to feedback statistics. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +statsInfoEnvRequest(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + STATS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* sanity check */ + if (fgIsUnderSuspend == true) + return WLAN_STATUS_SUCCESS; /* do not request stats after early suspend */ + + /* init command buffer */ + prCmdContent = (STATS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = STATS_CORE_CMD_ENV_REQUEST; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_STATS, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(STATS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(RX, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return WLAN_STATUS_RESOURCES; + } + + DBGLOG(RX, INFO, "%s cmd ok.\n", __func__); + return WLAN_STATUS_SUCCESS; +} + +/******************************************************************************* +* P U B L I C F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to handle any statistics event. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID statsEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + UINT32 u4EventId; + + /* sanity check */ +/* DBGLOG(RX, INFO, */ +/* (" %s: Rcv a event\n", __FUNCTION__)); */ + + if ((prGlueInfo == NULL) || (prInBuf == NULL)) + return; /* shall not be here */ + + /* handle */ + u4EventId = *(UINT32 *) prInBuf; + u4InBufLen -= 4; + +/* DBGLOG(RX, INFO, */ +/* (" %s: Rcv a event: %d\n", __FUNCTION__, u4EventId)); */ + + switch (u4EventId) { + case STATS_HOST_EVENT_ENV_REPORT: + statsInfoEnvDisplay(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + + default: + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to detect if we can request firmware to feedback statistics. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] ucStaRecIndex The station index +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID statsEnvReportDetect(ADAPTER_T *prAdapter, UINT8 ucStaRecIndex) +{ + STA_RECORD_T *prStaRec; + OS_SYSTIME rCurTime; + STATS_CMD_CORE_T rCmd; + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); + if (prStaRec == NULL) + return; + + prStaRec->u4StatsEnvTxCnt++; + GET_CURRENT_SYSTIME(&rCurTime); + + if (prStaRec->rStatsEnvTxPeriodLastTime == 0) { + prStaRec->rStatsEnvTxLastTime = rCurTime; + prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; + return; + } + + if (prStaRec->u4StatsEnvTxCnt > STATS_ENV_TX_CNT_REPORT_TRIGGER) { + if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxLastTime, + SEC_TO_SYSTIME(STATS_ENV_TX_CNT_REPORT_TRIGGER_SEC))) { + rCmd.ucStaRecIdx = ucStaRecIndex; + statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); + + prStaRec->rStatsEnvTxLastTime = rCurTime; + prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; + prStaRec->u4StatsEnvTxCnt = 0; + return; + } + } + + if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rStatsEnvTxPeriodLastTime, SEC_TO_SYSTIME(STATS_ENV_TIMEOUT_SEC))) { + rCmd.ucStaRecIdx = ucStaRecIndex; + statsInfoEnvRequest(prAdapter, &rCmd, 0, NULL); + + prStaRec->rStatsEnvTxPeriodLastTime = rCurTime; + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to handle rx done. +* +* \param[in] prStaRec Pointer to the STA_RECORD_T structure +* \param[in] prSwRfb Pointer to the received packet +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID StatsEnvRxDone(STA_RECORD_T *prStaRec, SW_RFB_T *prSwRfb) +{ + UINT32 u4LenId; + UINT32 u4CurTime, u4DifTime; + + /* sanity check */ + if (prStaRec == NULL) + return; + + /* stats: rx done count */ + prStaRec->u4StatsRxPassToOsCnt++; + + /* get length partition ID */ + u4LenId = 0; + if (prSwRfb->u2PacketLen < STATS_STAY_INT_BYTE_THRESHOLD) { + u4LenId = 0; + } else { + if ((STATS_STAY_INT_BYTE_THRESHOLD <= prSwRfb->u2PacketLen) && + (prSwRfb->u2PacketLen < (STATS_STAY_INT_BYTE_THRESHOLD << 1))) { + u4LenId = 1; + } else + u4LenId = 2; + } + + /* stats: rx delay */ + u4CurTime = kalGetTimeTick(); + + if ((u4CurTime > prSwRfb->rRxTime) && (prSwRfb->rRxTime != 0)) { + u4DifTime = u4CurTime - prSwRfb->rRxTime; + + if (prStaRec->u4StayIntMinRx[u4LenId] == 0) /* impossible */ + prStaRec->u4StayIntMinRx[u4LenId] = 0xffffffff; + + if (u4DifTime > prStaRec->u4StayIntMaxRx[u4LenId]) + prStaRec->u4StayIntMaxRx[u4LenId] = u4DifTime; + else if (u4DifTime < prStaRec->u4StayIntMinRx[u4LenId]) + prStaRec->u4StayIntMinRx[u4LenId] = u4DifTime; + + prStaRec->u4StayIntAvgRx[u4LenId] += u4DifTime; + if (prStaRec->u4StayIntAvgRx[u4LenId] != u4DifTime) + prStaRec->u4StayIntAvgRx[u4LenId] >>= 1; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to handle rx done. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +UINT_64 StatsEnvTimeGet(VOID) +{ + /* TODO: use better API to get time to save time, jiffies unit is 10ms, too large */ + +/* struct timeval tv; */ + +/* do_gettimeofday(&tv); */ +/* return tv.tv_usec + tv.tv_sec * (UINT_64)1000000; */ + + UINT_64 u8Clk; +/* UINT32 *pClk = &u8Clk; */ + + u8Clk = sched_clock(); /* unit: naro seconds */ +/* printk(" sched_clock() = %x %x %u\n", pClk[0], pClk[1], sizeof(jiffies)); */ + + return (UINT_64) u8Clk; /* sched_clock *//* jiffies size = 4B */ +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to handle rx done. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID StatsEnvTxTime2Hif(MSDU_INFO_T *prMsduInfo, HIF_TX_HEADER_T *prHwTxHeader) +{ + UINT_64 u8SysTime, u8SysTimeIn; + UINT32 u4TimeDiff; + + u8SysTime = StatsEnvTimeGet(); + u8SysTimeIn = GLUE_GET_PKT_XTIME(prMsduInfo->prPacket); + +/* printk(" hif: 0x%x %u %u %u\n", */ +/* prMsduInfo->prPacket, StatsEnvTimeGet(), u8SysTime, GLUE_GET_PKT_XTIME(prMsduInfo->prPacket)); */ + + if ((u8SysTimeIn > 0) && (u8SysTime > u8SysTimeIn)) { + u8SysTime = u8SysTime - u8SysTimeIn; + u4TimeDiff = (UINT32) u8SysTime; + u4TimeDiff = u4TimeDiff / 1000; /* ns to us */ + + /* pass the delay between OS to us and we to HIF */ + if (u4TimeDiff > 0xFFFF) + *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) 0xFFFF; /* 65535 us */ + else + *(UINT16 *) prHwTxHeader->aucReserved = (UINT16) u4TimeDiff; + +/* printk(" u4TimeDiff: %u\n", u4TimeDiff); */ + } else { + prHwTxHeader->aucReserved[0] = 0; + prHwTxHeader->aucReserved[1] = 0; + } +} + +static VOID statsParsePktInfo(PUINT_8 pucPkt, UINT_8 status, UINT_8 eventType, P_MSDU_INFO_T prMsduInfo) +{ + /* get ethernet protocol */ + UINT_16 u2EtherType = (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); + PUINT_8 pucEthBody = &pucPkt[ETH_HLEN]; + + switch (u2EtherType) { + case ETH_P_ARP: + { + UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; + if (eventType == EVENT_TX) + prMsduInfo->fgIsBasicRate = TRUE; + + if ((su2TxDoneCfg & CFG_ARP) == 0) + break; + + switch (eventType) { + case EVENT_RX: + if (u2OpCode == ARP_PRO_REQ) + DBGLOG(RX, INFO, " Arp Req From IP: %d.%d.%d.%d\n", + pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); + else if (u2OpCode == ARP_PRO_RSP) + DBGLOG(RX, INFO, " Arp Rsp from IP: %d.%d.%d.%d\n", + pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); + break; + case EVENT_TX: + if (u2OpCode == ARP_PRO_REQ) + DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", + pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); + else if (u2OpCode == ARP_PRO_RSP) + DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", + pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + break; + case EVENT_TX_DONE: + if (u2OpCode == ARP_PRO_REQ) + DBGLOG(TX, INFO, " Arp Req to IP: %d.%d.%d.%d\n", status, + pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); + else if (u2OpCode == ARP_PRO_RSP) + DBGLOG(TX, INFO, " Arp Rsp to IP: %d.%d.%d.%d\n", status, + pucEthBody[24], pucEthBody[25], pucEthBody[26], pucEthBody[27]); + break; + } + break; + } + case ETH_P_IP: + { + UINT_8 ucIpProto = pucEthBody[9]; /* IP header without options */ + UINT_8 ucIpVersion = (pucEthBody[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + UINT_16 u2IpId = pucEthBody[4]<<8 | pucEthBody[5]; + + if (ucIpVersion != IPVERSION) + break; + + switch (ucIpProto) { + case IP_PRO_ICMP: + { + /* the number of ICMP packets is seldom so we print log here */ + UINT_8 ucIcmpType; + UINT_16 u2IcmpId, u2IcmpSeq; + PUINT_8 pucIcmp = &pucEthBody[20]; + + ucIcmpType = pucIcmp[0]; + /* don't log network unreachable packet */ + if (((su2TxDoneCfg & CFG_ICMP) == 0) || ucIcmpType == 3) + break; + u2IcmpId = *(UINT_16 *) &pucIcmp[4]; + u2IcmpSeq = *(UINT_16 *) &pucIcmp[6]; + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " ICMP: Type %d, Id BE 0x%04x, Seq BE 0x%04x\n", + ucIcmpType, u2IcmpId, u2IcmpSeq); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " ICMP: Type %d, Id 0x04%x, Seq BE 0x%04x\n", + ucIcmpType, u2IcmpId, u2IcmpSeq); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " Type %d, Id 0x%04x, Seq 0x%04x\n", + status, ucIcmpType, u2IcmpId, u2IcmpSeq); + break; + } + break; + } + case IP_PRO_UDP: + { + /* the number of DHCP packets is seldom so we print log here */ + PUINT_8 pucUdp = &pucEthBody[20]; + PUINT_8 pucUdpPayload = &pucUdp[8]; + UINT_16 u2UdpDstPort; + UINT_16 u2UdpSrcPort; + + u2UdpDstPort = (pucUdp[2] << 8) | pucUdp[3]; + u2UdpSrcPort = (pucUdp[0] << 8) | pucUdp[1]; + /* dhcp */ + if ((u2UdpDstPort == UDP_PORT_DHCPS) || (u2UdpDstPort == UDP_PORT_DHCPC)) { + UINT_32 u4TransID = pucUdpPayload[4]<<24 | pucUdpPayload[5]<<16 | + pucUdpPayload[6]<<8 | pucUdpPayload[7]; + + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", + u2IpId, pucUdpPayload[0], u4TransID); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", + u2IpId, pucUdpPayload[0], u4TransID); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + prMsduInfo->fgIsBasicRate = TRUE; + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, + " DHCP: IPID 0x%02x, MsgType 0x%x, TransID 0x%08x\n", + status, u2IpId, pucUdpPayload[0], u4TransID); + break; + } + } else if (u2UdpDstPort == UDP_PORT_DNS) { /* tx dns */ + UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; + if (eventType == EVENT_TX) + prMsduInfo->fgIsBasicRate = TRUE; + + if ((su2TxDoneCfg & CFG_DNS) == 0) + break; + if (eventType == EVENT_TX) { + DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + } else if (eventType == EVENT_TX_DONE) + DBGLOG(TX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", + status, u2IpId, u2TransId); + } else if (u2UdpSrcPort == UDP_PORT_DNS && eventType == EVENT_RX) { /* rx dns */ + UINT_16 u2TransId = (pucUdpPayload[0] << 8) | pucUdpPayload[1]; + + if ((su2TxDoneCfg & CFG_DNS) == 0) + break; + DBGLOG(RX, INFO, " DNS: IPID 0x%02x, TransID 0x%04x\n", u2IpId, u2TransId); + } else if ((su2TxDoneCfg & CFG_UDP) != 0) { + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " UDP: IPID 0x%04x\n", u2IpId); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", u2IpId); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " UDP: IPID 0x%04x\n", status, u2IpId); + break; + } + } + break; + } + case IP_PRO_TCP: + if ((su2TxDoneCfg & CFG_TCP) == 0) + break; + + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " TCP: IPID 0x%04x\n", u2IpId); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", u2IpId); + prMsduInfo->fgNeedTxDoneStatus = TRUE; + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " TCP: IPID 0x%04x\n", status, u2IpId); + break; + } + break; + } + break; + } + case ETH_P_PRE_1X: + DBGLOG(RX, INFO, "pre-1x\n"); + case ETH_P_1X: + { + PUINT_8 pucEapol = pucEthBody; + UINT_8 ucEapolType = pucEapol[1]; + + switch (ucEapolType) { + case 0: /* eap packet */ + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " EAP Packet: code %d, id %d, type %d\n", + pucEapol[4], pucEapol[5], pucEapol[7]); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", + pucEapol[4], pucEapol[5], pucEapol[7]); + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d\n", + status, pucEapol[4], pucEapol[5], pucEapol[7]); + break; + } + break; + case 1: /* eapol start */ + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " EAPOL: start\n"); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " EAPOL: start\n"); + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " EAPOL: start\n", status); + break; + } + break; + case 3: /* key */ + { + UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; + + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, + " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", + u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], + pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); + break; + case EVENT_TX: + DBGLOG(TX, INFO, + " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", + u2KeyInfo, + pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], + pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, + " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x...\n", + status, u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], + pucEapol[20], pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24]); + break; + } + + break; + } + } + break; + } + case ETH_WPI_1X: + { + UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ + UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; + UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; + + switch (eventType) { + case EVENT_RX: + DBGLOG(RX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", + ucSubType, u2Length, u2Seq); + break; + case EVENT_TX: + DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", + ucSubType, u2Length, u2Seq); + break; + case EVENT_TX_DONE: + DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", + status, ucSubType, u2Length, u2Seq); + break; + } + break; + } + } +} +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display rx packet information. +* +* \param[in] pPkt Pointer to the packet +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID StatsRxPktInfoDisplay(UINT_8 *pPkt) +{ + statsParsePktInfo(pPkt, 0, EVENT_RX, NULL); +#if 0 /* carefully! too many ARP */ + if (pucIpHdr[0] == 0x00) { /* ARP */ + UINT_8 *pucDstIp = (UINT_8 *) pucIpHdr; + + if (pucDstIp[7] == ARP_PRO_REQ) { + DBGLOG(RX, TRACE, " OS rx a arp req from %d.%d.%d.%d\n", + pucDstIp[14], pucDstIp[15], pucDstIp[16], pucDstIp[17]); + } else if (pucDstIp[7] == ARP_PRO_RSP) { + DBGLOG(RX, TRACE, " OS rx a arp rsp from %d.%d.%d.%d\n", + pucDstIp[24], pucDstIp[25], pucDstIp[26], pucDstIp[27]); + } + } +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display tx packet information. +* +* \param[in] pPkt Pointer to the packet +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID StatsTxPktCallBack(UINT_8 *pPkt, P_MSDU_INFO_T prMsduInfo) +{ + UINT_16 u2EtherTypeLen; + + u2EtherTypeLen = (pPkt[ETH_TYPE_LEN_OFFSET] << 8) | (pPkt[ETH_TYPE_LEN_OFFSET + 1]); + statsParsePktInfo(pPkt, 0, EVENT_TX, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to handle display tx packet tx done information. +* +* \param[in] pPkt Pointer to the packet +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID StatsTxPktDoneInfoDisplay(ADAPTER_T *prAdapter, UINT_8 *pucEvtBuf) +{ + EVENT_TX_DONE_STATUS_T *prTxDone; + + prTxDone = (EVENT_TX_DONE_STATUS_T *) pucEvtBuf; + /* + * Why 65 Bytes: + * 8B + wlanheader(40B) + hif_tx_header(16B) + 6B + 6B(LLC) - 12B + */ + statsParsePktInfo(&prTxDone->aucPktBuf[64], prTxDone->ucStatus, EVENT_TX_DONE, NULL); +} + +VOID StatsSetCfgTxDone(UINT_16 u2Cfg, BOOLEAN fgSet) +{ + if (fgSet) + su2TxDoneCfg |= u2Cfg; + else + su2TxDoneCfg &= ~u2Cfg; +} + +UINT_16 StatsGetCfgTxDone(VOID) +{ + return su2TxDoneCfg; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c new file mode 100644 index 0000000000000..67eccbda9fa8f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/swcr.c @@ -0,0 +1,1170 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/swcr.c#1 +*/ + +/*! \file "swcr.c" + \brief + +*/ + +/* +** Log: swcr.c + * + * 06 04 2012 tsaiyuan.hsu + * [WCXRP00001249] [ALPS.ICS] Daily build warning on "wlan/mgmt/swcr.c#1" + * resolve build waring for "WNM_UNIT_TEST not defined". + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 11 22 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * keep debug counter setting after wake up. + * + * 11 15 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * fix debug counters of rx in driver. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of bb and ar for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters, eCurPsProf, for PS. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 08 31 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * remove obsolete code. + * + * 08 15 2011 tsaiyuan.hsu + * [WCXRP00000931] [MT5931 Wi-Fi][DRV/FW] add swcr to disable roaming from driver + * add swcr in driver reg, 0x9fxx0000, to disable roaming . + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 03 28 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Fix Klockwork warning. + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add swcr for test. + * +* +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_SWCR + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wformat" +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if 0 +SWCR_MOD_MAP_ENTRY_T g_arSwCrAllMaps[] = { + {SWCR_MAP_NUM(g_arRlmArSwCrMap), g_arRlmArSwCrMap}, /* 0x00nn */ + {0, NULL} +}; +#endif + +UINT_32 g_au4SwCr[SWCR_CR_NUM]; /*: 0: command other: data */ + +/* JB mDNS Filter*/ +UINT_32 g_u4mDNSRXFilter = 0; /* [31] 0: stop 1: start, [3] IPv6 [2] IPv4 */ + +static TIMER_T g_rSwcrDebugTimer; +static BOOLEAN g_fgSwcrDebugTimer = FALSE; +static UINT_32 g_u4SwcrDebugCheckTimeout; +static ENUM_SWCR_DBG_TYPE_T g_ucSwcrDebugCheckType; +static UINT_32 g_u4SwcrDebugFrameDumpType; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#define TEST_PS 1 + +static const PFN_CMD_RW_T g_arSwCtrlCmd[] = { + swCtrlCmdCategory0, + swCtrlCmdCategory1 +#if TEST_PS + , testPsCmdCategory0, testPsCmdCategory1 +#endif +#if CFG_SUPPORT_802_11V +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) + , testWNMCmdCategory0 +#endif +#endif +}; + +const PFN_SWCR_RW_T g_arSwCrModHandle[] = { + swCtrlSwCr, + NULL +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +enum { + SWCTRL_MAGIC, + SWCTRL_DEBUG, + SWCTRL_WIFI_VAR, + SWCTRL_ENABLE_INT, + SWCTRL_DISABLE_INT, + SWCTRL_TXM_INFO, + SWCTRL_RXM_INFO, + SWCTRL_DUMP_BSS, + SWCTRL_QM_INFO, + SWCTRL_DUMP_ALL_QUEUE_LEN, + SWCTRL_DUMP_MEM, + SWCTRL_TX_CTRL_INFO, + SWCTRL_DUMP_QUEUE, + SWCTRL_DUMP_QM_DBG_CNT, + SWCTRL_QM_DBG_CNT, + SWCTRL_RX_PKTS_DUMP, + SWCTRL_RX_MDNS_FILTER, + SWCTRL_CATA0_INDEX_NUM +}; + +enum { + SWCTRL_STA_INFO, + SWCTRL_DUMP_STA, + SWCTRL_STA_QUE_INFO, + SWCTRL_CATA1_INDEX_NUM +}; + +/* JB mDNS Filter*/ +#define RX_MDNS_FILTER_START (1<<31) +#define RX_MDNS_FILTER_IPV4 (1<<2) +#define RX_MDNS_FILTER_IPV6 (1<<3) +typedef enum _ENUM_SWCR_RX_MDNS_FILTER_CMD_T { + SWCR_RX_MDNS_FILTER_CMD_STOP = 0, + SWCR_RX_MDNS_FILTER_CMD_START, + SWCR_RX_MDNS_FILTER_CMD_ADD, + SWCR_RX_MDNS_FILTER_CMD_REMOVE, + SWCR_RX_MDNS_FILTER_NUM +} ENUM_SWCR_RX_MDNS_FILTER_CMD_T; + +#if TEST_PS +enum { + TEST_PS_MAGIC, + TEST_PS_SETUP_BSS, + TEST_PS_ENABLE_BEACON, + TEST_PS_TRIGGER_BMC, + TEST_PS_SEND_NULL, + TEST_PS_BUFFER_BMC, + TEST_PS_UPDATE_BEACON, + TEST_PS_CATA0_INDEX_NUM +}; + +enum { + TEST_PS_STA_PS, + TEST_PS_STA_ENTER_PS, + TEST_PS_STA_EXIT_PS, + TEST_PS_STA_TRIGGER_PSPOLL, + TEST_PS_STA_TRIGGER_FRAME, + TEST_PS_CATA1_INDEX_NUM +}; +#endif + +#if CFG_SUPPORT_802_11V +#if WNM_UNIT_TEST +enum { + TEST_WNM_TIMING_MEAS, + TEST_WNM_CATA0_INDEX_NUM +}; +#endif +#endif + +#define _SWCTRL_MAGIC 0x66201642 + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +void dumpQueue(P_ADAPTER_T prAdapter) +{ + + P_TX_CTRL_T prTxCtrl; + P_QUE_MGT_T prQM; + P_GLUE_INFO_T prGlueInfo; + UINT_32 i; + UINT_32 j; + + DEBUGFUNC("dumpQueue"); + + prTxCtrl = &prAdapter->rTxCtrl; + prQM = &prAdapter->rQM; + prGlueInfo = prAdapter->prGlueInfo; + + for (i = TC0_INDEX; i <= TC5_INDEX; i++) { + DBGLOG(SW4, INFO, "TC %u\n", i); + DBGLOG(SW4, INFO, "Max %u Free %u\n", + prTxCtrl->rTc.aucMaxNumOfBuffer[i], prTxCtrl->rTc.aucFreeBufferCount[i]); + + DBGLOG(SW4, INFO, "Average %u minReserved %u CurrentTcResource %u GuaranteedTcResource %u\n", + QM_GET_TX_QUEUE_LEN(prAdapter, i), + prQM->au4MinReservedTcResource[i], + prQM->au4CurrentTcResource[i], prQM->au4GuaranteedTcResource[i]); + + } + + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { + DBGLOG(SW4, INFO, + "TC %u HeadStaIdx %u ForwardCount %u\n", i, prQM->au4HeadStaRecIndex[i], + prQM->au4ForwardCount[i]); + } + + DBGLOG(SW4, INFO, "BMC or unknown TxQueue Len %u\n", prQM->arTxQueue[0].u4NumElem); + DBGLOG(SW4, INFO, "Pending %d\n", prGlueInfo->i4TxPendingFrameNum); + DBGLOG(SW4, INFO, "Pending Security %d\n", prGlueInfo->i4TxPendingSecurityFrameNum); +#if defined(LINUX) + for (i = 0; i < 4; i++) { + for (j = 0; j < CFG_MAX_TXQ_NUM; j++) { + DBGLOG(SW4, INFO, + "Pending Q[%u][%u] %d\n", i, j, prGlueInfo->ai4TxPendingFrameNumPerQueue[i][j]); + } + } +#endif + + DBGLOG(SW4, INFO, " rFreeSwRfbList %u\n", prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); + DBGLOG(SW4, INFO, " rReceivedRfbList %u\n", prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem); + DBGLOG(SW4, INFO, " rIndicatedRfbList %u\n", prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem); + DBGLOG(SW4, INFO, " ucNumIndPacket %u\n", prAdapter->rRxCtrl.ucNumIndPacket); + DBGLOG(SW4, INFO, " ucNumRetainedPacket %u\n", prAdapter->rRxCtrl.ucNumRetainedPacket); + +} + +void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + UINT_8 ucWTEntry; + UINT_32 i; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("dumpSTA"); + + ASSERT(prStaRec); + ucWTEntry = prStaRec->ucWTEntry; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + ASSERT(prBssInfo); + + DBGLOG(SW4, INFO, "Mac address: %pM Rcpi %u" "\n", prStaRec->aucMacAddr, prStaRec->ucRCPI); + + DBGLOG(SW4, INFO, "Idx %u Wtbl %u Used %u State %u Bss Phy 0x%x Sta DesiredPhy 0x%x\n", + prStaRec->ucIndex, ucWTEntry, + prStaRec->fgIsInUse, prStaRec->ucStaState, + prBssInfo->ucPhyTypeSet, prStaRec->ucDesiredPhyTypeSet); + + DBGLOG(SW4, INFO, "Sta Operation 0x%x DesiredNontHtRateSet 0x%x Mcs 0x%x u2HtCapInfo 0x%x\n", + prStaRec->u2OperationalRateSet, prStaRec->u2DesiredNonHTRateSet, prStaRec->ucMcsSet, + prStaRec->u2HtCapInfo); + + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) + DBGLOG(SW4, INFO, "TC %u Queue Len %u\n", i, prStaRec->arTxQueue[i].u4NumElem); + + DBGLOG(SW4, INFO, "BmpDeliveryAC %x\n", prStaRec->ucBmpDeliveryAC); + DBGLOG(SW4, INFO, "BmpTriggerAC %x\n", prStaRec->ucBmpTriggerAC); + DBGLOG(SW4, INFO, "UapsdSpSupproted %u\n", prStaRec->fgIsUapsdSupported); + DBGLOG(SW4, INFO, "IsQoS %u\n", prStaRec->fgIsQoS); + DBGLOG(SW4, INFO, "AssocId %u\n", prStaRec->u2AssocId); + + DBGLOG(SW4, INFO, "fgIsInPS %u\n", prStaRec->fgIsInPS); + DBGLOG(SW4, INFO, "ucFreeQuota %u\n", prStaRec->ucFreeQuota); + DBGLOG(SW4, INFO, "ucFreeQuotaForDelivery %u\n", prStaRec->ucFreeQuotaForDelivery); + DBGLOG(SW4, INFO, "ucFreeQuotaForNonDelivery %u\n", prStaRec->ucFreeQuotaForNonDelivery); + +#if 0 + DBGLOG(SW4, INFO, "IsQmmSup %u\n", prStaRec->fgIsWmmSupported); + DBGLOG(SW4, INFO, "IsUapsdSup %u\n", prStaRec->fgIsUapsdSupported); + DBGLOG(SW4, INFO, "AvailabaleDeliverPkts %u\n", prStaRec->ucAvailableDeliverPkts); + DBGLOG(SW4, INFO, "BmpDeliverPktsAC %u\n", prStaRec->u4BmpDeliverPktsAC); + DBGLOG(SW4, INFO, "BmpBufferAC %u\n", prStaRec->u4BmpBufferAC); + DBGLOG(SW4, INFO, "BmpNonDeliverPktsAC %u\n", prStaRec->u4BmpNonDeliverPktsAC); +#endif + + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { + if (prStaRec->aprRxReorderParamRefTbl[i]) { + DBGLOG(SW4, INFO, + "RxReorder fgIsValid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid); + DBGLOG(SW4, INFO, "RxReorder Tid: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->ucTid); + DBGLOG(SW4, INFO, + "RxReorder rReOrderQue Len: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->rReOrderQue.u4NumElem); + DBGLOG(SW4, INFO, + "RxReorder WinStart: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart); + DBGLOG(SW4, INFO, "RxReorder WinEnd: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd); + DBGLOG(SW4, INFO, "RxReorder WinSize: %u\n", prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize); + } + } + +} + +VOID dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + + DBGLOG(SW4, INFO, "SSID %s\n", prBssInfo->aucSSID); + DBGLOG(SW4, INFO, "OWN %pM\n", prBssInfo->aucOwnMacAddr); + DBGLOG(SW4, INFO, "BSSID %pM\n", prBssInfo->aucBSSID); + DBGLOG(SW4, INFO, "ucNetTypeIndex %u\n", prBssInfo->ucNetTypeIndex); + DBGLOG(SW4, INFO, "eConnectionState %u\n", prBssInfo->eConnectionState); + DBGLOG(SW4, INFO, "eCurrentOPMode %u\n", prBssInfo->eCurrentOPMode); + DBGLOG(SW4, INFO, "fgIsQBSS %u\n", prBssInfo->fgIsQBSS); + DBGLOG(SW4, INFO, "fgIsShortPreambleAllowed %u\n", prBssInfo->fgIsShortPreambleAllowed); + DBGLOG(SW4, INFO, "fgUseShortPreamble %u\n", prBssInfo->fgUseShortPreamble); + DBGLOG(SW4, INFO, "fgUseShortSlotTime %u\n", prBssInfo->fgUseShortSlotTime); + DBGLOG(SW4, INFO, "ucNonHTBasicPhyType %x\n", prBssInfo->ucNonHTBasicPhyType); + DBGLOG(SW4, INFO, "u2OperationalRateSet %x\n", prBssInfo->u2OperationalRateSet); + DBGLOG(SW4, INFO, "u2BSSBasicRateSet %x\n", prBssInfo->u2BSSBasicRateSet); + DBGLOG(SW4, INFO, "ucPhyTypeSet %x\n", prBssInfo->ucPhyTypeSet); + DBGLOG(SW4, INFO, "rStaRecOfClientList %d\n", prBssInfo->rStaRecOfClientList.u4NumElem); + DBGLOG(SW4, INFO, "u2CapInfo %x\n", prBssInfo->u2CapInfo); + DBGLOG(SW4, INFO, "u2ATIMWindow %x\n", prBssInfo->u2ATIMWindow); + DBGLOG(SW4, INFO, "u2AssocId %x\n", prBssInfo->u2AssocId); + DBGLOG(SW4, INFO, "ucDTIMPeriod %x\n", prBssInfo->ucDTIMPeriod); + DBGLOG(SW4, INFO, "ucDTIMCount %x\n", prBssInfo->ucDTIMCount); + DBGLOG(SW4, INFO, "fgIsNetAbsent %x\n", prBssInfo->fgIsNetAbsent); + DBGLOG(SW4, INFO, "eBand %d\n", prBssInfo->eBand); + DBGLOG(SW4, INFO, "ucPrimaryChannel %d\n", prBssInfo->ucPrimaryChannel); + DBGLOG(SW4, INFO, "ucHtOpInfo1 %d\n", prBssInfo->ucHtOpInfo1); + DBGLOG(SW4, INFO, "ucHtOpInfo2 %d\n", prBssInfo->u2HtOpInfo2); + DBGLOG(SW4, INFO, "ucHtOpInfo3 %d\n", prBssInfo->u2HtOpInfo3); + DBGLOG(SW4, INFO, "fgErpProtectMode %d\n", prBssInfo->fgErpProtectMode); + DBGLOG(SW4, INFO, "eHtProtectMode %d\n", prBssInfo->eHtProtectMode); + DBGLOG(SW4, INFO, "eGfOperationMode %d\n", prBssInfo->eGfOperationMode); + DBGLOG(SW4, INFO, "eRifsOperationMode %d\n", prBssInfo->eRifsOperationMode); + DBGLOG(SW4, INFO, "fgObssErpProtectMode %d\n", prBssInfo->fgObssErpProtectMode); + DBGLOG(SW4, INFO, "eObssHtProtectMode %d\n", prBssInfo->eObssHtProtectMode); + DBGLOG(SW4, INFO, "eObssGfProtectMode %d\n", prBssInfo->eObssGfOperationMode); + DBGLOG(SW4, INFO, "fgObssRifsOperationMode %d\n", prBssInfo->fgObssRifsOperationMode); + DBGLOG(SW4, INFO, "fgAssoc40mBwAllowed %d\n", prBssInfo->fgAssoc40mBwAllowed); + DBGLOG(SW4, INFO, "fg40mBwAllowed %d\n", prBssInfo->fg40mBwAllowed); + DBGLOG(SW4, INFO, "eBssSCO %d\n", prBssInfo->eBssSCO); + +} + +VOID swCtrlCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) +{ + UINT_8 ucIndex, ucRead; + UINT_32 i; + + DEBUGFUNC("swCtrlCmdCategory0"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + i = 0; + + if (ucIndex >= SWCTRL_CATA0_INDEX_NUM) + return; + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case SWCTRL_DEBUG: +#if DBG + aucDebugModule[ucOpt0] = (UINT_8) g_au4SwCr[1]; +#endif + break; + case SWCTRL_WIFI_VAR: + break; + +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for (i = 0; i < QM_DBG_CNT_NUM; i++) + prAdapter->rQM.au4QmDebugCounters[i] = 0; + break; + case SWCTRL_QM_DBG_CNT: + prAdapter->rQM.au4QmDebugCounters[ucOpt0] = g_au4SwCr[1]; + + break; +#endif +#if CFG_RX_PKTS_DUMP + case SWCTRL_RX_PKTS_DUMP: + /* DBGLOG(SW4, INFO,("SWCTRL_RX_PKTS_DUMP: mask %x\n", g_au4SwCr[1])); */ + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = g_au4SwCr[1]; + break; +#endif + case SWCTRL_RX_MDNS_FILTER: + { + UINT_32 u4rxfilter; + BOOLEAN fgUpdate = FALSE; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_STOP) { + g_u4mDNSRXFilter &= ~(RX_MDNS_FILTER_START); + + u4rxfilter = prAdapter->u4OsPacketFilter; + fgUpdate = TRUE; + } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_START) { + g_u4mDNSRXFilter |= (RX_MDNS_FILTER_START); + + u4rxfilter = prAdapter->u4OsPacketFilter; + if ((g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV4) || + (g_u4mDNSRXFilter & RX_MDNS_FILTER_IPV6)) { + u4rxfilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } + fgUpdate = TRUE; + } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_ADD) { + if (ucOpt1 < 31) + g_u4mDNSRXFilter |= (1 << ucOpt1); + } else if (ucOpt0 == SWCR_RX_MDNS_FILTER_CMD_REMOVE) { + if (ucOpt1 < 31) + g_u4mDNSRXFilter &= ~(1 << ucOpt1); + } + + if (fgUpdate == TRUE) { + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_RX_FILTER, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(UINT_32), /* u4SetQueryInfoLen */ + (PUINT_8)&u4rxfilter, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* un4SetQueryBufferLen */ + ); + } +/* DBGLOG(SW4, INFO,("SWCTRL_RX_MDNS_FILTER: g_u4mDNSRXFilter %x ucOpt0 %x ucOpt1 %x fgUpdate %x u4rxfilter %x, */ +/* rStatus %x\n", g_u4mDNSRXFilter, ucOpt0, ucOpt1, fgUpdate, u4rxfilter, rStatus)); */ + } + break; + default: + break; + } + } else { + switch (ucIndex) { + case SWCTRL_DEBUG: +#if DBG + g_au4SwCr[1] = aucDebugModule[ucOpt0]; +#endif + break; + case SWCTRL_MAGIC: + g_au4SwCr[1] = _SWCTRL_MAGIC; + /* DBGLOG(SW4, INFO, "BUILD TIME: %s %s\n", __DATE__, __TIME__); */ + break; + case SWCTRL_QM_INFO: + { + P_QUE_MGT_T prQM = &prAdapter->rQM; + + switch (ucOpt0) { + case 0: + g_au4SwCr[1] = (QM_GET_TX_QUEUE_LEN(prAdapter, ucOpt1)); + g_au4SwCr[2] = prQM->au4MinReservedTcResource[ucOpt1]; + g_au4SwCr[3] = prQM->au4CurrentTcResource[ucOpt1]; + g_au4SwCr[4] = prQM->au4GuaranteedTcResource[ucOpt1]; + break; + + case 1: + g_au4SwCr[1] = prQM->au4ForwardCount[ucOpt1]; + g_au4SwCr[2] = prQM->au4HeadStaRecIndex[ucOpt1]; + break; + + case 2: + g_au4SwCr[1] = prQM->arTxQueue[ucOpt1].u4NumElem; /* only one */ + + break; + } + + } + break; + case SWCTRL_TX_CTRL_INFO: + { + P_TX_CTRL_T prTxCtrl; + + prTxCtrl = &prAdapter->rTxCtrl; + switch (ucOpt0) { + case 0: + g_au4SwCr[1] = prAdapter->rTxCtrl.rTc.aucFreeBufferCount[ucOpt1]; + g_au4SwCr[2] = prAdapter->rTxCtrl.rTc.aucMaxNumOfBuffer[ucOpt1]; + break; + } + + } + break; + case SWCTRL_DUMP_QUEUE: + dumpQueue(prAdapter); + + break; +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for (i = 0; i < QM_DBG_CNT_NUM; i++) + DBGLOG(SW4, INFO, "QM:DBG %u %u\n", i, prAdapter->rQM.au4QmDebugCounters[i]); + break; + + case SWCTRL_QM_DBG_CNT: + g_au4SwCr[1] = prAdapter->rQM.au4QmDebugCounters[ucOpt0]; + break; +#endif + case SWCTRL_DUMP_BSS: + { + dumpBss(prAdapter, &(prAdapter->rWifiVar.arBssInfo[ucOpt0])); + } + break; + + default: + break; + } + + } +} + +VOID swCtrlCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) +{ + UINT_8 ucIndex, ucRead; + UINT_8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("swCtrlCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + if (ucOpt0 >= CFG_STA_REC_NUM) + return; + + /* prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); */ + prStaRec = &prAdapter->arStaRec[ucOpt0]; + ucWTEntry = prStaRec->ucWTEntry; + if (ucRead == SWCR_WRITE) { + /* Do nothing */ + } else { + /* Read */ + switch (ucIndex) { + case SWCTRL_STA_QUE_INFO: + { + g_au4SwCr[1] = prStaRec->arTxQueue[ucOpt1].u4NumElem; + } + break; + case SWCTRL_STA_INFO: + switch (ucOpt1) { + case 0: + g_au4SwCr[1] = prStaRec->fgIsInPS; + break; + } + + break; + + case SWCTRL_DUMP_STA: + { + dumpSTA(prAdapter, prStaRec); + } + break; + + default: + + break; + } + } + +} + +#if TEST_PS + +VOID +testPsSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN UINT_8 ucUP, + IN UINT_8 ucNetTypeIndex, + IN BOOLEAN fgBMC, + IN BOOLEAN fgIsBurstEnd, IN BOOLEAN ucPacketType, IN BOOLEAN ucPsSessionID, IN BOOLEAN fgSetEOSP) +{ + P_MSDU_INFO_T prMsduInfo; + UINT_16 u2EstimatedFrameLen; + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + + DEBUGFUNC("testPsSendQoSNullFrame"); + DBGLOG(SW4, LOUD, "\n"); + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SW4, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeQoSNullFrame(prAdapter, + (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prStaRec, ucUP, fgSetEOSP); + + prMsduInfo->eSrc = TX_PACKET_MGMT; + /* prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_DATA; */ + prMsduInfo->ucPacketType = ucPacketType; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_HEADER_QOS_LEN; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->fgIsBasicRate = TRUE; + prMsduInfo->fgIsBurstEnd = fgIsBurstEnd; + prMsduInfo->ucUserPriority = ucUP; + prMsduInfo->ucPsSessionID = ucPsSessionID /* 0~7 Test 7 means NOACK */; + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T) (((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD)); + + if (fgBMC) + prQoSNullFrame->aucAddr1[0] = 0xfd; + else + prQoSNullFrame->aucAddr1[5] = 0xdd; + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + +} + +VOID testPsSetupBss(IN P_ADAPTER_T prAdapter, IN UINT_8 ucNetworkTypeIndex) +{ + P_BSS_INFO_T prBssInfo; + UINT_8 _aucZeroMacAddr[] = NULL_MAC_ADDR; + + DEBUGFUNC("testPsSetupBss()"); + DBGLOG(SW4, INFO, "index %d\n", ucNetworkTypeIndex); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetworkTypeIndex]); + + /* 4 <1.2> Initiate PWR STATE */ + /* SET_NET_PWR_STATE_IDLE(prAdapter, ucNetworkTypeIndex); */ + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BSS_INFO_INIT(prAdapter, ucNetworkTypeIndex); + + prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eCurrentOPMode = OP_MODE_ACCESS_POINT; + prBssInfo->fgIsNetActive = TRUE; + prBssInfo->ucNetTypeIndex = (ucNetworkTypeIndex); + prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->u2BSSBasicRateSet = RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; + prBssInfo->fgErpProtectMode = FALSE; + prBssInfo->fgIsQBSS = TRUE; + + /* 4 <1.5> Setup MIB for current BSS */ + prBssInfo->u2BeaconInterval = 100; + prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + prBssInfo->u2ATIMWindow = 0; + + prBssInfo->ucBeaconTimeoutCount = 0; + + bssInitForAP(prAdapter, prBssInfo, TRUE); + + COPY_MAC_ADDR(prBssInfo->aucBSSID, _aucZeroMacAddr); + LINK_INITIALIZE(&prBssInfo->rStaRecOfClientList); + prBssInfo->fgIsBeaconActivated = TRUE; + prBssInfo->ucHwDefaultFixedRateCode = RATE_CCK_1M_LONG; + + COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, prAdapter->rWifiVar.aucMacAddress); + + /* 4 <3> Initiate BSS_INFO_T - private part */ + /* TODO */ + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 1; + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T) NULL; + + /* prBssInfo->fgErpProtectMode = eErpProectMode; */ + /* prBssInfo->eHtProtectMode = eHtProtectMode; */ + /* prBssInfo->eGfOperationMode = eGfOperationMode; */ + + /* 4 <4> Allocate MSDU_INFO_T for Beacon */ + prBssInfo->prBeacon = cnmMgtPktAlloc(prAdapter, OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prBssInfo->prBeacon) { + prBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prBssInfo->prBeacon->ucNetworkType = ucNetworkTypeIndex; + } else { + DBGLOG(SW4, INFO, "prBeacon allocation fail\n"); + } + +#if 0 + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; +#else + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = (UINT_8) prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (UINT_8) prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucUapsdSp = (UINT_8) prAdapter->u4MaxSpLen; +#endif + +#if 0 + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + prBssInfo->arACQueParms[eAci].fgIsACMSet = FALSE; + prBssInfo->arACQueParms[eAci].u2Aifsn = (UINT_16) eAci; + prBssInfo->arACQueParms[eAci].u2CWmin = 7; + prBssInfo->arACQueParms[eAci].u2CWmax = 31; + prBssInfo->arACQueParms[eAci].u2TxopLimit = eAci + 1; + DBGLOG(SW4, INFO, "MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, prBssInfo->arACQueParms[eAci].fgIsACMSet, + prBssInfo->arACQueParms[eAci].u2Aifsn, + prBssInfo->arACQueParms[eAci].u2CWmin, + prBssInfo->arACQueParms[eAci].u2CWmax, prBssInfo->arACQueParms[eAci].u2TxopLimit)); + + } +#endif + + DBGLOG(SW4, INFO, "[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, prBssInfo->rPmProfSetupInfo.ucUapsdSp); + +} + +VOID testPsCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) +{ + UINT_8 ucIndex, ucRead; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory0"); + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + DBGLOG(SW4, LOUD, "Read %u Index %u\n", ucRead, ucIndex); + + prStaRec = cnmGetStaRecByIndex(prAdapter, 0); + + if (ucIndex >= TEST_PS_CATA0_INDEX_NUM) + return; + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case TEST_PS_SETUP_BSS: + testPsSetupBss(prAdapter, ucOpt0); + break; + + case TEST_PS_ENABLE_BEACON: + break; + + case TEST_PS_TRIGGER_BMC: + /* txmForwardQueuedBmcPkts (ucOpt0); */ + break; + case TEST_PS_SEND_NULL: + { + + testPsSendQoSNullFrame(prAdapter, prStaRec, (UINT_8) (g_au4SwCr[1] & 0xFF), /* UP */ + ucOpt0, (BOOLEAN) ((g_au4SwCr[1] >> 8) & 0xFF), /* BMC */ + (BOOLEAN) ((g_au4SwCr[1] >> 16) & 0xFF), /* BurstEnd */ + (BOOLEAN) ((g_au4SwCr[1] >> 24) & 0xFF), /* Packet type */ + (UINT_8) ((g_au4SwCr[2]) & 0xFF), /* PS sesson ID 7: NOACK */ + FALSE /* EOSP */ + ); + } + break; + case TEST_PS_BUFFER_BMC: + /* g_aprBssInfo[ucOpt0]->fgApToBufferBMC = (g_au4SwCr[1] & 0xFF); */ + break; + case TEST_PS_UPDATE_BEACON: + bssUpdateBeaconContent(prAdapter, ucOpt0 /*networktype */); + break; + + default: + break; + } + } else { + switch (ucIndex) { + + case TEST_PS_MAGIC: + g_au4SwCr[1] = 0x88660011; + break; + + } + } +} + +#endif /* TEST_PS */ + +#if TEST_PS + +VOID testPsCmdCategory1(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) +{ + UINT_8 ucIndex, ucRead; + UINT_8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + if (ucOpt0 >= CFG_STA_REC_NUM) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucOpt0); + if (!prStaRec) + return; + ucWTEntry = prStaRec->ucWTEntry; + if (ucRead == SWCR_WRITE) { + + switch (ucIndex) { + case TEST_PS_STA_PS: + prStaRec->fgIsInPS = (BOOLEAN) (g_au4SwCr[1] & 0x1); + prStaRec->fgIsQoS = (BOOLEAN) (g_au4SwCr[1] >> 8 & 0xFF); + prStaRec->fgIsUapsdSupported = (BOOLEAN) (g_au4SwCr[1] >> 16 & 0xFF); + prStaRec->ucBmpDeliveryAC = (BOOLEAN) (g_au4SwCr[1] >> 24 & 0xFF); + break; + + } + + } else { + /* Read */ + switch (ucIndex) { + default: + break; + } + } + +} + +#endif /* TEST_PS */ + +#if CFG_SUPPORT_802_11V +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) +VOID testWNMCmdCategory0(P_ADAPTER_T prAdapter, UINT_8 ucCate, UINT_8 ucAction, UINT_8 ucOpt0, UINT_8 ucOpt1) +{ + UINT_8 ucIndex, ucRead; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testWNMCmdCategory0"); + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + DBGLOG(SW4, INFO, "Read %u Index %u\n", ucRead, ucIndex); + + if (ucIndex >= TEST_WNM_CATA0_INDEX_NUM) + return; + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case TEST_WNM_TIMING_MEAS: + wnmTimingMeasUnitTest1(prAdapter, ucOpt0); + break; + + default: + break; + } + } +} +#endif /* TEST_WNM */ +#endif /* CFG_SUPPORT_802_11V */ + +VOID swCtrlSwCr(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) +{ + /* According other register STAIDX */ + UINT_8 ucOffset; + + ucOffset = (u2Addr >> 2) & 0x3F; + + if (ucOffset >= SWCR_CR_NUM) + return; + + if (ucRead == SWCR_WRITE) { + g_au4SwCr[ucOffset] = *pu4Data; + if (ucOffset == 0x0) { + /* Commmand [31:24]: Category */ + /* Commmand [23:23]: 1(W) 0(R) */ + /* Commmand [22:16]: Index */ + /* Commmand [15:08]: Option0 */ + /* Commmand [07:00]: Option1 */ + UINT_8 ucCate; + UINT_32 u4Cmd; + + u4Cmd = g_au4SwCr[0]; + ucCate = (UINT_8) (u4Cmd >> 24); + if (ucCate < sizeof(g_arSwCtrlCmd) / sizeof(g_arSwCtrlCmd[0])) { + if (g_arSwCtrlCmd[ucCate] != NULL) { + g_arSwCtrlCmd[ucCate] (prAdapter, ucCate, (UINT_8) (u4Cmd >> 16 & 0xFF), + (UINT_8) ((u4Cmd >> 8) & 0xFF), (UINT_8) (u4Cmd & 0xFF)); + } + } + } + } else { + *pu4Data = g_au4SwCr[ucOffset]; + } +} + +VOID swCrReadWriteCmd(P_ADAPTER_T prAdapter, UINT_8 ucRead, UINT_16 u2Addr, UINT_32 *pu4Data) +{ + UINT_8 ucMod; + + ucMod = u2Addr >> 8; + /* Address [15:8] MOD ID */ + /* Address [7:0] OFFSET */ + + DEBUGFUNC("swCrReadWriteCmd"); + DBGLOG(SW4, TRACE, "%u addr 0x%x data 0x%x\n", ucRead, u2Addr, *pu4Data); + + if (ucMod < (sizeof(g_arSwCrModHandle) / sizeof(g_arSwCrModHandle[0]))) { + + if (g_arSwCrModHandle[ucMod] != NULL) + g_arSwCrModHandle[ucMod] (prAdapter, ucRead, u2Addr, pu4Data); + } /* ucMod */ +} + +/* Debug Support */ +VOID swCrFrameCheckEnable(P_ADAPTER_T prAdapter, UINT_32 u4DumpType) +{ + g_u4SwcrDebugFrameDumpType = u4DumpType; + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = u4DumpType; +} + +VOID swCrDebugInit(P_ADAPTER_T prAdapter) +{ + /* frame dump */ + if (g_u4SwcrDebugFrameDumpType) + swCrFrameCheckEnable(prAdapter, g_u4SwcrDebugFrameDumpType); + /* debug counter */ + g_fgSwcrDebugTimer = FALSE; + + cnmTimerInitTimer(prAdapter, &g_rSwcrDebugTimer, (PFN_MGMT_TIMEOUT_FUNC) swCrDebugCheckTimeout, (ULONG) NULL); + + if (g_u4SwcrDebugCheckTimeout) + swCrDebugCheckEnable(prAdapter, TRUE, g_ucSwcrDebugCheckType, g_u4SwcrDebugCheckTimeout); +} + +VOID swCrDebugUninit(P_ADAPTER_T prAdapter) +{ + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + + g_fgSwcrDebugTimer = FALSE; +} + +VOID swCrDebugCheckEnable(P_ADAPTER_T prAdapter, BOOLEAN fgIsEnable, UINT_8 ucType, UINT_32 u4Timeout) +{ + if (fgIsEnable) { + g_ucSwcrDebugCheckType = ucType; + g_u4SwcrDebugCheckTimeout = u4Timeout; + if (g_fgSwcrDebugTimer == FALSE) + swCrDebugCheckTimeout(prAdapter, 0); + } else { + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + g_u4SwcrDebugCheckTimeout = 0; + } + + g_fgSwcrDebugTimer = fgIsEnable; +} + +VOID swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + /* dump counters */ + if (prCmdSwCtrl) { + if (prCmdSwCtrl->u4Data == SWCR_DBG_TYPE_ALL) { + + /* TX Counter from fw */ + DBGLOG(SW4, INFO, "TX0\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_BCN_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_FAILED_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_RETRY_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_MGNT_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_ERROR_CNT]); +#if 1 + /* TX Counter from drv */ + DBGLOG(SW4, INFO, "TX1\n" + "%08x %08x %08x %08x\n", + (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_BSS_DROP), + (UINT_32) TX_GET_CNT(prTxCtrl, TX_INACTIVE_STA_DROP), + (UINT_32) TX_GET_CNT(prTxCtrl, TX_FORWARD_OVERFLOW_DROP), + (UINT_32) TX_GET_CNT(prTxCtrl, TX_AP_BORADCAST_DROP)); +#endif + + /* RX Counter */ + DBGLOG(SW4, INFO, "RX0\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DUP_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FCSERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_FIFOFULL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_PFDROP_CNT]); + + DBGLOG(SW4, INFO, "RX1\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + (UINT_32) RX_GET_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT), + (UINT_32) RX_GET_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT)); + + DBGLOG(SW4, INFO, "PWR\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PS_POLL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_IND_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE0], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE1], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF0], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_PWR_CUR_PS_PROF1]); + + DBGLOG(SW4, INFO, "ARM\n" + "%08x %08x %08x %08x\n" + "%08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RATE], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_BWGI], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ENABLE], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ROAM_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_ROAMING_INT_CNT]); + + DBGLOG(SW4, INFO, "BB\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_MDRDY_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_RX_FCSERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_PD_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_PD_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SFDERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_SIGERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT]); + + } + } + /* start the next check */ + if (g_u4SwcrDebugCheckTimeout) + cnmTimerStartTimer(prAdapter, &g_rSwcrDebugTimer, g_u4SwcrDebugCheckTimeout * MSEC_PER_SEC); +} + +VOID swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rStatus; + + rCmdSwCtrl.u4Id = (0xb000 << 16) + g_ucSwcrDebugCheckType; + rCmdSwCtrl.u4Data = 0; + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SW_DBG_CTRL, /* ucCID */ + FALSE, /* fgSetQuery */ + TRUE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + swCrDebugQuery, /* pfCmdDoneHandler */ + swCrDebugQueryTimeout, /* pfCmdTimeoutHandler */ + sizeof(CMD_SW_DBG_CTRL_T), /* u4SetQueryInfoLen */ + (PUINT_8)&rCmdSwCtrl, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + +} + +VOID swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + ASSERT(prAdapter); + + swCrDebugCheck(prAdapter, (P_CMD_SW_DBG_CTRL_T) (pucEventBuf)); +} + +VOID swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + swCrDebugCheck(prAdapter, NULL); +} + +#endif /* CFG_SUPPORT_SWCR */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c new file mode 100644 index 0000000000000..96293c57e2b03 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls.c @@ -0,0 +1,5199 @@ +/* +** Id: tdls.c#1 +*/ + +/*! \file tdls.c + \brief This file includes IEEE802.11z TDLS support. +*/ + +/* +** Log: tdls.c + * + * 11 13 2013 vend_samp.lin + * NULL + * Initial version. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************** + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************** + */ +#include "precomp.h" + +#if (CFG_SUPPORT_TDLS == 1) +#include "gl_wext.h" +#include "tdls.h" +#include "gl_cfg80211.h" +#include +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb); + +#if TDLS_CFG_CMD_TEST +static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static TDLS_STATUS +TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd); + +static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param); + +static TDLS_STATUS +TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); + +static TDLS_STATUS +TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static VOID +TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, + BOOLEAN fgIsTearDown, + UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers); + +static VOID +TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, + UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo); + +static TDLS_STATUS +TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static TDLS_STATUS +TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen); + +static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); + +static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen); + +#endif /* TDLS_CFG_CMD_TEST */ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static BOOLEAN fgIsPtiTimeoutSkip = FALSE; + +/******************************************************************************* +* P R I V A T E F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to indicate packets to upper layer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prSkb A pointer to the received packet +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static VOID TdlsCmdTestRxIndicatePkts(GLUE_INFO_T *prGlueInfo, struct sk_buff *prSkb) +{ + struct net_device *prNetDev; + + /* init */ + prNetDev = prGlueInfo->prDevHandler; + prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; + prGlueInfo->rNetDevStats.rx_packets++; + + /* pass to upper layer */ + //prNetDev->last_rx = jiffies; + prSkb->protocol = eth_type_trans(prSkb, prNetDev); + prSkb->dev = prNetDev; + + if (!in_interrupt()) + netif_rx_ni(prSkb); /* only in non-interrupt context */ + else + netif_rx(prSkb); +} + +#if TDLS_CFG_CMD_TEST + +#define LR_TDLS_FME_FIELD_FILL(__Len) \ +do { \ + pPkt += __Len; \ + u4PktLen += __Len; \ +} while (0) + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to add a TDLS peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_2_[Responder MAC] + + iwpriv wlan0 set_str_cmd 0_2_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestAddPeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; + struct wireless_dev *prWdev; + + /* reset */ + kalMemZero(&rCmd, sizeof(rCmd)); + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); + + /* init */ + rCmd.rPeerInfo.supported_rates = NULL; + rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; + rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ + rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); + + /* send command to wifi task to handle */ + prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; + mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_16_[Enable/Disable]_[Set/Clear] + + iwpriv wlan0 set_str_cmd 0_16_1_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestChSwProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + TDLS_CMD_CORE_T rCmd; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); + + /* command to do this */ + flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; + + aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; + aucTdlsTestExtCapElm[1] = 5; + aucTdlsTestExtCapElm[2] = 0; + aucTdlsTestExtCapElm[3] = 0; + aucTdlsTestExtCapElm[4] = 0; + aucTdlsTestExtCapElm[5] = 0; + aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 7); /* bit39 */ +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a channel switch request from the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_5_[TDLS Peer MAC]_[Chan]_[RegulatoryClass]_ + [SecondaryChannelOffset]_[SwitchTime]_[SwitchTimeout] + + iwpriv wlan0 set_str_cmd 0_1_5_00:11:22:33:44:01_1_255_0_15000_30000 + + RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) + Secondary Channel Offset: 0 (SCN - no secondary channel) + 1 (SCA - secondary channel above) + 2 (SCB - secondary channel below) + SwitchTime: units of microseconds + +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestChSwReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + + rCmd.Content.rCmdChStReqRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStReqRcv.u4RegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStReqRcv.u4SecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStReqRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s:[%pM]u4Chan=%u u4RegClass=%u u4SecChanOff=%u u4SwitchTime=%u u4SwitchTimeout=%u\n", + __func__, rCmd.aucPeerMac, + (UINT32) rCmd.Content.rCmdChStReqRcv.u4Chan, + (UINT32) rCmd.Content.rCmdChStReqRcv.u4RegClass, + (UINT32) rCmd.Content.rCmdChStReqRcv.u4SecChanOff, + (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTime, + (UINT32) rCmd.Content.rCmdChStReqRcv.u4SwitchTimeout); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestChStReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a channel switch response from the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_6_[TDLS Peer MAC]_[Chan]_ + [SwitchTime]_[SwitchTimeout]_[StatusCode] + + iwpriv wlan0 set_str_cmd 0_1_6_00:11:22:33:44:01_11_15000_30000_0 + + RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) + Secondary Channel Offset: 0 (SCN - no secondary channel) + 1 (SCA - secondary channel above) + 2 (SCB - secondary channel below) + SwitchTime: units of microseconds + +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestChSwRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + + rCmd.Content.rCmdChStRspRcv.u4Chan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStRspRcv.u4SwitchTime = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChStRspRcv.u4StatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: [ %pM ] u4Chan=%u u4SwitchTime=%u u4SwitchTimeout=%u u4StatusCode=%u\n", + __func__, rCmd.aucPeerMac, + (UINT32) rCmd.Content.rCmdChStRspRcv.u4Chan, + (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTime, + (UINT32) rCmd.Content.rCmdChStRspRcv.u4SwitchTimeout, + (UINT32) rCmd.Content.rCmdChStRspRcv.u4StatusCode); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestChStRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to inform firmware to skip channel switch timeout function. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_11_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestChSwTimeoutSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, + TdlsTestChSwTimeoutSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a data frame to the peer periodically. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static TIMER_T rTdlsTimerTestDataSend; +static UINT_8 aucTdlsTestDataSPeerMac[6]; +static UINT_16 u2TdlsTestDataSInterval; + +static void TdlsCmdTestDataContSend(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + BOOLEAN fgIsEnabled; + + /* init */ + prAdapter = prGlueInfo->prAdapter; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucTdlsTestDataSPeerMac); + u2TdlsTestDataSInterval = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + fgIsEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); + + if (fgIsEnabled == FALSE) { + /* stop test timer */ + return; + } + + /* re-init test timer */ + cnmTimerInitTimer(prAdapter, + &rTdlsTimerTestDataSend, (PFN_MGMT_TIMEOUT_FUNC) TdlsTimerTestDataContSend, (ULONG) NULL); + + cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a data frame from the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_0_x80_[TDLS Peer MAC]_[PM]_[UP]_[EOSP]_[IsNull] + + iwpriv wlan0 set_str_cmd 0_1_x80_00:11:22:33:44:01_0_0_0_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestDataRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + rCmd.Content.rCmdDatRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdDatRcv.u4UP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdDatRcv.u4EOSP = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdDatRcv.u4IsNull = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, + " %s: [%pM] PM(%u) UP(%u) EOSP(%u) NULL(%u)\n", + __func__, rCmd.aucPeerMac, + (UINT32) rCmd.Content.rCmdDatRcv.u4PM, + (UINT32) rCmd.Content.rCmdDatRcv.u4UP, + (UINT32) rCmd.Content.rCmdDatRcv.u4EOSP, (UINT32) rCmd.Content.rCmdDatRcv.u4IsNull); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestDataRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a data frame to the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_4_[Responder MAC]_[tx status] + + iwpriv wlan0 set_str_cmd 0_4_00:11:22:33:44:01_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestDataSend(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + P_ADAPTER_T prAdapter; + struct sk_buff *prMsduInfo; + UINT_8 *prPkt; + UINT_8 MAC[6]; + UINT_8 ucTxStatus; + + /* init */ + prAdapter = prGlueInfo->prAdapter; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, MAC); + ucTxStatus = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + /* allocate a data frame */ + prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); + return; + } + + /* init dev */ + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* init packet */ + prMsduInfo->len = 1000; + kalMemZero(prMsduInfo->data, 100); /* for QoS field */ + kalMemCopy(prMsduInfo->data, MAC, 6); + kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); + *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; + + /* simulate OS to send the packet */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_16_[mili seconds] + + iwpriv wlan0 set_str_cmd 0_19_1000 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestDelay(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + UINT32 u4Delay; + + u4Delay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(TDLS, INFO, "%s: Delay = %d\n", __func__, u4Delay); + + kalMdelay(u4Delay); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test discovery request frame command. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_10_[DialogToken]_[Peer MAC]_[BSSID] + + iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01 + iwpriv wlan0 set_str_cmd 0_1_10_1_00:11:22:33:44:01_00:22:33:44:11:22 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestDiscoveryReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + P_BSS_INFO_T prBssInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; + + /* parse arguments */ + ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); + + kalMemZero(aucZeroMac, sizeof(aucZeroMac)); + kalMemZero(aucBSSID, sizeof(aucBSSID)); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); + + DBGLOG(TDLS, INFO, + " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); + + /* allocate/init packet */ + prAdapter = prGlueInfo->prAdapter; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = TDLS_FRM_ACTION_DISCOVERY_REQ; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + else + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* pass to OS */ + TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to inform firmware to skip keep alive function. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_10_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_10_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestKeepAliveSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdKeepAliveSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdKeepAliveSkip.fgIsEnable); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, + TdlsTestKeepAliveSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to simulate to set the TDLS Prohibited bit. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_11_[Enable/Disable]_[Set/Clear] + + iwpriv wlan0 set_str_cmd 0_13_1_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestProhibitedBitSet(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + TDLS_CMD_CORE_T rCmd; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdProhibit.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdProhibit.fgIsSet = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdProhibit.fgIsEnable); + + /* command to do this */ + flgTdlsTestExtCapElm = rCmd.Content.rCmdProhibit.fgIsEnable; + + aucTdlsTestExtCapElm[0] = ELEM_ID_EXTENDED_CAP; + aucTdlsTestExtCapElm[1] = 5; + aucTdlsTestExtCapElm[2] = 0; + aucTdlsTestExtCapElm[3] = 0; + aucTdlsTestExtCapElm[4] = 0; + aucTdlsTestExtCapElm[5] = 0; + aucTdlsTestExtCapElm[6] = (rCmd.Content.rCmdProhibit.fgIsSet << 6); /* bit38 */ +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a PTI request from the AP. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_4_[TDLS Peer MAC]_[Dialog Token] + + iwpriv wlan0 set_str_cmd 0_1_4_00:11:22:33:44:01_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestPtiReqRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + + rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: [ %pM ] u4DialogToken = %u\n", + __func__, rCmd.aucPeerMac, (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestPtiReqRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a PTI response from the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_9_[TDLS Peer MAC]_[Dialog Token]_[PM] + + iwpriv wlan0 set_str_cmd 0_1_9_00:11:22:33:44:01_0_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestPtiRspRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + + rCmd.Content.rCmdPtiRspRcv.u4DialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdPtiRspRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: [%pM] u4DialogToken = %u %u\n", + __func__, rCmd.aucPeerMac, + (UINT32) rCmd.Content.rCmdPtiRspRcv.u4DialogToken, + (UINT32) rCmd.Content.rCmdPtiRspRcv.u4PM); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestPtiRspRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to inform firmware to simulate PTI tx done fail case. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_21_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_21_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestPtiTxDoneFail(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdPtiTxFail.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdPtiTxFail.fgIsEnable); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestPtiTxFail, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test frame. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestRvFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ +/* PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; */ +/* TDLS_STATUS u4Status; */ + UINT_32 u4Subcmd; +/* UINT_32 u4BufLen; */ + + /* parse sub-command */ + u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(TDLS, INFO, " test rv frame sub command = %u\n", (UINT32) u4Subcmd); + + /* parse command arguments */ + switch (u4Subcmd) { + case TDLS_FRM_ACTION_SETUP_REQ: + /* simulate to receive a setup request frame */ + TdlsCmdTestSetupReqRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_SETUP_RSP: + /* simulate to receive a setup response frame */ + TdlsCmdTestSetupRspRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_CONFIRM: + /* simulate to receive a setup confirm frame */ + TdlsCmdTestSetupConfirmRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_TEARDOWN: + /* simulate to receive a tear down frame */ + TdlsCmdTestTearDownRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_PTI: + /* simulate to receive a PTI request frame */ + TdlsCmdTestPtiReqRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_PTI_RSP: + /* simulate to receive a PTI response frame */ + TdlsCmdTestPtiRspRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_DATA_TEST_DATA: + /* simulate to receive a DATA frame */ + TdlsCmdTestDataRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_CHAN_SWITCH_REQ: + /* simulate to receive a channel switch request frame */ + TdlsCmdTestChSwReqRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_CHAN_SWITCH_RSP: + /* simulate to receive a channel switch response frame */ + TdlsCmdTestChSwRspRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + case TDLS_FRM_ACTION_DISCOVERY_REQ: + /* simulate to receive a discovery request frame */ + TdlsCmdTestDiscoveryReqRecv(prGlueInfo, prInBuf, u4InBufLen); + break; + + default: + DBGLOG(TDLS, ERROR, " wrong test rv frame sub command\n"); + return; + } + +/* if (u4Status != TDLS_STATUS_SUCCESS) */ + { +/* DBGLOG(TDLS, ERROR, (" command parse fail\n")); */ +/* return; */ + } + + /* send command to wifi task to handle */ +#if 0 + kalIoctl(prGlueInfo, + TdlsTestFrameSend, + (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test setup confirm frame command. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_2_[DialogToken]_[StatusCode]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_1_2_1_0_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestSetupConfirmRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + P_BSS_INFO_T prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; + + /* parse arguments */ + ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); + + DBGLOG(TDLS, INFO, + " %s: DialogToken=%d StatusCode=%d from %pM\n", + __func__, ucDialogToken, ucStatusCode, aucPeerMac); + + /* allocate/init packet */ + prAdapter = prGlueInfo->prAdapter; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = TDLS_FRM_ACTION_CONFIRM; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Status Code */ + *pPkt = ucStatusCode; + *(pPkt + 1) = 0x00; + LR_TDLS_FME_FIELD_FILL(2); + + /* 3. Frame Formation - (4) Dialog token */ + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (17) WMM Information element */ + if (prAdapter->rWifiVar.fgSupportQoS) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* pass to OS */ + TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test setup request frame command. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_0_[DialogToken]_[Peer MAC]_[BSSID] + + iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01 + iwpriv wlan0 set_str_cmd 0_1_0_1_00:11:22:33:44:01_00:22:33:44:11:22 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestSetupReqRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + P_BSS_INFO_T prBssInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + UINT_8 ucDialogToken, aucPeerMac[6], aucBSSID[6], aucZeroMac[6]; + UINT_16 u2CapInfo; + + /* parse arguments */ + ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); + + kalMemZero(aucZeroMac, sizeof(aucZeroMac)); + kalMemZero(aucBSSID, sizeof(aucBSSID)); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucBSSID); + + DBGLOG(TDLS, INFO, + " %s: DialogToken=%d from %pM\n", __func__, ucDialogToken, aucPeerMac); + + /* allocate/init packet */ + prAdapter = prGlueInfo->prAdapter; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = TDLS_FRM_ACTION_SETUP_REQ; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (4) Capability */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + LR_TDLS_FME_FIELD_FILL(2); + + /* 4. Append general IEs */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (10) Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ + + /* TDLS_EX_CAP_PEER_UAPSD */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + /* TDLS_EX_CAP_CHAN_SWITCH */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + /* TDLS_EX_CAP_TDLS */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + if (kalMemCmp(aucBSSID, aucZeroMac, 6) == 0) + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + else + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, aucBSSID, 6); + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* pass to OS */ + TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test setup response frame command. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_1_[DialogToken]_[StatusCode]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_1_1_1_0_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestSetupRspRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + P_BSS_INFO_T prBssInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + UINT_8 ucDialogToken, ucStatusCode, aucPeerMac[6]; + UINT_16 u2CapInfo; + + /* parse arguments */ + ucDialogToken = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + ucStatusCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); + + DBGLOG(TDLS, INFO, + " %s: DialogToken=%d StatusCode=%d from %pM\n", + __func__, ucDialogToken, ucStatusCode, aucPeerMac); + + /* allocate/init packet */ + prAdapter = prGlueInfo->prAdapter; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = TDLS_FRM_ACTION_SETUP_RSP; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Status Code */ + *pPkt = ucStatusCode; + *(pPkt + 1) = 0x00; + LR_TDLS_FME_FIELD_FILL(2); + + /* 3. Frame Formation - (4) Dialog token */ + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (5) Capability */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, NULL); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + LR_TDLS_FME_FIELD_FILL(2); + + /* 4. Append general IEs */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (10) Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ + + /* TDLS_EX_CAP_PEER_UAPSD */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + /* TDLS_EX_CAP_CHAN_SWITCH */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + /* TDLS_EX_CAP_TDLS */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* pass to OS */ + TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to inform firmware to skip channel switch timeout function. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_14_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_14_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestScanCtrl(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdScanSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdScanSkip.fgIsEnable); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestScanSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a test tear down frame command. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_1_3_[IsInitiator]_[ReasonCode]_[Peer MAC]_[Where] + + Where 0 (From driver) or 1 (From FW) + + iwpriv wlan0 set_str_cmd 0_1_3_1_26_00:11:22:33:44:01_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestTearDownRecv(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + ADAPTER_T *prAdapter; + P_BSS_INFO_T prBssInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + BOOLEAN fgIsInitiator; + UINT_8 ucReasonCode, aucPeerMac[6]; + BOOLEAN fgIsFromWhich; + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + fgIsInitiator = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + ucReasonCode = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, aucPeerMac); + fgIsFromWhich = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, + " %s: ReasonCode=%d from %pM %d\n", + __func__, ucReasonCode, aucPeerMac, fgIsFromWhich); + + if (fgIsFromWhich == 0) { + /* allocate/init packet */ + prAdapter = prGlueInfo->prAdapter; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, aucPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = TDLS_FRM_ACTION_TEARDOWN; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Reason Code */ + *pPkt = ucReasonCode; + *(pPkt + 1) = 0x00; + LR_TDLS_FME_FIELD_FILL(2); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + if (fgIsInitiator == 1) { + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, aucPeerMac, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prAdapter->rMyMacAddr, 6); + } else { + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, aucPeerMac, 6); + } + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* pass to OS */ + TdlsCmdTestRxIndicatePkts(prGlueInfo, prMsduInfo); + } else { + kalMemZero(&rCmd, sizeof(rCmd)); + kalMemCopy(rCmd.aucPeerMac, aucPeerMac, 6); + rCmd.Content.rCmdTearDownRcv.u4ReasonCode = (UINT32) ucReasonCode; + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, + TdlsTestTearDownRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to inform firmware to skip tx fail case. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_7_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_7_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestTxFailSkip(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + rCmd.Content.rCmdTxFailSkip.fgIsEnable = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: fgIsEnable = %d\n", __func__, rCmd.Content.rCmdTxFailSkip.fgIsEnable); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestTxFailSkip, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a test frame command to wifi task. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 +* +* EX: iwpriv wlan0 set_str_cmd 0_12_2_[FrameType]_[DialogToken]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_12_2_0_1_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestTxTdlsFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; + UINT32 u4Subcmd; + UINT_32 u4BufLen; + + /* parse sub-command */ + u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(TDLS, INFO, " test tx tdls frame sub command = %u\n", u4Subcmd); + + /* parse command arguments */ + rCmd.ucFmeType = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); + + switch (u4Subcmd) { + case TDLS_FRM_ACTION_SETUP_REQ: + case TDLS_FRM_ACTION_SETUP_RSP: + case TDLS_FRM_ACTION_CONFIRM: + rCmd.ucToken = CmdStringDecParse(prInBuf, &prInBuf, &u4BufLen); + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); + + DBGLOG(TDLS, INFO, " setup FmeType=%d Token=%d to [%pM]\n", + rCmd.ucFmeType, rCmd.ucToken, rCmd.arRspAddr); + break; + + default: + DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); + return; + } + + /* send command to wifi task to handle */ + kalIoctl(prGlueInfo, + TdlsTestTdlsFrameSend, + (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a test frame command to wifi task. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ + [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ + [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ + [Timeout]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestTxFrame(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; + TDLS_STATUS u4Status; + UINT_32 u4Subcmd; + UINT_32 u4BufLen; + + /* parse sub-command */ + u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(TDLS, INFO, " test tx frame sub command = %u\n", (UINT32) u4Subcmd); + + /* parse command arguments */ + switch (u4Subcmd) { + case TDLS_FRM_ACTION_SETUP_REQ: + u4Status = TdlsCmdTestTxFmeSetupReqBufTranslate(prInBuf, u4InBufLen, &rCmd); + break; + + default: + DBGLOG(TDLS, ERROR, " wrong test tx frame sub command\n"); + return; + } + + if (u4Status != TDLS_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, " command parse fail\n"); + return; + } + + /* send command to wifi task to handle */ + kalIoctl(prGlueInfo, + TdlsTestFrameSend, + (PVOID)&rCmd, sizeof(PARAM_CUSTOM_TDLS_CMD_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Parse the TDLS test frame command, setup request +* +* @param CmdBuf Pointer to the buffer. +* @param BufLen Record buffer length. +* @param CmdTspec Pointer to the structure. +* +* @retval WLAN_STATUS_SUCCESS: Translate OK. +* @retval WLAN_STATUS_FAILURE: Translate fail. +* @usage iwpriv wlan0 set_str_cmd [tdls]_[command] +* +* EX: iwpriv wlan0 set_str_cmd 0_0_0_[FrameType]_[DialogToken]_[Cap]_[ExCap]_ + [SupRate0]_[SupRate1]_[SupRate2]_[SupRate3]_ + [SupChan0]_[SupChan1]_[SupChan2]_[SupChan3]_ + [Timeout]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_0_0_0_1_1_7_0_0_0_0_0_0_0_0_300_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsCmdTestTxFmeSetupReqBufTranslate(UINT_8 *pCmdBuf, UINT_32 u4BufLen, PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd) +{ +/* dumpMemory8(ANDROID_LOG_INFO, pCmdBuf, u4BufLen); */ + + prCmd->ucFmeType = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->ucToken = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->u2Cap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->ucExCap = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupRate[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupRate[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupRate[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupRate[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupChan[0] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupChan[1] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupChan[2] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->arSupChan[3] = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + prCmd->u4Timeout = CmdStringDecParse(pCmdBuf, &pCmdBuf, &u4BufLen); + CmdStringMacParse(pCmdBuf, &pCmdBuf, &u4BufLen, prCmd->arRspAddr); + + DBGLOG(TDLS, INFO, " command content =\n"); + DBGLOG(TDLS, INFO, "\tPeer MAC = %pM\n", (prCmd->arRspAddr)); + DBGLOG(TDLS, INFO, "\tToken = %u, Cap = 0x%x, ExCap = 0x%x, Timeout = %us FrameType = %u\n", + (UINT32) prCmd->ucToken, prCmd->u2Cap, prCmd->ucExCap, + (UINT32) prCmd->u4Timeout, (UINT32) prCmd->ucFmeType); + DBGLOG(TDLS, INFO, "\tSupRate = 0x%x %x %x %x\n", + prCmd->arSupRate[0], prCmd->arSupRate[1], prCmd->arSupRate[2], prCmd->arSupRate[3]); + DBGLOG(TDLS, INFO, "\tSupChan = %d %d %d %d\n", + prCmd->arSupChan[0], prCmd->arSupChan[1], prCmd->arSupChan[2], prCmd->arSupChan[3]); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update a TDLS peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_3_[Responder MAC] + + iwpriv wlan0 set_str_cmd 0_3_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestUpdatePeer(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + PARAM_CUSTOM_TDLS_CMD_STRUCT_T rCmd; + struct wireless_dev *prWdev; + + /* reset */ + kalMemZero(&rCmd, sizeof(rCmd)); + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.arRspAddr); + + /* init */ + rCmd.rPeerInfo.supported_rates = rCmd.arSupRate; + rCmd.rPeerInfo.ht_capa = &rCmd.rHtCapa; + rCmd.rPeerInfo.vht_capa = &rCmd.rVhtCapa; /* LINUX_KERNEL_VERSION >= 3.10.0 */ + rCmd.rPeerInfo.sta_flags_set = BIT(NL80211_STA_FLAG_TDLS_PEER); + rCmd.rPeerInfo.uapsd_queues = 0xf; /* all AC */ + rCmd.rPeerInfo.max_sp = 0; /* delivery all packets */ + + /* send command to wifi task to handle */ + prWdev = prGlueInfo->prDevHandler->ieee80211_ptr; + mtk_cfg80211_add_station(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, &rCmd.rPeerInfo); + + /* update */ + TdlsexCfg80211TdlsOper(prWdev->wiphy, (void *)0x1, rCmd.arRspAddr, NL80211_TDLS_ENABLE_LINK); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a Null frame from the peer. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +* EX: iwpriv wlan0 set_str_cmd 0_5_[Responder MAC]_[PM bit] + + iwpriv wlan0 set_str_cmd 0_5_00:11:22:33:44:01_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdTestNullRecv(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + rCmd.Content.rCmdNullRcv.u4PM = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: [%pM] u4PM = %u\n", + __func__, (rCmd.aucPeerMac), (UINT32) rCmd.Content.rCmdNullRcv.u4PM); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsTestNullRecv, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a data frame to the peer periodically. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] u4Param no use +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_15_[Responder MAC]_[Interval: ms]_[Enable/Disable] + + iwpriv wlan0 set_str_cmd 0_15_00:11:22:33:44:01_5000_1 +*/ +/*----------------------------------------------------------------------------*/ +static VOID TdlsTimerTestDataContSend(ADAPTER_T *prAdapter, UINT_32 u4Param) +{ + GLUE_INFO_T *prGlueInfo; + struct sk_buff *prMsduInfo; + UINT_8 *prPkt; + + /* init */ + prGlueInfo = prAdapter->prGlueInfo; + + /* allocate a data frame */ + prMsduInfo = kalPacketAlloc(prGlueInfo, 1000, &prPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s allocate pkt fail!\n", __func__); + return; + } + + /* init dev */ + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s prMsduInfo->dev == NULL!\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return; + } + + /* init packet */ + prMsduInfo->len = 1000; + kalMemCopy(prMsduInfo->data, aucTdlsTestDataSPeerMac, 6); + kalMemCopy(prMsduInfo->data + 6, prAdapter->rMyMacAddr, 6); + *(UINT_16 *) (prMsduInfo->data + 12) = 0x0800; + + DBGLOG(TDLS, INFO, " %s try to send a data frame to %pM\n", + __func__, aucTdlsTestDataSPeerMac); + + /* simulate OS to send the packet */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + + /* restart test timer */ + cnmTimerStartTimer(prAdapter, &rTdlsTimerTestDataSend, u2TdlsTestDataSInterval); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a Channel Switch Request frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestChStReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_REQ; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a Channel Switch Response frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestChStRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_RSP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send a test frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; + P_BSS_INFO_T prBssInfo; + struct sk_buff *prMsduInfo; + UINT_8 *pPkt; + UINT_32 u4PktLen, u4IeLen; + + /* sanity check */ + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DBGLOG(TDLS, INFO, " %s\n", __func__); + + if (u4SetBufferLen == 0) + return TDLS_STATUS_INVALID_LENGTH; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + *pu4SetInfoLen = u4SetBufferLen; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAILURE; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, prCmd->arRspAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = prCmd->ucFmeType; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = prCmd->ucToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (4) Capability */ + WLAN_SET_FIELD_16(pPkt, prCmd->u2Cap); + LR_TDLS_FME_FIELD_FILL(2); + + /* 4. Append general IEs */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, NULL, 0, pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (10) Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ + + if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) */ + TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; + TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; + + TIMEOUT_INTERVAL_IE(pPkt)->ucType = IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; + TIMEOUT_INTERVAL_IE(pPkt)->u4Value = htonl(prCmd->u4Timeout); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, prCmd->arRspAddr, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 4. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + /* 5. send the data frame */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a NULL frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestNullRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_NULL_RCV; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a PTI frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestPtiReqRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_REQ; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a PTI response frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestPtiRspRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_RSP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a Tear Down frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestTearDownRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TEAR_DOWN; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to receive a data frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestDataRecv(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_DATA_RCV; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to skip PTI tx fail status. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestPtiTxFail(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_PTI_TX_FAIL; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send a TDLS action frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +* EX: iwpriv wlan0 set_str_cmd 0_12_0_[FrameType]_[DialogToken]_[Peer MAC] + + iwpriv wlan0 set_str_cmd 0_12_0_0_1_00:11:22:33:44:01 +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestTdlsFrameSend(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + PARAM_CUSTOM_TDLS_CMD_STRUCT_T *prCmd; + struct wireless_dev *prWdev; + + /* sanity check */ + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DBGLOG(TDLS, INFO, " %s\n", __func__); + + if (u4SetBufferLen == 0) + return TDLS_STATUS_INVALID_LENGTH; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + prCmd = (PARAM_CUSTOM_TDLS_CMD_STRUCT_T *) pvSetBuffer; + prWdev = (struct wireless_dev *)prGlueInfo->prDevHandler->ieee80211_ptr; + + TdlsexCfg80211TdlsMgmt(prWdev->wiphy, NULL, + prCmd->arRspAddr, prCmd->ucFmeType, 1, + 0, 0, /* open/none */ + FALSE, NULL, 0); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to skip tx fail status. So always success in tx done in firmware. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestTxFailSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_TX_FAIL_SKIP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to skip to do keep alive function in firmware. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestKeepAliveSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_KEEP_ALIVE_SKIP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to skip channel switch timeout. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestChSwTimeoutSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_CHSW_TIMEOUT_SKIP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to skip scan request. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsTestScanSkip(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_TEST_SCAN_SKIP; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +#endif /* TDLS_CFG_CMD_TEST */ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to configure channel switch parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsChSwConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_CHSW_CONF; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update channel switch parameters. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_9_[TDLS Peer MAC]_ + [NetworkTypeIndex]_[1 (Enable) or (0) Disable]_[1 (Start) or 0 (Stop)]_ + [RegClass]_[Chan]_[SecChanOff]_[1 (Reqular) or (0) One Shot] + + RegulatoryClass: TODO (reference to Annex I of 802.11n spec.) + Secondary Channel Offset: 0 (SCN - no secondary channel) + 1 (SCA - secondary channel above) + 2 (SCB - secondary channel below) + SwitchTime: units of microseconds + + iwpriv wlan0 set_str_cmd 0_9_00:11:22:33:44:01_0_1_0_0_1_0_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdChSwConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + + rCmd.Content.rCmdChSwConf.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.fgIsChSwStarted = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.ucRegClass = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.ucTargetChan = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.ucSecChanOff = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdChSwConf.fgIsChSwRegular = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: %pM ucNetTypeIndex=%d, fgIsChSwEnabled=%d, fgIsChSwStarted=%d", + __func__, (rCmd.aucPeerMac), + rCmd.Content.rCmdChSwConf.ucNetTypeIndex, + rCmd.Content.rCmdChSwConf.fgIsChSwEnabled, + rCmd.Content.rCmdChSwConf.fgIsChSwStarted); + DBGLOG(TDLS, INFO, " RegClass=%d, TargetChan=%d, SecChanOff=%d, Regular=%d\n", + rCmd.Content.rCmdChSwConf.ucRegClass, + rCmd.Content.rCmdChSwConf.ucTargetChan, + rCmd.Content.rCmdChSwConf.ucSecChanOff, rCmd.Content.rCmdChSwConf.fgIsChSwRegular); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsChSwConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display TDLS related information. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_18_[Peer MAC]_[Network Interface ID]_[IsClear] + + Network Interface ID: reference to ENUM_NETWORK_TYPE_INDEX_T + + typedef enum _ENUM_NETWORK_TYPE_INDEX_T { + NETWORK_TYPE_AIS_INDEX = 0, + NETWORK_TYPE_P2P_INDEX, + NETWORK_TYPE_BOW_INDEX, + NETWORK_TYPE_INDEX_NUM + } ENUM_NETWORK_TYPE_INDEX_T; + + iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(&rCmd, sizeof(rCmd)); + + CmdStringMacParse(prInBuf, &prInBuf, &u4InBufLen, rCmd.aucPeerMac); + rCmd.ucNetTypeIndex = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdInfoDisplay.fgIsToClearAllHistory = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, " %s: Command PeerMac=%pM in BSS%u\n", + __func__, (rCmd.aucPeerMac), rCmd.ucNetTypeIndex); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display key related information. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_20 + + iwpriv wlan0 set_str_cmd 0_20 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdKeyInfoDisplay(GLUE_INFO_T *prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(&rCmd, sizeof(rCmd)); + + DBGLOG(TDLS, INFO, " %s\n", __func__); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsKeyInfoDisplay, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update MIB parameters. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_6_[TdlsEn]_[UapsdEn]_[PsmEn]_[PtiWin]_[CWCap]_ + [AckMisRetry]_[RspTimeout]_[CWPbDelay]_[DRWin]_[LowestAcInt] + + iwpriv wlan0 set_str_cmd 0_6_1_1_0_1_1_3_5_1000_2_1 + + reference to TDLS_CMD_CORE_MIB_PARAM_UPDATE_T +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdMibParamUpdate(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* reset */ + kalMemZero(&rCmd, sizeof(rCmd)); + + /* parse arguments */ + rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval = + CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, " MIB param = %d %d %d %d %d %d %d %d %d %d\n", + rCmd.Content.rCmdMibUpdate.Tdlsdot11TunneledDirectLinkSetupImplemented, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDBufferSTAActivated, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerPSMActivated, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerUAPSDIndicationWindow, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSChannelSwitchingActivated, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSPeerSTAMissingAckRetryLimit, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSResponseTimeout, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSProbeDelay, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSDiscoveryRequestWindow, + rCmd.Content.rCmdMibUpdate.Tdlsdot11TDLSACDeterminationInterval); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsMibParamUpdate, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update setup parameters. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_17_[20/40 Support] + + iwpriv wlan0 set_str_cmd 0_17_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdSetupConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + + rCmd.Content.rCmdSetupConf.fgIs2040Supported = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + + DBGLOG(TDLS, INFO, "%s: rCmdSetupConf=%d\n", __func__, rCmd.Content.rCmdSetupConf.fgIs2040Supported); + + /* command to do this */ + prGlueInfo->rTdlsLink.fgIs2040Sup = rCmd.Content.rCmdSetupConf.fgIs2040Supported; + + rStatus = kalIoctl(prGlueInfo, TdlsSetupConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update UAPSD parameters. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +* EX: iwpriv wlan0 set_str_cmd 0_8_[SP timeout skip]_[PTI timeout skip] + + iwpriv wlan0 set_str_cmd 0_8_1_1 +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsCmdUapsdConf(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + WLAN_STATUS rStatus; + TDLS_CMD_CORE_T rCmd; + UINT_32 u4BufLen; + + /* parse arguments */ + kalMemZero(rCmd.aucPeerMac, sizeof(rCmd.aucPeerMac)); + + /* UAPSD Service Period */ + rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + /* PTI Service Period */ + fgIsPtiTimeoutSkip = rCmd.Content.rCmdUapsdConf.fgIsPtiTimeoutSkip; + + DBGLOG(TDLS, INFO, "%s: fgIsSpTimeoutSkip=%d, fgIsPtiTimeoutSkip=%d\n", + __func__, rCmd.Content.rCmdUapsdConf.fgIsSpTimeoutSkip, fgIsPtiTimeoutSkip); + + /* command to do this */ + rStatus = kalIoctl(prGlueInfo, TdlsUapsdConf, &rCmd, sizeof(rCmd), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s kalIoctl fail:%x\n", __func__, rStatus); + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display TDLS all information. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +* iwpriv wlan0 set_str_cmd 0_18_00:00:00:00:00:00_0_0 +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_CMD_CORE_T *prCmdContent; + STA_RECORD_T *prStaRec; + TDLS_INFO_LINK_T *prLink; + UINT32 u4StartIdx; + UINT32 u4PeerNum; + BOOLEAN fgIsListAll; + UINT8 ucMacZero[6]; + UINT32 u4HisIdx; + UINT8 ucNetTypeIndex; + + /* init */ + prGlueInfo = prAdapter->prGlueInfo; + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + u4StartIdx = 0; + u4PeerNum = 1; + fgIsListAll = TRUE; + kalMemZero(ucMacZero, sizeof(ucMacZero)); + ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + + /* display common information */ + DBGLOG(TDLS, TRACE, "TDLS common:\n"); + DBGLOG(TDLS, TRACE, "\t\trFreeSwRfbList=%u\n", (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); + DBGLOG(TDLS, TRACE, "\t\tjiffies=%u %ums (HZ=%d)\n", (UINT32) jiffies, (UINT32) kalGetTimeTick(), HZ); + + /* display disconnection history information */ + DBGLOG(TDLS, TRACE, "TDLS link history: %d\n", prGlueInfo->rTdlsLink.u4LinkIdx); + + for (u4HisIdx = prGlueInfo->rTdlsLink.u4LinkIdx + 1; u4HisIdx < TDLS_LINK_HISTORY_MAX; u4HisIdx++) { + prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; + + if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) + continue; /* skip all zero */ + + DBGLOG(TDLS, TRACE, + "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", + u4HisIdx, prLink->aucPeerMac, + prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), + prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), + prLink->ucReasonCode, + prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); + + if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { + DBGLOG(TDLS, TRACE, + "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", + prLink->ucHtBa[0], prLink->ucHtBa[1], + prLink->ucHtBa[2], prLink->ucHtBa[3], + prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); + } + } + for (u4HisIdx = 0; u4HisIdx <= prGlueInfo->rTdlsLink.u4LinkIdx; u4HisIdx++) { + prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4HisIdx]; + + if (kalMemCmp(prLink->aucPeerMac, ucMacZero, 6) == 0) + continue; /* skip all zero, use continue, not break */ + + DBGLOG(TDLS, TRACE, + "\t\t%d. %pM jiffies start(%lu %ums)end(%lu %ums)Reason(%u)fromUs(%u)Dup(%u)HT(%u)\n", + u4HisIdx, (prLink->aucPeerMac), + prLink->jiffies_start, jiffies_to_msecs(prLink->jiffies_start), + prLink->jiffies_end, jiffies_to_msecs(prLink->jiffies_end), + prLink->ucReasonCode, + prLink->fgIsFromUs, prLink->ucDupCount, (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP)); + + if (prLink->ucHtCap & TDLS_INFO_LINK_HT_CAP_SUP) { + DBGLOG(TDLS, TRACE, + "\t\t\tBA (0x%x %x %x %x %x %x %x %x)\n", + prLink->ucHtBa[0], prLink->ucHtBa[1], + prLink->ucHtBa[2], prLink->ucHtBa[3], + prLink->ucHtBa[4], prLink->ucHtBa[5], prLink->ucHtBa[6], prLink->ucHtBa[7]); + } + } + DBGLOG(TDLS, TRACE, "\n"); + + /* display link information */ + if (prCmdContent != NULL) { + if (kalMemCmp(prCmdContent->aucPeerMac, ucMacZero, 6) != 0) { + prStaRec = cnmGetStaRecByAddress(prAdapter, + prCmdContent->ucNetTypeIndex, prCmdContent->aucPeerMac); + if (prStaRec == NULL) + fgIsListAll = TRUE; + } + + ucNetTypeIndex = prCmdContent->ucNetTypeIndex; + } + + while (1) { + if (fgIsListAll == TRUE) { + /* list all TDLS peers */ + prStaRec = cnmStaTheTypeGet(prAdapter, ucNetTypeIndex, STA_TYPE_TDLS_PEER, &u4StartIdx); + if (prStaRec == NULL) + break; + } + + DBGLOG(TDLS, TRACE, "-------- TDLS %d: 0x %pM\n", u4PeerNum, (prStaRec->aucMacAddr)); + DBGLOG(TDLS, TRACE, "\t\t\t State %d, PM %d, Cap 0x%x\n", + prStaRec->ucStaState, prStaRec->fgIsInPS, prStaRec->u2CapInfo); + DBGLOG(TDLS, TRACE, "\t\t\t SetupDisable %d, ChSwDisable %d\n", + prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); + + if (fgIsListAll == FALSE) + break; /* only list one */ + } + + /* check if we need to clear all histories */ + if ((prCmdContent != NULL) && (prCmdContent->Content.rCmdInfoDisplay.fgIsToClearAllHistory == TRUE)) { + kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); + prGlueInfo->rTdlsLink.u4LinkIdx = TDLS_LINK_HISTORY_MAX - 1; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to display key information. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsKeyInfoDisplay(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_KEY_INFO; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to record a disconnection event. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure +* \param[in] fgIsTearDown TRUE: the link is torn down +* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer +* \param[in] fgIsFromUs TRUE: tear down is from us +* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +TdlsLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, + BOOLEAN fgIsTearDown, + UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode, VOID *prOthers) +{ + TDLS_INFO_LINK_T *prLink; + + DBGLOG(TDLS, INFO, + " %s: record history for %pM %d %d %d %d\n", + __func__, pucPeerMac, prGlueInfo->rTdlsLink.u4LinkIdx, + fgIsTearDown, fgIsFromUs, u2ReasonCode); + + /* check duplicate one */ + if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) { + DBGLOG(TDLS, ERROR, " %s: u4LinkIdx >= TDLS_LINK_HISTORY_MAX\n", __func__); + + /* reset to 0 */ + prGlueInfo->rTdlsLink.u4LinkIdx = 0; + } + + prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; + + if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) == 0) { + if ((prLink->ucReasonCode == u2ReasonCode) && (prLink->fgIsFromUs == fgIsFromUs)) { + /* same Peer MAC, Reason Code, Trigger source */ + if (fgIsTearDown == TRUE) { + if (prLink->jiffies_end != 0) { + /* already torn down */ + prLink->ucDupCount++; + return; + } + } else { + /* already built */ + prLink->ucDupCount++; + return; + } + } + } + + /* search old entry */ + if (fgIsTearDown == TRUE) { + /* TODO: need to search all entries to find it if we support multiple TDLS link design */ + if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { + /* error! can not find the link entry */ + DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); + return; + } + + prLink->jiffies_end = jiffies; + prLink->ucReasonCode = (UINT8) u2ReasonCode; + prLink->fgIsFromUs = fgIsFromUs; + } else { + /* record new one */ + prGlueInfo->rTdlsLink.u4LinkIdx++; + if (prGlueInfo->rTdlsLink.u4LinkIdx >= TDLS_LINK_HISTORY_MAX) + prGlueInfo->rTdlsLink.u4LinkIdx = 0; + + prLink = &prGlueInfo->rTdlsLink.rLinkHistory[prGlueInfo->rTdlsLink.u4LinkIdx]; + + prLink->jiffies_start = jiffies; + prLink->jiffies_end = 0; + kalMemCopy(&prLink->aucPeerMac, pucPeerMac, 6); + prLink->ucReasonCode = 0; + prLink->fgIsFromUs = (UINT8) fgIsFromUs; + prLink->ucDupCount = 0; + + if (prOthers != NULL) { + /* record other parameters */ + TDLS_LINK_HIS_OTHERS_T *prHisOthers; + + prHisOthers = (TDLS_LINK_HIS_OTHERS_T *) prOthers; + if (prHisOthers->fgIsHt == TRUE) + prLink->ucHtCap |= TDLS_INFO_LINK_HT_CAP_SUP; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update a disconnection event. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure +* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer +* \param[in] eFmeStatus TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME +* \param[in] pInfo other information +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +static VOID +TdlsLinkHistoryRecordUpdate(GLUE_INFO_T *prGlueInfo, + UINT8 *pucPeerMac, TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus, VOID *pInfo) +{ + TDLS_INFO_LINK_T *prLink; + UINT32 u4LinkIdx; + UINT32 u4Tid; + + /* sanity check */ + if ((eFmeStatus < TDLS_HOST_EVENT_SF_BA) || (eFmeStatus > TDLS_HOST_EVENT_SF_BA_RSP_DECLINE)) { + /* do not care these frames */ + return; + } + + DBGLOG(TDLS, INFO, + " %s: update history for %pM %d %d\n", + __func__, (pucPeerMac), prGlueInfo->rTdlsLink.u4LinkIdx, eFmeStatus); + + /* init */ + u4LinkIdx = prGlueInfo->rTdlsLink.u4LinkIdx; + prLink = &prGlueInfo->rTdlsLink.rLinkHistory[u4LinkIdx]; + + /* TODO: need to search all entries to find it if we support multiple TDLS link design */ + if (kalMemCmp(&prLink->aucPeerMac, pucPeerMac, 6) != 0) { + /* error! can not find the link entry */ + DBGLOG(TDLS, INFO, " %s: cannot find the same entry!!!\n", __func__); + return; + } + + /* update */ + u4Tid = *(UINT32 *) pInfo; + switch (eFmeStatus) { + case TDLS_HOST_EVENT_SF_BA: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP; + break; + + case TDLS_HOST_EVENT_SF_BA_OK: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_OK; + break; + + case TDLS_HOST_EVENT_SF_BA_DECLINE: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_SETUP_DECLINE; + break; + + case TDLS_HOST_EVENT_SF_BA_PEER: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_PEER; + break; + + case TDLS_HOST_EVENT_SF_BA_RSP_OK: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_OK; + break; + + case TDLS_HOST_EVENT_SF_BA_RSP_DECLINE: + prLink->ucHtBa[u4Tid] |= TDLS_INFO_LINK_HT_BA_RSP_DECLINE; + break; + } + + /* display TDLS link history */ + TdlsInfoDisplay(prGlueInfo->prAdapter, NULL, 0, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to configure TDLS MIB parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsMibParamUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_MIB_UPDATE; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to configure TDLS SETUP parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsSetupConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_SETUP_CONF; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to configure UAPSD parameters. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +* +*/ +/*----------------------------------------------------------------------------*/ +static TDLS_STATUS +TdlsUapsdConf(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + TDLS_CMD_CORE_T *prCmdContent; + WLAN_STATUS rStatus; + + /* init command buffer */ + prCmdContent = (TDLS_CMD_CORE_T *) pvSetBuffer; + prCmdContent->u4Command = TDLS_CORE_CMD_UAPSD_CONF; + + /* send the command */ + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_TDLS_CORE, /* ucCID */ + TRUE, /* fgSetQuery */ + FALSE, /* fgNeedResp */ + FALSE, /* fgIsOid */ + NULL, NULL, /* pfCmdTimeoutHandler */ + sizeof(TDLS_CMD_CORE_T), /* u4SetQueryInfoLen */ + (PUINT_8) prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(TDLS, ERROR, "%s wlanSendSetQueryCmd allocation fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + DBGLOG(TDLS, INFO, "%s cmd ok.\n", __func__); + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to update frame status. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsEventFmeStatus(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + TDLS_EVENT_HOST_SUBID_SPECIFIC_FRAME eFmeStatus; + STA_RECORD_T *prStaRec; + UINT32 u4Tid; + + /* init */ + u4Tid = *(UINT32 *) prInBuf; + prInBuf += 4; /* skip u4EventSubId */ + + /* sanity check */ + prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); + if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) + return; + prInBuf++; + + /* update status */ + eFmeStatus = *prInBuf; + TdlsLinkHistoryRecordUpdate(prGlueInfo, prStaRec->aucMacAddr, eFmeStatus, &u4Tid); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to collect TDLS statistics from firmware. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsEventStatistics(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + STA_RECORD_T *prStaRec; + STAT_CNT_INFO_FW_T *prStat; + UINT32 u4RateId; + + /* init */ + prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *prInBuf); + if ((prStaRec == NULL) || (!IS_TDLS_STA(prStaRec))) + return; + + prInBuf += 4; /* skip prStaRec->ucIndex */ + + /* update statistics */ + kalMemCopy(&prStaRec->rTdlsStatistics.rFw, prInBuf, sizeof(prStaRec->rTdlsStatistics.rFw)); + + /* display statistics */ + prStat = &prStaRec->rTdlsStatistics.rFw; + + DBGLOG(TDLS, TRACE, " peer [%pM] statistics:\n", (prStaRec->aucMacAddr)); + DBGLOG(TDLS, TRACE, "\t\tT%d %d %d (P%d %d) (%dus) - E%d 0x%x - R%d (P%d)\n", + prStat->u4NumOfTx, prStat->u4NumOfTxOK, prStat->u4NumOfTxRetry, + prStat->u4NumOfPtiRspTxOk, prStat->u4NumOfPtiRspTxErr, + prStat->u4TxDoneAirTimeMax, + prStat->u4NumOfTxErr, prStat->u4TxErrBitmap, prStat->u4NumOfRx, prStat->u4NumOfPtiRspRx); + + DBGLOG(TDLS, TRACE, "\t\t"); + + for (u4RateId = prStat->u4TxRateOkHisId; u4RateId < STAT_CNT_INFO_MAX_TX_RATE_OK_HIS_NUM; u4RateId++) + DBGLOG(TDLS, TRACE, + "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); + for (u4RateId = 0; u4RateId < prStat->u4TxRateOkHisId; u4RateId++) + DBGLOG(TDLS, TRACE, + "%d(%d) ", prStat->aucTxRateOkHis[u4RateId][0], prStat->aucTxRateOkHis[u4RateId][1]); + + DBGLOG(TDLS, TRACE, "\n\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to do tear down. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + STA_RECORD_T *prStaRec; + UINT16 u2ReasonCode; + UINT32 u4TearDownSubId; + UINT8 *pMac, aucZeroMac[6]; + + /* init */ + u4TearDownSubId = *(UINT32 *) prInBuf; + kalMemZero(aucZeroMac, sizeof(aucZeroMac)); + pMac = aucZeroMac; + + prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *(prInBuf + 4)); + if (prStaRec != NULL) + pMac = prStaRec->aucMacAddr; + + /* handle */ + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { + DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=PTI timeout\n", + __func__, pMac); + } else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) { + DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=AGE timeout\n", + __func__, pMac); + } else { + DBGLOG(TDLS, WARN, " %s: peer [%pM] Reason=%d\n", + __func__, pMac, u4TearDownSubId); + } + + /* sanity check */ + if (prStaRec == NULL) + return; + + if (fgIsPtiTimeoutSkip == TRUE) { + /* skip PTI timeout event */ + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { + DBGLOG(TDLS, WARN, " %s: skip PTI timeout\n", __func__); + return; + } + } + + /* record history */ + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_FAIL) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_NON_STATE3) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3; + else if (u4TearDownSubId == TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN) + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN; + else { + /* shall not be here */ + u2ReasonCode = TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN; + } + + TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, TRUE, u2ReasonCode, NULL); + + /* correct correct reason code for PTI or AGE timeout to supplicant */ + if ((u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT) || + (u2ReasonCode == TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT)) { + u2ReasonCode = TDLS_REASON_CODE_UNREACHABLE; + } + + /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ + cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, + prStaRec->aucMacAddr, NL80211_TDLS_TEARDOWN, u2ReasonCode, GFP_ATOMIC); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to do tx down. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +static void TdlsEventTxDone(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + /* UINT32 u4FmeIdx; */ + UINT8 *pucFmeHdr; + UINT8 ucErrStatus; + + ucErrStatus = *(UINT32 *) prInBuf; + + pucFmeHdr = prInBuf + 4; /* skip ucErrStatus */ + + if (ucErrStatus == 0) + DBGLOG(TDLS, TRACE, " %s: OK to tx a TDLS action:", __func__); + else + DBGLOG(TDLS, TRACE, " %s: fail to tx a TDLS action (err=0x%x):", __func__, ucErrStatus); + #if 0 + /* dump TX packet content from wlan header */ + for (u4FmeIdx = 0; u4FmeIdx < (u4InBufLen - 4); u4FmeIdx++) { + if ((u4FmeIdx % 16) == 0) + DBGLOG(TDLS, TRACE, "\n"); + + DBGLOG(TDLS, TRACE, "%02x ", *pucFmeHdr++); + } + DBGLOG(TDLS, TRACE, "\n\n"); + #endif +} + +/******************************************************************************* +* P U B L I C F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to parse TDLS Extended Capabilities element. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexBssExtCapParse(STA_RECORD_T *prStaRec, UINT_8 *pucIE) +{ + UINT_8 *pucIeExtCap; + + /* sanity check */ + if ((prStaRec == NULL) || (pucIE == NULL)) + return; + + if (IE_ID(pucIE) != ELEM_ID_EXTENDED_CAP) + return; + + /* + from bit0 ~ + + bit 38: TDLS Prohibited + The TDLS Prohibited subfield indicates whether the use of TDLS is prohibited. The + field is set to 1 to indicate that TDLS is prohibited and to 0 to indicate that TDLS is + allowed. + */ + if (IE_LEN(pucIE) < 5) + return; /* we need 39/8 = 5 bytes */ + + /* init */ + prStaRec->fgTdlsIsProhibited = FALSE; + prStaRec->fgTdlsIsChSwProhibited = FALSE; + + /* parse */ + pucIeExtCap = pucIE + 2; + pucIeExtCap += 4; /* shift to the byte we care about */ + + if ((*pucIeExtCap) & BIT(38 - 32)) + prStaRec->fgTdlsIsProhibited = TRUE; + if ((*pucIeExtCap) & BIT(39 - 32)) + prStaRec->fgTdlsIsChSwProhibited = TRUE; + + DBGLOG(TDLS, TRACE, + " %s: AP [%pM] tdls prohibit bit=%d %d\n", + __func__, + prStaRec->aucMacAddr, prStaRec->fgTdlsIsProhibited, prStaRec->fgTdlsIsChSwProhibited); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to transmit a TDLS data frame from nl80211. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] +* \param[in] +* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +int +TdlsexCfg80211TdlsMgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *buf, size_t len) +{ + ADAPTER_T *prAdapter; + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prAisBssInfo; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + TDLS_MGMT_TX_INFO *prMgmtTxInfo; + + /* + Have correct behavior for STAUT receiving TDLS Setup Request after sending TDLS + Set Request and before receiving TDLS Setup Response: + -- Source Address of received Request is higher than own MAC address + -- Source Address of received Request is lower than own MAC address + + ==> STA with larger MAC address will send the response frame. + + Supplicant will do this in wpa_tdls_process_tpk_m1(). + */ + + /* sanity check */ + if ((wiphy == NULL) || (peer == NULL)) { + DBGLOG(TDLS, ERROR, " %s: wrong 0x%p 0x%p!\n", __func__, wiphy, peer); + return -EINVAL; + } + + DBGLOG(TDLS, INFO, " %s: [%pM] %d %d %d 0x%p %u\n", + __func__, peer, action_code, dialog_token, status_code, buf, (UINT32) len); + + /* init */ + prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); + if (prGlueInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); + return -EINVAL; + } + + prAdapter = prGlueInfo->prAdapter; + if (prAdapter->fgTdlsIsSup == FALSE) { + DBGLOG(TDLS, ERROR, " %s: firmware TDLS is not supported!\n", __func__); + return -EBUSY; + } + + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + if (prAisBssInfo->fgTdlsIsProhibited == TRUE) { + /* do not send anything if TDLS is prohibited in the BSS */ + return 0; + } + + prMgmtTxInfo = kalMemAlloc(sizeof(TDLS_MGMT_TX_INFO), VIR_MEM_TYPE); + if (prMgmtTxInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate fail!\n", __func__); + return -ENOMEM; + } + + kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); + + if (peer != NULL) + kalMemCopy(prMgmtTxInfo->aucPeer, peer, 6); + prMgmtTxInfo->ucActionCode = action_code; + prMgmtTxInfo->ucDialogToken = dialog_token; + prMgmtTxInfo->u2StatusCode = status_code; + + if (buf != NULL) { + if (len > sizeof(prMgmtTxInfo->aucSecBuf)) { + kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); + return -EINVAL; + } + prMgmtTxInfo->u4SecBufLen = len; + kalMemCopy(prMgmtTxInfo->aucSecBuf, buf, len); + } + + /* send the TDLS action data frame */ + rStatus = kalIoctl(prGlueInfo, + TdlsexMgmtCtrl, + prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + /* + clear all content to avoid any bug if we dont yet execute TdlsexMgmtCtrl() + then kalIoctl finishes + */ + kalMemZero(prMgmtTxInfo, sizeof(TDLS_MGMT_TX_INFO)); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); + kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); + return -EINVAL; + } + + kalMemFree(prMgmtTxInfo, VIR_MEM_TYPE, sizeof(TDLS_MGMT_TX_INFO)); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to enable or disable TDLS link from upper layer. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] +* \param[in] +* \param[in] buf includes RSN IE + FT IE + Lifetimeout IE +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +int TdlsexCfg80211TdlsOper(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, enum nl80211_tdls_operation oper) +{ + ADAPTER_T *prAdapter; + GLUE_INFO_T *prGlueInfo; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + TDLS_CMD_LINK_T rCmdLink; + + /* sanity check */ + if (peer == NULL) { + DBGLOG(TDLS, ERROR, " %s: peer == NULL!\n", __func__); + return -EINVAL; + } + + DBGLOG(TDLS, INFO, " %s: [%pM] %d %d\n", + __func__, peer, oper, (wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)); + + if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) + return -ENOTSUPP; + + /* init */ + prGlueInfo = (GLUE_INFO_T *) wiphy_priv(wiphy); + if (prGlueInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: wrong prGlueInfo 0x%p!\n", __func__, prGlueInfo); + return -EINVAL; + } + prAdapter = prGlueInfo->prAdapter; + kalMemCopy(rCmdLink.aucPeerMac, peer, sizeof(rCmdLink.aucPeerMac)); + rCmdLink.fgIsEnabled = FALSE; + + /* + enum nl80211_tdls_operation { + NL80211_TDLS_DISCOVERY_REQ, + NL80211_TDLS_SETUP, + NL80211_TDLS_TEARDOWN, + NL80211_TDLS_ENABLE_LINK, + NL80211_TDLS_DISABLE_LINK, + }; + */ + + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + rCmdLink.fgIsEnabled = TRUE; + break; + + case NL80211_TDLS_DISABLE_LINK: + rCmdLink.fgIsEnabled = FALSE; + break; + + case NL80211_TDLS_TEARDOWN: + case NL80211_TDLS_SETUP: + case NL80211_TDLS_DISCOVERY_REQ: + /* we do not support setup/teardown/discovery from driver */ + return -ENOTSUPP; + + default: + return -ENOTSUPP; + } + + /* enable or disable TDLS link */ + rStatus = kalIoctl(prGlueInfo, + TdlsexLinkCtrl, &rCmdLink, sizeof(TDLS_CMD_LINK_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s enable or disable link fail:%x\n", __func__, rStatus); + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a command to TDLS module. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen) +{ + UINT_32 u4Subcmd; + static void (*TdlsCmdTestFunc)(P_GLUE_INFO_T, UINT_8 *, UINT_32); + + /* parse TDLS sub-command */ + u4Subcmd = CmdStringDecParse(prInBuf, &prInBuf, &u4InBufLen); + DBGLOG(TDLS, INFO, " sub command = %u\n", (UINT32) u4Subcmd); + TdlsCmdTestFunc = NULL; + + /* handle different sub-command */ + switch (u4Subcmd) { +#if TDLS_CFG_CMD_TEST /* only for unit test */ + case TDLS_CMD_TEST_TX_FRAME: + /* simulate to send a TDLS frame */ + /* TdlsCmdTestTxFrame(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestTxFrame; + break; + + case TDLS_CMD_TEST_TX_TDLS_FRAME: + /* simulate to send a TDLS frame from supplicant */ + /* TdlsCmdTestTxTdlsFrame(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestTxTdlsFrame; + break; + + case TDLS_CMD_TEST_RCV_FRAME: + /* simulate to receive a TDLS frame */ + /* TdlsCmdTestRvFrame(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestRvFrame; + break; + + case TDLS_CMD_TEST_PEER_ADD: + /* simulate to add a TDLS peer */ + /* TdlsCmdTestAddPeer(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestAddPeer; + break; + + case TDLS_CMD_TEST_PEER_UPDATE: + /* simulate to update a TDLS peer */ + /* TdlsCmdTestUpdatePeer(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestUpdatePeer; + break; + + case TDLS_CMD_TEST_DATA_FRAME: + /* simulate to send a data frame to the peer */ + /* TdlsCmdTestDataSend(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestDataSend; + break; + + case TDLS_CMD_TEST_RCV_NULL: + /* simulate to receive a QoS null frame from the peer */ + /* TdlsCmdTestNullRecv(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestNullRecv; + break; + + case TDLS_CMD_TEST_SKIP_TX_FAIL: + /* command firmware to skip tx fail case */ + /* TdlsCmdTestTxFailSkip(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestTxFailSkip; + break; + + case TDLS_CMD_TEST_SKIP_KEEP_ALIVE: + /* command firmware to skip keep alive function */ + /* TdlsCmdTestKeepAliveSkip(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestKeepAliveSkip; + break; + + case TDLS_CMD_TEST_SKIP_CHSW_TIMEOUT: + /* command firmware to skip channel switch timeout function */ + /* TdlsCmdTestChSwTimeoutSkip(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestChSwTimeoutSkip; + break; + + case TDLS_CMD_TEST_PROHIBIT_SET_IN_AP: + /* simulate to set Prohibited Bit in AP */ + /* TdlsCmdTestProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestProhibitedBitSet; + break; + + case TDLS_CMD_TEST_SCAN_DISABLE: + /* command to disable scan request to do channel switch */ + /* TdlsCmdTestScanCtrl(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestScanCtrl; + break; + + case TDLS_CMD_TEST_DATA_FRAME_CONT: + /* simulate to send a data frame to the peer periodically */ + /* TdlsCmdTestDataContSend(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestDataContSend; + break; + + case TDLS_CMD_TEST_CH_SW_PROHIBIT_SET_IN_AP: + /* simulate to set channel switch Prohibited Bit in AP */ + /* TdlsCmdTestChSwProhibitedBitSet(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestChSwProhibitedBitSet; + break; + + case TDLS_CMD_TEST_DELAY: + /* delay a where */ + /* TdlsCmdTestDelay(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestDelay; + break; + + case TDLS_CMD_TEST_PTI_TX_FAIL: + /* simulate the tx done fail for PTI */ + /* TdlsCmdTestPtiTxDoneFail(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdTestPtiTxDoneFail; + break; +#endif /* TDLS_CFG_CMD_TEST */ + + case TDLS_CMD_MIB_UPDATE: + /* update MIB parameters */ + /* TdlsCmdMibParamUpdate(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdMibParamUpdate; + break; + + case TDLS_CMD_UAPSD_CONF: + /* config UAPSD parameters */ + /* TdlsCmdUapsdConf(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdUapsdConf; + break; + + case TDLS_CMD_CH_SW_CONF: + /* enable or disable or start or stop channel switch function */ + /* TdlsCmdChSwConf(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdChSwConf; + break; + + case TDLS_CMD_SETUP_CONF: + /* config setup parameters */ + /* TdlsCmdSetupConf(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdSetupConf; + break; + + case TDLS_CMD_INFO: + /* display all TDLS information */ + /* TdlsCmdInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdInfoDisplay; + break; + + case TDLS_CMD_KEY_INFO: + /* display key information */ + /* TdlsCmdKeyInfoDisplay(prGlueInfo, prInBuf, u4InBufLen); */ + TdlsCmdTestFunc = TdlsCmdKeyInfoDisplay; + break; + + default: + break; + } + + if (TdlsCmdTestFunc != NULL) + TdlsCmdTestFunc(prGlueInfo, prInBuf, u4InBufLen); + +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to record a disconnection event. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure +* \param[in] fgIsTearDown TRUE: tear down +* \param[in] pucPeerMac Pointer to the MAC of the TDLS peer +* \param[in] fgIsFromUs TRUE: tear down is from us +* \param[in] u2ReasonCode Disconnection reason (TDLS_REASON_CODE) +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +TdlsexLinkHistoryRecord(GLUE_INFO_T *prGlueInfo, + BOOLEAN fgIsTearDown, UINT8 *pucPeerMac, BOOLEAN fgIsFromUs, UINT16 u2ReasonCode) +{ + /* sanity check */ + if ((prGlueInfo == NULL) || (pucPeerMac == NULL)) + return; + + DBGLOG(TDLS, INFO, + " %s: Rcv a inform from %pM %d %d\n", + __func__, pucPeerMac, fgIsFromUs, u2ReasonCode); + + /* record */ + TdlsLinkHistoryRecord(prGlueInfo, fgIsTearDown, pucPeerMac, fgIsFromUs, u2ReasonCode, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a command to TDLS module. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexEventHandle(GLUE_INFO_T *prGlueInfo, UINT8 *prInBuf, UINT32 u4InBufLen) +{ + UINT32 u4EventId; + + /* sanity check */ + if ((prGlueInfo == NULL) || (prInBuf == NULL)) + return; /* shall not be here */ + + /* handle */ + u4EventId = *(UINT32 *) prInBuf; + u4InBufLen -= 4; + + DBGLOG(TDLS, INFO, " %s: Rcv a event: %d\n", __func__, u4EventId); + + switch (u4EventId) { + case TDLS_HOST_EVENT_TEAR_DOWN: + TdlsEventTearDown(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + + case TDLS_HOST_EVENT_TX_DONE: + TdlsEventTxDone(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + + case TDLS_HOST_EVENT_FME_STATUS: + TdlsEventFmeStatus(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + + case TDLS_HOST_EVENT_STATISTICS: + TdlsEventStatistics(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in TDLS. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* @return TDLS_STATUS_SUCCESS: do not set key and key infor. is queued + TDLS_STATUS_FAILURE: set key +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexKeyHandle(ADAPTER_T *prAdapter, PARAM_KEY_T *prNewKey) +{ + STA_RECORD_T *prStaRec; + + /* sanity check */ + if ((prAdapter == NULL) || (prNewKey == NULL)) + return TDLS_STATUS_FAILURE; + + /* + supplicant will set key before updating station & enabling the link so we need to + backup the key information and set key when link is enabled + */ + prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prNewKey->arBSSID); + if ((prStaRec != NULL) && IS_TDLS_STA(prStaRec)) { + DBGLOG(TDLS, TRACE, " %s: [%pM] queue key (len=%d) until link is enabled\n", + __func__, prNewKey->arBSSID, (UINT32) prNewKey->u4KeyLength); + + if (prStaRec->ucStaState == STA_STATE_3) { + DBGLOG(TDLS, TRACE, " %s: [%pM] tear down the link due to STA_STATE_3\n", + __func__, prNewKey->arBSSID); + + /* re-key */ + TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, + prStaRec->aucMacAddr, TRUE, + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); + + /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ + cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, + prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, + TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); + return TDLS_STATUS_SUCCESS; + } + + /* backup the key */ + kalMemCopy(&prStaRec->rTdlsKeyTemp, prNewKey, sizeof(prStaRec->rTdlsKeyTemp)); + return TDLS_STATUS_SUCCESS; + } + + return TDLS_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initialize variables in TDLS. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexInit(ADAPTER_T *prAdapter) +{ + GLUE_INFO_T *prGlueInfo; + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + + /* reset */ + kalMemZero(&prGlueInfo->rTdlsLink, sizeof(prGlueInfo->rTdlsLink)); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to get any peer is in power save. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \retval TRUE (at least one peer is in power save) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN TdlsexIsAnyPeerInPowerSave(ADAPTER_T *prAdapter) +{ + STA_RECORD_T *prStaRec; + UINT32 u4StaId, u4StartIdx; + + for (u4StaId = 0, u4StartIdx = 0; u4StaId < CFG_STA_REC_NUM; u4StaId++) { + /* list all TDLS peers */ + prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); + if (prStaRec == NULL) + break; + + if (prStaRec->fgIsInPS == TRUE) { + DBGLOG(TDLS, TRACE, " yes, at least one peer is in ps\n"); + return TRUE; + } + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to enable or disable a TDLS link. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexLinkCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_CMD_LINK_T *prCmd; + BSS_INFO_T *prBssInfo; + STA_RECORD_T *prStaRec; + TDLS_LINK_HIS_OTHERS_T rHisOthers; + + /* sanity check */ + if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { + DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + *pu4SetInfoLen = sizeof(TDLS_CMD_LINK_T); + prCmd = (TDLS_CMD_LINK_T *) pvSetBuffer; + + /* search old entry */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); + if (prStaRec == NULL) { + DBGLOG(TDLS, ERROR, " %s: cannot find the peer! %pM\n", + __func__, prCmd->aucPeerMac); + return TDLS_STATUS_FAILURE; + } + + if (prCmd->fgIsEnabled == TRUE) { + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_ENABLE_LINK\n", __func__); + + /* update key information after cnmStaRecChangeState(STA_STATE_3) */ + prStaRec->fgTdlsInSecurityMode = FALSE; + + if (prStaRec->rTdlsKeyTemp.u4Length > 0) { + UINT_32 u4BufLen; /* no use */ + + DBGLOG(TDLS, INFO, " %s: key len=%d\n", + __func__, (UINT32) prStaRec->rTdlsKeyTemp.u4Length); + + /* + reminder the function that we are CIPHER_SUITE_CCMP, + do not change cipher type to CIPHER_SUITE_WEP128 + */ + _wlanoidSetAddKey(prAdapter, &prStaRec->rTdlsKeyTemp, + prStaRec->rTdlsKeyTemp.u4Length, FALSE, CIPHER_SUITE_CCMP, &u4BufLen); + + /* clear the temp key */ + prStaRec->fgTdlsInSecurityMode = TRUE; + kalMemZero(&prStaRec->rTdlsKeyTemp, sizeof(prStaRec->rTdlsKeyTemp)); + } + + /* check if we need to disable channel switch function */ + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + if (prBssInfo->fgTdlsIsChSwProhibited == TRUE) { + TDLS_CMD_CORE_T rCmd; + + kalMemZero(&rCmd, sizeof(TDLS_CMD_CORE_T)); + rCmd.Content.rCmdChSwConf.ucNetTypeIndex = prStaRec->ucNetTypeIndex; + rCmd.Content.rCmdChSwConf.fgIsChSwEnabled = FALSE; + kalMemCopy(rCmd.aucPeerMac, prStaRec->aucMacAddr, 6); + TdlsChSwConf(prAdapter, &rCmd, 0, 0); + + DBGLOG(TDLS, INFO, " %s: disable channel switch\n", __func__); + } + + TDLS_LINK_INCREASE(prGlueInfo); + + /* record link */ + if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) + rHisOthers.fgIsHt = TRUE; + else + rHisOthers.fgIsHt = FALSE; + + TdlsLinkHistoryRecord(prAdapter->prGlueInfo, FALSE, + prStaRec->aucMacAddr, !prStaRec->flgTdlsIsInitiator, 0, &rHisOthers); + } else { + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecFree(prAdapter, prStaRec, TRUE); /* release to other TDLS peers */ + DBGLOG(TDLS, TRACE, " %s: NL80211_TDLS_DISABLE_LINK\n", __func__); + + TDLS_LINK_DECREASE(prGlueInfo); +/* while(1); //sample debug */ + } + + /* work-around link count */ + if ((TDLS_LINK_COUNT(prGlueInfo) < 0) || (TDLS_LINK_COUNT(prGlueInfo) > 1)) { + /* ERROR case: work-around to recount by searching all station records */ + UINT32 u4Idx; + + TDLS_LINK_COUNT_RESET(prGlueInfo); + + for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { + prStaRec = &prAdapter->arStaRec[u4Idx]; + + if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) + TDLS_LINK_INCREASE(prGlueInfo); + } + + if (TDLS_LINK_COUNT(prGlueInfo) > 1) { + /* number of links is still > 1 */ + DBGLOG(TDLS, INFO, " %s: cTdlsLinkCnt %d > 1?\n", + __func__, TDLS_LINK_COUNT(prGlueInfo)); + + TDLS_LINK_COUNT_RESET(prGlueInfo); + + /* free all TDLS links */ + for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) { + prStaRec = &prAdapter->arStaRec[u4Idx]; + + if (prStaRec->fgIsInUse && IS_TDLS_STA(prStaRec)) + cnmStaRecFree(prAdapter, prStaRec, TRUE); + } + + /* maybe inform supplicant ? */ + } + } + + /* display TDLS link history */ + TdlsInfoDisplay(prAdapter, NULL, 0, NULL); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to send a TDLS action data frame. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexMgmtCtrl(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_MGMT_TX_INFO *prMgmtTxInfo; + STA_RECORD_T *prStaRec; + + /* sanity check */ + if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { + DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + *pu4SetInfoLen = sizeof(TDLS_MGMT_TX_INFO); + prMgmtTxInfo = (TDLS_MGMT_TX_INFO *) pvSetBuffer; + + switch (prMgmtTxInfo->ucActionCode) { + case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: + prStaRec = NULL; + break; + + case TDLS_FRM_ACTION_SETUP_REQ: + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); + if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3)) { + /* rekey? we reject re-setup link currently */ + /* TODO: Still can setup link during rekey */ + + /* + return success to avoid supplicant clear TDLS entry; + Or we cannot send out any TDLS tear down frame to the peer + */ + DBGLOG(TDLS, TRACE, " %s: skip new setup on the exist link!\n", __func__); + return TDLS_STATUS_SUCCESS; + } + + prStaRec = NULL; + break; + + case TDLS_FRM_ACTION_SETUP_RSP: + case TDLS_FRM_ACTION_CONFIRM: + case TDLS_FRM_ACTION_TEARDOWN: + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMgmtTxInfo->aucPeer); +#if 0 /* in some cases, the prStaRec is still NULL */ + /* + EX: if a peer sends us a TDLS setup request with wrong BSSID, + supplicant will not call TdlsexPeerAdd() to create prStaRec and + supplicant will send a TDLS setup response with status code 7. + + So in the case, prStaRec will be NULL. + */ + if (prStaRec == NULL) { + DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); + return -EINVAL; + } +#endif + break; + + /* + TODO: Discovery response frame + Note that the TDLS Discovery Response frame is not a TDLS frame but a 11 + Public Action frame. + In WiFi TDLS Tech Minutes June 8 2010.doc, + a public action frame (i.e. it is no longer an encapsulated data frame) + */ + + default: + DBGLOG(TDLS, ERROR, + " %s: wrong action_code %d!\n", __func__, prMgmtTxInfo->ucActionCode); + return TDLS_STATUS_FAILURE; + } + + /* send the TDLS data frame */ + if (prStaRec != NULL) { + DBGLOG(TDLS, INFO, " %s: [%pM] ps=%d status=%d\n", + __func__, prStaRec->aucMacAddr, + prStaRec->fgIsInPS, prMgmtTxInfo->u2StatusCode); + + if (prMgmtTxInfo->ucActionCode == TDLS_FRM_ACTION_TEARDOWN) { + /* record disconnect history */ + TdlsLinkHistoryRecord(prGlueInfo, TRUE, prMgmtTxInfo->aucPeer, + TRUE, prMgmtTxInfo->u2StatusCode, NULL); + } + } + + return TdlsDataFrameSend(prAdapter, + prStaRec, + prMgmtTxInfo->aucPeer, + prMgmtTxInfo->ucActionCode, + prMgmtTxInfo->ucDialogToken, + prMgmtTxInfo->u2StatusCode, + (UINT_8 *) prMgmtTxInfo->aucSecBuf, prMgmtTxInfo->u4SecBufLen); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to add a peer record. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexPeerAdd(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_CMD_PEER_ADD_T *prCmd; + BSS_INFO_T *prAisBssInfo; + STA_RECORD_T *prStaRec; + UINT_8 ucNonHTPhyTypeSet; + UINT32 u4StartIdx; + OS_SYSTIME rCurTime; + + /* sanity check */ + DBGLOG(TDLS, INFO, " %s\n", __func__); + + if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { + DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); + prCmd = (TDLS_CMD_PEER_ADD_T *) pvSetBuffer; + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + u4StartIdx = 0; + + /* search old entry */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); + + /* check if any TDLS link exists because we only support one TDLS link currently */ + if (prStaRec == NULL) { + /* the MAC is new peer */ + prStaRec = cnmStaTheTypeGet(prAdapter, NETWORK_TYPE_AIS_INDEX, STA_TYPE_TDLS_PEER, &u4StartIdx); + + if (prStaRec != NULL) { + /* a building TDLS link exists */ + DBGLOG(TDLS, ERROR, + " %s: one TDLS link setup [%pM] is going...\n", + __func__, prStaRec->aucMacAddr); + + if (prStaRec->ucStaState != STA_STATE_3) { + /* check timeout */ + GET_CURRENT_SYSTIME(&rCurTime); + + if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsSetupStartTime, + SEC_TO_SYSTIME(TDLS_SETUP_TIMEOUT_SEC))) { + /* free the StaRec */ + cnmStaRecFree(prAdapter, prStaRec, TRUE); + + DBGLOG(TDLS, ERROR, + " %s: free going TDLS link setup [%pM]\n", + __func__, (prStaRec->aucMacAddr)); + + /* handle new setup */ + prStaRec = NULL; + } else + return TDLS_STATUS_FAILURE; + } else { + /* the TDLS is built and works fine, reject new one */ + return TDLS_STATUS_FAILURE; + } + } + } else { + if (prStaRec->ucStaState == STA_STATE_3) { + /* the peer exists, maybe TPK lifetime expired, supplicant wants to renew key */ + TdlsLinkHistoryRecord(prAdapter->prGlueInfo, TRUE, + prStaRec->aucMacAddr, TRUE, + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY, NULL); + + /* 16 Nov 21:49 2012 http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 */ + cfg80211_tdls_oper_request(prAdapter->prGlueInfo->prDevHandler, + prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, + TDLS_REASON_CODE_UNSPECIFIED, GFP_ATOMIC); + + DBGLOG(TDLS, TRACE, + " %s: re-setup link for [%pM] maybe re-key?\n", + __func__, (prStaRec->aucMacAddr)); + return TDLS_STATUS_FAILURE; + } + } + + /* + create new entry if not exist + + 1. we are initiator + (1) send TDLS setup request + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); + create a station record with STA_STATE_1. + (2) got TDLS setup response and send TDLS setup confirm + wpa_tdls_enable_link() + update a station record with STA_STATE_3. + + 2. we are responder + (1) got TDLS setup request + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); + create a station record with STA_STATE_1. + (2) send TDLS setup response + (3) got TDLS setup confirm + wpa_tdls_enable_link() + update a station record with STA_STATE_3. + */ + if (prStaRec == NULL) { + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); + + if (prStaRec == NULL) { + /* shall not be here */ + DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + /* init the prStaRec */ + /* prStaRec will be zero first in cnmStaRecAlloc() */ + COPY_MAC_ADDR(prStaRec->aucMacAddr, prCmd->aucPeerMac); + +/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); */ + } else { +#if 0 + if ((prStaRec->ucStaState > STA_STATE_1) && (IS_TDLS_STA(prStaRec))) { + /* + test plan: The STAUT should locally tear down existing TDLS direct link and + respond with Set up Response frame. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } +#endif + } + + /* reference to bssCreateStaRecFromBssDesc() and use our best capability */ + /* reference to assocBuildReAssocReqFrameCommonIEs() to fill elements */ + + /* prStaRec->u2CapInfo */ + /* TODO: Need to parse elements from setup request frame */ + prStaRec->u2OperationalRateSet = prAisBssInfo->u2OperationalRateSet; + prStaRec->u2BSSBasicRateSet = prAisBssInfo->u2BSSBasicRateSet; + prStaRec->u2DesiredNonHTRateSet = prAdapter->rWifiVar.ucAvailablePhyTypeSet; + prStaRec->ucPhyTypeSet = prAisBssInfo->ucPhyTypeSet; + prStaRec->eStaType = STA_TYPE_TDLS_PEER; + + prStaRec->ucDesiredPhyTypeSet = /*prStaRec->ucPhyTypeSet & */ + prAdapter->rWifiVar.ucAvailablePhyTypeSet; + ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11ABG; + + /* check for Target BSS's non HT Phy Types */ + if (ucNonHTPhyTypeSet) { + if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ + + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = TRUE; + } else { + /* use mandatory for 11N only BSS */ +/* ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); */ + + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + prStaRec->fgHasBasicPhyType = FALSE; + } + + /* update non HT Desired Rate Set */ + { + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prStaRec->u2DesiredNonHTRateSet = + (prStaRec->u2OperationalRateSet & prConnSettings->u2DesiredNonHTRateSet); + } + +#if 0 /* TdlsexPeerAdd() will be called before we receive setup rsp in TdlsexRxFrameHandle() */ + /* check if the add is from the same peer in the 1st unhandled setup request frame */ + DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", + __func__, prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac); + + if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { + /* copy the HT capability from its setup request */ + kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); + + prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); + + /* reset backup */ + kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); + kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); + + DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); + } +#endif + + /* update WMM: must support due to UAPSD in TDLS link */ + prStaRec->fgIsWmmSupported = TRUE; + prStaRec->fgIsUapsdSupported = TRUE; + + /* update station record to firmware */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* update time */ + GET_CURRENT_SYSTIME(&prStaRec->rTdlsSetupStartTime); + + DBGLOG(TDLS, INFO, " %s: create a peer [%pM]\n", + __func__, (prStaRec->aucMacAddr)); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to update a peer record. +* +* \param[in] prAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval TDLS_STATUS_xx +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexPeerUpdate(ADAPTER_T *prAdapter, VOID *pvSetBuffer, UINT_32 u4SetBufferLen, UINT_32 *pu4SetInfoLen) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_CMD_PEER_UPDATE_T *prCmd; + BSS_INFO_T *prAisBssInfo; + STA_RECORD_T *prStaRec; + IE_HT_CAP_T *prHtCap; + + /* sanity check */ + DBGLOG(TDLS, INFO, " %s\n", __func__); + + if ((prAdapter == NULL) || (pvSetBuffer == NULL) || (pu4SetInfoLen == NULL)) { + DBGLOG(TDLS, ERROR, " %s: sanity fail!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + *pu4SetInfoLen = sizeof(TDLS_CMD_PEER_ADD_T); + prCmd = (TDLS_CMD_PEER_UPDATE_T *) pvSetBuffer; + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + /* search old entry */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prCmd->aucPeerMac); + + /* + create new entry if not exist + + 1. we are initiator + (1) send TDLS setup request + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); + create a station record with STA_STATE_1. + (2) got TDLS setup response and send TDLS setup confirm + wpa_tdls_enable_link() + update a station record with STA_STATE_3. + + 2. we are responder + (1) got TDLS setup request + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, NULL, 0); + create a station record with STA_STATE_1. + (2) send TDLS setup response + (3) got TDLS setup confirm + wpa_tdls_enable_link() + update a station record with STA_STATE_3. + */ + if ((prStaRec == NULL) || (prStaRec->fgIsInUse == 0)) { + DBGLOG(TDLS, ERROR, " %s: cannot find the peer!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + DBGLOG(TDLS, INFO, " %s: update a peer [%pM] %d -> %d, 0x%x\n", + __func__, (prStaRec->aucMacAddr), + prStaRec->ucStaState, STA_STATE_3, prStaRec->eStaType); + + if (!IS_TDLS_STA(prStaRec)) { + DBGLOG(TDLS, ERROR, " %s: peer is not TDLS one!\n", __func__); + return TDLS_STATUS_FAILURE; + } + + /* check if the add is from the same peer in the 1st unhandled setup request frame */ + DBGLOG(TDLS, INFO, " %s: [%pM] [%pM]\n", + __func__, (prGlueInfo->aucTdlsHtPeerMac), (prCmd->aucPeerMac)); + + if (kalMemCmp(prGlueInfo->aucTdlsHtPeerMac, prCmd->aucPeerMac, 6) == 0) { + /* copy the HT capability from its setup request */ + kalMemCopy(&prStaRec->rTdlsHtCap, &prGlueInfo->rTdlsHtCap, sizeof(IE_HT_CAP_T)); + + prStaRec->ucPhyTypeSet |= PHY_TYPE_SET_802_11N; + prStaRec->u2DesiredNonHTRateSet |= BIT(RATE_HT_PHY_INDEX); + + /* reset backup */ + kalMemZero(&prGlueInfo->rTdlsHtCap, sizeof(prStaRec->rTdlsHtCap)); + kalMemZero(prGlueInfo->aucTdlsHtPeerMac, sizeof(prGlueInfo->aucTdlsHtPeerMac)); + + DBGLOG(TDLS, INFO, " %s: peer is a HT device\n", __func__); + } + + /* update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = prCmd->u2StatusCode; + + /* prStaRec->ucStaState shall be STA_STATE_1 */ + + prStaRec->u2CapInfo = prCmd->u2Capability; +/* prStaRec->u2OperationalRateSet */ + prStaRec->u2AssocId = 0; /* no use */ + prStaRec->u2ListenInterval = 0; /* unknown */ +/* prStaRec->ucDesiredPhyTypeSet */ +/* prStaRec->u2DesiredNonHTRateSet */ +/* prStaRec->u2BSSBasicRateSet */ +/* prStaRec->ucMcsSet */ +/* prStaRec->fgSupMcs32 */ +/* prStaRec->u2HtCapInfo */ + prStaRec->fgIsQoS = TRUE; + prStaRec->fgIsUapsdSupported = (prCmd->UapsdBitmap == 0) ? FALSE : TRUE; +/* prStaRec->ucAmpduParam */ +/* prStaRec->u2HtExtendedCap */ + prStaRec->u4TxBeamformingCap = 0; /* no use */ + prStaRec->ucAselCap = 0; /* no use */ + prStaRec->ucRCPI = 0; + prStaRec->ucBmpTriggerAC = prCmd->UapsdBitmap; + prStaRec->ucBmpDeliveryAC = prCmd->UapsdBitmap; + prStaRec->ucUapsdSp = prCmd->UapsdMaxSp; + + /* update HT */ +#if (TDLS_CFG_HT_SUP == 1) + if (prCmd->fgIsSupHt == FALSE) { + /* no HT IE is from supplicant so we use the backup */ + prHtCap = (IE_HT_CAP_T *) &prStaRec->rTdlsHtCap; + + DBGLOG(TDLS, INFO, " %s: [%pM] update ht ie 0x%x\n", + __func__, (prStaRec->aucMacAddr), prHtCap->ucId); + + if (prHtCap->ucId == ELEM_ID_HT_CAP) { + prStaRec->ucMcsSet = prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & BIT(0)) ? TRUE : FALSE; + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + prStaRec->ucDesiredPhyTypeSet |= PHY_TYPE_SET_802_11N; + } + } else { + /* TODO: use the HT IE from supplicant */ + } +#endif /* TDLS_CFG_HT_SUP */ + + DBGLOG(TDLS, INFO, " %s: UAPSD 0x%x %d MCS=0x%x\n", + __func__, prCmd->UapsdBitmap, prCmd->UapsdMaxSp, prStaRec->ucMcsSet); + +/* cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); */ + + DBGLOG(TDLS, INFO, " %s: update a peer [%pM]\n", + __func__, (prStaRec->aucMacAddr)); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to check if we need to drop a TDLS action frame. +* +* \param[in] *pPkt Pointer to the struct sk_buff->data. +* \param[in] +* \param[in] +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN TdlsexRxFrameDrop(GLUE_INFO_T *prGlueInfo, UINT_8 *pPkt) +{ + ADAPTER_T *prAdapter; + UINT8 ucActionId; + + /* sanity check */ + if ((pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) + return FALSE; /* not TDLS data frame htons(0x890d) */ + +#if 0 /* supplicant handles this check */ + if (prStaRec == NULL) + return FALSE; /* shall not be here */ + + DBGLOG(TDLS, INFO, + " %s: Rcv a TDLS action frame (id=%d) %d %d\n", + __func__, *(pPkt + 13 + 4), prStaRec->fgTdlsIsProhibited, fgIsPtiTimeoutSkip); + + /* check if TDLS Prohibited bit is set in AP's beacon */ + if (prStaRec->fgTdlsIsProhibited == TRUE) + return TRUE; +#endif + + ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ + + if (fgIsPtiTimeoutSkip == TRUE) { + /* also skip any tear down frame from the peer */ + if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) + return TRUE; + } + + prAdapter = prGlueInfo->prAdapter; + DBGLOG(TDLS, INFO, + " %s: Rcv a TDLS action frame %d (%u)\n", + __func__, ucActionId, (UINT32) prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); + + if (ucActionId == TDLS_FRM_ACTION_TEARDOWN) { + DBGLOG(TDLS, WARN, " %s: Rcv a TDLS tear down frame %d, will DISABLE link\n", + __func__, *(pPkt + 13 + 4)); /* reason code */ + + /* record disconnect history */ + TdlsLinkHistoryRecord(prGlueInfo, TRUE, pPkt + 6, FALSE, *(pPkt + 13 + 4), NULL); + + /* inform tear down to supplicant only in OPEN/NONE mode */ + /* + we need to tear down the link manually; or supplicant will display + "No FTIE in TDLS Teardown" and it will not tear down the link + */ + cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, + pPkt + 6, TDLS_FRM_ACTION_TEARDOWN, *(pPkt + 13 + 4), GFP_ATOMIC); + } +#if 0 /* pass all to supplicant except same thing is handled in supplicant */ + if (((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI) || + ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_REQ) || + ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_CHAN_SWITCH_RSP) || + ((*(pPkt + 13 + 3)) == TDLS_FRM_ACTION_PTI_RSP)) { + return TRUE; + } +#endif + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to parse some IEs in the setup frame from the peer. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] pPkt Pointer to the ethernet packet +* +* \retval None +* +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexRxFrameHandle(GLUE_INFO_T *prGlueInfo, UINT8 *pPkt, UINT16 u2PktLen) +{ + ADAPTER_T *prAdapter; + STA_RECORD_T *prStaRec; + UINT8 ucActionId; + UINT8 *pucPeerMac, ucElmId, ucElmLen; + INT16 s2FmeLen; + + /* sanity check */ + if ((prGlueInfo == NULL) || (pPkt == NULL) || (*(pPkt + 12) != 0x89) || (*(pPkt + 13) != 0x0d)) + return; + + ucActionId = *(pPkt + 12 + 2 + 2); /* skip dst, src MAC, type, payload type, category */ + + if ((ucActionId != TDLS_FRM_ACTION_SETUP_REQ) && (ucActionId != TDLS_FRM_ACTION_SETUP_RSP)) + return; + + /* init */ + prAdapter = prGlueInfo->prAdapter; + pucPeerMac = pPkt + 6; + s2FmeLen = (INT16) u2PktLen; + + DBGLOG(TDLS, TRACE, + " %s: get a setup frame %d from %pM\n", + __func__, ucActionId, (pucPeerMac)); + + if (ucActionId == TDLS_FRM_ACTION_SETUP_REQ) + pPkt += 12 + 2 + 2 + 1 + 1 + 2; /* skip action, dialog token, capability */ + else + pPkt += 12 + 2 + 2 + 1 + 2 + 1 + 2; /* skip action, status code, dialog token, capability */ + + /* check station record */ + prStaRec = cnmGetStaRecByAddress(prGlueInfo->prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, pucPeerMac); + + if (prStaRec == NULL) { + prStaRec = cnmStaRecAlloc(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX); + + if (prStaRec == NULL) { + /* TODO: only one TDLS entry, need to free old one if timeout */ + DBGLOG(TDLS, ERROR, " %s: alloc prStaRec fail!\n", __func__); + return; + } + + /* init the prStaRec */ + /* prStaRec will be zero first in cnmStaRecAlloc() */ + COPY_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMac); + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + + /* backup HT IE to station record */ + /* TODO: Maybe our TDLS only supports non-11n */ + while (s2FmeLen > 0) { + ucElmId = *pPkt++; + ucElmLen = *pPkt++; + + switch (ucElmId) { + case ELEM_ID_HT_CAP: /* 0x2d */ + /* backup the HT IE of 1st unhandled setup request frame */ + if (prGlueInfo->rTdlsHtCap.ucId == 0x00) { + kalMemCopy(prGlueInfo->aucTdlsHtPeerMac, pucPeerMac, 6); + kalMemCopy(&prGlueInfo->rTdlsHtCap, pPkt - 2, ucElmLen + 2); + + /* + cannot backup in prStaRec; or + + 1. we build a TDLS link + 2. peer re-sends setup req + 3. we backup HT cap element + 4. supplicant disables the link + 5. we clear the prStaRec + */ + + DBGLOG(TDLS, TRACE, + " %s: %pM: find a HT IE\n", + __func__, (pucPeerMac)); + } + return; + + case ELEM_ID_EXTENDED_CAP: + /* TODO: backup the extended capability IE */ + break; + } + + pPkt += ucElmLen; + s2FmeLen -= (2 + ucElmLen); + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to get the TDLS station record. +* +* \param[in] prGlueInfo Pointer to the Adapter structure +* \param[in] prInBuf A pointer to the command string buffer +* \param[in] u4InBufLen The length of the buffer +* \param[out] None +* +* \retval TDLS_STATUS_SUCCESS: this is TDLS packet +* TDLS_STATUS_FAILURE: this is not TDLS packet +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS TdlsexStaRecIdxGet(ADAPTER_T *prAdapter, MSDU_INFO_T *prMsduInfo) +{ + BSS_INFO_T *prBssInfo; + STA_RECORD_T *prStaRec; + TDLS_STATUS Status; + + /* sanity check */ + if ((prAdapter == NULL) || (prMsduInfo == NULL)) + return TDLS_STATUS_FAILURE; + + if (prAdapter->prGlueInfo == NULL) + return TDLS_STATUS_FAILURE; + if (TDLS_IS_NO_LINK_GOING(prAdapter->prGlueInfo)) + return TDLS_STATUS_FAILURE; + + /* init */ + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + Status = TDLS_STATUS_SUCCESS; + + /* get record by ether dest */ + prStaRec = cnmGetStaRecByAddress(prAdapter, (UINT_8) NETWORK_TYPE_AIS_INDEX, prMsduInfo->aucEthDestAddr); + + /* + TDLS Setup Request frames, TDLS Setup Response frames and TDLS Setup Confirm + frames shall be transmitted through the AP and shall not be transmitted to a group + address. + + 1. In first time, prStaRec == NULL or prStaRec->ucStaState != STA_STATE_3, + we will send them to AP; + 2. When link is still on, if you command to send TDLS setup from supplicant, + supplicant will DISABLE LINK first, prStaRec will be NULL then send TDLS + setup frame to the peer. + */ + + do { + if ((prStaRec != NULL) && (prStaRec->ucStaState == STA_STATE_3) && (IS_TDLS_STA(prStaRec))) { + /* + TDLS Test Case 5.3 Tear Down + Automatically sends TDLS Teardown frame to STA 2 via AP + + 11.21.5 TDLS Direct Link Teardown + The TDLS Teardown frame shall be sent over the direct path and the reason + code shall be set to "TDLS 40 direct link teardown for unspecified reason", + except when the TDLS peer STA is unreachable via the TDLS direct link, + in which case, the TDLS Teardown frame shall be sent through the AP and + the reason code shall be set to "TDLS direct link teardown due to TDLS peer + STA unreachable via the TDLS direct link". + */ + /* if (prStaRec->fgIsInPS == TRUE) */ + /* + check if the packet is tear down: + we do not want to use PTI to indicate the tear down and + we want to send the tear down to AP then AP help us to send it + */ + struct sk_buff *prSkb; + UINT8 *pEth; + UINT_16 u2EtherTypeLen; + + prSkb = (struct sk_buff *)prMsduInfo->prPacket; + if (prSkb != NULL) { + UINT8 ucActionCode, ucReasonCode; + + /* init */ + pEth = prSkb->data; + u2EtherTypeLen = (pEth[ETH_TYPE_LEN_OFFSET] << 8) | + (pEth[ETH_TYPE_LEN_OFFSET + 1]); + ucActionCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 3]; + ucReasonCode = pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] | + (pEth[ETH_TYPE_LEN_OFFSET + 1 + 5] << 8); + + /* TDLS_REASON_CODE_UNREACHABLE: keep alive fail or PTI timeout */ + if ((u2EtherTypeLen == TDLS_FRM_PROT_TYPE) && + (ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && + (ucReasonCode == TDLS_REASON_CODE_UNREACHABLE)) { + /* + when we cannot reach the peer, + we need AP's help to send the tear down frame + */ + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prStaRec = prBssInfo->prStaRecOfAP; + if (prStaRec == NULL) { + Status = TDLS_STATUS_FAILURE; + break; + } +#if 0 + /* change status code */ + pEth[ETH_TYPE_LEN_OFFSET + 1 + 4] = TDLS_REASON_CODE_UNREACHABLE; +#endif + } + } + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + } + } while (FALSE); + + DBGLOG(TDLS, INFO, " %s: (Status=%x) [%pM] ucStaRecIndex = %d!\n", + __func__, (INT32) Status, (prMsduInfo->aucEthDestAddr), + prMsduInfo->ucStaRecIndex); + return Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to check if we suffer timeout for TX quota empty case. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexTxQuotaCheck(GLUE_INFO_T *prGlueInfo, STA_RECORD_T *prStaRec, UINT8 FreeQuota) +{ + OS_SYSTIME rCurTime; + + /* sanity check */ + if (!IS_TDLS_STA(prStaRec)) + return; + + if (FreeQuota != 0) { + /* reset timeout */ + prStaRec->rTdlsTxQuotaEmptyTime = 0; + return; + } + + /* work-around: check if the no free quota case is too long */ + GET_CURRENT_SYSTIME(&rCurTime); + + if (prStaRec->rTdlsTxQuotaEmptyTime == 0) { + prStaRec->rTdlsTxQuotaEmptyTime = rCurTime; + } else { + if (CHECK_FOR_TIMEOUT(rCurTime, prStaRec->rTdlsTxQuotaEmptyTime, + SEC_TO_SYSTIME(TDLS_TX_QUOTA_EMPTY_TIMEOUT))) { + /* tear down the link */ + DBGLOG(TDLS, WARN, + " %s: [%pM] TX quota empty timeout!\n", + __func__, (prStaRec->aucMacAddr)); + + /* record disconnect history */ + TdlsLinkHistoryRecord(prGlueInfo, TRUE, prStaRec->aucMacAddr, + TRUE, TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY, NULL); + + /* inform tear down to supplicant only in OPEN/NONE mode */ + /* + we need to tear down the link manually; or supplicant will display + "No FTIE in TDLS Teardown" and it will not tear down the link + */ + cfg80211_tdls_oper_request(prGlueInfo->prDevHandler, + prStaRec->aucMacAddr, TDLS_FRM_ACTION_TEARDOWN, + TDLS_REASON_CODE_UNREACHABLE, GFP_ATOMIC); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to un-initialize variables in TDLS. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID TdlsexUninit(ADAPTER_T *prAdapter) +{ +#if TDLS_CFG_CMD_TEST + cnmTimerStopTimer(prAdapter, &rTdlsTimerTestDataSend); +#endif /* TDLS_CFG_CMD_TEST */ +} + +#endif /* CFG_SUPPORT_TDLS */ + +/* End of tdls.c */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c new file mode 100644 index 0000000000000..5450cbb651837 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/tdls_com.c @@ -0,0 +1,741 @@ +/* +** Id: tdls_com.c#1 +*/ + +/*! \file tdls_com.c + \brief This file includes IEEE802.11z TDLS main support. +*/ + +/* +** Log: tdls_com.c + * + * 11 13 2013 vend_samp.lin + * NULL + * Initial version. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************** + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************** + */ + +#include "precomp.h" + +#if (CFG_SUPPORT_TDLS == 1) +#include "tdls.h" + + /******************************************************************************* + * C O N S T A N T S + ******************************************************************************** + */ + + /******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************** + */ + + /******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************** + */ + + /******************************************************************************* + * P R I V A T E F U N C T I O N S + ******************************************************************************** + */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to append general IEs. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] prStaRec Pointer to the STA_RECORD_T structure. +* \param[in] u2StatusCode Status code. +* \param[in] pPkt Pointer to the frame body +* +* \retval append length +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, UINT_16 u2StatusCode, UINT_8 *pPkt) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + UINT_32 u4NonHTPhyType; + UINT_16 u2SupportedRateSet; + UINT_8 aucAllSupportedRates[RATE_NUM] = { 0 }; + UINT_8 ucAllSupportedRatesLen; + UINT_8 ucSupRatesLen; + UINT_8 ucExtSupRatesLen; + UINT_32 u4PktLen, u4IeLen; + BOOLEAN fg40mAllowed; + + /* reference to assocBuildReAssocReqFrameCommonIEs() */ + + /* init */ + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + /* 3. Frame Formation - (5) Supported Rates element */ + /* use all sup rate we can support */ + if (prStaRec != NULL) + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + else + u4NonHTPhyType = PHY_TYPE_ERP_INDEX; /* default */ + + u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + + if (prStaRec != NULL) { + u2SupportedRateSet &= prStaRec->u2OperationalRateSet; + + if (u2SupportedRateSet == 0) + u2SupportedRateSet = rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + } + + rateGetDataRatesFromRateSet(u2SupportedRateSet, + prBssInfo->u2BSSBasicRateSet, aucAllSupportedRates, &ucAllSupportedRatesLen); + + ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? + ELEM_MAX_LEN_SUP_RATES : ucAllSupportedRatesLen); + + ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; + + if (ucSupRatesLen) { + SUP_RATES_IE(pPkt)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pPkt)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pPkt)->aucSupportedRates, aucAllSupportedRates, ucSupRatesLen); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (7) Extended sup rates element */ + if (ucExtSupRatesLen) { + + EXT_SUP_RATES_IE(pPkt)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pPkt)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pPkt)->aucExtSupportedRates, + &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (8) Supported channels element */ + /* + The Supported channels element is included in Request frame and also in Response + frame if Status Code 0 (successful). + */ + if (u2StatusCode == 0) { + SUPPORTED_CHANNELS_IE(pPkt)->ucId = ELEM_ID_SUP_CHS; + SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 2; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[0] = 1; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[1] = 11; + +#if CFG_SUPPORT_DFS + if (prAdapter->fgEnable5GBand == TRUE) { + /* 5G support */ + SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 10; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[2] = 36; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[3] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[4] = 52; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[5] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[6] = 149; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[7] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[8] = 165; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[9] = 4; + } +#endif /* CFG_SUPPORT_DFS */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (14) HT capabilities element */ + + /* no need to check AP capability */ +/* if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11N) && */ + + /* + after we set ucPhyTypeSet to PHY_TYPE_SET_802_11N in TdlsexRxFrameHandle(), + supplicant will disable link if exists and we will clear prStaRec. + + finally, prStaRec->ucPhyTypeSet will also be 0 + + so we have a fix in TdlsexPeerAdd(). + */ + if (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + /* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */ +#if 0 /* always support */ + if (prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode == CONFIG_BW_20M) + fg40mAllowed = FALSE; + else +#endif + fg40mAllowed = TRUE; + + u4IeLen = rlmFillHtCapIEByParams(fg40mAllowed, + prAdapter->rWifiVar.rConnSettings.fgRxShortGIDisabled, + prAdapter->rWifiVar.u8SupportRxSgi20, + prAdapter->rWifiVar.u8SupportRxSgi40, + prAdapter->rWifiVar.u8SupportRxGf, + prAdapter->rWifiVar.u8SupportRxSTBC, prBssInfo->eCurrentOPMode, pPkt); + + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (17) WMM Information element */ + + /* always support */ +/* if (prAdapter->rWifiVar.fgSupportQoS) */ + + { + /* force to support all UAPSD in TDLS link */ + u4IeLen = mqmGenerateWmmInfoIEByParam(TRUE /*prAdapter->rWifiVar.fgSupportUAPSD */ , + 0xf /*prPmProfSetupInfo->ucBmpDeliveryAC */ , + 0xf /*prPmProfSetupInfo->ucBmpTriggerAC */ , + WMM_MAX_SP_LENGTH_ALL /*prPmProfSetupInfo->ucUapsdSp */ , + pPkt); + + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + return u4PktLen; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to transmit a TDLS data frame (setup req/rsp/confirm and tear down). +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* \param[in] prStaRec Pointer to the STA_RECORD_T structure. +* \param[in] pPeerMac Pointer to the MAC of the TDLS peer +* \param[in] ucActionCode TDLS Action +* \param[in] ucDialogToken Dialog token +* \param[in] u2StatusCode Status code +* \param[in] pAppendIe Others IEs (here are security IEs from supplicant) +* \param[in] AppendIeLen IE length of others IEs +* +* \retval TDLS_STATUS_xx +*/ +/*----------------------------------------------------------------------------*/ +TDLS_STATUS +TdlsDataFrameSend(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + UINT_8 *pPeerMac, + UINT_8 ucActionCode, + UINT_8 ucDialogToken, UINT_16 u2StatusCode, UINT_8 *pAppendIe, UINT_32 AppendIeLen) +{ +#define LR_TDLS_FME_FIELD_FILL(__Len) \ +do { \ + pPkt += __Len; \ + u4PktLen += __Len; \ +} while (0) + + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + MSDU_INFO_T *prMsduInfoMgmt; + UINT8 *pPkt, *pucInitiator, *pucResponder; + UINT32 u4PktLen, u4IeLen; + UINT16 u2CapInfo; +/* UINT8 *pPktTemp; */ + + prGlueInfo = (GLUE_INFO_T *) prAdapter->prGlueInfo; + + DBGLOG(TDLS, INFO, " %s: 2040=%d\n", __func__, prGlueInfo->rTdlsLink.fgIs2040Sup); + + /* sanity check */ + if (prStaRec != NULL) { + if (prStaRec->ucNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { + DBGLOG(TDLS, ERROR, + " %s: net index %d fail\n", __func__, prStaRec->ucNetTypeIndex); + return TDLS_STATUS_FAILURE; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + } else { + /* prStaRec maybe NULL in setup request */ + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + } + + /* allocate/init packet */ + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + prMsduInfo = NULL; + prMsduInfoMgmt = NULL; + + /* make up frame content */ + if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { + /* + The STAUT will not respond to a TDLS Discovery Request Frame with different BSSID. + Supplicant will check this in wpa_tdls_process_discovery_request(). + */ + + /* TODO: reduce 1600 to correct size */ + prMsduInfo = kalPacketAlloc(prGlueInfo, 1600, &pPkt); + if (prMsduInfo == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate pkt fail\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + DBGLOG(TDLS, ERROR, " %s: MsduInfo->dev == NULL\n", __func__); + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAILURE; + } + + /* 1. 802.3 header */ +/* pPktTemp = pPkt; */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(UINT_16 *) pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + } else { + /* discovery response */ + WLAN_MAC_HEADER_T *prHdr; + + prMsduInfoMgmt = (MSDU_INFO_T *) + cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfoMgmt == NULL) { + DBGLOG(TDLS, ERROR, " %s: allocate mgmt pkt fail\n", __func__); + return TDLS_STATUS_RESOURCES; + } + + pPkt = (UINT8 *) prMsduInfoMgmt->prPacket; + prHdr = (WLAN_MAC_HEADER_T *) pPkt; + + /* 1. 802.11 header */ + prHdr->u2FrameCtrl = MAC_FRAME_ACTION; + prHdr->u2DurationID = 0; + kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr, TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, TDLS_FME_MAC_ADDR_LEN); + prHdr->u2SeqCtrl = 0; + LR_TDLS_FME_FIELD_FILL(sizeof(WLAN_MAC_HEADER_T)); + + /* Frame Formation - (1) Category */ + *pPkt = CATEGORY_PUBLIC_ACTION; + LR_TDLS_FME_FIELD_FILL(1); + } + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - Status Code */ + switch (ucActionCode) { + case TDLS_FRM_ACTION_SETUP_RSP: + case TDLS_FRM_ACTION_CONFIRM: + case TDLS_FRM_ACTION_TEARDOWN: + WLAN_SET_FIELD_16(pPkt, u2StatusCode); + LR_TDLS_FME_FIELD_FILL(2); + break; + } + + /* 3. Frame Formation - (3) Dialog token */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + } + + /* Fill elements */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + Capability + + Support Rates + Extended Support Rates + Supported Channels + HT Capabilities + WMM Information Element + + Extended Capabilities + Link Identifier + + RSNIE + FTIE + Timeout Interval + */ + if (ucActionCode != TDLS_FRM_ACTION_CONFIRM) { + /* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be set */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + LR_TDLS_FME_FIELD_FILL(2); + + /* 4. Append general IEs */ + /* + TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode + must be CONFIG_BW_20_40M. + + TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if + Tdls 20/40 is enabled. + */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, u2StatusCode, pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 5. Frame Formation - Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ + + /* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } else { + /* 5. Frame Formation - WMM Parameter element */ + if (prAdapter->rWifiVar.fgSupportQoS) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, + prBssInfo, pPkt, OP_MODE_INFRASTRUCTURE); + + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + } + } + + /* 6. Frame Formation - 20/40 BSS Coexistence */ + /* + Follow WiFi test plan, add 20/40 element to request/response/confirm. + */ +/* if (prGlueInfo->rTdlsLink.fgIs2040Sup == TRUE) */ /* force to enable */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + bit0 = 1: The Information Request field is used to indicate that a + transmitting STA is requesting the recipient to transmit a 20/40 BSS + Coexistence Management frame with the transmitting STA as the + recipient. + + bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an AP + that receives this information or reports of this information from + operating a 20/40 MHz BSS. + + bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit + a receiving AP from operating its BSS as a 20/40 MHz BSS. + */ + BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; + BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; + LR_TDLS_FME_FIELD_FILL(3); + } + + /* 6. Frame Formation - HT Operation element */ +/* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */ +/* LR_TDLS_FME_FIELD_FILL(u4IeLen); */ + + /* 7. Frame Formation - Link identifier element */ + /* Note1: Link ID sequence must be correct; Or the calculated MIC will be error */ + /* + Note2: When we receive a setup request with link ID, Marvell will send setup response + to the peer in link ID, not the SA in the WLAN header. + */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = ELEM_LEN_LINK_IDENTIFIER; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, 6); + + switch (ucActionCode) { + case TDLS_FRM_ACTION_SETUP_REQ: + case TDLS_FRM_ACTION_CONFIRM: + default: + /* we are initiator */ + pucInitiator = prBssInfo->aucOwnMacAddr; + pucResponder = pPeerMac; + + if (prStaRec != NULL) + prStaRec->flgTdlsIsInitiator = TRUE; + break; + + case TDLS_FRM_ACTION_SETUP_RSP: + case TDLS_FRM_ACTION_DISCOVERY_RESPONSE: + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + + if (prStaRec != NULL) + prStaRec->flgTdlsIsInitiator = FALSE; + break; + + case TDLS_FRM_ACTION_TEARDOWN: + if (prStaRec != NULL) { + if (prStaRec->flgTdlsIsInitiator == TRUE) { + /* we are initiator */ + pucInitiator = prBssInfo->aucOwnMacAddr; + pucResponder = pPeerMac; + } else { + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + } + } else { + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + } + break; + } + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pucInitiator, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pucResponder, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 8. Append security IEs */ + /* + 11.21.5 TDLS Direct Link Teardown + If the STA has security enabled on the link 37 with the AP, then the FTIE shall be + included in the TDLS Teardown frame. + + For ralink station, it can accept our tear down without FTIE but marvell station. + */ +/* if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) && (pAppendIe != NULL)) */ + if (pAppendIe != NULL) { + if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || + ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && + (prStaRec != NULL) && (prStaRec->fgTdlsInSecurityMode == TRUE))) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + } + + /* 7. Append Supported Operating Classes IE */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* Note: if we do not put the IE, Marvell STA will decline our TDLS setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 11. send the data or management frame */ + if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RESPONSE) { +#if 0 + /* + Note1: remember to modify our MAC & AP MAC & peer MAC in LINK ID + Note2: dialog token in rsp & confirm must be same as sender. + */ + +#if 1 + /* example for Ralink's and Broadcom's TDLS setup request frame in open/none */ + if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { +#if 0 + /* mediatek */ + char buffer[] = { 0x31, 0x04, + 0x01, 0x08, 0x02, 0x04, 0x0b, 0x16, 0xc, 0x12, 0x18, 0x24, + 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, + 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, + 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, + 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, + 0x48, 0x01, 0x01, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, + 0x1b, 0x1c, 0x1e, 0x20, 0x21, + 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e + }; +#endif + +#if 1 + /* ralink *//* from capability */ + char buffer[] = { 0x21, 0x04, + 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, + 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, + 0x32, 0x04, 0x0c, 0x18, 0x30, 0x60, + 0x24, 0x06, 0x01, 0x0b, 0x24, 0x08, 0x95, 0x04, + 0x7f, 0x05, 0x01, 0x00, 0x00, 0x50, 0x20, + 0x3b, 0x10, 0x20, 0x01, 0x02, 0x03, 0x04, 0x0c, 0x16, 0x17, 0x18, 0x19, + 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, + 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x48, 0x01, 0x01, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f + }; +#endif +#if 0 + /* 6630 */ + char buffer[] = { 0x01, 0x01, + 0x01, 0x04, 0x02, 0x04, 0x0b, 0x16, + 0x24, 0x02, 0x01, 0x0d, + 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0xff, + 0x2d, 0x1a, 0x61, 0x01, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, + 0x48, 0x01, 0x01, + 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, + 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, + 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00, + 0xbf, 0x0c, 0x30, 0x01, 0x80, 0x03, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, + 0x00, 0x00 + }; +#endif + + pPktTemp += 18; + memcpy(pPktTemp, buffer, sizeof(buffer)); + u4PktLen = 18 + sizeof(buffer); + } +#endif + +#if 1 + if (ucActionCode == TDLS_FRM_ACTION_CONFIRM) { + /* Note: dialog token must be same as request */ +#if 1 + /* ralink */ + char buffer[] = { 0x00, + 0x01, 0x2d, 0x1a, 0x6e, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x00, 0x03, + 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, + 0x62, 0x32, 0x2f, 0x00 + }; +#endif + +#if 0 + /* 6630 */ + char buffer[] = { 0x00, + 0x01, + 0x38, 0x05, 0x02, 0xc0, 0xa8, 0x00, 0x00, + 0x48, 0x01, 0x01, + 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, + 0x1b, 0x1c, 0x1d, 0x1e, 0x20, 0x21, + 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00, + 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00 + }; +#endif + +#if 0 + /* A/D die */ + char buffer[] = { 0x00, + 0x01, + 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x0f, 0x6b, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x00 0x65, 0x12, 0x00, 0x0c, 0x43, 0x31, 0x35, 0x97, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0x38, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, 0x1b, + 0x1c, 0x1e, 0x20, 0x21, + 0x07, 0x06, 0x55, 0x53, 0x20, 0x01, 0x0b, 0x1e + }; +#endif + + pPktTemp += 18; + memcpy(pPktTemp, buffer, sizeof(buffer)); + u4PktLen = 18 + sizeof(buffer); + } +#endif + +#else + +#if 0 + /* for test in open/none */ + if (ucActionCode == TDLS_FRM_ACTION_SETUP_REQ) { + char buffer[] = { 0x01, 0x04, + 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x12, 0x24, 0x48, 0x6c, + 0x07, 0x06, 0x55, 0x53, 0x20, 0xdd, 0x20, 0x00, + 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, + 0x24, 0x0a, 0x01, 0x0b, 0x24, 0x04, 0x34, 0x04, 0x95, 0x04, 0xa5, 0x01, + 0x2d, 0x1a, 0x72, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xdd, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x0f, + 0x7f, 0x05, 0x00, 0x00, 0x00, 0x50, 0x20, + 0x48, 0x01, 0x01, + 0x65, 0x12, 0x00, 0x0c, 0x43, 0x44, 0x0b, 0x1a, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x05, 0x00, 0x22, 0x58, 0x00, 0xcc, 0x0f, + 0x3b, 0x0d, 0x0c, 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, 0x19, + 0x1b, 0x1c, 0x1e, 0x20, 0x21 + }; + + pPktTemp += 18; + memcpy(pPktTemp, buffer, sizeof(buffer)); + u4PktLen = 18 + sizeof(buffer); + } +#endif +#endif /* 0 */ + + /* 9. Update packet length */ + prMsduInfo->len = u4PktLen; + dumpMemory8(prMsduInfo->data, u4PktLen); + + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + } else { + /* + A TDLS capable STA that receives a TDLS Discovery Request frame is required to + send the response "to the requesting STA, via the direct path." + However, prior to establishment of the direct link, the responding STA may not + know the rate capabilities of the requesting STA. In this case, the responding + STA shall send the TDLS Discovery Response frame using a rate from the + BSSBasicRateSet of the BSS to which the STA is currently associated. + */ + prMsduInfoMgmt->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; + prMsduInfoMgmt->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfoMgmt->ucNetworkType = prBssInfo->ucNetTypeIndex; + prMsduInfoMgmt->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfoMgmt->fgIs802_1x = FALSE; + prMsduInfoMgmt->fgIs802_11 = TRUE; + prMsduInfoMgmt->u2FrameLength = u4PktLen; + prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfoMgmt->pfTxDoneHandler = NULL; + prMsduInfoMgmt->fgIsBasicRate = TRUE; /* use basic rate */ + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt); + } + + return TDLS_STATUS_SUCCESS; +} + +#endif /* CFG_SUPPORT_TDLS */ + + /* End of tdls_com.c */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c new file mode 100644 index 0000000000000..af66ef95d17cf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wapi.c @@ -0,0 +1,491 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/wapi.c#1 +*/ + +/*! \file "wapi.c" + \brief This file including the WAPI related function. + + This file provided the macros and functions library support the wapi ie parsing, + cipher and AKM check to help the AP seleced deciding. +*/ + +/* +** Log: wapi.c +** +** 10 24 2012 wh.su +** [ALPS00376392] [klocwork 9.1] in wapi.c, line 344 +** Use MAX_NUM_SUPPORTED_WAPI_AKM_SUITESfor avoid Klocwork warning. +** +** 10 24 2012 wh.su +** [ALPS00376391] [klocwork 9.1] in wapi.c, line 311 +** Use the MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES for avoid Klccwork waring. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the debug module level. + * + * 10 20 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * fixed the network type + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 07 20 2010 wh.su + * + * . + * + * 04 06 2010 wh.su + * [BORA00000680][MT6620] Support the statistic for Micxxsoft os query + * fixed the firmware return the broadcast frame at wrong tc. + * + * 03 03 2010 wh.su + * [BORA00000637][MT6620 Wi-Fi] [Bug] WPA2 pre-authentication timer not correctly initialize + * move the AIS specific variable for security to AIS specific structure. + * + * 12 18 2009 cm.chang + * [BORA00000018]Integrate WIFI part into BORA for the 1st time + * . + * + * Dec 8 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the function to check and update the default wapi tx + * + * Dec 7 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * adding the generate wapi ie function, and replace the tabe by space + * + * Nov 23 2009 mtk01088 + * [BORA00000476] [Wi-Fi][firmware] Add the security module initialize code + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" +#if CFG_SUPPORT_WAPI + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to generate WPA IE for +* associate request frame. +* +* \param[in] prCurrentBss The Selected BSS description +* +* \retval The append WPA IE length +* +* \note +* Called by: AIS module, Associate request +*/ +/*----------------------------------------------------------------------------*/ +VOID wapiGenerateWAPIIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + PUINT_8 pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucNetworkType != NETWORK_TYPE_AIS_INDEX) + return; + + pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 68 :0x44 */ + if (/* prWlanInfo->fgWapiMode && */ prAdapter->prGlueInfo->u2WapiAssocInfoIESz) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWapiAssocInfoIEs, + prAdapter->prGlueInfo->u2WapiAssocInfoIESz); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WapiAssocInfoIESz; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to parse WAPI IE. +* +* \param[in] prInfoElem Pointer to the RSN IE +* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the +** WAPI information from the given WAPI IE +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wapiParseWapiIE(IN P_WAPI_INFO_ELEM_T prInfoElem, OUT P_WAPI_INFO_T prWapiInfo) +{ + UINT_32 i; + INT_32 u4RemainWapiIeLen; + UINT_16 u2Version; + UINT_16 u2Cap = 0; + UINT_32 u4GroupSuite = WAPI_CIPHER_SUITE_WPI; + UINT_16 u2PairSuiteCount = 0; + UINT_16 u2AuthSuiteCount = 0; + PUCHAR pucPairSuite = NULL; + PUCHAR pucAuthSuite = NULL; + PUCHAR cp; + + DEBUGFUNC("wapiParseWapiIE"); + + ASSERT(prInfoElem); + ASSERT(prWapiInfo); + + /* Verify the length of the WAPI IE. */ + if (prInfoElem->ucLength < 6) { + DBGLOG(SEC, TRACE, "WAPI IE length too short (length=%d)\n", prInfoElem->ucLength); + return FALSE; + } + + /* Check WAPI version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(SEC, TRACE, "Unsupported WAPI IE version: %d\n", u2Version); + return FALSE; + } + + cp = (PUCHAR) &prInfoElem->u2AuthKeyMgtSuiteCount; + u4RemainWapiIeLen = (INT_32) prInfoElem->ucLength - 2; + + do { + if (u4RemainWapiIeLen == 0) + break; + + /* + AuthCount : 2 + AuthSuite : 4 * authSuiteCount + PairwiseCount: 2 + PairwiseSuite: 4 * pairSuiteCount + GroupSuite : 4 + Cap : 2 */ + + /* Parse the Authentication and Key Management Cipher Suite Count + field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainWapiIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + field. */ + i = (UINT_32) u2AuthSuiteCount * 4; + if (u4RemainWapiIeLen < (INT_32) i) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainWapiIeLen -= (INT_32) i; + + if (u4RemainWapiIeLen == 0) + break; + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainWapiIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (UINT_32) u2PairSuiteCount * 4; + if (u4RemainWapiIeLen < (INT_32) i) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + pucPairSuite = cp; + + cp += i; + u4RemainWapiIeLen -= (INT_32) i; + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainWapiIeLen < 4) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainWapiIeLen -= 4; + + /* Parse the WAPI u2Capabilities field. */ + if (u4RemainWapiIeLen < 2) { + DBGLOG(SEC, TRACE, "Fail to parse WAPI IE in WAPI capabilities (IE len: %d)\n", + prInfoElem->ucLength); + return FALSE; + } + + WLAN_GET_FIELD_16(cp, &u2Cap); + u4RemainWapiIeLen -= 2; + + /* Todo:: BKID support */ + } while (FALSE); + + /* Save the WAPI information for the BSS. */ + + prWapiInfo->ucElemId = ELEM_ID_WAPI; + + prWapiInfo->u2Version = u2Version; + + prWapiInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(SEC, LOUD, "WAPI: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (UCHAR) (u4GroupSuite & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 8) & 0x000000FF), + (UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF)); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES) + u2PairSuiteCount = MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES; + + prWapiInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount; + + for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, &prWapiInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the pairwise key cipher suites is not present. + Use the default chipher suite for WAPI: WPI. */ + prWapiInfo->u4PairwiseKeyCipherSuiteCount = 1; + prWapiInfo->au4PairwiseKeyCipherSuite[0] = WAPI_CIPHER_SUITE_WPI; + + DBGLOG(SEC, LOUD, "WAPI: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWapiInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management suites + is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_WAPI_AKM_SUITES) + u2AuthSuiteCount = MAX_NUM_SUPPORTED_WAPI_AKM_SUITES; + + prWapiInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount; + + for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prWapiInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(SEC, LOUD, "WAPI: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (UINT_8) i, (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the authentication and key management suites + is not present. Use the default AKM suite for WAPI. */ + prWapiInfo->u4AuthKeyMgtSuiteCount = 1; + prWapiInfo->au4AuthKeyMgtSuite[0] = WAPI_AKM_SUITE_802_1X; + + DBGLOG(SEC, LOUD, "WAPI: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (UCHAR) (prWapiInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (UCHAR) ((prWapiInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); + } + + prWapiInfo->u2WapiCap = u2Cap; + DBGLOG(SEC, LOUD, "WAPI: cap: 0x%04x\n", prWapiInfo->u2WapiCap); + + return TRUE; +} /* wapiParseWapiIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to perform WAPI policy selection for a given BSS. +* +* \param[in] prAdapter Pointer to the adapter object data area. +* \param[in] prBss Pointer to the BSS description +* +* \retval TRUE - The WAPI policy selection for the given BSS is +* successful. The selected pairwise and group cipher suites +* are returned in the BSS description. +* \retval FALSE - The WAPI policy selection for the given BSS is failed. +* The driver shall not attempt to join the given BSS. +* +* \note The Encrypt status matched score will save to bss for final ap select. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wapiPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) +{ + UINT_32 i; + UINT_32 u4PairwiseCipher = 0; + UINT_32 u4GroupCipher = 0; + UINT_32 u4AkmSuite = 0; + P_WAPI_INFO_T prBssWapiInfo; + P_WLAN_INFO_T prWlanInfo; + + DEBUGFUNC("wapiPerformPolicySelection"); + + ASSERT(prBss); + + /* Notice!!!! WAPI AP not set the privacy bit for WAI and WAI-PSK at WZC configuration mode */ + prWlanInfo = &prAdapter->rWlanInfo; + + if (prBss->fgIEWAPI) { + prBssWapiInfo = &prBss->rIEWAPI; + } else { + if (prAdapter->rWifiVar.rConnSettings.fgWapiMode == FALSE) { + DBGLOG(SEC, TRACE, "-- No Protected BSS\n"); + return TRUE; + } + DBGLOG(SEC, TRACE, "WAPI Information Element does not exist.\n"); + return FALSE; + } + + /* Select pairwise/group ciphers */ + for (i = 0; i < prBssWapiInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (prBssWapiInfo->au4PairwiseKeyCipherSuite[i] == + prAdapter->rWifiVar.rConnSettings.u4WapiSelectedPairwiseCipher) { + u4PairwiseCipher = prBssWapiInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (prBssWapiInfo->u4GroupKeyCipherSuite == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedGroupCipher) + u4GroupCipher = prBssWapiInfo->u4GroupKeyCipherSuite; + + /* Exception handler */ + /* If we cannot find proper pairwise and group cipher suites to join the + BSS, do not check the supported AKM suites. */ + if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { + DBGLOG(SEC, TRACE, "Failed to select pairwise/group cipher (0x%08x/0x%08x)\n", + u4PairwiseCipher, u4GroupCipher); + return FALSE; + } + + /* Select AKM */ + /* If the driver cannot support any authentication suites advertised in + the given BSS, we fail to perform RSNA policy selection. */ + /* Attempt to find any overlapping supported AKM suite. */ + for (i = 0; i < prBssWapiInfo->u4AuthKeyMgtSuiteCount; i++) { + if (prBssWapiInfo->au4AuthKeyMgtSuite[i] == prAdapter->rWifiVar.rConnSettings.u4WapiSelectedAKMSuite) { + u4AkmSuite = prBssWapiInfo->au4AuthKeyMgtSuite[i]; + break; + } + } + + if (u4AkmSuite == 0) { + DBGLOG(SEC, TRACE, "Cannot support any AKM suites\n"); + return FALSE; + } + + DBGLOG(SEC, TRACE, "Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", + (UINT_8) (u4PairwiseCipher & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF), + (UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF), + (UINT_8) (u4GroupCipher & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), + (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF)); + + DBGLOG(SEC, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", + (UINT_8) (u4AkmSuite & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 8) & 0x000000FF), + (UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF)); + + return TRUE; +} /* wapiPerformPolicySelection */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is use for wapi mode, to update the current wpi tx idx ? 0 :1 . +* +* \param[in] prStaRec Pointer to the Sta record +* \param[out] ucWlanIdx The Rx status->wlanidx field +* +* \retval TRUE - Succeeded +* \retval FALSE - Failed +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wapiUpdateTxKeyIdx(IN P_STA_RECORD_T prStaRec, IN UINT_8 ucWlanIdx) +{ + UINT_8 ucKeyId; + + if ((ucWlanIdx & BITS(0, 3)) == CIPHER_SUITE_WPI) { + + ucKeyId = ((ucWlanIdx & BITS(4, 5)) >> 4); + + if (ucKeyId != g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey) { + DBGLOG(RSN, STATE, + "Change wapi key index from %d->%d\n", + g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey, ucKeyId); + g_prWifiVar->rAisSpecificBssInfo.ucWpiActivedPWKey = ucKeyId; + + prStaRec->ucWTEntry = + (ucKeyId == + WTBL_AIS_BSSID_WAPI_IDX_0) ? WTBL_AIS_BSSID_WAPI_IDX_0 : WTBL_AIS_BSSID_WAPI_IDX_1; + } + } +} +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c new file mode 100644 index 0000000000000..f54d229411485 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/mgmt/wnm.c @@ -0,0 +1,301 @@ +/* +** Id: //Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/mgmt/wnm.c#1 +*/ + +/*! \file "wnm.c" + \brief This file includes the 802.11v default vale and functions. +*/ + +/* +** Log: wnm.c + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#if CFG_SUPPORT_802_11V + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define WNM_MAX_TOD_ERROR 0 +#define WNM_MAX_TOA_ERROR 0 +#define MICRO_TO_10NANO(x) ((x)*100) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT_8 ucTimingMeasToken; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11v wnm category action frame. +* +* +* \note +* Called by: Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +VOID wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_ACTION_FRAME prRxFrame; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + if (prRxFrame->ucAction == ACTION_WNM_TIMING_MEASUREMENT_REQUEST) { + wnmTimingMeasRequest(prAdapter, prSwRfb); + return; + } +#endif + + DBGLOG(WNM, TRACE, "Unsupport WNM action frame: %d\n", prRxFrame->ucAction); +} + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to report timing measurement data. +* +*/ +/*----------------------------------------------------------------------------*/ +VOID wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIndex, IN UINT_32 u4ToD, IN UINT_32 u4ToA) +{ + P_STA_RECORD_T prStaRec; + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); + + if ((!prStaRec) || (!prStaRec->fgIsInUse)) + return; + + DBGLOG(WNM, TRACE, "wnmReportTimingMeas: u4ToD %x u4ToA %x", u4ToD, u4ToA); + + if (!prStaRec->rWNMTimingMsmt.ucTrigger) + return; + + prStaRec->rWNMTimingMsmt.u4ToD = MICRO_TO_10NANO(u4ToD); + prStaRec->rWNMTimingMsmt.u4ToA = MICRO_TO_10NANO(u4ToA); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will handle TxDone(TimingMeasurement) Event. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prMsduInfo Pointer to the MSDU_INFO_T. +* @param[in] rTxDoneStatus Return TX status of the Timing Measurement frame. +* +* @retval WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wnmRunEventTimgingMeasTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + DBGLOG(WNM, LOUD, "EVENT-TX DONE: Current Time = %u\n", kalGetTimeTick()); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((!prStaRec) || (!prStaRec->fgIsInUse)) + return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR STATUS CODE */ + + DBGLOG(WNM, TRACE, "wnmRunEventTimgingMeasTxDone: ucDialog %d ucFollowUp %d u4ToD %x u4ToA %x", + prStaRec->rWNMTimingMsmt.ucDialogToken, + prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken, + prStaRec->rWNMTimingMsmt.u4ToD, prStaRec->rWNMTimingMsmt.u4ToA); + + prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; + prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; + + wnmComposeTimingMeasFrame(prAdapter, prStaRec, NULL); + + return WLAN_STATUS_SUCCESS; + +} /* end of wnmRunEventTimgingMeasTxDone() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will compose the Timing Measurement frame. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] prStaRec Pointer to the STA_RECORD_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wnmComposeTimingMeasFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME prTxFrame; + UINT_16 u2PayloadLen; + + prBssInfo = &prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]; + ASSERT(prBssInfo); + + prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) + return; + + prTxFrame = (P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME) + ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_UNPROTECTED_WNM_ACTION; + prTxFrame->ucAction = ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT; + + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = prStaRec->rWNMTimingMsmt.ucDialogToken; + prTxFrame->ucFollowUpDialogToken = prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken; + prTxFrame->u4ToD = prStaRec->rWNMTimingMsmt.u4ToD; + prTxFrame->u4ToA = prStaRec->rWNMTimingMsmt.u4ToA; + prTxFrame->ucMaxToDErr = WNM_MAX_TOD_ERROR; + prTxFrame->ucMaxToAErr = WNM_MAX_TOA_ERROR; + + u2PayloadLen = 2 + ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN; + + /* 4 Update information of MSDU_INFO_T */ + prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */ + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucNetworkType = prStaRec->ucNetTypeIndex; + prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfo->fgIs802_1x = FALSE; + prMsduInfo->fgIs802_11 = TRUE; + prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->fgIsBasicRate = FALSE; + + DBGLOG(WNM, TRACE, "wnmComposeTimingMeasFrame: ucDialogToken %d ucFollowUpDialogToken %d u4ToD %x u4ToA %x\n", + prTxFrame->ucDialogToken, prTxFrame->ucFollowUpDialogToken, + prTxFrame->u4ToD, prTxFrame->u4ToA); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return; + +} /* end of wnmComposeTimingMeasFrame() */ + +/*----------------------------------------------------------------------------*/ +/*! +* +* \brief This routine is called to process the 802.11v timing measurement request. +* +* +* \note +* Handle Rx mgmt request +*/ +/*----------------------------------------------------------------------------*/ +VOID wnmTimingMeasRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_ACTION_WNM_TIMING_MEAS_REQ_FRAME prRxFrame = NULL; + P_STA_RECORD_T prStaRec; + + prRxFrame = (P_ACTION_WNM_TIMING_MEAS_REQ_FRAME) prSwRfb->pvHeader; + if (!prRxFrame) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if ((!prStaRec) || (!prStaRec->fgIsInUse)) + return; + + DBGLOG(WNM, TRACE, "IEEE 802.11: Received Timing Measuremen Request from %pM\n" + prStaRec->aucMacAdd); + + /* reset timing msmt */ + prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; + prStaRec->rWNMTimingMsmt.ucTrigger = prRxFrame->ucTrigger; + if (!prRxFrame->ucTrigger) + return; + + prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; + prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; + + wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); +} + +#if WNM_UNIT_TEST +VOID wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex) +{ + P_STA_RECORD_T prStaRec; + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); + if ((!prStaRec) || (!prStaRec->fgIsInUse)) + return; + + DBGLOG(WNM, INFO, "IEEE 802.11v: Test Timing Measuremen Request from %pM\n", + prStaRec->aucMacAddr); + + prStaRec->rWNMTimingMsmt.fgInitiator = TRUE; + prStaRec->rWNMTimingMsmt.ucTrigger = 1; + + prStaRec->rWNMTimingMsmt.ucDialogToken = ++ucTimingMeasToken; + prStaRec->rWNMTimingMsmt.ucFollowUpDialogToken = 0; + + wnmComposeTimingMeasFrame(prAdapter, prStaRec, wnmRunEventTimgingMeasTxDone); +} +#endif + +#endif /* CFG_SUPPORT_802_11V_TIMING_MEASUREMENT */ + +#endif /* CFG_SUPPORT_802_11V */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c new file mode 100644 index 0000000000000..6f1bb6fd771ec --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/cmd_buf.c @@ -0,0 +1,254 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/cmd_buf.c#1 +*/ + +/*! \file "cmd_buf.c" + \brief This file contain the management function of internal Command Buffer + for CMD_INFO_T. + + We'll convert the OID into Command Packet and then send to FW. Thus we need + to copy the OID information to Command Buffer for following reasons. + 1. The data structure of OID information may not equal to the data structure of + Command, we cannot use the OID buffer directly. + 2. If the Command was not generated by driver we also need a place to store the + information. + 3. Because the CMD is NOT FIFO when doing memory allocation (CMD will be generated + from OID or interrupt handler), thus we'll use the Block style of Memory Allocation + here. +*/ + +/* +** Log: cmd_buf.c + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 02 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. clear prPendingCmdInfo properly + * * 2. while allocating memory for cmdinfo, no need to add extra 4 bytes. +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-10-13 21:59:08 GMT mtk01084 +** remove un-neceasary spaces +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-05-20 12:24:26 GMT mtk01461 +** Increase CMD Buffer - HIF_RX_HW_APPENDED_LEN when doing CMD_INFO_T allocation +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 09:41:08 GMT mtk01461 +** Add init of Driver Domain MCR flag and fix lint MTK WARN +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-17 19:51:45 GMT mtk01461 +** allocation function of CMD_INFO_T +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static BOOLEAN fgCmdDumpIsDone = FALSE; +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to initial the MGMT memory pool for CMD Packet. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cmdBufInitialize(IN P_ADAPTER_T prAdapter) +{ + P_CMD_INFO_T prCmdInfo; + UINT_32 i; + + ASSERT(prAdapter); + + QUEUE_INITIALIZE(&prAdapter->rFreeCmdList); + + for (i = 0; i < CFG_TX_MAX_CMD_PKT_NUM; i++) { + prCmdInfo = &prAdapter->arHifCmdDesc[i]; + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + } + fgCmdDumpIsDone = FALSE; +} /* end of cmdBufInitialize() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief dump CMD queue and print to trace, for debug use only +* @param[in] prQueue Pointer to the command Queue to be dumped +* @param[in] quename Name of the queue +*/ +/*----------------------------------------------------------------------------*/ +VOID cmdBufDumpCmdQueue(P_QUE_T prQueue, CHAR *queName) +{ + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_HEAD(prQueue); + + DBGLOG(NIC, INFO, "Dump CMD info for %s, Elem number:%u\n", queName, prQueue->u4NumElem); + while (prCmdInfo) { + P_CMD_INFO_T prCmdInfo1, prCmdInfo2, prCmdInfo3; + + prCmdInfo1 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo); + if (!prCmdInfo1) { + DBGLOG(NIC, INFO, "CID:%d SEQ:%d\n", prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum); + break; + } + prCmdInfo2 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo1); + if (!prCmdInfo2) { + DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum); + break; + } + prCmdInfo3 = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo2); + if (!prCmdInfo3) { + DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, prCmdInfo1->ucCmdSeqNum, + prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum); + break; + } + DBGLOG(NIC, INFO, "CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d; CID:%d, SEQ:%d\n", + prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, prCmdInfo1->ucCID, + prCmdInfo1->ucCmdSeqNum, prCmdInfo2->ucCID, prCmdInfo2->ucCmdSeqNum, + prCmdInfo3->ucCID, prCmdInfo3->ucCmdSeqNum); + prCmdInfo = (P_CMD_INFO_T)QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prCmdInfo3); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Allocate CMD_INFO_T from a free list and MGMT memory pool. +* +* @param[in] prAdapter Pointer to the Adapter structure. +* @param[in] u4Length Length of the frame buffer to allocate. +* +* @retval NULL Pointer to the valid CMD Packet handler +* @retval !NULL Fail to allocat CMD Packet +*/ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Length) +{ + P_CMD_INFO_T prCmdInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufAllocateCmdInfo"); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + /* Setup initial value in CMD_INFO_T */ + /* Start address of allocated memory */ + prCmdInfo->pucInfoBuffer = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + + if (prCmdInfo->pucInfoBuffer == NULL) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + prCmdInfo = NULL; + + DBGLOG(NIC, ERROR, "Allocate prCmdInfo->pucInfoBuffer fail!\n"); + } else { + prCmdInfo->u2InfoBufLen = 0; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + } + fgCmdDumpIsDone = FALSE; + } else if (!fgCmdDumpIsDone) { + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_QUE_T prCmdQue = &prGlueInfo->rCmdQueue; + P_QUE_T prPendingCmdQue = &prAdapter->rPendingCmdQueue; + P_TX_TCQ_STATUS_T prTc = &prAdapter->rTxCtrl.rTc; + + fgCmdDumpIsDone = TRUE; + cmdBufDumpCmdQueue(prCmdQue, "waiting Tx CMD queue"); + cmdBufDumpCmdQueue(prPendingCmdQue, "waiting response CMD queue"); + DBGLOG(NIC, INFO, "Tc4 number:%d\n", prTc->aucFreeBufferCount[TC4_INDEX]); + if (prTc->aucFreeBufferCount[TC4_INDEX] != 0) + glDoChipReset(); + } + + return prCmdInfo; + +} /* end of cmdBufAllocateCmdInfo() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to free the CMD Packet to the MGMT memory pool. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo CMD Packet handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufFreeCmdInfo"); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo) { + if (prCmdInfo->pucInfoBuffer) { + cnmMemFree(prAdapter, prCmdInfo->pucInfoBuffer); + prCmdInfo->pucInfoBuffer = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + } + + return; + +} /* end of cmdBufFreeCmdPacket() */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c new file mode 100644 index 0000000000000..dfaaedd118bfb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic.c @@ -0,0 +1,4062 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic.c#2 +*/ + +/*! \file nic.c + \brief Functions that provide operation in NIC's (Network Interface Card) point of view. + + This file includes functions which unite multiple hal(Hardware) operations + and also take the responsibility of Software Resource Management in order + to keep the synchronization with Hardware Manipulation. +*/ + +/* +** Log: nic.c + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 05 02 2012 terry.wu + * NULL + * Set the default value of AP StaRec index to "STA_REC_INDEX_NOT_FOUND" in update firmware bss command. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when + * returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 11 22 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * keep debug counter setting after wake up. + * + * 11 19 2011 yuche.tsai + * NULL + * Update RSSI for P2P. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 11 04 2011 cp.wu + * [WCXRP00001079] [MT5931][Driver] Release pending MMPDU only when BSS is being deactivated + * pre-check for NULL before calling MMPDU free function + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * change the DBGLOG for "\n" and "\r\n". LABEL to LOUD for XLOG + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to + * the AP.. + * + * 10 11 2011 terry.wu + * NULL + * Rewrite Assert Dump Function for Portability. + * + * 09 20 2011 cm.chang + * [WCXRP00000997] [MT6620 Wi-Fi][Driver][FW] Handle change of BSS preamble type and slot time + * New CMD definition about RLM parameters + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * reuse firmware download logic of MT6620 for MT6628. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 03 2011 terry.wu + * [WCXRP00000899] [MT6620] [FW] Reply probe rsp in FW for hotspot mode + * Reply Probe Rsp in FW for Hotspot Mode. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device + * issue. + * Fix GO send deauth frame issue. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 07 11 2011 wh.su + * [WCXRP00000849] [MT6620 Wi-Fi][Driver] Remove some of the WAPI define for make sure the value is initialize, for + * customer not enable WAPI + * For make sure wapi initial value is set. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky + * AP which use space character as hidden SSID + * 1. correct logic + * 2. replace only BSS-DESC which doesn't have a valid SSID. + * + * 06 27 2011 cp.wu + * [WCXRP00000815] [MT6620 Wi-Fi][Driver] allow single BSSID with multiple SSID settings to work around some tricky + * AP which use space character as hidden SSID + * allow to have a single BSSID with multiple SSID to be presented in scanning result + * + * 05 12 2011 puff.wen + * NULL + * FW Assert information dump to driver + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 15 2011 cp.wu + * [WCXRP00000651] [MT6620 Wi-Fi][Driver] Refine RSSI buffering mechanism + * ROLLBACK due to the special design is to workaround incorrect initial RCPI value coming from firmware domain. + * + * 04 14 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected + * 2. add dummy function for both Win32 and Linux part. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for + * dedicated network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 04 12 2011 wh.su + * NULL + * enable the p2p check the cipher to set the bssInfo auth mode. + * + * 04 12 2011 wh.su + * NULL + * prepare the code for sync the auth mode and encryption status for P2P and BOW. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver. + * + * 04 10 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * Fix compiler issue. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 04 07 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside + * wlanAdapterStart + * . + * + * 04 07 2011 cp.wu + * [WCXRP00000616] [MT6620 Wi-Fi][Driver] Free memory to pool and kernel in case any unexpected failure happend inside + * wlanAdapterStart + * implementation of internal error handling of nicAllocateAdapterMemory. + * + * 03 31 2011 chinglan.wang + * [WCXRP00000613] [MT6620 Wi-Fi] [FW] [Driver] BssInfo can get the security mode which is WPA/WPA2/WAPI or not. + * . + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similar APIs to hide the difference. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 10 2011 cm.chang + * [WCXRP00000358] [MT6620 Wi-Fi][Driver] Provide concurrent information for each module + * Add some functions to let AIS/Tethering or AIS/BOW be the same channel + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after + * connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 08 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Use kalPrint to print firmware assert info. + * + * 02 01 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * . + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 31 2011 terry.wu + * [WCXRP00000412] [MT6620 Wi-Fi][FW/Driver] Dump firmware assert info at android kernel log + * Print firmware ASSERT info at Android kernel log, driver side + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 19 2011 cp.wu + * [WCXRP00000372] [MT6620 Wi-Fi][Driver] Check bus access failure inside nicProcessIST() + * check bus error and/or card removal when retrieving interrupt status from HAL + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * 1) correct typo in scan.c + * 2) TX descriptors, RX descriptos and management buffer should use virtually continuous buffer instead of + * physically contineous one + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 12 17 2010 cp.wu + * [WCXRP00000270] [MT6620 Wi-Fi][Driver] Clear issues after concurrent networking support has been merged + * before BSS disconnection is indicated to firmware, all correlated peer should be cleared and freed + * + * 12 07 2010 cm.chang + * [WCXRP00000239] MT6620 Wi-Fi][Driver][FW] Merge concurrent branch back to maintrunk + * 1. BSSINFO include RLM parameter + * 2. free all sta records when network is disconnected + * + * 12 02 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Add more control value but dont use it now. + * + * 11 30 2010 eddie.chen + * [WCXRP00000218] [MT6620 Wi-Fi][Driver] Add auto rate window control in registry + * Add auto rate check window in registry + * + * 11 10 2010 eddie.chen + * [WCXRP00000156] [MT6620][FW] Change Auto rate window to 64 and add throughput swcr + * Use autorate parameter 1 as phy rate mask. + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 10 26 2010 eddie.chen + * [WCXRP00000134] [MT6620 Wi-Fi][Driver] Add a registry to enable auto rate for SQA test by using E1 EVB + * Add auto rate parameter in registry. + * + * 10 18 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to + * BSOD when entering RF test with AIS associated + * 1. remove redundant variables in STA_REC structure + * 2. add STA-REC uninitialization routine for clearing pending events + * + * 10 18 2010 cp.wu + * [WCXRP00000103] [MT6620 Wi-Fi][Driver] Driver crashed when using WZC to connect to AP#B with connection with AP#A + * reset ptrs when IEs are going to be dropped + * + * 10 12 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * add HT (802.11n) fixed rate support. + * + * 10 08 2010 cp.wu + * [WCXRP00000084] [MT6620 Wi-Fi][Driver][FW] Add fixed rate support for distance test + * adding fixed rate support for distance test. (from registry setting) + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * load manufacture data when CFG_SUPPORT_NVRAM is set to 1 + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by + * ENUM_NETWORK_TYPE_INDEX_T only remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test + * with AIS associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 26 2010 yuche.tsai + * NULL + * Fix someones coding error while enable WIFI_DIRECT. + * + * 08 25 2010 george.huang + * NULL + * update OID/ registry control path for PM related settings + * + * 08 24 2010 cm.chang + * NULL + * Support RLM initail channel of Ad-hoc, P2P and BOW + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 08 23 2010 chinghwa.yu + * NULL + * Update for BOW. + * + * 08 20 2010 yuche.tsai + * NULL + * Add state change indication. + * + * 08 16 2010 yuche.tsai + * NULL + * Add support for P2P BSS update info. + * + * 08 12 2010 cp.wu + * NULL + * [removing debugging] not to dump beacon content. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 04 2010 yarco.yang + * NULL + * Add TX_AMPDU and ADDBA_REJECT command + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 28 2010 cp.wu + * NULL + * 1) eliminate redundant variable eOPMode in prAdapter->rWlanInfo + * 2) change nicMediaStateChange() API prototype + * + * 07 28 2010 cp.wu + * NULL + * sync. CMD_BSS_INFO structure change to CMD-EVENT v0.15. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * FIX: structure of CMD_SET_BSS_INFO has been changed but no follow-ups are done. + * + * 07 22 2010 george.huang + * + * . + * + * 07 22 2010 george.huang + * + * Update fgIsQoS information in BSS INFO by CMD + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * update prStaRecOfAP with BSS-INFO. + * + * 07 06 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Update arguments for nicUpdateBeaconIETemplate() + * + * 07 06 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * STA-REC is maintained by CNM only. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) ignore RSN checking when RSN is not turned on. + * 2) set STA-REC deactivation callback as NULL + * 3) add variable initialization API based on PHY configuration + * + * 07 01 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Support sync command of STA_REC + * + * 06 30 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync. with CMD/EVENT document ver0.07. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * correct variable naming for 8-bit variable used in CMD_BEACON_TEMPLATE_UPDATE. + * + * 06 29 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) sync to. CMD/EVENT document v0.03 + * 2) simplify DTIM period parsing in scan.c only, bss.c no longer parses it again. + * 3) send command packet to indicate FW-PM after + * a) 1st beacon is received after AIS has connected to an AP + * b) IBSS-ALONE has been created + * c) IBSS-MERGE has occurred + * + * 06 25 2010 george.huang + * [WPD00001556]Basic power managemenet function + * Create beacon update path, with expose bssUpdateBeaconContent() + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill fgIsUapsdConnection when indicating BSS-CREATE with AIS-STA mode. + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00003827][MT6620 Wi-Fi] Chariot fail and following ping fail, no pkt send from driver + * correct nicProcessIST_impl() for interrupt status brought up by RX enhanced response + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX response + * + * 03 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always process TX interrupt first then RX interrupt. + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add checksum offloading support. +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-12-16 18:03:43 GMT mtk02752 +** handling enhanced response which fields are fetched at different moments +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-12-15 17:00:29 GMT mtk02752 +** if RX enhanced response is used, D2H interrupt status should be coming from buffered result as well +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-12-15 12:01:55 GMT mtk02752 +** if TX_DONE bit is not set but WTSR0/WTSR1 is non-zero, then set TX_DONE +** bit due to time latency of interrupt status enhanced response +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-12-10 16:52:52 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-24 20:51:01 GMT mtk02752 +** integrate with SD1 by invoking qmHandleMailboxRxMessage() +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-16 17:32:33 GMT mtk02752 +** prepare code for invoking rxHandleMailboxRxMessage() +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:08 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-09 22:56:41 GMT mtk01084 +** modify HW access routines +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:20 GMT mtk01084 +** prevent warning +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:54:57 GMT mtk01084 +** init HIF +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:30 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:12 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-09-09 17:26:15 GMT mtk01084 +** modify for CFG_TEST_WITH_MT5921 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-19 10:55:22 GMT mtk01461 +** Unmask the unused HISR +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-18 15:59:13 GMT mtk01084 +** remove debug purpose code +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 14:05:02 GMT mtk01084 +** update for WIFI ownback part on initial +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-04 21:32:57 GMT mtk01084 +** add temporarily code to set driver own on adapter initialization +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:35:41 GMT mtk01461 +** Add init of TX aggregation and fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-24 21:12:10 GMT mtk01104 +** Add function nicRestoreSpiDefMode() +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-21 09:43:31 GMT mtk01461 +** Revise for MTK coding style - nicInitializeAdapter() +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-17 19:52:47 GMT mtk01461 +** Update allocate Adapter Memory for MGMT Memory pool +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:57:08 GMT mtk01461 +** Refine the order of release memory from pucRxCoalescingBufCached +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-19 18:32:57 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:00:14 GMT mtk01426 +** Add CFG_SDIO_RX_ENHANCE support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:27 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:25:59 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const UINT_8 aucPhyCfg2PhyTypeSet[PHY_CONFIG_NUM] = { + PHY_TYPE_SET_802_11ABG, /* PHY_CONFIG_802_11ABG */ + PHY_TYPE_SET_802_11BG, /* PHY_CONFIG_802_11BG */ + PHY_TYPE_SET_802_11G, /* PHY_CONFIG_802_11G */ + PHY_TYPE_SET_802_11A, /* PHY_CONFIG_802_11A */ + PHY_TYPE_SET_802_11B, /* PHY_CONFIG_802_11B */ + PHY_TYPE_SET_802_11ABGN, /* PHY_CONFIG_802_11ABGN */ + PHY_TYPE_SET_802_11BGN, /* PHY_CONFIG_802_11BGN */ + PHY_TYPE_SET_802_11AN, /* PHY_CONFIG_802_11AN */ + PHY_TYPE_SET_802_11GN /* PHY_CONFIG_802_11GN */ +}; + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) +#define REQ_GATING_ENABLE_H2D_INT BIT(31) +#define REQ_GATING_DISABLE_H2D_INT BIT(30) +#define ACK_GATING_ENABLE_D2H_INT BIT(31) +#define ACK_GATING_DISABLE_D2H_INT BIT(30) + +#define GATING_CONTROL_POLL_LIMIT 64 +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +static INT_EVENT_MAP_T arIntEventMapTable[] = { + {WHISR_ABNORMAL_INT, INT_EVENT_ABNORMAL}, + {WHISR_D2H_SW_INT, INT_EVENT_SW_INT}, + {WHISR_TX_DONE_INT, INT_EVENT_TX}, + {(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT), INT_EVENT_RX} +}; + +static const UINT_8 ucIntEventMapSize = (sizeof(arIntEventMapTable) / sizeof(INT_EVENT_MAP_T)); + +static IST_EVENT_FUNCTION apfnEventFuncTable[] = { + nicProcessAbnormalInterrupt, /*!< INT_EVENT_ABNORMAL */ + nicProcessSoftwareInterrupt, /*!< INT_EVENT_SW_INT */ + nicProcessTxInterrupt, /*!< INT_EVENT_TX */ + nicProcessRxInterrupt, /*!< INT_EVENT_RX */ +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*! This macro is used to reduce coding errors inside nicAllocateAdapterMemory() + * and also enhance the readability. + */ +#define LOCAL_NIC_ALLOCATE_MEMORY(pucMem, u4Size, eMemType, pucComment) \ + { \ + DBGLOG(NIC, INFO, "Allocating %u bytes for %s.\n", u4Size, pucComment); \ + pucMem = (PUINT_8)kalMemAlloc(u4Size, eMemType); \ + if (pucMem == (PUINT_8)NULL) { \ + DBGLOG(NIC, ERROR, "Could not allocate %u bytes for %s.\n", u4Size, pucComment); \ + break; \ + } \ + ASSERT(((ULONG)pucMem % 4) == 0); \ + DBGLOG(NIC, TRACE, "Virtual Address = %p for %s.\n", pucMem, pucComment); \ + } + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter) +{ + dumpMemory32((PUINT_32)prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); +} + +VOID HifRegDump(P_ADAPTER_T prAdapter) +{ + UINT_32 i; + UINT_32 RegVal = 0; + + for (i = 0; i <= 0x58; i += 4) { + if ((i != MCR_WTDR0) && (i != MCR_WTDR1) && (i != MCR_WRDR0) && + (i != MCR_WRDR1) && (i != MCR_WSDIOCSR) && (i != MCR_WRPLR)) { + HAL_MCR_RD(prAdapter, i, &RegVal); + DBGLOG(NIC, WARN, "HIF Reg 0x%x = 0x%x\n", i, RegVal); + } + } + DBGLOG(NIC, WARN, "\n\n"); +} + +BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter) +{ + return prAdapter->fgIsFwOwn; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is responsible for the allocation of the data structures +* inside the Adapter structure, include: +* 1. SW_RFB_Ts +* 2. Common coalescing buffer for TX PATH. +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @retval WLAN_STATUS_SUCCESS - Has enough memory. +* @retval WLAN_STATUS_RESOURCES - Memory is not enough. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS status = WLAN_STATUS_RESOURCES; + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + DEBUGFUNC("nicAllocateAdapterMemory"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + prTxCtrl = &prAdapter->rTxCtrl; + + do { + /* 4 <0> Reset all Memory Handler */ +#if CFG_DBG_MGT_BUF + prAdapter->u4MemFreeDynamicCount = 0; + prAdapter->u4MemAllocDynamicCount = 0; +#endif + prAdapter->pucMgtBufCached = (PUINT_8) NULL; + prRxCtrl->pucRxCached = (PUINT_8) NULL; + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; + + /* 4 <1> Memory for Management Memory Pool and CMD_INFO_T */ + /* Allocate memory for the CMD_INFO_T and its MGMT memory pool. */ + prAdapter->u4MgtBufCachedSize = MGT_BUFFER_SIZE; + + LOCAL_NIC_ALLOCATE_MEMORY(prAdapter->pucMgtBufCached, + prAdapter->u4MgtBufCachedSize, VIR_MEM_TYPE, "COMMON MGMT MEMORY POOL"); + + /* 4 <2> Memory for RX Descriptor */ + /* Initialize the number of rx buffers we will have in our queue. */ + /* We may setup ucRxPacketDescriptors by GLUE Layer, and using + * this variable directly. + */ + /* Allocate memory for the SW receive structures. */ + prRxCtrl->u4RxCachedSize = CFG_RX_MAX_PKT_NUM * ALIGN_4(sizeof(SW_RFB_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize, VIR_MEM_TYPE, "SW_RFB_T"); + + /* 4 <3> Memory for TX DEscriptor */ + prTxCtrl->u4TxCachedSize = CFG_TX_MAX_PKT_NUM * ALIGN_4(sizeof(MSDU_INFO_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prTxCtrl->pucTxCached, prTxCtrl->u4TxCachedSize, VIR_MEM_TYPE, "MSDU_INFO_T"); + + /* 4 <4> Memory for Common Coalescing Buffer */ +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; + + /* Allocate memory for the common coalescing buffer. */ + prAdapter->u4CoalescingBufCachedSize = CFG_COALESCING_BUFFER_SIZE > CFG_RX_COALESCING_BUFFER_SIZE ? + CFG_COALESCING_BUFFER_SIZE : CFG_RX_COALESCING_BUFFER_SIZE; + + prAdapter->pucCoalescingBufCached = kalAllocateIOBuffer(prAdapter->u4CoalescingBufCachedSize); + + if (prAdapter->pucCoalescingBufCached == NULL) { + DBGLOG(NIC, ERROR, + "Could not allocate %u bytes for coalescing buffer.\n", + prAdapter->u4CoalescingBufCachedSize); + break; + } +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + /* 4 <5> Memory for enhanced interrupt response */ + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) + kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + if (prAdapter->prSDIOCtrl == NULL) { + DBGLOG(NIC, ERROR, + "Could not allocate %zu bytes for interrupt response.\n", + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + break; + } + + status = WLAN_STATUS_SUCCESS; + + } while (FALSE); + + if (status != WLAN_STATUS_SUCCESS) + nicReleaseAdapterMemory(prAdapter); + + return status; + +} /* end of nicAllocateAdapterMemory() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is responsible for releasing the allocated memory by +* nicAllocatedAdapterMemory(). +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + /* 4 <5> Memory for enhanced interrupt response */ + if (prAdapter->prSDIOCtrl) { + kalReleaseIOBuffer((PVOID) prAdapter->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; + } + /* 4 <4> Memory for Common Coalescing Buffer */ +#if CFG_COALESCING_BUFFER_SIZE || CFG_SDIO_RX_AGG + if (prAdapter->pucCoalescingBufCached) { + kalReleaseIOBuffer((PVOID) prAdapter->pucCoalescingBufCached, prAdapter->u4CoalescingBufCachedSize); + prAdapter->pucCoalescingBufCached = (PUINT_8) NULL; + } +#endif /* CFG_COALESCING_BUFFER_SIZE */ + + /* 4 <3> Memory for TX Descriptor */ + if (prTxCtrl->pucTxCached) { + kalMemFree((PVOID) prTxCtrl->pucTxCached, VIR_MEM_TYPE, prTxCtrl->u4TxCachedSize); + prTxCtrl->pucTxCached = (PUINT_8) NULL; + } + /* 4 <2> Memory for RX Descriptor */ + if (prRxCtrl->pucRxCached) { + kalMemFree((PVOID) prRxCtrl->pucRxCached, VIR_MEM_TYPE, prRxCtrl->u4RxCachedSize); + prRxCtrl->pucRxCached = (PUINT_8) NULL; + } + /* 4 <1> Memory for Management Memory Pool */ + if (prAdapter->pucMgtBufCached) { + kalMemFree((PVOID) prAdapter->pucMgtBufCached, VIR_MEM_TYPE, prAdapter->u4MgtBufCachedSize); + prAdapter->pucMgtBufCached = (PUINT_8) NULL; + } +#if CFG_DBG_MGT_BUF + /* Check if all allocated memories are free */ + ASSERT(prAdapter->u4MemFreeDynamicCount == prAdapter->u4MemAllocDynamicCount); +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief disable global interrupt +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicDisableInterrupt(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + prAdapter->fgIsIntEnable = FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief enable global interrupt +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicEnableInterrupt(IN P_ADAPTER_T prAdapter) +{ + BOOLEAN fgIsIntEnableCache; + + ASSERT(prAdapter); + fgIsIntEnableCache = prAdapter->fgIsIntEnable; + + prAdapter->fgIsIntEnable = TRUE; /* NOTE(Kevin): It must be placed before MCR GINT write. */ + + /* If need enable INT and also set LPOwn at the same time. */ + if (prAdapter->fgIsIntEnableWithLPOwnSet) { + prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; /* NOTE(Kevin): It's better to place it + * before MCR GINT write. + */ + /* If INT was enabled, only set LPOwn */ + if (fgIsIntEnableCache) { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); + prAdapter->fgIsFwOwn = TRUE; + } + /* If INT was not enabled, enable it and also set LPOwn now */ + else { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET | WHLPCR_INT_EN_SET); + prAdapter->fgIsFwOwn = TRUE; + } + } + /* If INT was not enabled, enable it now */ + else if (!fgIsIntEnableCache) + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); + +} /* end of nicEnableInterrupt() */ + +#if CFG_SDIO_INTR_ENHANCE +/*----------------------------------------------------------------------------*/ +/*! +* @brief For SDIO enhance mode, set the max rx len and tx status +* +* @param prAdapter a pointer to adapter private data structure. +* +* @return - none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicSDIOInit(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4Value = 0; + + ASSERT(prAdapter); + + /* 4 <1> Check STATUS Buffer is DW alignment. */ + ASSERT(IS_ALIGN_4((ULONG)&prAdapter->prSDIOCtrl->u4WHISR)); + + /* 4 <2> Setup STATUS count. */ + { + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); + + /* 4 <2.1> Setup the number of maximum RX length to be report */ + u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); + u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); + + /* 4 <2.2> Setup RX enhancement mode */ +#if CFG_SDIO_RX_ENHANCE + u4Value |= WHCR_RX_ENHANCE_MODE_EN; +#else + u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; +#endif /* CFG_SDIO_RX_AGG */ + + HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); + } + + return; + +} /* end of nicSDIOInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read interrupt status from hardware +* +* @param prAdapter pointer to the Adapter handler +* @param the interrupts +* +* @return N/A +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicSDIOReadIntStatus(IN P_ADAPTER_T prAdapter, OUT PUINT_32 pu4IntStatus) +{ + P_SDIO_CTRL_T prSDIOCtrl; + + DEBUGFUNC("nicSDIOReadIntStatus"); + + ASSERT(prAdapter); + ASSERT(pu4IntStatus); + + /* + prSDIOCtrl is from IO buffer. + prAdapter->prSDIOCtrl = (P_SDIO_CTRL_T) + kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + */ + prSDIOCtrl = prAdapter->prSDIOCtrl; + ASSERT(prSDIOCtrl); + + HAL_PORT_RD(prAdapter, + MCR_WHISR, + sizeof(ENHANCE_MODE_DATA_STRUCT_T), (PUINT_8) prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + *pu4IntStatus = 0; + return; + } + + /* workaround */ + if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && + (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { + prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; + } + + if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && + HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && + (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { + prSDIOCtrl->u4WHISR |= BIT(31); + } + + *pu4IntStatus = prSDIOCtrl->u4WHISR; + +} /* end of nicSDIOReadIntStatus() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function used to read interrupt status and then invoking +* dispatching procedure for the appropriate functions +* corresponding to specific interrupt bits +* +* @param prAdapter pointer to the Adapter handler +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 u4IntStatus = 0; + UINT_32 i; + + DEBUGFUNC("nicProcessIST"); + /* DBGLOG(NIC, LOUD, ("\n")); */ + + ASSERT(prAdapter); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, "Fail in set nicProcessIST! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == TRUE) + nicDisableClockGating(prAdapter); +#endif + + for (i = 0; i < CFG_IST_LOOP_COUNT; i++) { /* CFG_IST_LOOP_COUNT = 1 */ + +#if CFG_SDIO_INTR_ENHANCE + nicSDIOReadIntStatus(prAdapter, &u4IntStatus); +#else + HAL_MCR_RD(prAdapter, MCR_WHISR, &u4IntStatus); +#endif /* CFG_SDIO_INTR_ENHANCE */ + +/* DBGLOG(NIC, TRACE, ("u4IntStatus: 0x%x\n", u4IntStatus)); */ + + if (u4IntStatus & ~(WHIER_DEFAULT | WHIER_FW_OWN_BACK_INT_EN)) { + DBGLOG(INTR, WARN, "Un-handled HISR %#x, HISR = %#x (HIER:0x%x)\n", + (UINT_32) (u4IntStatus & ~WHIER_DEFAULT), u4IntStatus, + (UINT_32) WHIER_DEFAULT); + u4IntStatus &= WHIER_DEFAULT; + } + + nicProcessIST_impl(prAdapter, u4IntStatus); + + if (u4IntStatus == 0) { + if (i == 0) + u4Status = WLAN_STATUS_NOT_INDICATING; + break; + } + } + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + if (prAdapter->fgIsClockGatingEnabled == FALSE) + nicEnableClockGating(prAdapter); +#endif + + return u4Status; +} /* end of nicProcessIST() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief The function used to dispatch the appropriate functions for specific +* interrupt bits +* +* @param prAdapter pointer to the Adapter handler +* u4IntStatus interrupt status bits +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_ADAPTER_NOT_READY +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN UINT_32 u4IntStatus) +{ + UINT_32 u4IntCount = 0; + P_INT_EVENT_MAP_T prIntEventMap = NULL; + + ASSERT(prAdapter); + + prAdapter->u4IntStatus = u4IntStatus; + + /* Process each of the interrupt status consequently */ + prIntEventMap = &arIntEventMapTable[0]; + for (u4IntCount = 0; u4IntCount < ucIntEventMapSize; prIntEventMap++, u4IntCount++) { + if (prIntEventMap->u4Int & prAdapter->u4IntStatus) { + if (prIntEventMap->u4Event == INT_EVENT_RX && prAdapter->fgIsEnterD3ReqIssued == TRUE) { + /* ignore */ + } else if (apfnEventFuncTable[prIntEventMap->u4Event] != NULL) { + apfnEventFuncTable[prIntEventMap->u4Event] (prAdapter); + } else { + DBGLOG(INTR, WARN, + "Empty INTR handler! ISAR bit#: %u, event:%u, func: %p\n", + prIntEventMap->u4Int, prIntEventMap->u4Event, + apfnEventFuncTable[prIntEventMap->u4Event]); + + ASSERT(0); /* to trap any NULL interrupt handler */ + } + prAdapter->u4IntStatus &= ~prIntEventMap->u4Int; + } + } + + return WLAN_STATUS_SUCCESS; +} /* end of nicProcessIST_impl() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Verify the CHIP ID +* +* @param prAdapter a pointer to adapter private data structure. +* +* +* @retval TRUE CHIP ID is the same as the setting compiled +* @retval FALSE CHIP ID is different from the setting compiled +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN nicVerifyChipID(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4CIR = 0; + + ASSERT(prAdapter); + + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR); + + DBGLOG(NIC, TRACE, "Chip ID: 0x%x\n", (UINT_32) (u4CIR & WCIR_CHIP_ID)); + DBGLOG(NIC, TRACE, "Revision ID: 0x%x\n", (UINT_32) ((u4CIR & WCIR_REVISION_ID) >> 16)); + +#if 0 + if (((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_72) && ((u4CIR & WCIR_CHIP_ID) != MTK_CHIP_REV_82)) + return FALSE; +#endif + + prAdapter->ucRevID = (UINT_8) (((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the MCR to the appropriate init value, and verify the init +* value +* +* @param prAdapter a pointer to adapter private data structure. +* +* @return - +*/ +/*----------------------------------------------------------------------------*/ +VOID nicMCRInit(IN P_ADAPTER_T prAdapter) +{ + + ASSERT(prAdapter); + + /* 4 <0> Initial value */ +} + +VOID nicHifInit(IN P_ADAPTER_T prAdapter) +{ + + ASSERT(prAdapter); +#if 0 + /* reset event */ + nicPutMailbox(prAdapter, 0, 0x52455345); /* RESE */ + nicPutMailbox(prAdapter, 1, 0x545F5746); /* T_WF */ + nicSetSwIntr(prAdapter, BIT(16)); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the Adapter soft variable +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; + + do { + if (!nicVerifyChipID(prAdapter)) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + /* 4 <1> MCR init */ + nicMCRInit(prAdapter); + +#if CFG_SDIO_INTR_ENHANCE + nicSDIOInit(prAdapter); +#endif /* CFG_SDIO_INTR_ENHANCE */ + + HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); + + /* 4 <2> init FW HIF */ + nicHifInit(prAdapter); + } while (FALSE); + + return u4Status; +} + +#if defined(_HIF_SPI) +/*----------------------------------------------------------------------------*/ +/*! +* \brief Restore the SPI Mode Select to default mode, +* this is important while driver is unload, and this must be last mcr +* since the operation will let the hif use 8bit mode access +* +* \param[in] prAdapter a pointer to adapter private data structure. +* \param[in] eGPIO2_Mode GPIO2 operation mode +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +void nicRestoreSpiDefMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + HAL_MCR_WR(prAdapter, MCR_WCSR, SPICSR_8BIT_MODE_DATA); + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process rx interrupt. When the rx +* Interrupt is asserted, it means there are frames in queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4Value = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = prAdapter->prGlueInfo; + prGlueInfo->IsrAbnormalCnt++; + HAL_MCR_RD(prAdapter, MCR_WASR, &u4Value); + DBGLOG(REQ, WARN, "MCR_WASR: 0x%x\n", u4Value); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief . +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicProcessFwOwnBackInterrupt(IN P_ADAPTER_T prAdapter) +{ + +} /* end of nicProcessFwOwnBackInterrupt() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief . +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4IntrBits; + + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); + + prGlueInfo->IsrSoftWareCnt++; + + if ((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { + nicPrintFirmwareAssertInfo(prAdapter); +#if CFG_CHIP_RESET_SUPPORT + glSendResetRequest(); +#endif + } +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) + ASSERT((u4IntrBits & (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)) + != (ACK_GATING_ENABLE_D2H_INT | ACK_GATING_DISABLE_D2H_INT)); + + if (u4IntrBits & ACK_GATING_ENABLE_D2H_INT) + prAdapter->fgIsClockGatingEnabled = TRUE; + + if (u4IntrBits & ACK_GATING_DISABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = FALSE; + + /* Indicate Service Thread for TX */ + if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) + kalSetEvent(prAdapter->prGlueInfo); + } +#endif + + DBGLOG(REQ, WARN, "u4IntrBits: 0x%x\n", u4IntrBits); +} /* end of nicProcessSoftwareInterrupt() */ + +VOID nicPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data) +{ + if (u4MailboxNum == 0) { + /* HAL_MCR_WR */ + HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); + } else if (u4MailboxNum == 1) { + /* HAL_MCR_WR */ + HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); + } else { + ASSERT(0); + } +} + +VOID nicGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data) +{ + if (u4MailboxNum == 0) { + /* HAL_MCR_RD */ + HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); + } else if (u4MailboxNum == 1) { + /* HAL_MCR_RD */ + HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); + } else { + ASSERT(0); + } +} + +VOID nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4SwIntrBitmap) +{ + /* NOTE: + * SW interrupt in HW bit 16 is mapping to SW bit 0 (shift 16bit in HW transparancy) + * SW interrupt valid from b0~b15 + */ + ASSERT((u4SwIntrBitmap & BITS(0, 15)) == 0); +/* DBGLOG(NIC, TRACE, ("u4SwIntrBitmap: 0x%08x\n", u4SwIntrBitmap)); */ + + HAL_MCR_WR(prAdapter, MCR_WSICR, u4SwIntrBitmap); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to dequeue from prAdapter->rPendingCmdQueue +* with specified sequential number +* +* @param prAdapter Pointer of ADAPTER_T +* ucSeqNum Sequential Number +* +* @retval - P_CMD_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->ucCmdSeqNum == ucSeqNum) + break; + + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + + prCmdInfo = NULL; + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + return prCmdInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to dequeue from prAdapter->rTxCtrl.rTxMgmtTxingQueue +* with specified sequential number +* +* @param prAdapter Pointer of ADAPTER_T +* ucSeqNum Sequential Number +* +* @retval - P_MSDU_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, IN UINT_8 ucSeqNum) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; + + if (prMsduInfo->ucTxSeqNum == ucSeqNum) + break; + + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + return prMsduInfo; +} + +P_MSDU_INFO_T nicGetPendingStaMMPDU(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx) +{ + P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; + P_QUE_T prTxingQue = (P_QUE_T) NULL; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; + GLUE_SPIN_LOCK_DECLARATION(); + + if (prAdapter == NULL) { + ASSERT(FALSE); + return NULL; + } + + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + do { + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; + + if ((prMsduInfo->ucStaRecIndex == ucStaRecIdx) && (prMsduInfo->pfTxDoneHandler != NULL)) { + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfo, prMsduInfoListHead); + prMsduInfoListHead = prMsduInfo; + } else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + + } while (FALSE); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + return prMsduInfoListHead; +} /* nicGetPendingStaMMPDU */ + +VOID nicFreePendingTxMsduInfoByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T) NULL; + P_MSDU_INFO_T prMsduInfoListTail = (P_MSDU_INFO_T) NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; + + if ((ENUM_NETWORK_TYPE_INDEX_T) (prMsduInfo->ucNetworkType) == eNetworkType) { + if (prMsduInfoListHead == NULL) { + prMsduInfoListHead = prMsduInfoListTail = prMsduInfo; + } else { + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, prMsduInfo); + prMsduInfoListTail = prMsduInfo; + } + } else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + /* free */ + if (prMsduInfoListHead) + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + + return; + +} /* end of nicFreePendingTxMsduInfoByNetwork() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to retrieve a CMD sequence number atomically +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval - UINT_8 +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + prAdapter->ucCmdSeqNum++; + ucRetval = prAdapter->ucCmdSeqNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + return ucRetval; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This procedure is used to retrieve a TX sequence number atomically +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval - UINT_8 +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + prAdapter->ucTxSeqNum++; + ucRetval = prAdapter->ucTxSeqNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + return ucRetval; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to handle +* media state change event +* +* @param +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicMediaStateChange(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, IN P_EVENT_CONNECTION_STATUS prConnectionStatus) +{ + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + switch (eNetworkType) { + case NETWORK_TYPE_AIS_INDEX: + if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { /* disconnected */ + if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + DBGLOG(NIC, TRACE, "DisByMC\n"); + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + + /* reset buffered link quality information */ + prAdapter->fgIsLinkQualityValid = FALSE; + prAdapter->fgIsLinkRateValid = FALSE; + } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { /* connected */ + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + + /* fill information for association result */ + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prConnectionStatus->aucBssid, MAC_ADDR_LEN); + prAdapter->rWlanInfo.rCurrBssId.u4Privacy + = prConnectionStatus->ucEncryptStatus; /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse + = PARAM_NETWORK_TYPE_AUTOMODE; /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod + = prConnectionStatus->u2BeaconPeriod; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow = prConnectionStatus->u2ATIMWindow; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig = prConnectionStatus->u4FreqInKHz; + prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; + prAdapter->rWlanInfo.rCurrBssId.eOpMode + = (ENUM_PARAM_OP_MODE_T) prConnectionStatus->ucInfraMode; + + /* always indicate to OS according to MSDN (re-association/roaming) */ + if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); + } else { + /* connected -> connected : roaming ? */ + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_ROAM_OUT_FIND_BEST, NULL, 0); + } + } + break; + +#if CFG_ENABLE_BT_OVER_WIFI + case NETWORK_TYPE_BOW_INDEX: + break; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + case NETWORK_TYPE_P2P_INDEX: + break; +#endif + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} /* nicMediaStateChange */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to convert between +* frequency and channel number +* +* @param u4ChannelNum +* +* @retval - Frequency in unit of KHz, 0 for invalid channel number +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 nicChannelNum2Freq(UINT_32 u4ChannelNum) +{ + UINT_32 u4ChannelInMHz; + + if (u4ChannelNum >= 1 && u4ChannelNum <= 13) + u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; + else if (u4ChannelNum == 14) + u4ChannelInMHz = 2484; + else if (u4ChannelNum == 133) + u4ChannelInMHz = 3665; /* 802.11y */ + else if (u4ChannelNum == 137) + u4ChannelInMHz = 3685; /* 802.11y */ + else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) + u4ChannelInMHz = 5000 + u4ChannelNum * 5; + else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) + u4ChannelInMHz = 4000 + u4ChannelNum * 5; + else + u4ChannelInMHz = 0; + + return 1000 * u4ChannelInMHz; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to convert between +* frequency and channel number +* +* @param u4FreqInKHz +* +* @retval - Frequency Number, 0 for invalid freqency +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 nicFreq2ChannelNum(UINT_32 u4FreqInKHz) +{ + switch (u4FreqInKHz) { + case 2412000: + return 1; + case 2417000: + return 2; + case 2422000: + return 3; + case 2427000: + return 4; + case 2432000: + return 5; + case 2437000: + return 6; + case 2442000: + return 7; + case 2447000: + return 8; + case 2452000: + return 9; + case 2457000: + return 10; + case 2462000: + return 11; + case 2467000: + return 12; + case 2472000: + return 13; + case 2484000: + return 14; + case 3665000: + return 133; /* 802.11y */ + case 3685000: + return 137; /* 802.11y */ + case 4915000: + return 183; + case 4920000: + return 184; + case 4925000: + return 185; + case 4930000: + return 186; + case 4935000: + return 187; + case 4940000: + return 188; + case 4945000: + return 189; + case 4960000: + return 192; + case 4980000: + return 196; + case 5170000: + return 34; + case 5180000: + return 36; + case 5190000: + return 38; + case 5200000: + return 40; + case 5210000: + return 42; + case 5220000: + return 44; + case 5230000: + return 46; + case 5240000: + return 48; + case 5250000: + return 50; + case 5260000: + return 52; + case 5270000: + return 54; + case 5280000: + return 56; + case 5290000: + return 58; + case 5300000: + return 60; + case 5320000: + return 64; + case 5500000: + return 100; + case 5520000: + return 104; + case 5540000: + return 108; + case 5560000: + return 112; + case 5580000: + return 116; + case 5600000: + return 120; + case 5620000: + return 124; + case 5640000: + return 128; + case 5660000: + return 132; + case 5680000: + return 136; + case 5700000: + return 140; + case 5745000: + return 149; + case 5765000: + return 153; + case 5785000: + return 157; + case 5805000: + return 161; + case 5825000: + return 165; + case 5845000: + return 169; + case 5865000: + return 173; + default: + return 0; + } +} + +/* firmware command wrapper */ +/* NETWORK (WIFISYS) */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to activate WIFISYS for specified network +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of network type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + rCmdActivateCtrl.ucActive = 1; + + if (((UINT_8) eNetworkTypeIdx) < NETWORK_TYPE_INDEX_NUM) { + prBssInfo = &prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]; + prBssInfo->fg40mBwAllowed = FALSE; + prBssInfo->fgAssoc40mBwAllowed = FALSE; + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_BSS_ACTIVATE_CTRL, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to deactivate WIFISYS for specified network +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of network type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + WLAN_STATUS u4Status; + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdActivateCtrl.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + rCmdActivateCtrl.ucActive = 0; + + u4Status = wlanSendSetQueryCmd(prAdapter, + CMD_ID_BSS_ACTIVATE_CTRL, + TRUE, + FALSE, + FALSE, + NULL, + NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), (PUINT_8)&rCmdActivateCtrl, NULL, 0); + + /* free all correlated station records */ + cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); + qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); + nicFreePendingTxMsduInfoByNetwork(prAdapter, eNetworkTypeIdx); + kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); + + return u4Status; +} + +/* BSS-INFO */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to sync bss info with firmware +* when a new BSS has been connected or disconnected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO type +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + WLAN_STATUS u4Status; + P_BSS_INFO_T prBssInfo; + CMD_SET_BSS_INFO rCmdSetBssInfo; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + kalMemZero(&rCmdSetBssInfo, sizeof(CMD_SET_BSS_INFO)); + + rCmdSetBssInfo.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + rCmdSetBssInfo.ucConnectionState = (UINT_8) prBssInfo->eConnectionState; + rCmdSetBssInfo.ucCurrentOPMode = (UINT_8) prBssInfo->eCurrentOPMode; + rCmdSetBssInfo.ucSSIDLen = (UINT_8) prBssInfo->ucSSIDLen; + kalMemCopy(rCmdSetBssInfo.aucSSID, prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + COPY_MAC_ADDR(rCmdSetBssInfo.aucBSSID, prBssInfo->aucBSSID); + rCmdSetBssInfo.ucIsQBSS = (UINT_8) prBssInfo->fgIsQBSS; + rCmdSetBssInfo.ucNonHTBasicPhyType = prBssInfo->ucNonHTBasicPhyType; + rCmdSetBssInfo.u2OperationalRateSet = prBssInfo->u2OperationalRateSet; + rCmdSetBssInfo.u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + rCmdSetBssInfo.ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + rCmdSetBssInfo.fgHiddenSsidMode = prBssInfo->eHiddenSsidType; +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + COPY_MAC_ADDR(rCmdSetBssInfo.aucOwnMac, prBssInfo->aucOwnMacAddr); +#endif + + rlmFillSyncCmdParam(&rCmdSetBssInfo.rBssRlmParam, prBssInfo); + + rCmdSetBssInfo.fgWapiMode = (UINT_8) FALSE; + + if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + rCmdSetBssInfo.ucAuthMode = (UINT_8) prConnSettings->eAuthMode; + rCmdSetBssInfo.ucEncStatus = (UINT_8) prConnSettings->eEncStatus; + rCmdSetBssInfo.fgWapiMode = (UINT_8) prConnSettings->fgWapiMode; + } +#if CFG_ENABLE_BT_OVER_WIFI + else if (rCmdSetBssInfo.ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) { + /* P_CONNECTION_SETTINGS_T prConnSettings = &(prAdapter->rWifiVar.rConnSettings); */ + rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; + } +#endif + else { +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + if (kalP2PGetCipher(prAdapter->prGlueInfo)) { + rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; + } else { + rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_OPEN; + rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION_DISABLED; + } + /* Need the probe response to detect the PBC overlap */ + rCmdSetBssInfo.fgIsApMode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); + } +#else + rCmdSetBssInfo.ucAuthMode = (UINT_8) AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (UINT_8) ENUM_ENCRYPTION3_KEY_ABSENT; +#endif + } + + if (eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX && + prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && prBssInfo->prStaRecOfAP != NULL) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + + cnmAisInfraConnectNotify(prAdapter); + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && (prBssInfo->prStaRecOfAP != NULL)) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + else if (eNetworkTypeIdx == NETWORK_TYPE_BOW_INDEX && + prBssInfo->eCurrentOPMode == OP_MODE_BOW && prBssInfo->prStaRecOfAP != NULL) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#endif + else + rCmdSetBssInfo.ucStaRecIdxOfAP = STA_REC_INDEX_NOT_FOUND; + + u4Status = wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_BSS_INFO, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_SET_BSS_INFO), (PUINT_8)&rCmdSetBssInfo, NULL, 0); + + /* if BSS-INFO is going to be disconnected state, free all correlated station records */ + if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + /* clear client list */ + bssClearClientList(prAdapter, prBssInfo); + + /* free all correlated station records */ + cnmStaFreeAllStaByNetType(prAdapter, eNetworkTypeIdx, FALSE); + qmFreeAllByNetType(prAdapter, eNetworkTypeIdx); + kalClearSecurityFramesByNetType(prAdapter->prGlueInfo, eNetworkTypeIdx); +#if CFG_ENABLE_GTK_FRAME_FILTER + if (prBssInfo->prIpV4NetAddrList) + FREE_IPV4_NETWORK_ADDR_LIST(prBssInfo->prIpV4NetAddrList); +#endif + } + + return u4Status; +} + +/* BSS-INFO Indication (PM) */ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been created. (for AdHoc / P2P-GO) +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CREATED rCmdIndicatePmBssCreated; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + rCmdIndicatePmBssCreated.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + rCmdIndicatePmBssCreated.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssCreated.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssCreated.u2AtimWindow = prBssInfo->u2ATIMWindow; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_CREATED, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_CREATED), (PUINT_8)&rCmdIndicatePmBssCreated, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been connected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CONNECTED rCmdIndicatePmBssConnected; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + + rCmdIndicatePmBssConnected.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + rCmdIndicatePmBssConnected.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssConnected.u2AssocId = prBssInfo->u2AssocId; + rCmdIndicatePmBssConnected.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssConnected.u2AtimWindow = prBssInfo->u2ATIMWindow; + + rCmdIndicatePmBssConnected.ucBmpDeliveryAC = prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC; + rCmdIndicatePmBssConnected.ucBmpTriggerAC = prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC; + + /* DBGPRINTF("nicPmIndicateBssConnected: ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x", */ + /* rCmdIndicatePmBssConnected.ucBmpDeliveryAC, */ + /* rCmdIndicatePmBssConnected.ucBmpTriggerAC); */ + + if ((eNetworkTypeIdx == NETWORK_TYPE_AIS_INDEX) +#if CFG_ENABLE_WIFI_DIRECT + || ((eNetworkTypeIdx == NETWORK_TYPE_P2P_INDEX) && (prAdapter->fgIsP2PRegistered)) +#endif + ) { + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = + (UINT_8) prBssInfo->prStaRecOfAP->fgIsUapsdSupported; + } else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; /* @FIXME */ + } + } else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; + } + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_CONNECTED, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_CONNECTED), + (PUINT_8)&rCmdIndicatePmBssConnected, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate PM that +* a BSS has been disconnected +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + CMD_INDICATE_PM_BSS_ABORT rCmdIndicatePmBssAbort; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + rCmdIndicatePmBssAbort.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_INDICATE_PM_BSS_ABORT, + TRUE, + FALSE, + FALSE, + NULL, + NULL, + sizeof(CMD_INDICATE_PM_BSS_ABORT), (PUINT_8)&rCmdIndicatePmBssAbort, NULL, 0); +} + +WLAN_STATUS +nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, PARAM_POWER_MODE ePwrMode, BOOLEAN fgEnCmdEvent) +{ + DEBUGFUNC("nicConfigPowerSaveProfile"); + DBGLOG(NIC, TRACE, "eNetTypeIndex:%d, ePwrMode:%d, fgEnCmdEvent:%d\n", + eNetTypeIndex, ePwrMode, fgEnCmdEvent); + + ASSERT(prAdapter); + + if (eNetTypeIndex >= NETWORK_TYPE_INDEX_NUM) { + ASSERT(0); + return WLAN_STATUS_NOT_SUPPORTED; + } +/* prAdapter->rWlanInfo.ePowerSaveMode.ucNetTypeIndex = eNetTypeIndex; */ +/* prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile = (UINT_8)ePwrMode; */ + prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucNetTypeIndex = eNetTypeIndex; + prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex].ucPsProfile = (UINT_8) ePwrMode; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_POWER_SAVE_MODE, + TRUE, + FALSE, + (fgEnCmdEvent ? TRUE : FALSE), + (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), + (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), + sizeof(CMD_PS_PROFILE_T), + (PUINT_8)&(prAdapter->rWlanInfo.arPowerSaveMode[eNetTypeIndex]), + NULL, sizeof(PARAM_POWER_MODE) + ); + +} /* end of wlanoidSetAcpiDevicePowerStateMode() */ + +WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, BOOLEAN fgEnterCtia, BOOLEAN fgEnCmdEvent) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + CMD_ACCESS_REG rCmdAccessReg; + WLAN_STATUS rWlanStatus; + + DEBUGFUNC("nicEnterCtiaMode"); + DBGLOG(NIC, TRACE, "nicEnterCtiaMode: %d\n", fgEnterCtia); + + ASSERT(prAdapter); + + rWlanStatus = WLAN_STATUS_SUCCESS; + + if (fgEnterCtia) { + /* 1. Disable On-Lin Scan */ + prAdapter->fgEnOnlineScan = FALSE; + + /* 3. Disable FIFO FULL no ack */ + rCmdAccessReg.u4Address = 0x60140028; + rCmdAccessReg.u4Data = 0x904; + wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ + FALSE, /* TRUE, */ + FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); + + /* 4. Disable Roaming */ + rCmdSwCtrl.u4Id = 0x90000204; + rCmdSwCtrl.u4Data = 0x0; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + rCmdSwCtrl.u4Id = 0x90000200; + rCmdSwCtrl.u4Data = 0x820000; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + /* Disalbe auto tx power */ + rCmdSwCtrl.u4Id = 0xa0100003; + rCmdSwCtrl.u4Data = 0x0; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + /* 2. Keep at CAM mode */ + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 0; + prAdapter->fgEnCtiaPowerMode = TRUE; + + ePowerMode = Param_PowerModeCAM; + rWlanStatus = nicConfigPowerSaveProfile(prAdapter, + NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); + } + + /* 5. Disable Beacon Timeout Detection */ + prAdapter->fgDisBcnLostDetection = TRUE; + } else { + /* 1. Enaable On-Lin Scan */ + prAdapter->fgEnOnlineScan = TRUE; + + /* 3. Enable FIFO FULL no ack */ + rCmdAccessReg.u4Address = 0x60140028; + rCmdAccessReg.u4Data = 0x905; + wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, TRUE, /* FALSE, */ + FALSE, /* TRUE, */ + FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8)&rCmdAccessReg, NULL, 0); + + /* 4. Enable Roaming */ + rCmdSwCtrl.u4Id = 0x90000204; + rCmdSwCtrl.u4Data = 0x1; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + rCmdSwCtrl.u4Id = 0x90000200; + rCmdSwCtrl.u4Data = 0x820000; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + /* Enable auto tx power */ + /* */ + + rCmdSwCtrl.u4Id = 0xa0100003; + rCmdSwCtrl.u4Data = 0x1; + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SW_DBG_CTRL, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), (PUINT_8)&rCmdSwCtrl, NULL, 0); + + /* 2. Keep at Fast PS */ + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 2; + prAdapter->fgEnCtiaPowerMode = TRUE; + + ePowerMode = Param_PowerModeFast_PSP; + rWlanStatus = nicConfigPowerSaveProfile(prAdapter, + NETWORK_TYPE_AIS_INDEX, ePowerMode, fgEnCmdEvent); + } + + /* 5. Enable Beacon Timeout Detection */ + prAdapter->fgDisBcnLostDetection = FALSE; + + } + + return rWlanStatus; +} /* end of nicEnterCtiaMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to indicate firmware domain +* for beacon generation parameters +* +* @param prAdapter Pointer of ADAPTER_T +* eIeUpdMethod, Update Method +* eNetTypeIndex Index of Network +* u2Capability Capability +* aucIe Pointer to buffer of IEs +* u2IELen Length of IEs +* +* @retval - WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* WLAN_STATUS_PENDING +* WLAN_STATUS_INVALID_DATA +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex, + IN UINT_16 u2Capability, IN PUINT_8 aucIe, IN UINT_16 u2IELen) +{ + P_CMD_BEACON_TEMPLATE_UPDATE prCmdBcnUpdate; + UINT_16 u2CmdBufLen = 0; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + UINT_8 ucCmdSeqNum; + + DEBUGFUNC("wlanUpdateBeaconIETemplate"); + + DBGLOG(NIC, LOUD, "\nnicUpdateBeaconIETemplate\n"); + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + if (u2IELen > MAX_IE_LENGTH) + return WLAN_STATUS_INVALID_DATA; + + if (eIeUpdMethod == IE_UPD_METHOD_UPDATE_RANDOM || eIeUpdMethod == IE_UPD_METHOD_UPDATE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, aucIE) + u2IELen; + } else if (eIeUpdMethod == IE_UPD_METHOD_DELETE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, u2IELen); + } else { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + /* prepare command info */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u2CmdBufLen)); + if (!prCmdInfo) { + DBGLOG(NIC, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->eNetworkType = eNetTypeIndex; + prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + u2CmdBufLen); + prCmdInfo->pfCmdDoneHandler = NULL; /* @FIXME */ + prCmdInfo->pfCmdTimeoutHandler = NULL; /* @FIXME */ + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->ucCID = CMD_ID_UPDATE_BEACON_CONTENT; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + prCmdInfo->fgDriverDomainMCR = FALSE; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u2CmdBufLen; + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount_UserPriority = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdBcnUpdate = (P_CMD_BEACON_TEMPLATE_UPDATE) (prWifiCmd->aucBuffer); + + /* fill beacon updating command */ + prCmdBcnUpdate->ucUpdateMethod = (UINT_8) eIeUpdMethod; + prCmdBcnUpdate->ucNetTypeIndex = (UINT_8) eNetTypeIndex; + prCmdBcnUpdate->u2Capability = u2Capability; + prCmdBcnUpdate->u2IELen = u2IELen; + if (u2IELen > 0) + kalMemCopy(prCmdBcnUpdate->aucIE, aucIe, u2IELen); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to initialization PHY related +* varaibles +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prConnSettings->eDesiredPhyConfig >= PHY_CONFIG_NUM) { + ASSERT(0); + return; + } + + prAdapter->rWifiVar.ucAvailablePhyTypeSet = aucPhyCfg2PhyTypeSet[prConnSettings->eDesiredPhyConfig]; + + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_BIT_ERP) + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_ERP_INDEX; + /* NOTE(Kevin): Because we don't have N only mode, TBD */ + else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ + + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_HR_DSSS_INDEX; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* eNetworkTypeIdx Index of BSS-INFO +* +* @retval - +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + P_BSS_INFO_T prBssInfo; + CMD_UPDATE_WMM_PARMS_T rCmdUpdateWmmParms; + + ASSERT(prAdapter); + ASSERT(eNetworkTypeIdx < NETWORK_TYPE_INDEX_NUM); + + DBGLOG(QM, EVENT, "sizeof(AC_QUE_PARMS_T): %zu\n", sizeof(AC_QUE_PARMS_T)); + DBGLOG(QM, EVENT, "sizeof(CMD_UPDATE_WMM_PARMS): %zu\n", sizeof(CMD_UPDATE_WMM_PARMS_T)); + DBGLOG(QM, EVENT, "sizeof(WIFI_CMD_T): %zu\n", sizeof(WIFI_CMD_T)); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkTypeIdx]); + rCmdUpdateWmmParms.ucNetTypeIndex = (UINT_8) eNetworkTypeIdx; + kalMemCopy(&rCmdUpdateWmmParms.arACQueParms[0], &prBssInfo->arACQueParms[0], (sizeof(AC_QUE_PARMS_T) * AC_NUM)); + + rCmdUpdateWmmParms.fgIsQBSS = prBssInfo->fgIsQBSS; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_UPDATE_WMM_PARMS, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_UPDATE_WMM_PARMS_T), (PUINT_8)&rCmdUpdateWmmParms, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update TX power gain corresponding to +* each band/modulation combination +* +* @param prAdapter Pointer of ADAPTER_T +* prTxPwrParam Pointer of TX power parameters +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) +{ + DEBUGFUNC("nicUpdateTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_TX_PWR, + TRUE, + FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to set auto tx power parameter +* +* @param prAdapter Pointer of ADAPTER_T +* prTxPwrParam Pointer of Auto TX power parameters +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam) +{ + DEBUGFUNC("nicSetAutoTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_AUTOPWR_CTRL, + TRUE, + FALSE, + FALSE, + NULL, NULL, sizeof(CMD_AUTO_POWER_PARAM_T), (PUINT_8) prAutoPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update TX power gain corresponding to +* each band/modulation combination +* +* @param prAdapter Pointer of ADAPTER_T +* prTxPwrParam Pointer of TX power parameters +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicSetAutoTxPowerControl(IN P_ADAPTER_T prAdapter, IN P_CMD_TX_PWR_T prTxPwrParam) +{ + DEBUGFUNC("nicUpdateTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_TX_PWR, + TRUE, + FALSE, FALSE, NULL, NULL, sizeof(CMD_TX_PWR_T), (PUINT_8) prTxPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update power offset around 5GHz band +* +* @param prAdapter Pointer of ADAPTER_T +* pr5GPwrOffset Pointer of 5GHz power offset parameter +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset) +{ + DEBUGFUNC("nicUpdate5GOffset"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_5G_PWR_OFFSET, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_5G_PWR_OFFSET_T), (PUINT_8) pr5GPwrOffset, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update DPD calibration result +* +* @param prAdapter Pointer of ADAPTER_T +* pr5GPwrOffset Pointer of parameter for DPD calibration result +* +* @retval WLAN_STATUS_PENDING +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, IN P_CMD_PWR_PARAM_T prDpdCalResult) +{ + DEBUGFUNC("nicUpdateDPD"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_PWR_PARAM, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_PWR_PARAM_T), (PUINT_8) prDpdCalResult, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function starts system service such as timer and +* memory pools +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicInitSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* <1> Initialize MGMT Memory pool and STA_REC */ + cnmMemInit(prAdapter); + cnmStaRecInit(prAdapter); + cmdBufInitialize(prAdapter); + + /* <2> Mailbox Initialization */ + mboxInitialize(prAdapter); + + /* <3> Timer Initialization */ + cnmTimerInitialize(prAdapter); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function reset some specific system service, +* such as STA-REC +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicResetSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicUninitSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* Timer Destruction */ + cnmTimerDestroy(prAdapter); + + /* Mailbox Destruction */ + mboxDestroy(prAdapter); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) +{ + ASSERT(prAdapter); + + /* CNM Module - initialization */ + cnmInit(prAdapter); + + /* RLM Module - initialization */ + rlmFsmEventInit(prAdapter); + + /* SCN Module - initialization */ + scnInit(prAdapter); + + /* AIS Module - intiailization */ + aisInitializeConnectionSettings(prAdapter, prRegInfo); + aisFsmInit(prAdapter); + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - intiailization */ + roamingFsmInit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + +#if CFG_SUPPORT_SWCR + swCrDebugInit(prAdapter); +#endif /* CFG_SUPPORT_SWCR */ + +#if (CFG_SUPPORT_TDLS == 1) + TdlsexInit(prAdapter); +#endif /* CFG_SUPPORT_TDLS */ + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to update WMM Parms +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicUninitMGMT(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + +#if CFG_SUPPORT_SWCR + swCrDebugUninit(prAdapter); +#endif /* CFG_SUPPORT_SWCR */ + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - unintiailization */ + roamingFsmUninit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + /* AIS Module - unintiailization */ + aisFsmUninit(prAdapter); + + /* SCN Module - unintiailization */ + scnUninit(prAdapter); + + /* RLM Module - uninitialization */ + rlmFsmEventUninit(prAdapter); + + /* CNM Module - uninitialization */ + cnmUninit(prAdapter); + +#if (CFG_SUPPORT_TDLS == 1) + TdlsexUninit(prAdapter); +#endif /* CFG_SUPPORT_TDLS */ + +} + +#if (MT6620_E1_ASIC_HIFSYS_WORKAROUND == 1) +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is to inform firmware to enable MCU clock gating +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicEnableClockGating(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i, u4WHISR = 0; + + ASSERT(prAdapter); + + if (prAdapter->fgIsClockGatingEnabled == TRUE) + return WLAN_STATUS_SUCCESS; + + nicSetSwIntr(prAdapter, REQ_GATING_ENABLE_H2D_INT); + + i = 0; + while (i < GATING_CONTROL_POLL_LIMIT) { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) + return WLAN_STATUS_FAILURE; + + HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); + + if (u4WHISR & ACK_GATING_ENABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = TRUE; + return WLAN_STATUS_SUCCESS; + } + } + + ASSERT(0); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is to inform firmware to disable MCU clock gating +* +* @param prAdapter Pointer of ADAPTER_T +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicDisableClockGating(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i, u4WHISR = 0; + + ASSERT(prAdapter); + + if (prAdapter->fgIsClockGatingEnabled == FALSE) + return WLAN_STATUS_SUCCESS; + + nicSetSwIntr(prAdapter, REQ_GATING_DISABLE_H2D_INT); + + i = 0; + while (i < GATING_CONTROL_POLL_LIMIT) { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) + return WLAN_STATUS_FAILURE; + + HAL_READ_INTR_STATUS(prAdapter, sizeof(UINT_32), (PUINT_8)&u4WHISR); + + if (u4WHISR & ACK_GATING_DISABLE_D2H_INT) { + prAdapter->fgIsClockGatingEnabled = FALSE; + return WLAN_STATUS_SUCCESS; + } + } + + ASSERT(0); + return WLAN_STATUS_PENDING; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked to buffer scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param rMacAddr BSSID +* @param prSsid Pointer to SSID +* @param u4Privacy Privacy settings (0: Open / 1: WEP/WPA/WPA2 enabled) +* @param rRssi Received Strength (-10 ~ -200 dBm) +* @param eNetworkType Network Type (a/b/g) +* @param prConfiguration Network Parameter +* @param eOpMode Infra/Ad-Hoc +* @param rSupportedRates Supported basic rates +* @param u2IELength IE Length +* @param pucIEBuf Pointer to Information Elements(IEs) +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicAddScanResult(IN P_ADAPTER_T prAdapter, + IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, + IN UINT_32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, IN UINT_16 u2IELength, IN PUINT_8 pucIEBuf) +{ + BOOLEAN bReplace; + UINT_32 i; + UINT_32 u4IdxWeakest = 0; + PARAM_RSSI rWeakestRssi; + UINT_32 u4BufferSize; + + ASSERT(prAdapter); + + rWeakestRssi = (PARAM_RSSI) INT_MAX; + u4BufferSize = sizeof(prAdapter->rWlanInfo.aucScanIEBuf) / sizeof(prAdapter->rWlanInfo.aucScanIEBuf[0]); + + bReplace = FALSE; + + /* decide to replace or add */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + /* find weakest entry && not connected one */ + if (UNEQUAL_MAC_ADDR + (prAdapter->rWlanInfo.arScanResult[i].arMacAddress, prAdapter->rWlanInfo.rCurrBssId.arMacAddress) + && prAdapter->rWlanInfo.arScanResult[i].rRssi < rWeakestRssi) { + u4IdxWeakest = i; + rWeakestRssi = prAdapter->rWlanInfo.arScanResult[i].rRssi; + } + + if (prAdapter->rWlanInfo.arScanResult[i].eOpMode == eOpMode && + EQUAL_MAC_ADDR(&(prAdapter->rWlanInfo.arScanResult[i].arMacAddress), rMacAddr) && + (EQUAL_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen) + || prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen == 0)) { + /* replace entry */ + bReplace = TRUE; + + /* free IE buffer then zero */ + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; + + /* IE - allocate buffer and update pointer */ + if (u2IELength > 0) { + if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(& + (prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + break; + } + } + + if (bReplace == FALSE) { + if (prAdapter->rWlanInfo.u4ScanResultNum < (CFG_MAX_NUM_BSS_LIST - 1)) { + i = prAdapter->rWlanInfo.u4ScanResultNum; + + /* zero */ + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; + + /* IE - allocate buffer and update pointer */ + if (u2IELength > 0) { + if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(& + (prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + prAdapter->rWlanInfo.u4ScanResultNum++; + } else if (rWeakestRssi != (PARAM_RSSI) INT_MAX) { + /* replace weakest one */ + i = u4IdxWeakest; + + /* free IE buffer then zero */ + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (UINT_32) u2IELength; + + if (u2IELength > 0) { + /* IE - allocate buffer and update pointer */ + if (ALIGN_4(u2IELength) + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= u4BufferSize) { + kalMemCopy(& + (prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter-> + rWlanInfo.aucScanIEBuf[prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is invoked to free IE buffer for dedicated scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param u4Idx Index of Scan Result +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Idx) +{ + UINT_32 i; + PUINT_8 pucPivot, pucMovePivot; + UINT_32 u4MoveSize, u4FreeSize, u4ReserveSize; + + ASSERT(prAdapter); + ASSERT(u4Idx < CFG_MAX_NUM_BSS_LIST); + + if (prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength == 0 + || prAdapter->rWlanInfo.apucScanResultIEs[u4Idx] == NULL) { + return; + } + + u4FreeSize = ALIGN_4(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength); + + pucPivot = prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]; + pucMovePivot = (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]) + u4FreeSize); + + u4ReserveSize = ((ULONG) pucPivot) - (ULONG) (&(prAdapter->rWlanInfo.aucScanIEBuf[0])); + u4MoveSize = prAdapter->rWlanInfo.u4ScanIEBufferUsage - u4ReserveSize - u4FreeSize; + + /* 1. rest of buffer to move forward */ + kalMemCopy(pucPivot, pucMovePivot, u4MoveSize); + + /* 1.1 modify pointers */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + if (i != u4Idx) { + if (prAdapter->rWlanInfo.apucScanResultIEs[i] >= pucMovePivot) { + prAdapter->rWlanInfo.apucScanResultIEs[i] = + (PUINT_8) ((ULONG) (prAdapter->rWlanInfo.apucScanResultIEs[i]) - u4FreeSize); + } + } + } + + /* 1.2 reset the freed one */ + prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + + /* 2. reduce IE buffer usage */ + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4FreeSize; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is to hack parameters for WLAN TABLE for +* fixed rate settings +* +* @param prAdapter Pointer to the Adapter structure. +* @param eRateSetting +* @param pu2DesiredNonHTRateSet, +* @param pu2BSSBasicRateSet, +* @param pucMcsSet +* @param pucSupMcs32 +* @param pu2HtCapInfo +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams(IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN PUINT_8 pucDesiredPhyTypeSet, + IN PUINT_16 pu2DesiredNonHTRateSet, + IN PUINT_16 pu2BSSBasicRateSet, + IN PUINT_8 pucMcsSet, IN PUINT_8 pucSupMcs32, IN PUINT_16 pu2HtCapInfo) +{ + ASSERT(prAdapter); + ASSERT(eRateSetting > FIXED_RATE_NONE && eRateSetting < FIXED_RATE_NUM); + + switch (prAdapter->rWifiVar.eRateSetting) { + case FIXED_RATE_1M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_1M; + *pu2BSSBasicRateSet = RATE_SET_BIT_1M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_2M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_2M; + *pu2BSSBasicRateSet = RATE_SET_BIT_2M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_5_5M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_5_5M; + *pu2BSSBasicRateSet = RATE_SET_BIT_5_5M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_11M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_11M; + *pu2BSSBasicRateSet = RATE_SET_BIT_11M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_6M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_6M; + *pu2BSSBasicRateSet = RATE_SET_BIT_6M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_9M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_9M; + *pu2BSSBasicRateSet = RATE_SET_BIT_9M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_12M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_12M; + *pu2BSSBasicRateSet = RATE_SET_BIT_12M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_18M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_18M; + *pu2BSSBasicRateSet = RATE_SET_BIT_18M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_24M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_24M; + *pu2BSSBasicRateSet = RATE_SET_BIT_24M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_36M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_36M; + *pu2BSSBasicRateSet = RATE_SET_BIT_36M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_48M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_48M; + *pu2BSSBasicRateSet = RATE_SET_BIT_48M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_54M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_54M; + *pu2BSSBasicRateSet = RATE_SET_BIT_54M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_MCS0_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS1_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS2_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS3_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS4_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS5_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS6_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS7_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH + | HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS0_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS1_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS2_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS3_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS4_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS5_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS6_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS7_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS0_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS1_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS2_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS3_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS4_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS5_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS6_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS7_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS32_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS32_INDEX; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS0_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS0_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS1_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS1_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS2_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS2_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS3_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS3_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS4_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS4_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS5_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS5_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS6_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS6_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS7_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS7_INDEX; + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS32_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = HT_RATE_MCS32_INDEX; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to write the register +* +* @param u4Address Register address +* u4Value the value to be written +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Address, IN UINT_32 u4Value) +{ + CMD_ACCESS_REG rCmdAccessReg; + + rCmdAccessReg.u4Address = u4Address; + rCmdAccessReg.u4Data = u4Value; + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_ACCESS_REG, + TRUE, + FALSE, + FALSE, NULL, NULL, sizeof(CMD_ACCESS_REG), (PUINT_8) &rCmdAccessReg, NULL, 0); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to modify the auto rate parameters +* +* @param u4ArSysParam0 see description below +* u4ArSysParam1 +* u4ArSysParam2 +* u4ArSysParam3 +* +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* +* @note +* ArSysParam0[0:3] -> auto rate version (0:disable 1:version1 2:version2) +* ArSysParam0[4:5]-> auto bw version (0:disable 1:version1 2:version2) +* ArSysParam0[6:7]-> auto gi version (0:disable 1:version1 2:version2) +* ArSysParam0[8:15]-> HT rate clear mask +* ArSysParam0[16:31]-> Legacy rate clear mask +* ArSysParam1[0:7]-> Auto Rate check weighting window +* ArSysParam1[8:15]-> Auto Rate v1 Force Rate down +* ArSysParam1[16:23]-> Auto Rate v1 PerH +* ArSysParam1[24:31]-> Auto Rate v1 PerL +* +* Examples +* ArSysParam0 = 1, +* Enable auto rate version 1 +* +* ArSysParam0 = 983041, +* Enable auto rate version 1 +* Remove CCK 1M, 2M, 5.5M, 11M +* +* ArSysParam0 = 786433 +* Enable auto rate version 1 +* Remove CCK 5.5M 11M +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4ArSysParam0, + IN UINT_32 u4ArSysParam1, IN UINT_32 u4ArSysParam2, IN UINT_32 u4ArSysParam3) +{ + UINT_8 ucArVer, ucAbwVer, ucAgiVer; + UINT_16 u2HtClrMask; + UINT_16 u2LegacyClrMask; + UINT_8 ucArCheckWindow; + UINT_8 ucArPerL; + UINT_8 ucArPerH; + UINT_8 ucArPerForceRateDownPer; + + ucArVer = (UINT_8) (u4ArSysParam0 & BITS(0, 3)); + ucAbwVer = (UINT_8) ((u4ArSysParam0 & BITS(4, 5)) >> 4); + ucAgiVer = (UINT_8) ((u4ArSysParam0 & BITS(6, 7)) >> 6); + u2HtClrMask = (UINT_16) ((u4ArSysParam0 & BITS(8, 15)) >> 8); + u2LegacyClrMask = (UINT_16) ((u4ArSysParam0 & BITS(16, 31)) >> 16); + +#if 0 + ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); + ucArPerForceRateDownPer = (UINT_8) ((u4ArSysParam1 & BITS(8, 15) >> 8)); + ucArPerH = (UINT_8) ((u4ArSysParam1 & BITS(16, 23)) >> 16); + ucArPerL = (UINT_8) ((u4ArSysParam1 & BITS(24, 31)) >> 24); +#endif + + ucArCheckWindow = (UINT_8) (u4ArSysParam1 & BITS(0, 7)); + ucArPerForceRateDownPer = (UINT_8) (((u4ArSysParam1 >> 8) & BITS(0, 7))); + ucArPerH = (UINT_8) (((u4ArSysParam1 >> 16) & BITS(0, 7))); + ucArPerL = (UINT_8) (((u4ArSysParam1 >> 24) & BITS(0, 7))); + + DBGLOG(NIC, INFO, "ArParam %u %u %u %u\n", u4ArSysParam0, u4ArSysParam1, u4ArSysParam2, u4ArSysParam3); + DBGLOG(NIC, INFO, "ArVer %u AbwVer %u AgiVer %u\n", ucArVer, ucAbwVer, ucAgiVer); + DBGLOG(NIC, INFO, "HtMask %x LegacyMask %x\n", u2HtClrMask, u2LegacyClrMask); + DBGLOG(NIC, INFO, + "CheckWin %u RateDownPer %u PerH %u PerL %u\n", ucArCheckWindow, ucArPerForceRateDownPer, ucArPerH, + ucArPerL); + +#define SWCR_DATA_ADDR(MOD, ADDR) (0x90000000+(MOD<<8)+(ADDR)) +#define SWCR_DATA_CMD(CATE, WRITE, INDEX, OPT0, OPT1) ((CATE<<24) | (WRITE<<23) | (INDEX<<16) | (OPT0 << 8) | OPT1) +#define SWCR_DATA0 0x0 +#define SWCR_DATA1 0x4 +#define SWCR_DATA2 0x8 +#define SWCR_DATA3 0xC +#define SWCR_DATA4 0x10 +#define SWCR_WRITE 1 +#define SWCR_READ 0 + + if (ucArVer > 0) { + /* dummy = WiFi.WriteMCR(&h90000104, &h00000001) */ + /* dummy = WiFi.WriteMCR(&h90000100, &h00850000) */ + + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 1); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); + } else { + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 0); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); + } + + /* ucArVer 0: none 1:PER 2:Rcpi */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArVer); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 7, 0, 0)); + + /* Candidate rate Ht mask */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2HtClrMask); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1c, 0, 0)); + + /* Candidate rate legacy mask */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2LegacyClrMask); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1d, 0, 0)); + +#if 0 + if (ucArCheckWindow != 0) { + /* TX DONE MCS INDEX CHECK STA RATE DOWN TH */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x14, 0, 0)); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArCheckWindow); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0xc, 0, 0)); + } + + if (ucArPerForceRateDownPer != 0) { + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerForceRateDownPer); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x18, 0, 0)); + } + if (ucArPerH != 0) { + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerH); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x1, 0, 0)); + } + if (ucArPerL != 0) { + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArPerL); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), SWCR_DATA_CMD(0, SWCR_WRITE, 0x2, 0, 0)); + } +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This utility function is used to enable roaming +* +* @param u4EnableRoaming +* +* +* @retval WLAN_STATUS_SUCCESS +* WLAN_STATUS_FAILURE +* +* @note +* u4EnableRoaming -> Enable Romaing +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, IN UINT_32 u4EnableRoaming) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prConnSettings->fgIsEnableRoaming = ((u4EnableRoaming > 0) ? (TRUE) : (FALSE)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief dump firmware Assert message +* +* \param[in] +* prAdapter +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID nicPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4MailBox0, u4MailBox1; + UINT_32 line = 0; + UINT_8 aucAssertFile[7]; + UINT_32 u4ChipId; + +#if CFG_SDIO_INTR_ENHANCE + u4MailBox0 = prAdapter->prSDIOCtrl->u4RcvMailbox0; + u4MailBox1 = prAdapter->prSDIOCtrl->u4RcvMailbox1; +#else + nicGetMailbox(prAdapter, 0, &u4MailBox0); + nicGetMailbox(prAdapter, 1, &u4MailBox1); +#endif + + line = u4MailBox0 & 0x0000FFFF; + + u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); + + kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); + kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); + + aucAssertFile[6] = '\0'; + +#if defined(MT6620) + u4ChipId = 6620; +#elif defined(MT6628) + u4ChipId = 6582; +#endif + + kalPrint("\n[MT%u][wifi][Firmware] Assert at \"%s\" #%u\n\n", u4ChipId, aucAssertFile, line); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* prEventLinkQuality +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN P_EVENT_LINK_QUALITY prEventLinkQuality) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + ASSERT(prEventLinkQuality); + + switch (eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* check is to prevent RSSI to be updated by incorrect initial RSSI from hardware */ + /* buffer statistics for further query */ + if (prAdapter->fgIsLinkQualityValid == FALSE + || (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + nicUpdateRSSI(prAdapter, eNetTypeIdx, prEventLinkQuality->cRssi, + prEventLinkQuality->cLinkQuality); + } + + if (prAdapter->fgIsLinkRateValid == FALSE + || (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + nicUpdateLinkSpeed(prAdapter, eNetTypeIdx, prEventLinkQuality->u2LinkSpeed); + } + } + break; +#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY + case NETWORK_TYPE_P2P_INDEX: + if (prAdapter->fgIsP2pLinkQualityValid == FALSE + || (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) > CFG_LINK_QUALITY_VALID_PERIOD) { + P_EVENT_LINK_QUALITY_EX prEventLQEx = (P_EVENT_LINK_QUALITY_EX) prEventLinkQuality; + + nicUpdateRSSI(prAdapter, NETWORK_TYPE_P2P_INDEX, prEventLQEx->cRssiP2P, + prEventLQEx->cLinkQualityP2P); + } + break; +#endif + default: + break; + + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update RSSI and Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicUpdateRSSI(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + + switch (eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + prAdapter->fgIsLinkQualityValid = TRUE; + prAdapter->rLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.cRssi = cRssi; + prAdapter->rLinkQuality.cLinkQuality = cLinkQuality; + + /* indicate to glue layer */ + kalUpdateRSSI(prAdapter->prGlueInfo, + KAL_NETWORK_TYPE_AIS_INDEX, + prAdapter->rLinkQuality.cRssi, prAdapter->rLinkQuality.cLinkQuality); + } + + break; +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case NETWORK_TYPE_P2P_INDEX: + prAdapter->fgIsP2pLinkQualityValid = TRUE; + prAdapter->rP2pLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rP2pLinkQuality.cRssi = cRssi; + prAdapter->rP2pLinkQuality.cLinkQuality = cLinkQuality; + + kalUpdateRSSI(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_P2P_INDEX, cRssi, cLinkQuality); + break; +#endif +#endif + default: + break; + + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called to update Link Quality information +* +* @param prAdapter Pointer of Adapter Data Structure +* eNetTypeIdx +* prEventLinkQuality +* cRssi +* cLinkQuality +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN UINT_16 u2LinkSpeed) +{ + ASSERT(prAdapter); + ASSERT(eNetTypeIdx < NETWORK_TYPE_INDEX_NUM); + + switch (eNetTypeIdx) { + case NETWORK_TYPE_AIS_INDEX: + if (prAdapter->rWifiVar.arBssInfo[eNetTypeIdx].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* buffer statistics for further query */ + prAdapter->fgIsLinkRateValid = TRUE; + prAdapter->rLinkRateUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.u2LinkSpeed = u2LinkSpeed; + } + break; + + default: + break; + + } + +} + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, IN P_CMD_RDD_CH_T prRddChParam) +{ + DEBUGFUNC("nicUpdateRddTestMode.\n"); + + ASSERT(prAdapter); + +/* aisFsmScanRequest(prAdapter, NULL); */ + + return wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_RDD_CH, + TRUE, + FALSE, FALSE, NULL, NULL, sizeof(CMD_RDD_CH_T), (PUINT_8) prRddChParam, NULL, 0); +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c new file mode 100644 index 0000000000000..3c9c24f9542bc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_cmd_event.c @@ -0,0 +1,1636 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_cmd_event.c#1 +*/ + +/*! \file nic_cmd_event.c + \brief Callback functions for Command packets. + + Various Event packet handlers which will be setup in the callback function of + a command packet. +*/ + +/* +** Log: nic_cmd_event.c + * + * 04 10 2012 yuche.tsai + * NULL + * Update address for wifi direct connection issue. + * + * 06 15 2011 cm.chang + * [WCXRP00000785] [MT6620 Wi-Fi][Driver][FW] P2P/BOW MAC address is XOR with AIS MAC address + * P2P/BOW mac address XOR with local bit instead of OR + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 02 24 2011 cp.wu + * [WCXRP00000493] [MT6620 Wi-Fi][Driver] Do not indicate redundant disconnection to host when entering into RF + * test mode + * only indicate DISCONNECTION to host when entering RF test if necessary (connected -> disconnected cases) + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to + * system scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being + * loaded + * + * 12 01 2010 cp.wu + * [WCXRP00000223] MT6620 Wi-Fi][Driver][FW] Adopt NVRAM parameters when enter/exit RF test mode + * reload NVRAM settings before entering RF test mode and leaving from RF test mode. + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 20 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * use OID_CUSTOM_TEST_MODE as indication for driver reset + * by dropping pending TX packets + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + * associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 15 2010 yuche.tsai + * NULL + * Start to test AT GO only when P2P state is not IDLE. + * + * 09 09 2010 yuche.tsai + * NULL + * Add AT GO Test mode after MAC address available. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 16 2010 cp.wu + * NULL + * Replace CFG_SUPPORT_BOW by CFG_ENABLE_BT_OVER_WIFI. + * There is no CFG_SUPPORT_BOW in driver domain source. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 11 2010 yuche.tsai + * NULL + * Add support for P2P Device Address query from FW. + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 08 02 2010 cp.wu + * NULL + * reset FSMs before entering RF test mode. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 05 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) change fake BSS_DESC from channel 6 to channel 1 due to channel switching is not done yet. + * 2) after MAC address is queried from firmware, all related variables in driver domain should be updated as well + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change upon request: indicate as disconnected in driver domain when leaving from RF test mode + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * do not clear scanning list array after disassociation + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) disable NETWORK_LAYER_ADDRESSES handling temporally. + * 2) finish statistics OIDs + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * change OID behavior to meet WHQL requirement. + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 05 17 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct OID_802_11_DISASSOCIATE handling. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * are done in adapter layer. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glude code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sync statistics data structure definition with firmware implementation + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * statistics information OIDs are now handled by querying from firmware domain + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * indicate media stream mode after set is done + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement custom OID: EEPROM read/write access + * + * 03 03 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_3_MULTICAST_LIST oid handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * limit RSSI return value to micxxsoft defined range. + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * block until firmware finished RF test enter/leave then indicate completion to upper layer + * + * 01 29 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when entering RF test mode and leaving from RF test mode, wait for W_FUNC_RDY bit to be asserted forever until it + * is set or card is removed. + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * * 4. correct some HAL implementation + * + * 01 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Under WinXP with SDIO, use prGlueInfo->rHifInfo.pvInformationBuffer instead of prGlueInfo->pvInformationBuffer + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * * OID_802_11_RSSI, + * * * * * OID_802_11_RSSI_TRIGGER, + * * * * * OID_802_11_STATISTICS, + * * * * * OID_802_11_DISASSOCIATE, + * * * * * OID_802_11_POWER_MODE + * + * 01 21 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement OID_802_11_MEDIA_STREAM_MODE + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-10 16:47:47 GMT mtk02752 +** only handle MCR read when accessing FW domain register +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-08 17:37:28 GMT mtk02752 +** * refine nicCmdEventQueryMcrRead +** + add TxStatus/RxStatus for RF test QueryInformation OIDs +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 22:05:45 GMT mtk02752 +** kalOidComplete() will decrease i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-12-01 23:02:57 GMT mtk02752 +** remove unnecessary spin locks +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-12-01 22:51:18 GMT mtk02752 +** maintein i4OidPendingCount +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-11-30 10:55:03 GMT mtk02752 +** modify for compatibility +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-23 14:46:32 GMT mtk02752 +** add another version of command-done handler upon new event structure +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-04-29 15:42:33 GMT mtk01461 +** Add comment +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-04-21 19:32:42 GMT mtk01461 +** Add nicCmdEventSetCommon() for general set OID +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-04-21 01:40:35 GMT mtk01461 +** Command Done Handler +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +VOID nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_ACCESS_REG prCmdAccessReg; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prCmdAccessReg = (P_CMD_ACCESS_REG) (pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; + prMcrRdInfo->u4McrOffset = prCmdAccessReg->u4Address; + prMcrRdInfo->u4McrData = prCmdAccessReg->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + +VOID nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_SW_DBG_CTRL_T prCmdSwCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prCmdSwCtrl = (P_CMD_SW_DBG_CTRL_T) (pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T) prCmdInfo->pvInformationBuffer; + prSwCtrlInfo->u4Id = prCmdSwCtrl->u4Id; + prSwCtrlInfo->u4Data = prCmdSwCtrl->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + +VOID nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, prCmdInfo->u4InformationBufferLength, WLAN_STATUS_SUCCESS); + } + +} + +VOID nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + } + + DBGLOG(NIC, TRACE, "DisByCmdE\n"); + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + +#if !defined(LINUX) + prAdapter->fgIsRadioOff = TRUE; +#endif + +} + +VOID nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4Count; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + u4Count = (prCmdInfo->u4SetInfoLen - OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress)) + / sizeof(IPV4_NETWORK_ADDRESS); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress) + u4Count * + (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP)), + WLAN_STATUS_SUCCESS); + } + +} + +VOID nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_TEST_STATUS prTestStatus, prQueryBuffer; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTestStatus = (P_EVENT_TEST_STATUS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prQueryBuffer = (P_EVENT_TEST_STATUS) prCmdInfo->pvInformationBuffer; + + kalMemCopy(prQueryBuffer, prTestStatus, sizeof(EVENT_TEST_STATUS)); + + u4QueryInfoLen = sizeof(EVENT_TEST_STATUS); + + /* Update Query Information Length */ + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} + +VOID nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + PARAM_RSSI rRssi, *prRssi; + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; + + rRssi = (PARAM_RSSI) prLinkQuality->cRssi; /* ranged from (-128 ~ 30) in unit of dBm */ + DBGLOG(NIC, INFO, " %s: rRssi = %d\n", __func__, rRssi); + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } else { + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prRssi = (PARAM_RSSI *) prCmdInfo->pvInformationBuffer; + + kalMemCopy(prRssi, &rRssi, sizeof(PARAM_RSSI)); + u4QueryInfoLen = sizeof(PARAM_RSSI); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is in response of OID_GEN_LINK_SPEED query request +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the pending command info +* @param pucEventBuf +* +* @retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4LinkSpeed; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prLinkQuality = (P_EVENT_LINK_QUALITY) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + pu4LinkSpeed = (PUINT_32) (prCmdInfo->pvInformationBuffer); + + *pu4LinkSpeed = prLinkQuality->u2LinkSpeed * 5000; + + u4QueryInfoLen = sizeof(UINT_32); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + u4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T) prCmdInfo->pvInformationBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount = prEventStatistics->rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount = prEventStatistics->rMulticastTransmittedFrameCount; + prStatistics->rFailedCount = prEventStatistics->rFailedCount; + prStatistics->rRetryCount = prEventStatistics->rRetryCount; + prStatistics->rMultipleRetryCount = prEventStatistics->rMultipleRetryCount; + prStatistics->rRTSSuccessCount = prEventStatistics->rRTSSuccessCount; + prStatistics->rRTSFailureCount = prEventStatistics->rRTSFailureCount; + prStatistics->rACKFailureCount = prEventStatistics->rACKFailureCount; + prStatistics->rFrameDuplicateCount = prEventStatistics->rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount = prEventStatistics->rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount = prEventStatistics->rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount = prEventStatistics->rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart = 0; + prStatistics->rTKIPICVErrors.QuadPart = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; + prStatistics->rTKIPReplays.QuadPart = 0; + prStatistics->rCCMPFormatErrors.QuadPart = 0; + prStatistics->rCCMPReplays.QuadPart = 0; + prStatistics->rCCMPDecryptErrors.QuadPart = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart = 0; + prStatistics->rWEPUndecryptableCount.QuadPart = 0; + prStatistics->rWEPICVErrorCount.QuadPart = 0; + prStatistics->rDecryptSuccessCount.QuadPart = 0; + prStatistics->rDecryptFailureCount.QuadPart = 0; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ +#define WAIT_FW_READY_RETRY_CNT 200 + + UINT_32 u4WHISR = 0, u4Value = 0; + UINT_8 aucTxCount[8]; + UINT_16 u2RetryCnt = 0; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + /* [driver-land] */ + prAdapter->fgTestMode = TRUE; + + /* 0. always indicate disconnection */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + /* 1. Remove pending TX */ + nicTxRelease(prAdapter); + + /* 1.1 clear pending Security / Management Frames */ + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + /* 1.2 clear pending TX packet queued in glue layer */ + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 2. Reset driver-domain FSMs */ + nicUninitMGMT(prAdapter); + + nicResetSystemService(prAdapter); + nicInitMGMT(prAdapter, NULL); + + /* 3. Disable Interrupt */ + HAL_INTR_DISABLE(prAdapter); + + /* 4. Block til firmware completed entering into RF test mode */ + kalMsleep(500); + while (1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || + kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); + + } + return; + } + kalMsleep(10); + u2RetryCnt++; + } + + /* 5. Clear Interrupt Status */ + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if (HAL_IS_TX_DONE_INTR(u4WHISR)) + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + /* 6. Reset TX Counter */ + nicTxResetResource(prAdapter); + + /* 7. Re-enable Interrupt */ + HAL_INTR_ENABLE(prAdapter); + + /* 8. completion indication */ + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } +#if CFG_SUPPORT_NVRAM + /* 9. load manufacture data */ + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + +} + +VOID nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ +#define WAIT_FW_READY_RETRY_CNT 200 + + UINT_32 u4WHISR = 0, u4Value = 0; + UINT_8 aucTxCount[8]; + UINT_16 u2RetryCnt = 0; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + /* 1. Disable Interrupt */ + HAL_INTR_DISABLE(prAdapter); + + /* 2. Block til firmware completed leaving from RF test mode */ + kalMsleep(500); + while (1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE || + kalIsResetting() || u2RetryCnt >= WAIT_FW_READY_RETRY_CNT) { + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, WLAN_STATUS_NOT_SUPPORTED); + + } + return; + } + kalMsleep(10); + u2RetryCnt++; + } + + /* 3. Clear Interrupt Status */ + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR); + if (HAL_IS_TX_DONE_INTR(u4WHISR)) + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + /* 4. Reset TX Counter */ + nicTxResetResource(prAdapter); + + /* 5. Re-enable Interrupt */ + HAL_INTR_ENABLE(prAdapter); + + /* 6. set driver-land variable */ + prAdapter->fgTestMode = FALSE; + + /* 7. completion indication */ + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } + + /* 8. Indicate as disconnected */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } +#if CFG_SUPPORT_NVRAM + /* 9. load manufacture data */ + wlanLoadManufactureData(prAdapter, kalGetConfiguration(prAdapter->prGlueInfo)); +#endif + + /* 10. Override network address */ + wlanUpdateNetworkAddress(prAdapter); + +} + +VOID nicCmdEventQueryAddress(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_BASIC_CONFIG prEventBasicConfig; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + prEventBasicConfig = (P_EVENT_BASIC_CONFIG) (pucEventBuf); + + /* copy to adapter */ + kalMemCopy(&(prAdapter->rMyMacAddr), &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + kalMemCopy(prCmdInfo->pvInformationBuffer, &(prEventBasicConfig->rMyMacAddr), MAC_ADDR_LEN); + u4QueryInfoLen = MAC_ADDR_LEN; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + /* 4 <3> Update new MAC address and all 3 networks */ + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, prAdapter->rMyMacAddr); + COPY_MAC_ADDR(prAdapter->rWifiVar.aucDeviceAddress, prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucDeviceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucInterfaceAddress, prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucInterfaceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].aucOwnMacAddr, prAdapter->rMyMacAddr); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + COPY_MAC_ADDR(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_BOW_INDEX].aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); +#endif + +#if CFG_TEST_WIFI_DIRECT_GO + if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_IDLE) { + wlanEnableP2pFunction(prAdapter); + + wlanEnableATGO(prAdapter); + } +#endif + + kalUpdateMACAddress(prAdapter->prGlueInfo, prAdapter->rWifiVar.aucMacAddress); + +} + +VOID nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_MAC_MCAST_ADDR prEventMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventMacMcastAddr = (P_EVENT_MAC_MCAST_ADDR) (pucEventBuf); + + u4QueryInfoLen = prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN; + + /* buffer length check */ + if (prCmdInfo->u4InformationBufferLength < u4QueryInfoLen) { + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_BUFFER_TOO_SHORT); + } else { + kalMemCopy(prCmdInfo->pvInformationBuffer, + prEventMacMcastAddr->arAddress, + prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + } +} + +VOID nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_ACCESS_EEPROM prEventAccessEeprom; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventAccessEeprom = (P_EVENT_ACCESS_EEPROM) (pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + prEepromRdInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T) prCmdInfo->pvInformationBuffer; + prEepromRdInfo->ucEepromIndex = (UINT_8) (prEventAccessEeprom->u2Offset); + prEepromRdInfo->u2EepromData = prEventAccessEeprom->u2Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + + return; + +} + +VOID nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + PARAM_MEDIA_STREAMING_INDICATION rParamMediaStreamIndication; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } + + rParamMediaStreamIndication.rStatus.eStatusType = ENUM_STATUS_TYPE_MEDIA_STREAM_MODE; + rParamMediaStreamIndication.eMediaStreamMode = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? ENUM_MEDIA_STREAM_OFF : ENUM_MEDIA_STREAM_ON; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)&rParamMediaStreamIndication, sizeof(PARAM_MEDIA_STREAMING_INDICATION)); +} + +/* Statistics responder */ +VOID nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rTransmittedFragmentCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rTransmittedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rReceivedFragmentCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rReceivedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not calculated */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = 0; /* @FIXME? */ + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = 0; /* @FIXME? */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFCSErrorCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) 0; /* @FIXME */ + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = 0; /* @FIXME */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = + (UINT_32) (prEventStatistics->rMultipleRetryCount.QuadPart - + prEventStatistics->rRetryCount.QuadPart); + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = + (UINT_64) (prEventStatistics->rMultipleRetryCount.QuadPart - + prEventStatistics->rRetryCount.QuadPart); + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rMultipleRetryCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rMultipleRetryCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +VOID nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4QueryInfoLen; + PUINT_32 pu4Data; + PUINT_64 pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prEventStatistics = (P_EVENT_STATISTICS) pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(UINT_32)) { + u4QueryInfoLen = sizeof(UINT_32); + + pu4Data = (PUINT_32) prCmdInfo->pvInformationBuffer; + *pu4Data = (UINT_32) prEventStatistics->rFailedCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(UINT_64); + + pu8Data = (PUINT_64) prCmdInfo->pvInformationBuffer; + *pu8Data = (UINT_64) prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when command by OID/ioctl has been timeout +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* +* @return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +VOID nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is a generic command timeout handler +* +* @param pfnOidHandler Pointer to the OID handler +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when command for entering RF test has +* failed sending due to timeout (highly possibly by firmware crash) +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + /* 1. Remove pending TX frames */ + nicTxRelease(prAdapter); + + /* 1.1 clear pending Security / Management Frames */ + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + /* 1.2 clear pending TX packet queued in glue layer */ + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 2. indicate for OID failure */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when command for memory dump has +* replied a event. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_DUMP_MEM_T prEventDumpMem; + static UINT_8 aucPath[256]; + static UINT_32 u4CurTimeTick; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventDumpMem = (P_EVENT_DUMP_MEM_T) (pucEventBuf); + + u4QueryInfoLen = sizeof(P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T); + + prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T) prCmdInfo->pvInformationBuffer; + prMemDumpInfo->u4Address = prEventDumpMem->u4Address; + prMemDumpInfo->u4Length = prEventDumpMem->u4Length; + prMemDumpInfo->u4RemainLength = prEventDumpMem->u4RemainLength; + prMemDumpInfo->ucFragNum = prEventDumpMem->ucFragNum; + +#if 0 + do { + UINT_32 i = 0; + + DBGLOG(REQ, TRACE, "Rx dump address 0x%X, Length %d, FragNum %d, remain %d\n", + prEventDumpMem->u4Address, + prEventDumpMem->u4Length, prEventDumpMem->ucFragNum, prEventDumpMem->u4RemainLength); +#if 0 + for (i = 0; i < prEventDumpMem->u4Length; i++) { + DBGLOG(REQ, TRACE, "%02X ", prEventDumpMem->aucBuffer[i]); + if (i % 32 == 31) + DBGLOG(REQ, TRACE, "\n"); + } +#endif + } while (FALSE); +#endif + + if (prEventDumpMem->ucFragNum == 1) { + /* Store memory dump into sdcard, + * path /sdcard/dump___.hex + */ + u4CurTimeTick = kalGetTimeTick(); + sprintf(aucPath, "/sdcard/dump_%d_0x%08X_%d.hex", + u4CurTimeTick, + prEventDumpMem->u4Address, prEventDumpMem->u4Length + prEventDumpMem->u4RemainLength); + kalWriteToFile(aucPath, FALSE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); + } else { + /* Append current memory dump to the hex file */ + kalWriteToFile(aucPath, TRUE, &prEventDumpMem->aucBuffer[0], prEventDumpMem->u4Length); + } + + if (prEventDumpMem->u4RemainLength == 0 || prEventDumpMem->u4Address == 0xFFFFFFFF) { + /* The request is finished or firmware response a error */ + /* Reply time tick to iwpriv */ + *((PUINT_32) prCmdInfo->pvInformationBuffer) = u4CurTimeTick; + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } else { + /* The memory dump request is not finished, Send next command */ + wlanSendMemDumpCmd(prAdapter, + prCmdInfo->pvInformationBuffer, prCmdInfo->u4InformationBufferLength); + } + } + + return; + +} + +#if CFG_SUPPORT_BATCH_SCAN +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when event for SUPPORT_BATCH_SCAN +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to the event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_EVENT_BATCH_RESULT_T prEventBatchResult; + P_GLUE_INFO_T prGlueInfo; + + DBGLOG(SCN, TRACE, "nicCmdEventBatchScanResult"); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEventBatchResult = (P_EVENT_BATCH_RESULT_T) pucEventBuf; + + u4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); + kalMemCopy(prCmdInfo->pvInformationBuffer, prEventBatchResult, sizeof(EVENT_BATCH_RESULT_T)); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} +#endif + +#if CFG_SUPPORT_BUILD_DATE_CODE +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when event for build date code information +* has been retrieved +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to the event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_EVENT_BUILD_DATE_CODE prEvent; + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEvent = (P_EVENT_BUILD_DATE_CODE) pucEventBuf; + + u4QueryInfoLen = sizeof(UINT_8) * 16; + kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent->aucDateCode, sizeof(UINT_8) * 16); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when event for query STA link status +* has been retrieved +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to the event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_EVENT_STA_STATISTICS_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_PARAM_GET_STA_STATISTICS prStaStatistics; + + if ((prAdapter == NULL) + || (prCmdInfo == NULL) + || (pucEventBuf == NULL) + || (prCmdInfo->pvInformationBuffer == NULL)) { + ASSERT(FALSE); + return; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEvent = (P_EVENT_STA_STATISTICS_T) pucEventBuf; + prStaStatistics = (P_PARAM_GET_STA_STATISTICS) prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(PARAM_GET_STA_STA_STATISTICS); + + /* Statistics from FW is valid */ + if (prEvent->u4Flags & BIT(0)) { + prStaStatistics->ucPer = prEvent->ucPer; + prStaStatistics->ucRcpi = prEvent->ucRcpi; + prStaStatistics->u4PhyMode = prEvent->u4PhyMode; + prStaStatistics->u2LinkSpeed = prEvent->u2LinkSpeed; + + prStaStatistics->u4TxFailCount = prEvent->u4TxFailCount; + prStaStatistics->u4TxLifeTimeoutCount = prEvent->u4TxLifeTimeoutCount; + + if (prEvent->u4TxCount) { + UINT_32 u4TxDoneAirTimeMs = USEC_TO_MSEC(prEvent->u4TxDoneAirTime * 32); + + prStaStatistics->u4TxAverageAirTime = (u4TxDoneAirTimeMs / prEvent->u4TxCount); + } else { + prStaStatistics->u4TxAverageAirTime = 0; + } + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + +/* 4 Auto Channel Selection */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when event for query STA link status +* has been retrieved +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to the event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicCmdEventQueryChannelLoad(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_EVENT_CHN_LOAD_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_PARAM_GET_CHN_LOAD prChnLoad; + + if ((prAdapter == NULL) + || (prCmdInfo == NULL) + || (pucEventBuf == NULL) + || (prCmdInfo->pvInformationBuffer == NULL)) { + ASSERT(FALSE); + return; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEvent = (P_EVENT_CHN_LOAD_T) pucEventBuf; /* 4 The firmware responsed data */ + /* 4 Fill the firmware data in and send it back to host */ + prChnLoad = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); + + /* Statistics from FW is valid */ + if (prEvent->u4Flags & BIT(0)) { + prChnLoad->rEachChnLoad[0].ucChannel = prEvent->ucChannel; + prChnLoad->rEachChnLoad[0].u2ChannelLoad = prEvent->u2ChannelLoad; + DBGLOG(P2P, INFO, "CHN[%d]=%d\n", prEvent->ucChannel, prEvent->u2ChannelLoad); + + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} + +VOID nicCmdEventQueryLTESafeChn(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_8 ucIdx = 0; + UINT_32 u4QueryInfoLen; + P_EVENT_LTE_MODE_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_PARAM_GET_CHN_LOAD prLteSafeChnInfo; + + if ((prAdapter == NULL) + || (prCmdInfo == NULL) + || (pucEventBuf == NULL) + || (prCmdInfo->pvInformationBuffer == NULL)) { + ASSERT(FALSE); + return; + } + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEvent = (P_EVENT_LTE_MODE_T) pucEventBuf; /* 4 The firmware responsed data */ + + prLteSafeChnInfo = (P_PARAM_GET_CHN_LOAD) prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(PARAM_GET_CHN_LOAD); + + /* Statistics from FW is valid */ + if (prEvent->u4Flags & BIT(0)) { + for (ucIdx = 0; ucIdx < (NL80211_TESTMODE_AVAILABLE_CHAN_NUM - 1); ucIdx++) { + prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx] = + prEvent->rLteSafeChn.au4SafeChannelBitmask[ucIdx]; + + DBGLOG(P2P, INFO, + "[Auto Channel]LTE safe channels [%d]=[%x]\n", ucIdx, + (UINT32) prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx]); + } + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is called when event for query FW bss info +* has been retrieved +* +* @param prAdapter Pointer to the Adapter structure. +* @param prCmdInfo Pointer to the command information +* @param pucEventBuf Pointer to the event buffer +* +* @return none +* +*/ +/*----------------------------------------------------------------------------*/ + +VOID nicCmdEventGetBSSInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf) +{ + UINT_32 u4QueryInfoLen; + P_EVENT_AIS_BSS_INFO_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prEvent = (P_EVENT_AIS_BSS_INFO_T) pucEventBuf; + + u4QueryInfoLen = sizeof(EVENT_AIS_BSS_INFO_T); + kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent, sizeof(EVENT_AIS_BSS_INFO_T)); + prAisBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + + if (prEvent->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + if (prEvent->eConnectionState != prAisBssInfo->eConnectionState) { + DBGLOG(NIC, ERROR, "driver[%d] & FW[%d] status didn't sync !!!\n", + prAisBssInfo->eConnectionState, prEvent->eCurrentOPMode); + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, FALSE); + } + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c new file mode 100644 index 0000000000000..cf80fd999a240 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_pwr_mgt.c @@ -0,0 +1,669 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_pwr_mgt.c#1 +*/ + +/*! \file "nic_pwr_mgt.c" + \brief In this file we define the STATE and EVENT for Power Management FSM. + + The SCAN FSM is responsible for performing SCAN behavior when the Arbiter enter + ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with detail + description. +*/ + +/* +** Log: nic_pwr_mgt.c + * + * 11 28 2011 cp.wu + * [WCXRP00001125] [MT6620 Wi-Fi][Firmware] Strengthen Wi-Fi power off sequence to have a clearroom environment when + * returining to ROM code + * 1. Due to firmware now stops HIF DMA for powering off, do not try to receive any packet from firmware + * 2. Take use of prAdapter->fgIsEnterD3ReqIssued for tracking whether it is powering off or not + * + * 10 03 2011 cp.wu + * [WCXRP00001022] [MT6628 Driver][Firmware Download] Add multi section independent download functionality + * add firmware download path in divided scatters. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * reuse firmware download logic of MT6620 for MT6628. + * + * 05 11 2011 cp.wu + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * ACPI APIs migrate to wlan_lib.c for glue layer to invoke. + * + * 04 29 2011 cp.wu + * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) + * fix for compilation error when applied with FW_DOWNLOAD = 0 + * + * 04 18 2011 cp.wu + * [WCXRP00000636] [WHQL][MT5931 Driver] 2c_PMHibernate (hang on 2h) + * 1) add API for glue layer to query ACPI state + * 2) Windows glue should not access to hardware after switched into D3 state + * + * 04 13 2011 cp.wu + * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete + * refine for MT5931/MT6620 logic separation. + * + * 04 13 2011 cp.wu + * [WCXRP00000639] [WHQL][MT5931 Driver] 2c_PMStandby test item can not complete + * bugfix: firmware download procedure for ACPI state transition is not complete. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system + * scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being + * loaded + * + * 12 31 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * check success or failure for setting fw-own + * + * 12 30 2010 cp.wu + * [WCXRP00000327] [MT6620 Wi-Fi][Driver] Improve HEC WHQA 6972 workaround coverage in driver side + * host driver not to set FW-own when there is still pending interrupts + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * add firmware download for MT5931. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + * associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 30 2010 cp.wu + * NULL + * reset ACPI power state before waking up MT6620 Wi-Fi firmware. + * + * 08 12 2010 cp.wu + * NULL + * [AIS-FSM] honor registry setting for adhoc running mode. (A/B/G) + * + * 08 03 2010 cp.wu + * NULL + * Centralize mgmt/system service procedures into independent calls. + * + * 07 22 2010 cp.wu + * + * 1) refine AIS-FSM indent. + * 2) when entering RF Test mode, flush 802.1X frames as well + * 3) when entering D3 state, flush 802.1X frames as well + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) when acquiring LP-own, write for clr-own with lower frequency compared to read poll + * 2) correct address list parsing + * + * 05 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * sleepy notify is only used for sleepy state, + * while wake-up state is automatically set when host needs to access device + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct hibernation problem. + * + * 04 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) surpress compiler warning + * 2) when acqruing LP-own, keep writing WHLPCR whenever OWN is not acquired yet + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when acquiring driver-own, wait for up to 8 seconds. + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove redundant firmware image unloading + * * 2) use compile-time macros to separate logic related to accquiring own + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * are now handled in glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * ePowerCtrl is not necessary as a glue variable. + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * always send CMD_NIC_POWER_CTRL packet when nic is being halted + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct typo. + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX + * response + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-10-13 21:59:15 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-09-09 17:26:36 GMT mtk01084 +** remove CMD52 access +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-05-18 14:50:29 GMT mtk01084 +** modify lines in nicpmSetDriverOwn() +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-23 16:55:37 GMT mtk01084 +** modify nicpmSetDriverOwn() +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-19 18:33:00 GMT mtk01084 +** update for basic power management functions +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-03-19 15:05:32 GMT mtk01084 +** Initial version +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to process the POWER ON procedure. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt) +{ + UINT_32 u4RegValue = 0; + + ASSERT(prAdapter); + + if (prAdapter->fgIsFwOwn == TRUE) + return; + + if (nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + /* pending interrupts */ + return; + } + + if (fgEnableGlobalInt) { + prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; + } else { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); + + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); + if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { + /* if set firmware own not successful (possibly pending interrupts), */ + /* indicate an own clear event */ + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + + return; + } + + prAdapter->fgIsFwOwn = TRUE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to process the POWER OFF procedure. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 u4OriRegValue = 0; +BOOLEAN nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter) +{ +#define LP_OWN_BACK_TOTAL_DELAY_MS 2000 /* exponential of 2 */ +#define LP_OWN_BACK_LOOP_DELAY_MS 1 /* exponential of 2 */ +#define LP_OWN_BACK_CLR_OWN_ITERATION 256 /* exponential of 2 */ + + BOOLEAN fgStatus = TRUE; + UINT_32 i, u4CurrTick; + UINT_32 u4RegValue = 0; + GL_HIF_INFO_T *HifInfo; + + ASSERT(prAdapter); + + if (prAdapter->fgIsFwOwn == FALSE) + return fgStatus; + + HifInfo = &prAdapter->prGlueInfo->rHifInfo; + + u4CurrTick = kalGetTimeTick(); + STATS_DRIVER_OWN_START_RECORD(); + i = 0; + + while (1) { + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); + + if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { + HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); + prAdapter->fgIsFwOwn = FALSE; + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE + || fgIsBusAccessFailed == TRUE + || (kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS || fgIsResetting == TRUE) { + /* ERRORLOG(("LP cannot be own back (for %ld ms)", kalGetTimeTick() - u4CurrTick)); */ + fgStatus = FALSE; + if (fgIsResetting != TRUE) { + UINT_32 u4FwCnt; + static unsigned int u4OwnCnt; + /* MCR_D2HRM2R: low 4 bit means interrupt times, + * high 4 bit means firmware response times. + * ORI_MCR_D2HRM2R: the last successful value. + * for example: + * MCR_D2HRM2R = 0x44, ORI_MCR_D2HRM2R = 0x44 + * means firmware no receive interrupt form hardware. + * MCR_D2HRM2R = 0x45, ORI_MCR_D2HRM2R = 0x44 + * means firmware no send response. + * MCR_D2HRM2R = 0x55, ORI_MCR_D2HRM2R = 0x44 + * means firmware send response, but driver no receive. */ + HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); + DBGLOG(NIC, WARN, " [1]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", + u4RegValue, u4OriRegValue); + + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &u4RegValue); + if (u4RegValue & WHLPCR_FW_OWN_REQ_SET) { + HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4OriRegValue); + prAdapter->fgIsFwOwn = FALSE; + break; + } + HAL_MCR_RD(prAdapter, MCR_D2HRM2R, &u4RegValue); + DBGLOG(NIC, WARN, " [2]MCR_D2HRM2R = 0x%x, ORI_MCR_D2HRM2R = 0x%x\n", + u4RegValue, u4OriRegValue); + DBGLOG(NIC, WARN, + " Fatal error! Driver own fail!!!!!!!!!!!! %d, fgIsBusAccessFailed: %d\n", + u4OwnCnt++, fgIsBusAccessFailed); + + DBGLOG(NIC, WARN, "CONNSYS FW CPUINFO:\n"); + for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) + DBGLOG(NIC, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); + /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ + kalSendAeeWarning("[Fatal error! Driver own fail!]", __func__); + glDoChipReset(); + } + break; + } + if ((i & (LP_OWN_BACK_CLR_OWN_ITERATION - 1)) == 0) { + /* Software get LP ownership - per 256 iterations */ + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); + } + + /* Delay for LP engine to complete its operation. */ + kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); + i++; + } + + STATS_DRIVER_OWN_END_RECORD(); + STATS_DRIVER_OWN_STOP(); + + return fgStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set ACPI power mode to D0. +* +* \param[in] pvAdapter Pointer to the Adapter structure. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + UINT_32 u4Value = 0, u4WHISR = 0; + UINT_8 aucTxCount[8]; + UINT_32 i; +#if CFG_ENABLE_FW_DOWNLOAD + UINT_32 u4FwImgLength, u4FwLoadAddr, u4ImgSecSize; + PVOID prFwMappingHandle; + PVOID pvFwImageMapFile = NULL; +#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + UINT_32 j; + P_FIRMWARE_DIVIDED_DOWNLOAD_T prFwHead; + BOOLEAN fgValidHead; + const UINT_32 u4CRCOffset = offsetof(FIRMWARE_DIVIDED_DOWNLOAD_T, u4NumOfEntries); +#endif +#endif + + DEBUGFUNC("nicpmSetAcpiPowerD0"); + ASSERT(prAdapter); + + do { + /* 0. Reset variables in ADAPTER_T */ + prAdapter->fgIsFwOwn = TRUE; + prAdapter->fgWiFiInSleepyState = FALSE; + prAdapter->rAcpiState = ACPI_STATE_D0; + prAdapter->fgIsEnterD3ReqIssued = FALSE; + + /* 1. Request Ownership to enter F/W download state */ + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); +#if !CFG_ENABLE_FULL_PM + nicpmSetDriverOwn(prAdapter); +#endif + + /* 2. Initialize the Adapter */ + u4Status = nicInitializeAdapter(prAdapter); + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "nicInitializeAdapter failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + +#if CFG_ENABLE_FW_DOWNLOAD + prFwMappingHandle = kalFirmwareImageMapping(prAdapter->prGlueInfo, &pvFwImageMapFile, &u4FwImgLength); + if (!prFwMappingHandle) { + DBGLOG(NIC, ERROR, "Fail to load FW image from file!\n"); + pvFwImageMapFile = NULL; + } + + if (pvFwImageMapFile == NULL) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + + /* 3.1 disable interrupt, download is done by polling mode only */ + nicDisableInterrupt(prAdapter); + + /* 3.2 Initialize Tx Resource to fw download state */ + nicTxInitResetResource(prAdapter); + + /* 3.3 FW download here */ + u4FwLoadAddr = kalGetFwLoadAddress(prAdapter->prGlueInfo); + +#if CFG_ENABLE_FW_DIVIDED_DOWNLOAD + /* 3a. parse file header for decision of divided firmware download or not */ + prFwHead = (P_FIRMWARE_DIVIDED_DOWNLOAD_T) pvFwImageMapFile; + + if (prFwHead->u4Signature == MTK_WIFI_SIGNATURE && + prFwHead->u4CRC == wlanCRC32((PUINT_8) pvFwImageMapFile + u4CRCOffset, + u4FwImgLength - u4CRCOffset)) { + fgValidHead = TRUE; + } else { + fgValidHead = FALSE; + } + + /* 3b. engage divided firmware downloading */ + if (fgValidHead == TRUE) { + for (i = 0; i < prFwHead->u4NumOfEntries; i++) { +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if (wlanImageSectionDownloadAggregated(prAdapter, + prFwHead->arSection[i].u4DestAddr, + prFwHead->arSection[i].u4Length, + (PUINT_8) pvFwImageMapFile + + prFwHead->arSection[i].u4Offset) != + WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + } +#else + for (j = 0; j < prFwHead->arSection[i].u4Length; j += CMD_PKT_SIZE_FOR_IMAGE) { + if (j + CMD_PKT_SIZE_FOR_IMAGE < prFwHead->arSection[i].u4Length) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = prFwHead->arSection[i].u4Length - j; + + if (wlanImageSectionDownload(prAdapter, + prFwHead->arSection[i].u4DestAddr + j, + u4ImgSecSize, + (PUINT_8) pvFwImageMapFile + + prFwHead->arSection[i].u4Offset + j) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } +#endif + /* escape from loop if any pending error occurs */ + if (u4Status == WLAN_STATUS_FAILURE) + break; + } + } else +#endif +#if CFG_ENABLE_FW_DOWNLOAD_AGGREGATION + if (wlanImageSectionDownloadAggregated(prAdapter, + u4FwLoadAddr, + u4FwImgLength, + (PUINT_8) pvFwImageMapFile) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + } +#else + for (i = 0; i < u4FwImgLength; i += CMD_PKT_SIZE_FOR_IMAGE) { + if (i + CMD_PKT_SIZE_FOR_IMAGE < u4FwImgLength) + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + else + u4ImgSecSize = u4FwImgLength - i; + + if (wlanImageSectionDownload(prAdapter, + u4FwLoadAddr + i, + u4ImgSecSize, + (PUINT_8) pvFwImageMapFile + i) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "wlanImageSectionDownload failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } +#endif + + if (u4Status != WLAN_STATUS_SUCCESS) { + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + break; + } +#if !CFG_ENABLE_FW_DOWNLOAD_ACK + /* Send INIT_CMD_ID_QUERY_PENDING_ERROR command and wait for response */ + if (wlanImageQueryStatus(prAdapter) != WLAN_STATUS_SUCCESS) { + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + u4Status = WLAN_STATUS_FAILURE; + break; + } +#endif + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, prFwMappingHandle, pvFwImageMapFile); + + /* 4. send Wi-Fi Start command */ +#if CFG_OVERRIDE_FW_START_ADDRESS + wlanConfigWifiFunc(prAdapter, TRUE, kalGetFwStartAddress(prAdapter->prGlueInfo)); +#else + wlanConfigWifiFunc(prAdapter, FALSE, 0); +#endif +#endif /* if CFG_ENABLE_FW_DOWNLOAD */ + + /* 5. check Wi-Fi FW asserts ready bit */ + DBGLOG(NIC, TRACE, "wlanAdapterStart(): Waiting for Ready bit..\n"); + i = 0; + while (1) { + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4Value); + + if (u4Value & WCIR_WLAN_READY) { + DBGLOG(NIC, TRACE, "Ready bit asserted\n"); + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } else if (i >= CFG_RESPONSE_POLLING_TIMEOUT) { + DBGLOG(NIC, ERROR, "Waiting for Ready bit: Timeout\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + i++; + kalMsleep(10); + } + + if (u4Status == WLAN_STATUS_SUCCESS) { + /* 6.1 reset interrupt status */ + HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)(&u4WHISR)); + if (HAL_IS_TX_DONE_INTR(u4WHISR)) + HAL_READ_TX_RELEASED_COUNT(prAdapter, aucTxCount); + + /* 6.2 reset TX Resource for normal operation */ + nicTxResetResource(prAdapter); + + /* 6.3 Enable interrupt */ + nicEnableInterrupt(prAdapter); + + /* 6.4 Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + /* 6.5 indicate disconnection as default status */ + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE); + + /* MGMT Initialization */ + nicInitMGMT(prAdapter, NULL); + + } while (FALSE); + + if (u4Status != WLAN_STATUS_SUCCESS) + return FALSE; + else + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is used to set ACPI power mode to D3. +* +* @param prAdapter pointer to the Adapter handler +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i; + + ASSERT(prAdapter); + + /* 1. MGMT - unitialization */ + nicUninitMGMT(prAdapter); + + /* 2. Disable Interrupt */ + nicDisableInterrupt(prAdapter); + + /* 3. emit CMD_NIC_POWER_CTRL command packet */ + wlanSendNicPowerCtrlCmd(prAdapter, 1); + + /* 4. Clear Interrupt Status */ + i = 0; + while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) { + i++; + }; + + /* 5. Remove pending TX */ + nicTxRelease(prAdapter); + + /* 5.1 clear pending Security / Management Frames */ + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + /* 5.2 clear pending TX packet queued in glue layer */ + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 6. Set Onwership to F/W */ + nicpmSetFWOwn(prAdapter, FALSE); + + /* 7. Set variables */ + prAdapter->rAcpiState = ACPI_STATE_D3; + + return TRUE; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c new file mode 100644 index 0000000000000..ba4840414da85 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_rx.c @@ -0,0 +1,3782 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_rx.c#3 +*/ + +/*! \file nic_rx.c + \brief Functions that provide many rx-related functions + + This file includes the functions used to process RFB and dispatch RFBs to + the appropriate related rx functions for protocols. +*/ + +/* +** Log: nic_rx.c +** +** 08 31 2012 yuche.tsai +** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, +** one device reboots automatically with KE +** Fix possible KE when concurrent & disconnect. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 02 14 2012 cp.wu + * NULL + * remove another assertion by error message dump + * + * 01 05 2012 tsaiyuan.hsu + * [WCXRP00001157] [MT6620 Wi-Fi][FW][DRV] add timing measurement support for 802.11v + * add timing measurement support for 802.11v. + * + * 11 19 2011 yuche.tsai + * NULL + * Update RSSI for P2P. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 09 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for beacon timeout and sta aging timeout. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 10 21 2011 eddie.chen + * [WCXRP00001051] [MT6620 Wi-Fi][Driver/Fw] Adjust the STA aging timeout + * Add switch to ignore the STA aging timeout. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 08 26 2011 cp.wu + * [WCXRP00000958] [MT6620 Wi-Fi][Driver] Extend polling timeout from 25ms to 1sec due to RF calibration might took + * up to 600ms + * extend polling RX response timeout period from 25ms to 1000ms. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 27 2011 cp.wu + * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count + * correct comment. + * + * 07 27 2011 cp.wu + * [WCXRP00000876] [MT5931][Drver] Decide to retain according to currently available RX counter and QUE_MGT used count + * take use of QUE_MGT exported function to estimate currently RX buffer usage count. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 06 09 2011 tsaiyuan.hsu + * [WCXRP00000760] [MT5931 Wi-Fi][FW] Refine rxmHandleMacRxDone to reduce code size + * move send_auth at rxmHandleMacRxDone in firmware to driver to reduce code size. + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 05 05 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * add delay after whole-chip resetting for MT5931 E1 ASIC. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support for GO. + * + * 04 01 2011 tsaiyuan.hsu + * [WCXRP00000615] [MT 6620 Wi-Fi][Driver] Fix klocwork issues + * fix the klocwork issues, 57500, 57501, 57502 and 57503. + * + * 03 19 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Add beacon timeout support for WiFi Direct Network. + * + * 03 18 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * enable the Anti_piracy check at driver . + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after + * connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000419] [Volunteer Patch][MT6620/MT5931][Driver] Provide function of disconnect to target station for AAA + * module. + * Remove Station Record after Aging timeout. + * + * 02 10 2011 cp.wu + * [WCXRP00000434] [MT6620 Wi-Fi][Driver] Obsolete unused event packet handlers + * EVENT_ID_CONNECTION_STATUS has been obsoleted and no need to handle. + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add MLME deauthentication support for Hot-Spot mode. + * + * 02 09 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Adjust variable order. + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * . + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Remove comments. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 24 2011 cm.chang + * [WCXRP00000384] [MT6620 Wi-Fi][Driver][FW] Handle 20/40 action frame in AP mode and stop ampdu timer when sta_rec + * is freed + * Process received 20/40 coexistence action frame for AP mode + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * update beacon for NoA + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 27 2010 george.huang + * [WCXRP00000127] [MT6620 Wi-Fi][Driver] Add a registry to disable Beacon Timeout function for SQA test by using E1 EVB + * Support registry option for disable beacon lost detection. + * + * 10 20 2010 wh.su + * NULL + * add a cmd to reset the p2p key + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * fixed compilier error. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 23 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * eliminate reference of CFG_RESPONSE_MAX_PKT_SIZE + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + * associated + * release RX packet to packet pool when in RF test mode + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + @ associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 08 2010 cp.wu + * NULL + * use static memory pool for storing IEs of scanning result. + * + * 09 07 2010 yuche.tsai + * NULL + * Add a common buffer, store the IE of a P2P device in this common buffer. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 20 2010 cm.chang + * NULL + * Migrate RLM code to host from FW + * + * 08 20 2010 yuche.tsai + * NULL + * When enable WiFi Direct function, check each packet to tell which interface to indicate. + * + * 08 05 2010 yuche.tsai + * NULL + * Add P2P Device Discovery Function. + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 george.huang + * NULL + * handle event for updating NOA parameters indicated from FW + * + * 08 02 2010 yuche.tsai + * NULL + * Add support API for RX public action frame. + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 30 2010 cp.wu + * NULL + * 1) BoW wrapper: use definitions instead of hard-coded constant for error code + * 2) AIS-FSM: eliminate use of desired RF parameters, use prTargetBssDesc instead + * 3) add handling for RX_PKT_DESTINATION_HOST_WITH_FORWARD for GO-broadcast frames + * + * 07 26 2010 yuche.tsai + * + * Update Device Capability Bitmap & Group Capability Bitmap from 16 bits to 8 bits. + * + * 07 24 2010 wh.su + * + * .support the Wi-Fi RSN + * + * 07 23 2010 cp.wu + * + * add AIS-FSM handling for beacon timeout event. + * + * 07 21 2010 yuche.tsai + * + * Add P2P Scan & Scan Result Parsing & Saving. + * + * 07 19 2010 cm.chang + * + * Set RLM parameters and enable CNM channel manager + * + * 07 19 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration. + * Add Ad-Hoc support to AIS-FSM + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 15 2010 cp.wu + * + * sync. bluetooth-over-Wi-Fi interface to driver interface document v0.2.6. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill ucStaRecIdx into SW_RFB_T. + * + * 07 02 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) for event packet, no need to fill RFB. + * 2) when wlanAdapterStart() failed, no need to initialize state machines + * 3) after Beacon/ProbeResp parsing, corresponding BSS_DESC_T should be marked as IE-parsed + * + * 07 01 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implementation of DRV-SCN and related mailbox message handling. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * refine TX-DONE callback. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * implement TX_DONE callback path. + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add TX Done Event handle entry + * + * 06 21 2010 wh.su + * [WPD00003840][MT6620 5931] Security migration + * remove duplicate variable for migration. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * saa_fsm.c is migrated. + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add management dispatching function table. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) eliminate CFG_CMD_EVENT_VERSION_0_9 + * 2) when disconnected, indicate nic directly (no event is needed) + * + * 06 08 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * cnm_timer has been migrated. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * merge wlan_def.h. + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * sync with MT6620 driver for scan result replacement policy + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) integrate OID_GEN_NETWORK_LAYER_ADDRESSES with CMD_ID_SET_IP_ADDRESS + * 2) buffer statistics data for 2 seconds + * 3) use default value for adhoc parameters instead of 0 + * + * 05 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) do not take timeout mechanism for power mode oids + * 2) retrieve network type from connection status + * 3) after disassciation, set radio state to off + * 4) TCP option over IPv6 is supported + * + * 04 29 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * fixing the PMKID candicate indicate code. + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * basic implementation for EVENT_BT_OVER_WIFI + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 16 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * treat BUS access failure as kind of card removal. + * + * 04 14 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * nicRxProcessEvent packet doesn't access spin-lock directly from now on. + * + * 04 14 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * do not need to release the spin lock due to it is done inside nicGetPendingCmdInfo() + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add channel frequency <-> number conversion + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * 2) add KAPI for handling association info + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve Linux supplicant compliance + * + * 03 31 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl which may cause cmdinfo memory leak + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * rWlanInfo is modified before data is indicated to OS + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * rWlanInfo is modified before data is indicated to OS + * + * 03 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a temporary flag for integration with CMD/EVENT v0.9. + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * * the frequency is used for adhoc connection only + * * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * . + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * * + * + * 03 19 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add ACPI D0/D3 state switching support + * * * * * * * * * 2) use more formal way to handle interrupt when the status is retrieved from enhanced RX + * response + * + * 03 15 2010 kevin.huang + * [WPD00003820][MT6620 Wi-Fi] Modify the code for meet the WHQL test + * Add event for activate STA_RECORD_T + * + * 03 12 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct fgSetQuery/fgNeedResp check + * + * 03 11 2010 cp.wu + * [WPD00003821][BUG] Host driver stops processing RX packets from HIF RX0 + * add RX starvation warning debug message controlled by CFG_HIF_RX_STARVATION_WARNING + * + * 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) the use of prPendingOid revised, all accessing are now protected by spin lock + * * * * 2) ensure wlanReleasePendingOid will clear all command queues + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * move EVENT_ID_ASSOC_INFO from nic_rx.c to gl_kal_ndis_51.c + * * 'cause it involves OS dependent data structure handling + * + * 02 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * correct behavior to prevent duplicated RX handling for RX0_DONE and RX1_DONE + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Updated API interfaces for qmHandleEventRxAddBa() and qmHandleEventRxDelBa() + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement host-side firmware download logic + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * * 4) nicRxWaitResponse() revised + * * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 01 27 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * . + * + * 01 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * implement following 802.11 OIDs: + * * * * * * OID_802_11_RSSI, + * * * * * * OID_802_11_RSSI_TRIGGER, + * * * * * * OID_802_11_STATISTICS, + * * * * * * OID_802_11_DISASSOCIATE, + * * * * * * OID_802_11_POWER_MODE + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * * 2) add 4 counter for recording aggregation statistics + * + * 12 23 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add a precheck: if free sw rfb is not enough, do not invoke read transactionu1rwduu`wvpghlqg|fu+rp + * + * 12 22 2009 cp.wu + * [WPD00003809][Bug] Host driver will crash when processing reordered MSDUs + * The root cause is pointer accessing by mistake. After dequeued from reordering-buffer, handling logic should access + * returned pointer instead of pointer which has been passed in before. +** \main\maintrunk.MT6620WiFiDriver_Prj\58 2009-12-17 13:40:33 GMT mtk02752 +** always update prAdapter->rSDIOCtrl when enhanced response is read by RX +** \main\maintrunk.MT6620WiFiDriver_Prj\57 2009-12-16 18:01:38 GMT mtk02752 +** if interrupt enhanced response is fetched by RX enhanced response, RX needs to invoke interrupt handlers too +** \main\maintrunk.MT6620WiFiDriver_Prj\56 2009-12-16 14:16:52 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\55 2009-12-15 20:03:12 GMT mtk02752 +** ASSERT when RX FreeSwRfb is not enough +** \main\maintrunk.MT6620WiFiDriver_Prj\54 2009-12-15 17:01:29 GMT mtk02752 +** when CFG_SDIO_RX_ENHANCE is enabled, after enhanced response is read, rx procedure should process +** 1) TX_DONE_INT 2) D2H INT as well +** \main\maintrunk.MT6620WiFiDriver_Prj\53 2009-12-14 20:45:28 GMT mtk02752 +** when CFG_SDIO_RX_ENHANCE is set, TC counter must be updated each time RX enhance response is read +** +** \main\maintrunk.MT6620WiFiDriver_Prj\52 2009-12-14 11:34:16 GMT mtk02752 +** correct a trivial logic issue +** \main\maintrunk.MT6620WiFiDriver_Prj\51 2009-12-14 10:28:25 GMT mtk02752 +** add a protection to avoid out-of-boundary access +** \main\maintrunk.MT6620WiFiDriver_Prj\50 2009-12-10 16:55:18 GMT mtk02752 +** code clean +** \main\maintrunk.MT6620WiFiDriver_Prj\49 2009-12-09 14:06:47 GMT MTK02468 +** Added parsing event packets with EVENT_ID_RX_ADDBA or EVENT_ID_RX_DELBA +** \main\maintrunk.MT6620WiFiDriver_Prj\48 2009-12-08 17:37:51 GMT mtk02752 +** handle EVENT_ID_TEST_STATUS as well +** \main\maintrunk.MT6620WiFiDriver_Prj\47 2009-12-04 17:59:11 GMT mtk02752 +** to pass free-build compilation check +** \main\maintrunk.MT6620WiFiDriver_Prj\46 2009-12-04 12:09:52 GMT mtk02752 +** correct trivial mistake +** \main\maintrunk.MT6620WiFiDriver_Prj\45 2009-12-04 11:53:37 GMT mtk02752 +** all API should be compilable under SD1_SD3_DATAPATH_INTEGRATION == 0 +** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-03 16:19:48 GMT mtk01461 +** Fix the Connected Event +** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-11-30 10:56:18 GMT mtk02752 +** 1st DW of WIFI_EVENT_T is shared with HIF_RX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-11-30 10:11:27 GMT mtk02752 +** implement replacement for bss scan result +** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-11-27 11:08:05 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-11-26 09:38:59 GMT mtk02752 +** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-11-26 09:29:40 GMT mtk02752 +** enable packet forwarding path (for AP mode) +** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-11-25 21:37:00 GMT mtk02752 +** sync. with EVENT_SCAN_RESULT_T change, and add an assert for checking event size +** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-25 20:17:41 GMT mtk02752 +** fill HIF_TX_HEADER_T.u2SeqNo +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-25 18:18:57 GMT mtk02752 +** buffer scan result to prGlueInfo->rWlanInfo.arScanResult directly. +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-24 22:42:45 GMT mtk02752 +** add nicRxAddScanResult() to prepare to handle SCAN_RESULT event (not implemented yet) +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-24 20:51:41 GMT mtk02752 +** integrate with SD1's data path API +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-24 19:56:17 GMT mtk02752 +** adopt P_HIF_RX_HEADER_T in new path +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-23 20:31:21 GMT mtk02752 +** payload to send into pfCmdDoneHandler() will not include WIFI_EVENT_T +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-23 17:51:34 GMT mtk02752 +** when event packet corresponding to some pendingOID is received, pendingOID should be cleared +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 14:46:54 GMT mtk02752 +** implement nicRxProcessEventPacket() +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-17 22:40:54 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-16 21:48:22 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION data path handling +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-16 15:41:18 GMT mtk01084 +** modify the length to be read in emu mode +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-13 17:00:12 GMT mtk02752 +** add blank function for event packet +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-13 13:54:24 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-11 14:41:51 GMT mtk02752 +** fix typo +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-11 14:33:46 GMT mtk02752 +** add protection when there is no packet avilable +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 12:33:36 GMT mtk02752 +** add RX1 read path for aggregated/enhanced/normal packet read procedures +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-11 10:36:18 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-11-04 14:11:08 GMT mtk01084 +** modify lines in RX aggregation +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-30 18:17:23 GMT mtk01084 +** modify RX aggregation handling +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-29 19:56:12 GMT mtk01084 +** modify HAL part +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-10-23 16:08:34 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-10-13 21:59:20 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-10-02 13:59:08 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-05-21 23:39:05 GMT mtk01461 +** Fix the paste error of RX STATUS in OOB of HIF Loopback CTRL +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-05-20 12:25:32 GMT mtk01461 +** Fix process of Read Done, and add u4MaxEventBufferLen to nicRxWaitResponse() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-05-18 21:13:18 GMT mtk01426 +** Fixed compiler error +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-05-18 21:05:29 GMT mtk01426 +** Fixed nicRxSDIOAggReceiveRFBs() ASSERT issue +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-28 10:38:43 GMT mtk01461 +** Fix RX STATUS is DW align for SDIO_STATUS_ENHANCE mode and refine nicRxSDIOAggeceiveRFBs() for RX Aggregation +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-22 09:12:17 GMT mtk01461 +** Fix nicRxProcessHIFLoopbackPacket(), the size of HIF CTRL LENGTH field is 1 byte +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-14 15:51:26 GMT mtk01426 +** Update RX OOB Setting +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-03 14:58:58 GMT mtk01426 +** Fixed logical error +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-04-01 10:58:31 GMT mtk01461 +** Rename the HIF_PKT_TYPE_DATA +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 21:51:18 GMT mtk01461 +** Fix u4HeaderOffset in nicRxProcessHIFLoopbackPacket() +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 21:02:58 GMT mtk01426 +** Add CFG_SDIO_RX_ENHANCE and CFG_HIF_LOOPBACK support +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-17 20:20:59 GMT mtk01426 +** Add nicRxWaitResponse function +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:01 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#ifndef LINUX +#include +#else +#include +#endif + +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include +#include +#include +#include "gl_cfg80211.h" +#include "gl_vendor.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define RX_RESPONSE_TIMEOUT (1000) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if CFG_MGMT_FRAME_HANDLING +static PROCESS_RX_MGT_FUNCTION apfnProcessRxMgtFrame[MAX_NUM_OF_FC_SUBTYPES] = { +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0000: Association request */ +#else + NULL, /* subtype 0000: Association request */ +#endif /* CFG_SUPPORT_AAA */ + saaFsmRunEventRxAssoc, /* subtype 0001: Association response */ +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0010: Reassociation request */ +#else + NULL, /* subtype 0010: Reassociation request */ +#endif /* CFG_SUPPORT_AAA */ + saaFsmRunEventRxAssoc, /* subtype 0011: Reassociation response */ +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) + bssProcessProbeRequest, /* subtype 0100: Probe request */ +#else + NULL, /* subtype 0100: Probe request */ +#endif /* CFG_SUPPORT_ADHOC */ + scanProcessBeaconAndProbeResp, /* subtype 0101: Probe response */ + NULL, /* subtype 0110: reserved */ + NULL, /* subtype 0111: reserved */ + scanProcessBeaconAndProbeResp, /* subtype 1000: Beacon */ + NULL, /* subtype 1001: ATIM */ + saaFsmRunEventRxDisassoc, /* subtype 1010: Disassociation */ + authCheckRxAuthFrameTransSeq, /* subtype 1011: Authentication */ + saaFsmRunEventRxDeauth, /* subtype 1100: Deauthentication */ + nicRxProcessActionFrame, /* subtype 1101: Action */ + NULL, /* subtype 1110: reserved */ + NULL /* subtype 1111: reserved */ +}; +#endif + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief Initialize the RFBs +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxInitialize(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucMemHandle; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + UINT_32 i; + + DEBUGFUNC("nicRxInitialize"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + + /* 4 <0> Clear allocated memory. */ + kalMemZero((PVOID) prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize); + + /* 4 <1> Initialize the RFB lists */ + QUEUE_INITIALIZE(&prRxCtrl->rFreeSwRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rReceivedRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rIndicatedRfbList); + + pucMemHandle = prRxCtrl->pucRxCached; + for (i = CFG_RX_MAX_PKT_NUM; i != 0; i--) { + prSwRfb = (P_SW_RFB_T) pucMemHandle; + + nicRxSetupRFB(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + + pucMemHandle += ALIGN_4(sizeof(SW_RFB_T)); + } + + ASSERT(prRxCtrl->rFreeSwRfbList.u4NumElem == CFG_RX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization function */ + ASSERT((ULONG) (pucMemHandle - prRxCtrl->pucRxCached) == prRxCtrl->u4RxCachedSize); + + /* 4 <2> Clear all RX counters */ + RX_RESET_ALL_CNTS(prRxCtrl); + +#if CFG_SDIO_RX_AGG + prRxCtrl->pucRxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, CFG_SDIO_MAX_RX_AGG_NUM); +#else + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, 1); +#endif + +#if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum = 0; + prRxCtrl->u4TotalRxPacketNum = 0; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt = 0; + prRxCtrl->u4DequeuedCnt = 0; +#endif + +} /* end of nicRxInitialize() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Uninitialize the RFBs +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxUninitialize(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + nicRxFlush(prAdapter); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (prSwRfb) { + if (prSwRfb->pvPacket) + kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); + prSwRfb->pvPacket = NULL; + } else { + break; + } + } while (TRUE); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (prSwRfb) { + if (prSwRfb->pvPacket) + kalPacketFree(prAdapter->prGlueInfo, prSwRfb->pvPacket); + prSwRfb->pvPacket = NULL; + } else { + break; + } + } while (TRUE); + +} /* end of nicRxUninitialize() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Fill RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb specify the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_HIF_RX_HEADER_T prHifRxHdr; + + UINT_32 u4PktLen = 0; + UINT_32 u4MacHeaderLen; + UINT_32 u4HeaderOffset; + + DEBUGFUNC("nicRxFillRFB"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + u4PktLen = prHifRxHdr->u2PacketLen; + + u4HeaderOffset = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); + u4MacHeaderLen = (UINT_32) (prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_LEN) + >> HIF_RX_HDR_HEADER_LEN_OFFSET; + + /* DBGLOG(RX, TRACE, ("u4HeaderOffset = %d, u4MacHeaderLen = %d\n", */ + /* u4HeaderOffset, u4MacHeaderLen)); */ + + prSwRfb->u2HeaderLen = (UINT_16) u4MacHeaderLen; + prSwRfb->pvHeader = (PUINT_8) prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; + prSwRfb->u2PacketLen = (UINT_16) (u4PktLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); + + /* DBGLOG(RX, TRACE, ("Dump Rx packet, u2PacketLen = %d\n", prSwRfb->u2PacketLen)); */ + /* DBGLOG_MEM8(RX, TRACE, prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ + +#if 0 + if (prHifRxHdr->ucReorder & HIF_RX_HDR_80211_HEADER_FORMAT) { + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_802_11_FORMAT; + DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_802_11_FORMAT\n"); + } + + if (prHifRxHdr->ucReorder & HIF_RX_HDR_DO_REORDER) { + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_DO_REORDERING; + DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_DO_REORDERING\n"); + + /* Get Seq. No and TID, Wlan Index info */ + if (prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_BAR_FRAME) { + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_BAR_FRAME; + DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_BAR_FRAME\n"); + } + + prSwRfb->u2SSN = prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_SEQ_NO_MASK; + prSwRfb->ucTid = (UINT_8) ((prHifRxHdr->u2SeqNoTid & HIF_RX_HDR_TID_MASK) + >> HIF_RX_HDR_TID_OFFSET); + DBGLOG(RX, TRACE, "u2SSN = %d, ucTid = %d\n", prSwRfb->u2SSN, prSwRfb->ucTid); + } + + if (prHifRxHdr->ucReorder & HIF_RX_HDR_WDS) { + prSwRfb->u4HifRxHdrFlag |= HIF_RX_HDR_FLAG_AMP_WDS; + DBGLOG(RX, TRACE, "HIF_RX_HDR_FLAG_AMP_WDS\n"); + } +#endif +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 +/*----------------------------------------------------------------------------*/ +/*! +* @brief Fill checksum status in RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* @param u4TcpUdpIpCksStatus specify the Checksum status +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, IN UINT_32 u4TcpUdpIpCksStatus) +{ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (prAdapter->u4CSUMFlags != CSUM_NOT_SUPPORTED) { + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv4) { /* IPv4 packet */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_IP) { /* IP packet csum failed */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_SUCCESS; + } + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; + } + } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv6) { /* IPv6 packet */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_SUCCESS; + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP packet */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_TCP) { /* TCP packet csum failed */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_SUCCESS; + } + } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_UDP) { /* UDP packet */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_UDP) { /* UDP packet csum failed */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_SUCCESS; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + } + } + +} +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process packet doesn't need to do buffer reordering +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + BOOLEAN fgIsRetained = FALSE; + UINT_32 u4CurrentRxBufferCount; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL; + + DEBUGFUNC("nicRxProcessPktWithoutReorder"); + /* DBGLOG(RX, TRACE, ("\n")); */ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + u4CurrentRxBufferCount = prRxCtrl->rFreeSwRfbList.u4NumElem; + /* QM USED = $A, AVAILABLE COUNT = $B, INDICATED TO OS = $C + * TOTAL = $A + $B + $C + * + * Case #1 (Retain) + * ------------------------------------------------------- + * $A + $B < THRESHOLD := $A + $B + $C < THRESHOLD + $C := $TOTAL - THRESHOLD < $C + * => $C used too much, retain + * + * Case #2 (Non-Retain) + * ------------------------------------------------------- + * $A + $B > THRESHOLD := $A + $B + $C > THRESHOLD + $C := $TOTAL - THRESHOLD > $C + * => still available for $C to use + * + */ + fgIsRetained = (((u4CurrentRxBufferCount + + qmGetRxReorderQueuedBufferCount(prAdapter) + + prTxCtrl->i4PendingFwdFrameCount) < CFG_RX_RETAINED_PKT_THRESHOLD) ? TRUE : FALSE); + + /* DBGLOG(RX, INFO, ("fgIsRetained = %d\n", fgIsRetained)); */ + + if (kalProcessRxPacket(prAdapter->prGlueInfo, + prSwRfb->pvPacket, + prSwRfb->pvHeader, + (UINT_32) prSwRfb->u2PacketLen, fgIsRetained, prSwRfb->aeCSUM) != WLAN_STATUS_SUCCESS) { + DBGLOG(RX, ERROR, "kalProcessRxPacket return value != WLAN_STATUS_SUCCESS\n"); + ASSERT(0); + + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec) { +#if CFG_ENABLE_WIFI_DIRECT + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX && prAdapter->fgIsP2PRegistered == TRUE) + GLUE_SET_PKT_FLAG_P2P(prSwRfb->pvPacket); +#endif +#if CFG_ENABLE_BT_OVER_WIFI + if (prStaRec->ucNetTypeIndex == NETWORK_TYPE_BOW_INDEX) + GLUE_SET_PKT_FLAG_PAL(prSwRfb->pvPacket); +#endif + + /* record the count to pass to os */ + STATS_RX_PASS2OS_INC(prStaRec, prSwRfb); + } + prRxCtrl->apvIndPacket[prRxCtrl->ucNumIndPacket] = prSwRfb->pvPacket; + prRxCtrl->ucNumIndPacket++; + + if (fgIsRetained) { + prRxCtrl->apvRetainedPacket[prRxCtrl->ucNumRetainedPacket] = prSwRfb->pvPacket; + prRxCtrl->ucNumRetainedPacket++; + /* TODO : error handling of nicRxSetupRFB */ + nicRxSetupRFB(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + } else { + prSwRfb->pvPacket = NULL; + nicRxReturnRFB(prAdapter, prSwRfb); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process forwarding data packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_MSDU_INFO_T prMsduInfo, prRetMsduInfoList; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessForwardPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rFreeMsduInfoList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if (prMsduInfo && kalProcessRxPacket(prAdapter->prGlueInfo, + prSwRfb->pvPacket, + prSwRfb->pvHeader, + (UINT_32) prSwRfb->u2PacketLen, + prRxCtrl->rFreeSwRfbList.u4NumElem < + CFG_RX_RETAINED_PKT_THRESHOLD ? TRUE : FALSE, + prSwRfb->aeCSUM) == WLAN_STATUS_SUCCESS) { + + prMsduInfo->eSrc = TX_PACKET_FORWARDING; + /* pack into MSDU_INFO_T */ + nicTxFillMsduInfo(prAdapter, prMsduInfo, (P_NATIVE_PACKET) (prSwRfb->pvPacket)); + /* Overwrite the ucNetworkType */ + prMsduInfo->ucNetworkType = HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr); + + /* release RX buffer (to rIndicatedRfbList) */ + prSwRfb->pvPacket = NULL; + nicRxReturnRFB(prAdapter, prSwRfb); + + /* increase forward frame counter */ + GLUE_INC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + + /* send into TX queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfoList = qmEnqueueTxPackets(prAdapter, prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prRetMsduInfoList != NULL) { /* TX queue refuses queuing the packet */ + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfoList); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfoList); + } + /* indicate service thread for sending */ + if (prTxCtrl->i4PendingFwdFrameCount > 0) + kalSetEvent(prAdapter->prGlueInfo); + } else /* no TX resource */ + nicRxReturnRFB(prAdapter, prSwRfb); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process broadcast data packet for both host and forwarding +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_SW_RFB_T prSwRfbDuplicated; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + P_HIF_RX_HEADER_T prHifRxHdr; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessGOBroadcastPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + ASSERT(CFG_NUM_OF_QM_RX_PKT_NUM >= 16); + + if (prRxCtrl->rFreeSwRfbList.u4NumElem + >= (CFG_RX_MAX_PKT_NUM - (CFG_NUM_OF_QM_RX_PKT_NUM - 16 /* Reserved for others */))) { + + /* 1. Duplicate SW_RFB_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfbDuplicated, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (prSwRfbDuplicated) { + kalMemCopy(prSwRfbDuplicated->pucRecvBuff, + prSwRfb->pucRecvBuff, ALIGN_4(prHifRxHdr->u2PacketLen + HIF_RX_HW_APPENDED_LEN)); + + prSwRfbDuplicated->ucPacketType = HIF_RX_PKT_TYPE_DATA; + prSwRfbDuplicated->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); + nicRxFillRFB(prAdapter, prSwRfbDuplicated); + + /* 2. Modify eDst */ + prSwRfbDuplicated->eDst = RX_PKT_DESTINATION_FORWARD; + + /* 4. Forward */ + nicRxProcessForwardPkt(prAdapter, prSwRfbDuplicated); + } + } else { + DBGLOG(RX, WARN, "Stop to forward BMC packet due to less free Sw Rfb %u\n", + prRxCtrl->rFreeSwRfbList.u4NumElem); + } + + /* 3. Indicate to host */ + prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process HIF data packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prRetSwRfb, prNextSwRfb; + P_HIF_RX_HEADER_T prHifRxHdr; + P_STA_RECORD_T prStaRec; + BOOLEAN fIsDummy = FALSE; + + DEBUGFUNC("nicRxProcessDataPacket"); + /* DBGLOG(RX, TRACE, ("\n")); */ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prHifRxHdr = prSwRfb->prHifRxHdr; + prRxCtrl = &prAdapter->rRxCtrl; + + fIsDummy = (prHifRxHdr->u2PacketLen >= 12) ? FALSE : TRUE; + + nicRxFillRFB(prAdapter, prSwRfb); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + { + UINT_32 u4TcpUdpIpCksStatus; + + u4TcpUdpIpCksStatus = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); + nicRxFillChksumStatus(prAdapter, prSwRfb, u4TcpUdpIpCksStatus); + + } +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + prStaRec = cnmGetStaRecByIndex(prAdapter, prHifRxHdr->ucStaRecIdx); + if (secCheckClassError(prAdapter, prSwRfb, prStaRec) == TRUE && prAdapter->fgTestMode == FALSE) { +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt++; +#endif + prRetSwRfb = qmHandleRxPackets(prAdapter, prSwRfb); + if (prRetSwRfb != NULL) { + do { + /* save next first */ + prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prRetSwRfb); + if (fIsDummy == TRUE) { + nicRxReturnRFB(prAdapter, prRetSwRfb); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + DBGLOG(RX, WARN, "Drop Dummy Packets"); + + } else { + switch (prRetSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: +#if ARP_MONITER_ENABLE + if (IS_STA_IN_AIS(prStaRec)) + qmHandleRxArpPackets(prAdapter, prRetSwRfb); +#endif + nicRxProcessPktWithoutReorder(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + nicRxProcessForwardPkt(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + nicRxProcessGOBroadcastPkt(prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + nicRxReturnRFB(prAdapter, prRetSwRfb); + RX_INC_CNT(prRxCtrl, RX_DST_NULL_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + break; + + default: + break; + } + } +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + prRetSwRfb = prNextSwRfb; + } while (prRetSwRfb); + } + } else { + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process HIF event packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ + +UINT_8 nicRxProcessGSCNEvent(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_WIFI_EVENT_T prEvent; + P_GLUE_INFO_T prGlueInfo; + struct sk_buff *skb; + struct wiphy *wiphy; + + UINT_32 real_num = 0; + + P_EVENT_GSCAN_SCAN_AVAILABLE_T prEventGscnAvailable; + P_EVENT_GSCAN_RESULT_T prEventBuffer; + P_WIFI_GSCAN_RESULT_T prEventGscnResult; + INT_32 i4Status = -EINVAL; + struct nlattr *attr; + UINT_32 scan_id; + UINT_8 scan_flag; + P_EVENT_GSCAN_CAPABILITY_T prEventGscnCapbiblity; + P_EVENT_GSCAN_SCAN_COMPLETE_T prEventGscnScnDone; + P_WIFI_GSCAN_RESULT_T prEventGscnFullResult; + P_PARAM_WIFI_GSCAN_RESULT prParamGscnFullResult; + P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnSignificantChange; + P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T prEventGscnGeofenceFound; + + P_PARAM_WIFI_GSCAN_RESULT prResults; + + DEBUGFUNC("nicRxProcessGSCNEvent"); + /* DBGLOG(RX, TRACE, ("\n")); */ + + DBGLOG(SCN, INFO, "nicRxProcessGSCNEvent\n"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; + prGlueInfo = prAdapter->prGlueInfo; + + /* Push the data to the skb */ + wiphy = priv_to_wiphy(prGlueInfo); + + /* prGlueInfo-> */ + + /* Event Handling */ + switch (prEvent->ucEID) { + case EVENT_ID_GSCAN_SCAN_AVAILABLE: + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_AVAILABLE\n"); + + prEventGscnAvailable = (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer); + memcpy(prEventGscnAvailable, (P_EVENT_GSCAN_SCAN_AVAILABLE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SCAN_AVAILABLE_T)); + + mtk_cfg80211_vendor_event_scan_results_available(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, + prEventGscnAvailable->u2Num); + } + break; + + case EVENT_ID_GSCAN_RESULT: + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_RESULT 2\n"); + + prEventBuffer = (P_EVENT_GSCAN_RESULT_T) (prEvent->aucBuffer); + prEventGscnResult = prEventBuffer->rResult; +/* + the following event struct should moved to kal and use the kal api to avoid future porting effort + +*/ + scan_id = prEventBuffer->u2ScanId; + scan_flag = prEventBuffer->u2ScanFlags; + real_num = prEventBuffer->u2NumOfResults; + + DBGLOG(SCN, INFO, "scan_id=%d, scan_flag =%d, real_num=%d\r\n", scan_id, scan_flag, real_num); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num); + if (!skb) { + DBGLOG(RX, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); + return -ENOMEM; + } + + attr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS); + /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_SCAN_ID, scan_id);*/ + { + unsigned int __tmp = scan_id; + + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_ID, sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, 1);*/ + { + unsigned char __tmp = 1; + + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, sizeof(u8), &__tmp) < 0)) + goto nla_put_failure; + } + /*NLA_PUT_U32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, real_num);*/ + { + unsigned int __tmp = real_num; + + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + prResults = (P_PARAM_WIFI_GSCAN_RESULT) prEventGscnResult; + if (prResults) + DBGLOG(SCN, INFO, "ssid=%s, rssi=%d, channel=%d \r\n", + prResults->ssid, prResults->rssi, prResults->channel); + /*NLA_PUT(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, sizeof(PARAM_WIFI_GSCAN_RESULT) * real_num, + prResults);*/ + + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS, + sizeof(PARAM_WIFI_GSCAN_RESULT)*real_num, prResults) < 0)) + goto nla_put_failure; + + DBGLOG(SCN, INFO, "NLA_PUT scan results over\t"); + + if (attr) + nla_nest_end(skb, attr); + /* report_events=1 */ + /*NLA_PUT_U8(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, 1);*/ + { + unsigned char __tmp = 1; + + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + + i4Status = cfg80211_vendor_cmd_reply(skb); + skb = NULL; + DBGLOG(SCN, INFO, " i4Status %d\n", i4Status); + } + break; + + case EVENT_ID_GSCAN_CAPABILITY: + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_CAPABILITY\n"); + + prEventGscnCapbiblity = (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer); + memcpy(prEventGscnCapbiblity, (P_EVENT_GSCAN_CAPABILITY_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_CAPABILITY_T)); + + mtk_cfg80211_vendor_get_gscan_capabilities(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, + prEventGscnCapbiblity, sizeof(EVENT_GSCAN_CAPABILITY_T)); + } + break; + + case EVENT_ID_GSCAN_SCAN_COMPLETE: + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_SCAN_COMPLETE\n"); + prEventGscnScnDone = (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer); + memcpy(prEventGscnScnDone, (P_EVENT_GSCAN_SCAN_COMPLETE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SCAN_COMPLETE_T)); + + mtk_cfg80211_vendor_event_complete_scan(wiphy, prGlueInfo->prDevHandler->ieee80211_ptr, + prEventGscnScnDone->ucScanState); + } + break; + + case EVENT_ID_GSCAN_FULL_RESULT: + { + DBGLOG(SCN, INFO, "EVENT_ID_GSCAN_FULL_RESULT\n"); + + prEventGscnFullResult = kalMemAlloc(sizeof(WIFI_GSCAN_RESULT_T), VIR_MEM_TYPE); + if (prEventGscnFullResult) + memcpy(prEventGscnFullResult, (P_WIFI_GSCAN_RESULT_T) (prEvent->aucBuffer), + sizeof(WIFI_GSCAN_RESULT_T)); + + prParamGscnFullResult = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_RESULT), VIR_MEM_TYPE); + if (prEventGscnFullResult && prParamGscnFullResult) { + kalMemZero(prParamGscnFullResult, sizeof(PARAM_WIFI_GSCAN_RESULT)); + memcpy(prParamGscnFullResult, prEventGscnFullResult, sizeof(WIFI_GSCAN_RESULT_T)); + + mtk_cfg80211_vendor_event_full_scan_results(wiphy, + prGlueInfo->prDevHandler->ieee80211_ptr, + prParamGscnFullResult, + sizeof(PARAM_WIFI_GSCAN_RESULT)); + } + } + break; + + case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: + { + prEventGscnSignificantChange = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); + memcpy(prEventGscnSignificantChange, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); + } + break; + + case EVENT_ID_GSCAN_GEOFENCE_FOUND: + { + prEventGscnGeofenceFound = (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer); + memcpy(prEventGscnGeofenceFound, (P_EVENT_GSCAN_SIGNIFICANT_CHANGE_T) (prEvent->aucBuffer), + sizeof(EVENT_GSCAN_SIGNIFICANT_CHANGE_T)); + } + break; + + default: + DBGLOG(SCN, INFO, "not GSCN event ????\n"); + break; + } + + DBGLOG(SCN, INFO, "Done with GSCN event handling\n"); + return real_num; /* cfg80211_vendor_cmd_reply(skb); */ + +nla_put_failure: + if (skb != NULL) + kfree_skb(skb); + DBGLOG(SCN, INFO, "nla_put_failure\n"); + return 0; /* cfg80211_vendor_cmd_reply(skb); */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process HIF event packet +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + P_WIFI_EVENT_T prEvent; + P_GLUE_INFO_T prGlueInfo; + + DEBUGFUNC("nicRxProcessEventPacket"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; + prGlueInfo = prAdapter->prGlueInfo; + + DBGLOG(RX, EVENT, "prEvent->ucEID = 0x%02x\n", prEvent->ucEID); + /* Event Handling */ + switch (prEvent->ucEID) { + case EVENT_ID_CMD_RESULT: + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + P_EVENT_CMD_RESULT prCmdResult; + + prCmdResult = (P_EVENT_CMD_RESULT) ((PUINT_8) prEvent + EVENT_HDR_SIZE); + + /* CMD_RESULT should be only in response to Set commands */ + ASSERT(prCmdInfo->fgSetQuery == FALSE || prCmdInfo->fgNeedResp == TRUE); + + if (prCmdResult->ucStatus == 0) { /* success */ + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + } else if (prCmdInfo->fgIsOid == TRUE) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + } else if (prCmdResult->ucStatus == 1) { /* reject */ + if (prCmdInfo->fgIsOid == TRUE) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); + } else if (prCmdResult->ucStatus == 2) { /* unknown CMD */ + if (prCmdInfo->fgIsOid == TRUE) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_NOT_SUPPORTED); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + +#if 0 + case EVENT_ID_CONNECTION_STATUS: + /* OBSELETE */ + { + P_EVENT_CONNECTION_STATUS prConnectionStatus; + + prConnectionStatus = (P_EVENT_CONNECTION_STATUS) (prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_CONNECTION_STATUS = %d\n", prConnectionStatus->ucMediaStatus); + if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_DISCONNECTED) { + /* disconnected */ + if (kalGetMediaStateIndicated(prGlueInfo) != PARAM_MEDIA_STATE_DISCONNECTED) { + + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + } else if (prConnectionStatus->ucMediaStatus == PARAM_MEDIA_STATE_CONNECTED) { + /* connected */ + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + + /* fill information for association result */ + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = prConnectionStatus->ucSsidLen; + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prConnectionStatus->aucSsid, prConnectionStatus->ucSsidLen); + + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prConnectionStatus->aucBssid, MAC_ADDR_LEN); + + /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.u4Privacy = prConnectionStatus->ucEncryptStatus; + prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ + /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse = PARAM_NETWORK_TYPE_AUTOMODE; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod + = prConnectionStatus->u2BeaconPeriod; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow + = prConnectionStatus->u2ATIMWindow; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig + = prConnectionStatus->u4FreqInKHz; + prAdapter->rWlanInfo.ucNetworkType = prConnectionStatus->ucNetworkType; + + switch (prConnectionStatus->ucInfraMode) { + case 0: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_IBSS; + break; + case 1: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_INFRA; + break; + case 2: + default: + prAdapter->rWlanInfo.rCurrBssId.eOpMode = NET_TYPE_AUTO_SWITCH; + break; + } + /* always indicate to OS according to MSDN (re-association/roaming) */ + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); + } + } + break; + + case EVENT_ID_SCAN_RESULT: + /* OBSELETE */ + break; +#endif + + case EVENT_ID_RX_ADDBA: + /* The FW indicates that an RX BA agreement will be established */ + qmHandleEventRxAddBa(prAdapter, prEvent); + break; + + case EVENT_ID_RX_DELBA: + /* The FW indicates that an RX BA agreement has been deleted */ + qmHandleEventRxDelBa(prAdapter, prEvent); + break; + + case EVENT_ID_LINK_QUALITY: +#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY + if (prEvent->u2PacketLen == EVENT_HDR_SIZE + sizeof(EVENT_LINK_QUALITY_EX)) { + P_EVENT_LINK_QUALITY_EX prLqEx = (P_EVENT_LINK_QUALITY_EX) (prEvent->aucBuffer); + + if (prLqEx->ucIsLQ0Rdy) + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); + if (prLqEx->ucIsLQ1Rdy) + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_P2P_INDEX, (P_EVENT_LINK_QUALITY) prLqEx); + } else { + /* For old FW, P2P may invoke link quality query, and make driver flag becone TRUE. */ + DBGLOG(P2P, WARN, "Old FW version, not support P2P RSSI query.\n"); + + /* Must not use NETWORK_TYPE_P2P_INDEX, cause the structure is mismatch. */ + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, + (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); + } +#else + nicUpdateLinkQuality(prAdapter, NETWORK_TYPE_AIS_INDEX, (P_EVENT_LINK_QUALITY) (prEvent->aucBuffer)); +#endif + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + else if (prCmdInfo->fgIsOid) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +#ifndef LINUX + if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_GREATER && + prAdapter->rWlanInfo.rRssiTriggerValue >= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), + sizeof(PARAM_RSSI)); + } else if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_LESS + && prAdapter->rWlanInfo.rRssiTriggerValue <= (PARAM_RSSI) (prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID)&(prAdapter->rWlanInfo.rRssiTriggerValue), + sizeof(PARAM_RSSI)); + } +#endif + + break; + + case EVENT_ID_MIC_ERR_INFO: + { + P_EVENT_MIC_ERR_INFO prMicError; + /* P_PARAM_AUTH_EVENT_T prAuthEvent; */ + P_STA_RECORD_T prStaRec; + + DBGLOG(RSN, EVENT, "EVENT_ID_MIC_ERR_INFO\n"); + + prMicError = (P_EVENT_MIC_ERR_INFO) (prEvent->aucBuffer); + prStaRec = cnmGetStaRecByAddress(prAdapter, + (UINT_8) NETWORK_TYPE_AIS_INDEX, + prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + ASSERT(prStaRec); + + if (prStaRec) + rsnTkipHandleMICFailure(prAdapter, prStaRec, (BOOLEAN) prMicError->u4Flags); + else + DBGLOG(RSN, WARN, "No STA rec!!\n"); +#if 0 + prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; + + /* Status type: Authentication Event */ + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; + + /* Authentication request */ + prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); + kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, + (PVOID) prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + /* whsu:Todo? */PARAM_MAC_ADDR_LEN); + + if (prMicError->u4Flags != 0) + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; + else + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); +#endif + } + break; + + case EVENT_ID_ASSOC_INFO: + { + P_EVENT_ASSOC_INFO prAssocInfo; + + prAssocInfo = (P_EVENT_ASSOC_INFO) (prEvent->aucBuffer); + + kalHandleAssocInfo(prAdapter->prGlueInfo, prAssocInfo); + } + break; + + case EVENT_ID_802_11_PMKID: + { + P_PARAM_AUTH_EVENT_T prAuthEvent; + PUINT_8 cp; + UINT_32 u4LenOfUsedBuffer; + + prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer; + + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; + + u4LenOfUsedBuffer = (UINT_32) (prEvent->u2PacketLen - 8); + + prAuthEvent->arRequest[0].u4Length = u4LenOfUsedBuffer; + + cp = (PUINT_8) &prAuthEvent->arRequest[0]; + + /* Status type: PMKID Candidatelist Event */ + kalMemCopy(cp, (P_EVENT_PMKID_CANDIDATE_LIST_T) (prEvent->aucBuffer), prEvent->u2PacketLen - 8); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (PVOID) prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + u4LenOfUsedBuffer); + } + break; + +#if 0 + case EVENT_ID_ACTIVATE_STA_REC_T: + { + P_EVENT_ACTIVATE_STA_REC_T prActivateStaRec; + + prActivateStaRec = (P_EVENT_ACTIVATE_STA_REC_T) (prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_ACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", + prActivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); + + qmActivateStaRec(prAdapter, + (UINT_32) prActivateStaRec->ucStaRecIdx, + ((prActivateStaRec->fgIsQoS) ? TRUE : FALSE), + prActivateStaRec->ucNetworkTypeIndex, + ((prActivateStaRec->fgIsAP) ? TRUE : FALSE), prActivateStaRec->aucMacAddr); + + } + break; + + case EVENT_ID_DEACTIVATE_STA_REC_T: + { + P_EVENT_DEACTIVATE_STA_REC_T prDeactivateStaRec; + + prDeactivateStaRec = (P_EVENT_DEACTIVATE_STA_REC_T) (prEvent->aucBuffer); + + DbgPrint("RX EVENT: EVENT_ID_DEACTIVATE_STA_REC_T Index:%d, MAC:[%pM]\n", + prDeactivateStaRec->ucStaRecIdx, prActivateStaRec->aucMacAddr); + + qmDeactivateStaRec(prAdapter, prDeactivateStaRec->ucStaRecIdx); + } + break; +#endif + + case EVENT_ID_SCAN_DONE: + scnEventScanDone(prAdapter, (P_EVENT_SCAN_DONE) (prEvent->aucBuffer)); + break; + + case EVENT_ID_TX_DONE_STATUS: + STATS_TX_PKT_DONE_INFO_DISPLAY(prAdapter, prEvent->aucBuffer); + break; + + case EVENT_ID_TX_DONE: + { + P_EVENT_TX_DONE_T prTxDone; + + prTxDone = (P_EVENT_TX_DONE_T) (prEvent->aucBuffer); + if (prTxDone->ucStatus) + DBGLOG(RX, INFO, "EVENT_ID_TX_DONE PacketSeq:%u ucStatus: %u SN: %u\n", + prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->u2SequenceNumber); + + /* call related TX Done Handler */ + prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucPacketSeq); + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + DBGLOG(RX, TRACE, "EVENT_ID_TX_DONE u4TimeStamp = %x u2AirDelay = %x\n", + prTxDone->au4Reserved1, prTxDone->au4Reserved2); + + wnmReportTimingMeas(prAdapter, prMsduInfo->ucStaRecIndex, + prTxDone->au4Reserved1, prTxDone->au4Reserved1 + prTxDone->au4Reserved2); +#endif + + if (prMsduInfo) { + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, + (ENUM_TX_RESULT_CODE_T) (prTxDone->ucStatus)); + + cnmMgtPktFree(prAdapter, prMsduInfo); + } + } + break; + case EVENT_ID_SLEEPY_NOTIFY: + { + P_EVENT_SLEEPY_NOTIFY prEventSleepyNotify; + + prEventSleepyNotify = (P_EVENT_SLEEPY_NOTIFY) (prEvent->aucBuffer); + + /* DBGLOG(RX, INFO, ("ucSleepyState = %d\n", prEventSleepyNotify->ucSleepyState)); */ + + prAdapter->fgWiFiInSleepyState = (BOOLEAN) (prEventSleepyNotify->ucSleepyState); + } + break; + case EVENT_ID_BT_OVER_WIFI: +#if CFG_ENABLE_BT_OVER_WIFI + { + UINT_8 aucTmp[sizeof(AMPC_EVENT) + sizeof(BOW_LINK_DISCONNECTED)]; + P_EVENT_BT_OVER_WIFI prEventBtOverWifi; + P_AMPC_EVENT prBowEvent; + P_BOW_LINK_CONNECTED prBowLinkConnected; + P_BOW_LINK_DISCONNECTED prBowLinkDisconnected; + + prEventBtOverWifi = (P_EVENT_BT_OVER_WIFI) (prEvent->aucBuffer); + + /* construct event header */ + prBowEvent = (P_AMPC_EVENT) aucTmp; + + if (prEventBtOverWifi->ucLinkStatus == 0) { + /* Connection */ + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_CONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_CONNECTED); + + /* fill event body */ + prBowLinkConnected = (P_BOW_LINK_CONNECTED) (prBowEvent->aucPayload); + prBowLinkConnected->rChannel.ucChannelNum = prEventBtOverWifi->ucSelectedChannel; + kalMemZero(prBowLinkConnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); + } else { + /* Disconnection */ + prBowEvent->rHeader.ucEventId = BOW_EVENT_ID_LINK_DISCONNECTED; + prBowEvent->rHeader.ucSeqNumber = 0; + prBowEvent->rHeader.u2PayloadLength = sizeof(BOW_LINK_DISCONNECTED); + + /* fill event body */ + prBowLinkDisconnected = (P_BOW_LINK_DISCONNECTED) (prBowEvent->aucPayload); + prBowLinkDisconnected->ucReason = 0; /* @FIXME */ + kalMemZero(prBowLinkDisconnected->aucPeerAddress, MAC_ADDR_LEN); /* @FIXME */ + + kalIndicateBOWEvent(prAdapter->prGlueInfo, prBowEvent); + } + } + break; +#endif + case EVENT_ID_STATISTICS: + /* buffer statistics for further query */ + prAdapter->fgIsStatValid = TRUE; + prAdapter->rStatUpdateTime = kalGetTimeTick(); + kalMemCopy(&prAdapter->rStatStruct, prEvent->aucBuffer, sizeof(EVENT_STATISTICS)); + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + else if (prCmdInfo->fgIsOid) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + + case EVENT_ID_CH_PRIVILEGE: + cnmChMngrHandleChEvent(prAdapter, prEvent); + break; + + case EVENT_ID_BSS_ABSENCE_PRESENCE: + qmHandleEventBssAbsencePresence(prAdapter, prEvent); + break; + + case EVENT_ID_STA_CHANGE_PS_MODE: + qmHandleEventStaChangePsMode(prAdapter, prEvent); + break; +#if CFG_ENABLE_WIFI_DIRECT + case EVENT_ID_STA_UPDATE_FREE_QUOTA: + qmHandleEventStaUpdateFreeQuota(prAdapter, prEvent); + break; +#endif + case EVENT_ID_BSS_BEACON_TIMEOUT: + if (prAdapter->fgDisBcnLostDetection == FALSE) { + P_EVENT_BSS_BEACON_TIMEOUT_T prEventBssBeaconTimeout; + + prEventBssBeaconTimeout = (P_EVENT_BSS_BEACON_TIMEOUT_T) (prEvent->aucBuffer); + + DBGLOG(RX, INFO, "Beacon Timeout Reason = %u\n", prEventBssBeaconTimeout->ucReason); + + if (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_AIS_INDEX) { + /* Request stats report before beacon timeout */ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + if (prBssInfo) { + prStaRec = cnmGetStaRecByAddress(prAdapter, + NETWORK_TYPE_AIS_INDEX, + prBssInfo->aucBSSID); + if (prStaRec) + STATS_ENV_REPORT_DETECT(prAdapter, prStaRec->ucIndex); + } + aisBssBeaconTimeout(prAdapter); + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (prEventBssBeaconTimeout->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX)) + + p2pFsmRunEventBeaconTimeout(prAdapter); +#endif + else { + DBGLOG(RX, ERROR, "EVENT_ID_BSS_BEACON_TIMEOUT: (ucNetTypeIdx = %d)\n", + prEventBssBeaconTimeout->ucNetTypeIndex); + } + } + + break; + case EVENT_ID_UPDATE_NOA_PARAMS: +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam; + + prEventUpdateNoaParam = (P_EVENT_UPDATE_NOA_PARAMS_T) (prEvent->aucBuffer); + + if (prEventUpdateNoaParam->ucNetTypeIndex == NETWORK_TYPE_P2P_INDEX) { + p2pProcessEvent_UpdateNOAParam(prAdapter, + prEventUpdateNoaParam->ucNetTypeIndex, + prEventUpdateNoaParam); + } else { + ASSERT(0); + } + } +#else + ASSERT(0); +#endif + break; + + case EVENT_ID_STA_AGING_TIMEOUT: +#if CFG_ENABLE_WIFI_DIRECT + { + if (prAdapter->fgDisStaAgingTimeoutDetection == FALSE) { + P_EVENT_STA_AGING_TIMEOUT_T prEventStaAgingTimeout; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T) NULL; + + prEventStaAgingTimeout = (P_EVENT_STA_AGING_TIMEOUT_T) (prEvent->aucBuffer); + prStaRec = cnmGetStaRecByIndex(prAdapter, prEventStaAgingTimeout->ucStaRecIdx); + if (prStaRec == NULL) + break; + + DBGLOG(RX, INFO, "EVENT_ID_STA_AGING_TIMEOUT %u %pM\n", + prEventStaAgingTimeout->ucStaRecIdx, + prStaRec->aucMacAddr); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + bssRemoveStaRecFromClientList(prAdapter, prBssInfo, prStaRec); + + /* Call False Auth */ + if (prAdapter->fgIsP2PRegistered) + p2pFuncDisconnect(prAdapter, prStaRec, TRUE, REASON_CODE_DISASSOC_INACTIVITY); + + } + /* gDisStaAgingTimeoutDetection */ + } +#endif + break; + + case EVENT_ID_AP_OBSS_STATUS: +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + rlmHandleObssStatusEventPkt(prAdapter, (P_EVENT_AP_OBSS_STATUS_T) prEvent->aucBuffer); +#endif + break; + + case EVENT_ID_ROAMING_STATUS: +#if CFG_SUPPORT_ROAMING + { + P_ROAMING_PARAM_T prParam; + + prParam = (P_ROAMING_PARAM_T) (prEvent->aucBuffer); + roamingFsmProcessEvent(prAdapter, prParam); + } +#endif /* CFG_SUPPORT_ROAMING */ + break; + case EVENT_ID_SEND_DEAUTH: + { + P_WLAN_MAC_HEADER_T prWlanMacHeader; + P_STA_RECORD_T prStaRec; + + prWlanMacHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; + DBGLOG(RSN, INFO, "nicRx: aucAddr1: %pM, nicRx: aucAddr2: %pM\n", + prWlanMacHeader->aucAddr1, prWlanMacHeader->aucAddr2); + prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS_INDEX, prWlanMacHeader->aucAddr2); + if (prStaRec != NULL && prStaRec->ucStaState == STA_STATE_3) { + DBGLOG(RSN, WARN, "Ignore Deauth for Rx Class 3 error!\n"); + } else { + /* receive packets without StaRec */ + prSwRfb->pvHeader = (P_WLAN_MAC_HEADER_T) &prEvent->aucBuffer[0]; + if (WLAN_STATUS_SUCCESS == authSendDeauthFrame(prAdapter, + NULL, + prSwRfb, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER) NULL)) + DBGLOG(RSN, INFO, "Send Deauth for Rx Class3 Error\n"); + else + DBGLOG(RSN, WARN, "failed to send deauth for Rx class3 error\n"); + } + } + break; + +#if CFG_SUPPORT_RDD_TEST_MODE + case EVENT_ID_UPDATE_RDD_STATUS: + { + P_EVENT_RDD_STATUS_T prEventRddStatus; + + prEventRddStatus = (P_EVENT_RDD_STATUS_T) (prEvent->aucBuffer); + + prAdapter->ucRddStatus = prEventRddStatus->ucRddStatus; + } + + break; +#endif + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + case EVENT_ID_UPDATE_BWCS_STATUS: + { + P_PTA_IPC_T prEventBwcsStatus; + + prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(RSN, INFO, + "BCM BWCS Event: %02x%02x%02x%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); + + DBGLOG(RSN, INFO, + "BCM BWCS Event: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); +#endif + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_BWCS_UPDATE, + (PVOID) prEventBwcsStatus, sizeof(PTA_IPC_T)); + } + + break; + + case EVENT_ID_UPDATE_BCM_DEBUG: + { + P_PTA_IPC_T prEventBwcsStatus; + + prEventBwcsStatus = (P_PTA_IPC_T) (prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(RSN, INFO, + "BCM FW status: %02x%02x%02x%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]); + + DBGLOG(RSN, INFO, + "BCM FW status: BTPParams[0]:%02x, BTPParams[1]:%02x, BTPParams[2]:%02x, BTPParams[3]:%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], prEventBwcsStatus->u.aucBTPParams[3]; +#endif + } + + break; +#endif + + case EVENT_ID_DEBUG_CODE: /* only for debug */ + { + UINT_32 u4CodeId; + + DBGLOG(RSN, INFO, "[wlan-fw] function sequence: "); + for (u4CodeId = 0; u4CodeId < 1000; u4CodeId++) + DBGLOG(RSN, INFO, "%d ", prEvent->aucBuffer[u4CodeId]); + DBGLOG(RSN, INFO, "\n\n"); + } + break; + + case EVENT_ID_RFTEST_READY: + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + else if (prCmdInfo->fgIsOid) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + + case EVENT_ID_GSCAN_SCAN_AVAILABLE: + case EVENT_ID_GSCAN_CAPABILITY: + case EVENT_ID_GSCAN_SCAN_COMPLETE: + case EVENT_ID_GSCAN_FULL_RESULT: + case EVENT_ID_GSCAN_SIGNIFICANT_CHANGE: + case EVENT_ID_GSCAN_GEOFENCE_FOUND: + nicRxProcessGSCNEvent(prAdapter, prSwRfb); + break; + + case EVENT_ID_GSCAN_RESULT: + { + + UINT_8 realnum = 0; + + DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent ----->\n"); + realnum = nicRxProcessGSCNEvent(prAdapter, prSwRfb); + DBGLOG(SCN, TRACE, "nicRxProcessGSCNEvent <-----\n"); + +#if 0 /* workaround for FW events cnt mis-match with the actual reqirements from wifi_hal */ + if (g_GetResultsCmdCnt == 0) { + DBGLOG(SCN, INFO, + "FW report events more than the wifi_hal asked number, buffer the results\n"); + UINT_8 i = 0; + + for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { +#if 1 + if (!g_arGscanResultsIndicateNumber[i]) { + DBGLOG(SCN, INFO, + "found available index %d to insert results number %d into buffer\r\n", + i, realnum); + + g_arGscnResultsTempBuffer[i] = prSwRfb; + g_arGscanResultsIndicateNumber[i] = realnum; + g_GetResultsBufferedCnt++; + fgKeepprSwRfb = TRUE; + DBGLOG(SCN, INFO, "results buffered in index[%d] \r\n", i); + break; + } +#endif + } + if (i == MAX_BUFFERED_GSCN_RESULTS) + DBGLOG(SCN, INFO, + "Gscn results buffer is full(all valid), no space to buffer result\r\n"); + } else if (g_GetResultsCmdCnt > 0) { + DBGLOG(SCN, INFO, "FW report events match the wifi_hal asked number\n"); + g_GetResultsCmdCnt--; + } else + DBGLOG(SCN, INFO, "g_GetResultsCmdCnt < 0 ??? unexpected case\n"); +#endif + /* end of workaround */ + + } + break; + + case EVENT_ID_NLO_DONE: + prAdapter->rWifiVar.rScanInfo.fgPscnOnnning = FALSE; + + DBGLOG(INIT, INFO, "EVENT_ID_NLO_DONE\n"); + scnEventNloDone(prAdapter, (P_EVENT_NLO_DONE_T) (prEvent->aucBuffer)); + + break; + +#if CFG_SUPPORT_BATCH_SCAN + case EVENT_ID_BATCH_RESULT: + DBGLOG(SCN, TRACE, "Got EVENT_ID_BATCH_RESULT"); + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + else if (prCmdInfo->fgIsOid) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; +#endif /* CFG_SUPPORT_BATCH_SCAN */ + +#if (CFG_SUPPORT_TDLS == 1) + case EVENT_ID_TDLS: + TdlsexEventHandle(prAdapter->prGlueInfo, + (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); + break; +#endif /* CFG_SUPPORT_TDLS */ + +#if (CFG_SUPPORT_STATISTICS == 1) + case EVENT_ID_STATS_ENV: + statsEventHandle(prAdapter->prGlueInfo, + (UINT8 *) prEvent->aucBuffer, (UINT32) (prEvent->u2PacketLen - 8)); + break; +#endif /* CFG_SUPPORT_STATISTICS */ + + case EVENT_ID_FW_LOG_ENV: + { + P_EVENT_FW_LOG_T prEventLog; + + prEventLog = (P_EVENT_FW_LOG_T) (prEvent->aucBuffer); + DBGLOG(RX, INFO, "[F-L]%s\n", prEventLog->log); + } + break; + + default: + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prEvent->aucBuffer); + else if (prCmdInfo->fgIsOid) + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + + break; + } + + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief nicRxProcessMgmtPacket is used to dispatch management frames +* to corresponding modules +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSWRfb the RFB to receive rx data +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + UINT_8 ucSubtype; +#if CFG_SUPPORT_802_11W + BOOLEAN fgMfgDrop = FALSE; +#endif + ASSERT(prAdapter); + ASSERT(prSwRfb); + + nicRxFillRFB(prAdapter, prSwRfb); + + ucSubtype = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FC_SUBTYPE) >> OFFSET_OF_FC_SUBTYPE; + +#if 0 /* CFG_RX_PKTS_DUMP */ + { + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_16 u2TxFrameCtrl; + + prHifRxHdr = prSwRfb->prHifRxHdr; + u2TxFrameCtrl = (*(PUINT_8) (prSwRfb->pvHeader) & MASK_FRAME_TYPE); + /* if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_MANAGEMENT)) { */ + /* if (u2TxFrameCtrl == MAC_FRAME_BEACON || */ + /* u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { */ + + DBGLOG(RX, INFO, "QM RX MGT: net %u sta idx %u wlan idx %u ssn %u ptype %u subtype %u 11 %u\n", + (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), prHifRxHdr->ucStaRecIdx, + prSwRfb->ucWlanIdx, (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr),/* The new SN of the frame */ + prSwRfb->ucPacketType, ucSubtype, HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); + + /* DBGLOG_MEM8(SW4, TRACE, (PUINT_8)prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ + /* } */ + /* } */ + } +#endif + + if ((prAdapter->fgTestMode == FALSE) && (prAdapter->prGlueInfo->fgIsRegistered == TRUE)) { +#if CFG_MGMT_FRAME_HANDLING +#if CFG_SUPPORT_802_11W + fgMfgDrop = rsnCheckRxMgmt(prAdapter, prSwRfb, ucSubtype); + if (fgMfgDrop) { +#if DBG + LOG_FUNC("QM RX MGT: Drop Unprotected Mgmt frame!!!\n"); +#endif + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + return; + } +#endif + if (apfnProcessRxMgtFrame[ucSubtype]) { + switch (apfnProcessRxMgtFrame[ucSubtype] (prAdapter, prSwRfb)) { + case WLAN_STATUS_PENDING: + return; + case WLAN_STATUS_SUCCESS: + case WLAN_STATUS_FAILURE: + break; + + default: + DBGLOG(RX, WARN, + "Unexpected MMPDU(0x%02X) returned with abnormal status\n", ucSubtype); + break; + } + } +#endif + } + + nicRxReturnRFB(prAdapter, prSwRfb); +} + +#if CFG_SUPPORT_WAKEUP_REASON_DEBUG +static VOID nicRxCheckWakeupReason(P_SW_RFB_T prSwRfb) +{ + PUINT_8 pvHeader = NULL; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_16 u2PktLen = 0; + UINT_32 u4HeaderOffset; + + if (!prSwRfb) + return; + prHifRxHdr = prSwRfb->prHifRxHdr; + if (!prHifRxHdr) + return; + + switch (prSwRfb->ucPacketType) { + case HIF_RX_PKT_TYPE_DATA: + { + UINT_16 u2Temp = 0; + + if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { + DBGLOG(RX, INFO, "BAR frame[SSN:%d, TID:%d] wakeup host\n", + (UINT_16)HIF_RX_HDR_GET_SN(prHifRxHdr), (UINT_8)HIF_RX_HDR_GET_TID(prHifRxHdr)); + break; + } + u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); + pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; + u2PktLen = (UINT_16)(prHifRxHdr->u2PacketLen - (HIF_RX_HDR_SIZE + u4HeaderOffset)); + if (!pvHeader) { + DBGLOG(RX, ERROR, "data packet but pvHeader is NULL!\n"); + break; + } + u2Temp = (pvHeader[ETH_TYPE_LEN_OFFSET] << 8) | (pvHeader[ETH_TYPE_LEN_OFFSET + 1]); + + switch (u2Temp) { + case ETH_P_IPV4: + u2Temp = *(UINT_16 *) &pvHeader[ETH_HLEN + 4]; + DBGLOG(RX, INFO, "IP Packet from:%d.%d.%d.%d, IP ID 0x%04x wakeup host\n", + pvHeader[ETH_HLEN + 12], pvHeader[ETH_HLEN + 13], + pvHeader[ETH_HLEN + 14], pvHeader[ETH_HLEN + 15], u2Temp); + break; + case ETH_P_ARP: + { + PUINT_8 pucEthBody = &pvHeader[ETH_HLEN]; + UINT_16 u2OpCode = (pucEthBody[6] << 8) | pucEthBody[7]; + + if (u2OpCode == ARP_PRO_REQ) + DBGLOG(RX, INFO, "Arp Req From IP: %d.%d.%d.%d wakeup host\n", + pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); + else if (u2OpCode == ARP_PRO_RSP) + DBGLOG(RX, INFO, "Arp Rsp from IP: %d.%d.%d.%d wakeup host\n", + pucEthBody[14], pucEthBody[15], pucEthBody[16], pucEthBody[17]); + break; + } + case ETH_P_1X: + case ETH_P_PRE_1X: +#if CFG_SUPPORT_WAPI + case ETH_WPI_1X: +#endif + case ETH_P_AARP: + case ETH_P_IPV6: + case ETH_P_IPX: + case 0x8100: /* VLAN */ + case 0x890d: /* TDLS */ + DBGLOG(RX, INFO, "Data Packet, EthType 0x%04x wakeup host\n", u2Temp); + break; + default: + DBGLOG(RX, WARN, "maybe abnormal data packet, EthType 0x%04x wakeup host, dump it\n", + u2Temp); + DBGLOG_MEM8(RX, INFO, pvHeader, u2PktLen > 50 ? 50:u2PacketLen); + break; + } + break; + } + case HIF_RX_PKT_TYPE_EVENT: + { + P_WIFI_EVENT_T prEvent = (P_WIFI_EVENT_T) prSwRfb->pucRecvBuff; + + DBGLOG(RX, INFO, "Event 0x%02x wakeup host\n", prEvent->ucEID); + break; + } + case HIF_RX_PKT_TYPE_MANAGEMENT: + { + UINT_8 ucSubtype; + P_WLAN_MAC_MGMT_HEADER_T prWlanMgmtHeader; + + u4HeaderOffset = (UINT_32)(prHifRxHdr->ucHerderLenOffset & HIF_RX_HDR_HEADER_OFFSET_MASK); + pvHeader = (PUINT_8)prHifRxHdr + HIF_RX_HDR_SIZE + u4HeaderOffset; + if (!pvHeader) { + DBGLOG(RX, ERROR, "Mgmt Frame but pvHeader is NULL!\n"); + break; + } + prWlanMgmtHeader = (P_WLAN_MAC_MGMT_HEADER_T)pvHeader; + ucSubtype = (prWlanMgmtHeader->u2FrameCtrl & MASK_FC_SUBTYPE) >> + OFFSET_OF_FC_SUBTYPE; + DBGLOG(RX, INFO, "MGMT frame subtype: %d SeqCtrl %d wakeup host\n", + ucSubtype, prWlanMgmtHeader->u2SeqCtrl); + break; + } + default: + DBGLOG(RX, WARN, "Unknown Packet %d wakeup host\n", prSwRfb->ucPacketType); + break; + } +} +#endif +/*----------------------------------------------------------------------------*/ +/*! +* @brief nicProcessRFBs is used to process RFBs in the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxProcessRFBs(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prRxCtrl->ucNumIndPacket = 0; + prRxCtrl->ucNumRetainedPacket = 0; + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (prSwRfb) { +#if CFG_SUPPORT_WAKEUP_REASON_DEBUG + if (kalIsWakeupByWlan(prAdapter)) + nicRxCheckWakeupReason(prSwRfb); +#endif + switch (prSwRfb->ucPacketType) { + case HIF_RX_PKT_TYPE_DATA: + nicRxProcessDataPacket(prAdapter, prSwRfb); + break; + + case HIF_RX_PKT_TYPE_EVENT: + nicRxProcessEventPacket(prAdapter, prSwRfb); + break; + + case HIF_RX_PKT_TYPE_TX_LOOPBACK: +#if (CONF_HIF_LOOPBACK_AUTO == 1) + { + kalDevLoopbkRxHandle(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + } +#else + DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); +#endif /* CONF_HIF_LOOPBACK_AUTO */ + break; + + case HIF_RX_PKT_TYPE_MANAGEMENT: + nicRxProcessMgmtPacket(prAdapter, prSwRfb); + break; + + default: + RX_INC_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + DBGLOG(RX, ERROR, "ucPacketType = %d\n", prSwRfb->ucPacketType); + nicRxReturnRFB(prAdapter, prSwRfb); /* need to free it */ + break; + } + } else { + break; + } + } while (TRUE); + + if (prRxCtrl->ucNumIndPacket > 0) { + RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, prRxCtrl->ucNumIndPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT, prRxCtrl->ucNumRetainedPacket); + + /* DBGLOG(RX, INFO, ("%d packets indicated, Retained cnt = %d\n", */ + /* prRxCtrl->ucNumIndPacket, prRxCtrl->ucNumRetainedPacket)); */ +#if CFG_NATIVE_802_11 + kalRxIndicatePkts(prAdapter->prGlueInfo, (UINT_32) prRxCtrl->ucNumIndPacket, + (UINT_32) prRxCtrl->ucNumRetainedPacket); +#else + kalRxIndicatePkts(prAdapter->prGlueInfo, prRxCtrl->apvIndPacket, (UINT_32) prRxCtrl->ucNumIndPacket); +#endif + } + +} /* end of nicRxProcessRFBs() */ + +#if !CFG_SDIO_INTR_ENHANCE +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read the rx data from data port and setup RFB +* +* @param prAdapter pointer to the Adapter handler +* @param prSWRfb the RFB to receive rx data +* +* @retval WLAN_STATUS_SUCCESS: SUCCESS +* @retval WLAN_STATUS_FAILURE: FAILURE +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucBuf; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4PktLen = 0, u4ReadBytes; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + BOOLEAN fgResult = TRUE; + UINT_32 u4RegValue; + UINT_32 rxNum; + + DEBUGFUNC("nicRxReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(pucBuf); + DBGLOG(RX, TRACE, "pucBuf= 0x%x, prHifRxHdr= 0x%x\n", pucBuf, prHifRxHdr); + + do { + /* Read the RFB DW length and packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); + if (!fgResult) { + DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); + return WLAN_STATUS_FAILURE; + } + /* 20091021 move the line to get the HIF RX header (for RX0/1) */ + if (u4RegValue == 0) { + DBGLOG(RX, ERROR, "No RX packet\n"); + return WLAN_STATUS_FAILURE; + } + + u4PktLen = u4RegValue & BITS(0, 15); + if (u4PktLen != 0) { + rxNum = 0; + } else { + rxNum = 1; + u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; + } + + DBGLOG(RX, TRACE, "RX%d: u4PktLen = %d\n", rxNum, u4PktLen); + + /* 4 <4> Read Entire RFB and packet, include HW appended DW (Checksum Status) */ + u4ReadBytes = ALIGN_4(u4PktLen) + 4; + HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, CFG_RX_MAX_PKT_SIZE); + + /* 20091021 move the line to get the HIF RX header */ + /* u4PktLen = (UINT_32)prHifRxHdr->u2PacketLen; */ + if (u4PktLen != (UINT_32) prHifRxHdr->u2PacketLen) { + DBGLOG(RX, ERROR, "Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", + u4PktLen, prHifRxHdr->u2PacketLen); +#if DBG + dumpMemory8((PUINT_8) prHifRxHdr, + (prHifRxHdr->u2PacketLen > 4096) ? 4096 : prHifRxHdr->u2PacketLen); +#endif + ASSERT(0); + } + /* u4PktLen is byte unit, not inlude HW appended DW */ + + prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); + + prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); + + /* fgResult will be updated in MACRO */ + if (!fgResult) + return WLAN_STATUS_FAILURE; + + DBGLOG(RX, TRACE, "Dump RX buffer, length = 0x%x\n", u4ReadBytes); + DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); + } while (FALSE); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port, fill RFB +* and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + P_HIF_RX_HEADER_T prHifRxHdr; + + UINT_32 u4HwAppendDW; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxReceiveRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, "No More RFB\n"); + break; + } + /* need to consider */ + if (nicRxReadBuffer(prAdapter, prSwRfb) == WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, "halRxFillRFB failed\n"); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + prHifRxHdr = prSwRfb->prHifRxHdr; + u4HwAppendDW = *((PUINT_32) ((ULONG) prHifRxHdr + (UINT_32) (ALIGN_4(prHifRxHdr->u2PacketLen)))); + DBGLOG(RX, TRACE, "u4HwAppendDW = 0x%x\n", u4HwAppendDW); + DBGLOG(RX, TRACE, "u2PacketLen = 0x%x\n", prHifRxHdr->u2PacketLen); + } while (FALSE); /* while (RX_STATUS_TEST_MORE_FLAG(u4HwAppendDW)); */ + + return; + +} /* end of nicReceiveRFBs() */ + +#else +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port, fill RFB +* and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* @param u4DataPort Specify which port to read +* @param u2RxLength Specify to the the rx packet length in Byte. +* @param prSwRfb the RFB to receive rx data. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, + IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucBuf; + P_HIF_RX_HEADER_T prHifRxHdr; + UINT_32 u4PktLen = 0; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + BOOLEAN fgResult = TRUE; + + DEBUGFUNC("nicRxEnhanceReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + ASSERT(pucBuf); + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + /* DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); */ + + do { + /* 4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW */ + HAL_READ_RX_PORT(prAdapter, + u4DataPort, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), pucBuf, CFG_RX_MAX_PKT_SIZE); + + if (!fgResult) { + DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); + break; + } + + u4PktLen = (UINT_32) (prHifRxHdr->u2PacketLen); + /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ + + prSwRfb->ucPacketType = (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ + + prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); + + /* 4 <2> if the RFB dw size or packet size is zero */ + if (u4PktLen == 0) { + DBGLOG(RX, ERROR, "Packet Length = %u\n", u4PktLen); + ASSERT(0); + break; + } + /* 4 <3> if the packet is too large or too small */ + if (u4PktLen > CFG_RX_MAX_PKT_SIZE) { + DBGLOG(RX, TRACE, "Read RX Packet Lentgh Error (%u)\n", u4PktLen); + ASSERT(0); + break; + } + + u4Status = WLAN_STATUS_SUCCESS; + } while (FALSE); + + DBGLOG_MEM8(RX, TRACE, pucBuf, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port for SDIO +* I/F, fill RFB and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_SDIO_CTRL_T prSDIOCtrl; + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + UINT_32 i, rxNum; + UINT_16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxSDIOReceiveRFBs"); + + ASSERT(prAdapter); + + prSDIOCtrl = prAdapter->prSDIOCtrl; + ASSERT(prSDIOCtrl); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + for (rxNum = 0; rxNum < 2; rxNum++) { + u2RxPktNum = + (rxNum == 0 ? prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); + + if (u2RxPktNum == 0) + continue; + + for (i = 0; i < u2RxPktNum; i++) { + if (rxNum == 0) { + /* HAL_READ_RX_LENGTH */ + HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, &u2Tmp); + } else if (rxNum == 1) { + /* HAL_READ_RX_LENGTH */ + HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, &u2RxLength); + } + + if (!u2RxLength) + break; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, "No More RFB\n"); + break; + } + ASSERT(prSwRfb); + + if (nicRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, prSwRfb) == WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, "nicRxEnhanceRxReadBuffer failed\n"); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + /* prSDIOCtrl->au4RxLength[i] = 0; */ + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + } + } + + prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; + prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; + +} /* end of nicRxSDIOReceiveRFBs() */ + +#endif /* CFG_SDIO_INTR_ENHANCE */ + +#if CFG_SDIO_RX_AGG +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read frames from the data port for SDIO with Rx aggregation enabled +* I/F, fill RFB and put each frame into the rReceivedRFBList queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; + P_RX_CTRL_T prRxCtrl; + P_SDIO_CTRL_T prSDIOCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; + UINT_32 u4RxLength; + UINT_32 i, rxNum; + UINT_32 u4RxAggCount = 0, u4RxAggLength = 0; + UINT_32 u4RxAvailAggLen, u4CurrAvailFreeRfbCnt; + PUINT_8 pucSrcAddr; + P_HIF_RX_HEADER_T prHifRxHdr; + BOOLEAN fgResult = TRUE; + BOOLEAN fgIsRxEnhanceMode; + UINT_16 u2RxPktNum; +#if CFG_SDIO_RX_ENHANCE + UINT_32 u4MaxLoopCount = CFG_MAX_RX_ENHANCE_LOOP_COUNT; +#endif + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxSDIOAggReceiveRFBs"); + + ASSERT(prAdapter); + prEnhDataStr = prAdapter->prSDIOCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + prSDIOCtrl = prAdapter->prSDIOCtrl; + +#if CFG_SDIO_RX_ENHANCE + fgIsRxEnhanceMode = TRUE; +#else + fgIsRxEnhanceMode = FALSE; +#endif + + do { +#if CFG_SDIO_RX_ENHANCE + /* to limit maximum loop for RX */ + u4MaxLoopCount--; + if (u4MaxLoopCount == 0) + break; +#endif + + if (prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) + break; + + for (rxNum = 0; rxNum < 2; rxNum++) { + u2RxPktNum = + (rxNum == + 0 ? prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); + + /* if this assertion happened, it is most likely a F/W bug */ + ASSERT(u2RxPktNum <= 16); + + if (u2RxPktNum > 16) + continue; + + if (u2RxPktNum == 0) + continue; + +#if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum++; + prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; +#endif + + u4CurrAvailFreeRfbCnt = prRxCtrl->rFreeSwRfbList.u4NumElem; + + /* if SwRfb is not enough, abort reading this time */ + if (u4CurrAvailFreeRfbCnt < u2RxPktNum) { +#if CFG_HIF_RX_STARVATION_WARNING + DbgPrint("FreeRfb is not enough: %d available, need %d\n", u4CurrAvailFreeRfbCnt, + u2RxPktNum); + DbgPrint("Queued Count: %d / Dequeud Count: %d\n", prRxCtrl->u4QueuedCnt, + prRxCtrl->u4DequeuedCnt); +#endif + continue; + } +#if CFG_SDIO_RX_ENHANCE + u4RxAvailAggLen = + CFG_RX_COALESCING_BUFFER_SIZE - (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + + 4 /* extra HW padding */); +#else + u4RxAvailAggLen = CFG_RX_COALESCING_BUFFER_SIZE; +#endif + u4RxAggCount = 0; + + for (i = 0; i < u2RxPktNum; i++) { + u4RxLength = (rxNum == 0 ? + (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : + (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); + + if (!u4RxLength) { + ASSERT(0); + break; + } + + if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < u4RxAvailAggLen) { + if (u4RxAggCount < u4CurrAvailFreeRfbCnt) { + u4RxAvailAggLen -= ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN); + u4RxAggCount++; + } else { + /* no FreeSwRfb for rx packet */ + ASSERT(0); + break; + } + } else { + /* CFG_RX_COALESCING_BUFFER_SIZE is not large enough */ + ASSERT(0); + break; + } + } + + u4RxAggLength = (CFG_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); + /* DBGLOG(RX, INFO, ("u4RxAggCount = %d, u4RxAggLength = %d\n", */ + /* u4RxAggCount, u4RxAggLength)); */ + + HAL_READ_RX_PORT(prAdapter, + rxNum, + u4RxAggLength, prRxCtrl->pucRxCoalescingBufPtr, CFG_RX_COALESCING_BUFFER_SIZE); + if (!fgResult) { + DBGLOG(RX, ERROR, "Read RX Agg Packet Error\n"); + continue; + } + + pucSrcAddr = prRxCtrl->pucRxCoalescingBufPtr; + for (i = 0; i < u4RxAggCount; i++) { + UINT_16 u2PktLength; + + u2PktLength = (rxNum == 0 ? + prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : + prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + ASSERT(prSwRfb); + kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, + ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); + + /* record the rx time */ + STATS_RX_ARRIVE_TIME_RECORD(prSwRfb); /* ms */ + + prHifRxHdr = prSwRfb->prHifRxHdr; + ASSERT(prHifRxHdr); + + prSwRfb->ucPacketType = + (UINT_8) (prHifRxHdr->u2PacketType & HIF_RX_HDR_PACKET_TYPE_MASK); + /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ + + prSwRfb->ucStaRecIdx = (UINT_8) (prHifRxHdr->ucStaRecIdx); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); + /* prEnhDataStr->au4RxLength[i] = 0; */ + } + +#if CFG_SDIO_RX_ENHANCE + kalMemCopy(prAdapter->prSDIOCtrl, (pucSrcAddr + 4), sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + /* do the same thing what nicSDIOReadIntStatus() does */ + if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && + (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1])) { + prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; + } + + if ((prSDIOCtrl->u4WHISR & BIT(31)) == 0 && + HAL_GET_MAILBOX_READ_CLEAR(prAdapter) == TRUE && + (prSDIOCtrl->u4RcvMailbox0 != 0 || prSDIOCtrl->u4RcvMailbox1 != 0)) { + prSDIOCtrl->u4WHISR |= BIT(31); + } + + /* dispatch to interrupt handler with RX bits masked */ + nicProcessIST_impl(prAdapter, + prSDIOCtrl->u4WHISR & (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))); +#endif + } + +#if !CFG_SDIO_RX_ENHANCE + prEnhDataStr->rRxInfo.u.u2NumValidRx0Len = 0; + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len = 0; +#endif + } while ((prEnhDataStr->rRxInfo.u.u2NumValidRx0Len || prEnhDataStr->rRxInfo.u.u2NumValidRx1Len) + && fgIsRxEnhanceMode); + +} +#endif /* CFG_SDIO_RX_AGG */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Setup a RFB and allocate the os packet to the RFB +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSwRfb Pointer to the RFB +* +* @retval WLAN_STATUS_SUCCESS +* @retval WLAN_STATUS_RESOURCES +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + PVOID pvPacket; + PUINT_8 pucRecvBuff; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (!prSwRfb->pvPacket) { + kalMemZero(prSwRfb, sizeof(SW_RFB_T)); + pvPacket = kalPacketAlloc(prAdapter->prGlueInfo, CFG_RX_MAX_PKT_SIZE, &pucRecvBuff); + if (pvPacket == NULL) + return WLAN_STATUS_RESOURCES; + + prSwRfb->pvPacket = pvPacket; + prSwRfb->pucRecvBuff = (PVOID) pucRecvBuff; + } else { + kalMemZero(((PUINT_8) prSwRfb + OFFSET_OF(SW_RFB_T, prHifRxHdr)), + (sizeof(SW_RFB_T) - OFFSET_OF(SW_RFB_T, prHifRxHdr))); + } + + prSwRfb->prHifRxHdr = (P_HIF_RX_HEADER_T) (prSwRfb->pucRecvBuff); + + return WLAN_STATUS_SUCCESS; + +} /* end of nicRxSetupRFB() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is called to put a RFB back onto the "RFB with Buffer" list +* or "RFB without buffer" list according to pvPacket. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prSwRfb Pointer to the RFB +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_QUE_ENTRY_T prQueEntry; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + prRxCtrl = &prAdapter->rRxCtrl; + prQueEntry = &prSwRfb->rQueEntry; + + ASSERT(prQueEntry); + + /* The processing on this RFB is done, so put it back on the tail of + our list */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + if (prSwRfb->pvPacket) { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(&prRxCtrl->rFreeSwRfbList, prQueEntry); + } else { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(&prRxCtrl->rIndicatedRfbList, prQueEntry); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); +} /* end of nicRxReturnRFB() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process rx interrupt. When the rx +* Interrupt is asserted, it means there are frames in queue. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + prGlueInfo->IsrRxCnt++; +#if CFG_SDIO_INTR_ENHANCE +#if CFG_SDIO_RX_AGG + nicRxSDIOAggReceiveRFBs(prAdapter); +#else + nicRxSDIOReceiveRFBs(prAdapter); +#endif +#else + nicRxReceiveRFBs(prAdapter); +#endif /* CFG_SDIO_INTR_ENHANCE */ + + nicRxProcessRFBs(prAdapter); + + return; + +} /* end of nicProcessRxInterrupt() */ + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* @brief Used to update IP/TCP/UDP checksum statistics of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param aeCSUM The array of checksum result. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, IN const ENUM_CSUM_RESULT_T aeCSUM[]) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(aeCSUM); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS) || + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_SUCCESS_COUNT); + } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) || (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_FAILED)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_FAILED_COUNT); + } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L3_PKT_COUNT); + } else { + ASSERT(0); + } + + if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) { + /* count success num */ + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_SUCCESS_COUNT); + } else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_FAILED_COUNT); + } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_SUCCESS_COUNT); + } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_FAILED_COUNT); + } else if ((aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_NONE) && (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_NONE)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L4_PKT_COUNT); + } else { + ASSERT(0); + } + +} /* end of nicRxUpdateCSUMStatistics() */ +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to query current status of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param pucBuffer Pointer to the message buffer. +* @param pu4Count Pointer to the buffer of message length count. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucCurrBuf = pucBuffer; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ + ASSERT(pu4Count); + + SPRINTF(pucCurrBuf, ("\n\nRX CTRL STATUS:")); + SPRINTF(pucCurrBuf, ("\n===============")); + SPRINTF(pucCurrBuf, ("\nFREE RFB w/i BUF LIST :%9u", prRxCtrl->rFreeSwRfbList.u4NumElem)); + SPRINTF(pucCurrBuf, ("\nFREE RFB w/o BUF LIST :%9u", prRxCtrl->rIndicatedRfbList.u4NumElem)); + SPRINTF(pucCurrBuf, ("\nRECEIVED RFB LIST :%9u", prRxCtrl->rReceivedRfbList.u4NumElem)); + + SPRINTF(pucCurrBuf, ("\n\n")); + + /* *pu4Count = (UINT_32)((UINT_32)pucCurrBuf - (UINT_32)pucBuffer); */ + +} /* end of nicRxQueryStatus() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Clear RX related counters +* +* @param prAdapter Pointer of Adapter Data Structure +* +* @return - (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxClearStatistics(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + RX_RESET_ALL_CNTS(prRxCtrl); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to query current statistics of RX Module. +* +* @param prAdapter Pointer to the Adapter structure. +* @param pucBuffer Pointer to the message buffer. +* @param pu4Count Pointer to the buffer of message length count. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuffer, OUT PUINT_32 pu4Count) +{ + P_RX_CTRL_T prRxCtrl; + PUINT_8 pucCurrBuf = pucBuffer; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of sprintf() */ + ASSERT(pu4Count); + +#define SPRINTF_RX_COUNTER(eCounter) \ + SPRINTF(pucCurrBuf, ("%-30s : %u\n", #eCounter, (UINT_32)prRxCtrl->au8Statistics[eCounter])) + + SPRINTF_RX_COUNTER(RX_MPDU_TOTAL_COUNT); + SPRINTF_RX_COUNTER(RX_SIZE_ERR_DROP_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_INDICATION_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETURNED_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETAINED_COUNT); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + SPRINTF_RX_COUNTER(RX_CSUM_TCP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_TCP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L4_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L3_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_IP_V6_PKT_CCOUNT); +#endif + + /* *pu4Count = (UINT_32)(pucCurrBuf - pucBuffer); */ + + nicRxClearStatistics(prAdapter); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Read the Response data from data port +* +* @param prAdapter pointer to the Adapter handler +* @param pucRspBuffer pointer to the Response buffer +* +* @retval WLAN_STATUS_SUCCESS: Response packet has been read +* @retval WLAN_STATUS_FAILURE: Read Response packet timeout or error occurred +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxWaitResponse(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length) +{ + UINT_32 u4Value = 0, u4PktLen = 0; + UINT_32 i = 0; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + BOOLEAN fgResult = TRUE; + UINT_32 u4Time, u4Current; + + DEBUGFUNC("nicRxWaitResponse"); + + ASSERT(prAdapter); + ASSERT(pucRspBuffer); + ASSERT(ucPortIdx < 2); + + u4Time = kalGetTimeTick(); + + do { + /* Read the packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); + + if (!fgResult) { + DBGLOG(RX, ERROR, "Read Response Packet Error\n"); + return WLAN_STATUS_FAILURE; + } + + if (ucPortIdx == 0) + u4PktLen = u4Value & 0xFFFF; + else + u4PktLen = (u4Value >> 16) & 0xFFFF; + +/* DBGLOG(RX, TRACE, ("i = %d, u4PktLen = %d\n", i, u4PktLen)); */ + + if (u4PktLen == 0) { + /* timeout exceeding check */ + u4Current = kalGetTimeTick(); + + if ((u4Current > u4Time) && ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) { + DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT1 %u %d %u\n", u4PktLen, i, u4Current); + return WLAN_STATUS_FAILURE; + } else if (u4Current < u4Time && ((u4Current + (0xFFFFFFFF - u4Time)) > RX_RESPONSE_TIMEOUT)) { + DBGLOG(RX, ERROR, "RX_RESPONSE_TIMEOUT2 %u %d %u\n", u4PktLen, i, u4Current); + return WLAN_STATUS_FAILURE; + } + + /* Response packet is not ready */ + kalUdelay(50); + + i++; + continue; + } + if (u4PktLen > u4MaxRespBufferLen) { + /* + TO: buffer is not enough but we still need to read all data from HIF to avoid + HIF crazy. + */ + DBGLOG(RX, ERROR, + "Not enough Event Buffer: required length = 0x%x, available buffer length = %d\n", + u4PktLen, u4MaxRespBufferLen); + DBGLOG(RX, ERROR, "i = %d, u4PktLen = %u\n", i, u4PktLen); + return WLAN_STATUS_FAILURE; + } + HAL_PORT_RD(prAdapter, + ucPortIdx == 0 ? MCR_WRDR0 : MCR_WRDR1, u4PktLen, pucRspBuffer, u4MaxRespBufferLen); + + /* fgResult will be updated in MACRO */ + if (!fgResult) { + DBGLOG(RX, ERROR, "Read Response Packet Error\n"); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(RX, TRACE, "Dump Response buffer, length = 0x%x\n", u4PktLen); + DBGLOG_MEM8(RX, TRACE, pucRspBuffer, u4PktLen); + + *pu4Length = u4PktLen; + break; + } while (TRUE); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Set filter to enable Promiscuous Mode +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + +} /* end of nicRxEnablePromiscuousMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Set filter to disable Promiscuous Mode +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + +} /* end of nicRxDisablePromiscuousMode() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function flushes all packets queued in reordering module +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Flushed successfully +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter) +{ + P_SW_RFB_T prSwRfb; + + ASSERT(prAdapter); + + prSwRfb = qmFlushRxQueues(prAdapter); + if (prSwRfb != NULL) { + do { + P_SW_RFB_T prNextSwRfb; + + /* save next first */ + prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); + + /* free */ + nicRxReturnRFB(prAdapter, prSwRfb); + + prSwRfb = prNextSwRfb; + } while (prSwRfb); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief +* +* @param +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_ACTION_FRAME prActFrame; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (prSwRfb->u2PacketLen < sizeof(WLAN_ACTION_FRAME) - 1) + return WLAN_STATUS_INVALID_PACKET; + prActFrame = (P_WLAN_ACTION_FRAME) prSwRfb->pvHeader; + DBGLOG(RX, INFO, "Category %u\n", prActFrame->ucCategory); + + switch (prActFrame->ucCategory) { + case CATEGORY_PUBLIC_ACTION: + if (HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) + aisFuncValidateRxActionFrame(prAdapter, prSwRfb); +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered) { + rlmProcessPublicAction(prAdapter, prSwRfb); + + p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); + + } +#endif + break; + + case CATEGORY_HT_ACTION: +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + rlmProcessHtAction(prAdapter, prSwRfb); +#endif + break; + case CATEGORY_VENDOR_SPECIFIC_ACTION: +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) + p2pFuncValidateRxActionFrame(prAdapter, prSwRfb); +#endif + break; +#if CFG_SUPPORT_802_11W + case CATEGORY_SA_QUERT_ACTION: + { + P_HIF_RX_HEADER_T prHifRxHdr; + + prHifRxHdr = prSwRfb->prHifRxHdr; + + if ((HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr) == NETWORK_TYPE_AIS_INDEX) + && prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) { + if (!(prHifRxHdr->ucReserved & CONTROL_FLAG_UC_MGMT_NO_ENC)) { + /* MFP test plan 5.3.3.4 */ + rsnSaQueryAction(prAdapter, prSwRfb); + } else { + DBGLOG(RSN, TRACE, "Un-Protected SA Query, do nothing\n"); + } + } + } + break; +#endif +#if CFG_SUPPORT_802_11V + case CATEGORY_WNM_ACTION: + { + wnmWNMAction(prAdapter, prSwRfb); + } + break; +#endif + +#if CFG_SUPPORT_DFS /* Add by Enlai */ + case CATEGORY_SPEC_MGT: + { + if (prAdapter->fgEnable5GBand == TRUE) + rlmProcessSpecMgtAction(prAdapter, prSwRfb); + } + break; +#endif + +#if (CFG_SUPPORT_TDLS == 1) + case 12: /* shall not be here */ + /* + A received TDLS Action frame with the Type field set to Management shall + be discarded. Note that the TDLS Discovery Response frame is not a TDLS + frame but a Public Action frame. + */ + break; +#endif /* CFG_SUPPORT_TDLS */ + + default: + break; + } /* end of switch case */ + + return WLAN_STATUS_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c new file mode 100644 index 0000000000000..024bd95076037 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/nic_tx.c @@ -0,0 +1,2350 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_tx.c#1 +*/ + +/*! \file nic_tx.c + \brief Functions that provide TX operation in NIC Layer. + + This file provides TX functions which are responsible for both Hardware and + Software Resource Management and keep their Synchronization. +*/ + +/* +** Log: nic_tx.c + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 11 18 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add log counter for tx + * + * 11 09 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for beacon timeout and sta aging timeout. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 05 17 2011 cp.wu + * [WCXRP00000732] [MT6620 Wi-Fi][AIS] No need to switch back to IDLE state when DEAUTH frame is dropped due to bss + * disconnection + * when TX DONE status is TX_RESULT_DROPPED_IN_DRIVER, no need to switch back to IDLE state. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame + * dropping cases for TC4 path + * remove unused variables. + * + * 04 12 2011 cp.wu + * [WCXRP00000631] [MT6620 Wi-Fi][Driver] Add an API for QM to retrieve current TC counter value and processing frame + * dropping cases for TC4 path + * 1. add nicTxGetResource() API for QM to make decisions. + * 2. if management frames is decided by QM for dropping, the call back is invoked to indicate such a case. + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 02 16 2011 cp.wu + * [WCXRP00000449] [MT6620 Wi-Fi][Driver] Refine CMD queue handling by adding an extra API for checking available count + * and modify behavior + * 1. add new API: nicTxGetFreeCmdCount() + * 2. when there is insufficient command descriptor, nicTxEnqueueMsdu() will drop command packets directly + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation + * needs such information + * fill mac header length information for 802.1x frames. + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system + * scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being + * loaded + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 10 18 2010 cp.wu + * [WCXRP00000117] [MT6620 Wi-Fi][Driver] Add logic for suspending driver when MT6620 is not responding anymore + * 1. when wlanAdapterStop() failed to send POWER CTRL command to firmware, do not poll for ready bit dis-assertion + * 2. shorten polling count for shorter response time + * 3. if bad I/O operation is detected during TX resource polling, then further operation is aborted as well + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 09 29 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue. + * + * 09 27 2010 wh.su + * NULL + * since the u2TxByteCount_UserPriority will or another setting, keep the overall buffer for avoid error + * + * 09 24 2010 wh.su + * NULL + * [WCXRP000000058][MT6620 Wi-Fi][Driver] Fail to handshake with WAPI AP due the 802.1x frame send to fw with extra + * bytes padding. + * + * 09 01 2010 cp.wu + * NULL + * HIFSYS Clock Source Workaround + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 08 30 2010 cp.wu + * NULL + * eliminate klockwork errors + * + * 08 20 2010 wh.su + * NULL + * adding the eapol callback setting. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 05 2010 yuche.tsai + * NULL + * . + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 13 2010 cp.wu + * + * 1) MMPDUs are now sent to MT6620 by CMD queue for keeping strict order of 1X/MMPDU/CMD packets + * 2) integrate with qmGetFrameAction() for deciding which MMPDU/1X could pass checking for sending + * 2) enhance CMD_INFO_T descriptor number from 10 to 32 to avoid descriptor underflow under concurrent network + * operation + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 24 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 802.1x and bluetooth-over-Wi-Fi security frames are now delievered to firmware via command path instead of data path. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 22 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) add command warpper for STA-REC/BSS-INFO sync. + * 2) enhance command packet sending procedure for non-oid part + * 3) add command packet definitions for STA-REC/BSS-INFO sync. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add checking for TX descriptor poll. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * TX descriptors are now allocated once for reducing allocation overhead + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change zero-padding for TX port access to HAL. + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 15 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * . + * + * 06 14 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * fill extra information for revised HIF_TX_HEADER. + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 10 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change to enqueue TX frame infinitely. + * + * 06 09 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add TX_PACKET_MGMT to indicate the frame is coming from management modules + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Tag the packet for QoS on Tx path + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove driver-land statistics. + * + * 03 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * + * 03 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * generate information for OID_GEN_RCV_OK & OID_GEN_XMIT_OK + * * * * * + * +* 03 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code clean: removing unused variables and structure definitions + * + * 03 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) add another spin-lock to protect MsduInfoList due to it might be accessed by different thread. + * * * * 2) change own-back acquiring procedure to wait for up to 16.67 seconds + * + * 03 02 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add mutex to avoid multiple access to qmTxQueue simultaneously. + * + * 02 26 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * avoid referring to NDIS-specific data structure directly from non-glue layer. + * + * 02 24 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add Ethernet destination address information in packet info for TX + * + * 02 10 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) remove unused function in nic_rx.c [which has been handled in que_mgt.c] + * * * * * * 2) firmware image length is now retrieved via NdisFileOpen + * * * * * * 3) firmware image is not structured by (P_IMG_SEC_HDR_T) anymore + * * * * * * 4) nicRxWaitResponse() revised + * * * * * * 5) another set of TQ counter default value is added for fw-download state + * * * * * * 6) Wi-Fi load address is now retrieved from registry too + * + * 02 09 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. Permanent and current MAC address are now retrieved by CMD/EVENT packets instead of hard-coded address + * * * * * * * * * 2. follow MSDN defined behavior when associates to another AP + * * * * * * * * * 3. for firmware download, packet size could be up to 2048 bytes + * + * 02 08 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * prepare for implementing fw download logic + * + * 01 27 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. eliminate improper variable in rHifInfo + * * * * * * * * * 2. block TX/ordinary OID when RF test mode is engaged + * * * * * * * * * 3. wait until firmware finish operation when entering into and leaving from RF test mode + * * * * * * * * * 4. correct some HAL implementation + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism + * + * 01 13 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * TX: fill ucWlanHeaderLength/ucPktFormtId_Flags according to info provided by prMsduInfo + * + * 12 30 2009 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) According to CMD/EVENT documentation v0.8, + * * * * * * * * * * OID_CUSTOM_TEST_RX_STATUS & OID_CUSTOM_TEST_TX_STATUS is no longer used, + * * * * * * * * * * and result is retrieved by get ATInfo instead + * * * * * * * * * * 2) add 4 counter for recording aggregation statistics +** \main\maintrunk.MT6620WiFiDriver_Prj\44 2009-12-10 16:52:15 GMT mtk02752 +** remove unused API +** \main\maintrunk.MT6620WiFiDriver_Prj\43 2009-12-07 22:44:24 GMT mtk02752 +** correct assertion criterion +** \main\maintrunk.MT6620WiFiDriver_Prj\42 2009-12-07 21:15:52 GMT mtk02752 +** correct trivial mistake +** \main\maintrunk.MT6620WiFiDriver_Prj\41 2009-12-04 15:47:21 GMT mtk02752 +** + always append a dword of zero on TX path to avoid TX aggregation to triggered on uninitialized data +** + add more assertion for packet size check +** \main\maintrunk.MT6620WiFiDriver_Prj\40 2009-12-04 14:51:55 GMT mtk02752 +** nicTxMsduInfo(): save ptr for next entry before attaching to qDataPort +** \main\maintrunk.MT6620WiFiDriver_Prj\39 2009-12-04 11:54:54 GMT mtk02752 +** add 2 assertion for size check +** \main\maintrunk.MT6620WiFiDriver_Prj\38 2009-12-03 16:20:35 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\37 2009-11-30 10:57:10 GMT mtk02752 +** 1st DW of WIFI_CMD_T is shared with HIF_TX_HEADER_T +** \main\maintrunk.MT6620WiFiDriver_Prj\36 2009-11-30 09:20:43 GMT mtk02752 +** use TC4 instead of TC5 for command packet +** \main\maintrunk.MT6620WiFiDriver_Prj\35 2009-11-27 11:08:11 GMT mtk02752 +** add flush for reset +** \main\maintrunk.MT6620WiFiDriver_Prj\34 2009-11-26 20:31:22 GMT mtk02752 +** fill prMsduInfo->ucUserPriority +** \main\maintrunk.MT6620WiFiDriver_Prj\33 2009-11-25 21:04:33 GMT mtk02752 +** fill u2SeqNo +** \main\maintrunk.MT6620WiFiDriver_Prj\32 2009-11-24 20:52:12 GMT mtk02752 +** integration with SD1's data path API +** \main\maintrunk.MT6620WiFiDriver_Prj\31 2009-11-24 19:54:25 GMT mtk02752 +** nicTxRetransmitOfOsSendQue & nicTxData but changed to use nicTxMsduInfoList +** \main\maintrunk.MT6620WiFiDriver_Prj\30 2009-11-23 17:53:18 GMT mtk02752 +** add nicTxCmd() for SD1_SD3_DATAPATH_INTEGRATION, which will append only HIF_TX_HEADER. seqNum, +** WIFI_CMD_T will be created inside oid handler +** \main\maintrunk.MT6620WiFiDriver_Prj\29 2009-11-20 15:10:24 GMT mtk02752 +** use TxAccquireResource instead of accessing TCQ directly. +** \main\maintrunk.MT6620WiFiDriver_Prj\28 2009-11-17 22:40:57 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\27 2009-11-17 17:35:40 GMT mtk02752 +** add nicTxMsduInfoList () implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\26 2009-11-17 11:07:10 GMT mtk02752 +** add nicTxAdjustTcq() implementation +** \main\maintrunk.MT6620WiFiDriver_Prj\25 2009-11-16 22:28:38 GMT mtk02752 +** move aucFreeBufferCount/aucMaxNumOfBuffer into another structure +** \main\maintrunk.MT6620WiFiDriver_Prj\24 2009-11-16 21:45:32 GMT mtk02752 +** add SD1_SD3_DATAPATH_INTEGRATION data path handling +** \main\maintrunk.MT6620WiFiDriver_Prj\23 2009-11-13 13:29:56 GMT mtk01084 +** modify TX hdr format, fix tx retransmission issue +** \main\maintrunk.MT6620WiFiDriver_Prj\22 2009-11-11 10:36:21 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\21 2009-11-04 14:11:11 GMT mtk01084 +** modify TX SW data structure +** \main\maintrunk.MT6620WiFiDriver_Prj\20 2009-10-29 19:56:17 GMT mtk01084 +** modify HAL part +** \main\maintrunk.MT6620WiFiDriver_Prj\19 2009-10-13 21:59:23 GMT mtk01084 +** update for new HW design +** \main\maintrunk.MT6620WiFiDriver_Prj\18 2009-10-02 14:00:18 GMT mtk01725 +** \main\maintrunk.MT6620WiFiDriver_Prj\17 2009-05-20 12:26:06 GMT mtk01461 +** Assign SeqNum to CMD Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\16 2009-05-19 10:54:04 GMT mtk01461 +** Add debug message +** \main\maintrunk.MT6620WiFiDriver_Prj\15 2009-05-12 09:41:55 GMT mtk01461 +** Fix Query Command need resp issue +** \main\maintrunk.MT6620WiFiDriver_Prj\14 2009-04-29 15:44:38 GMT mtk01461 +** Move OS dependent code to kalQueryTxOOBData() +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-04-28 10:40:03 GMT mtk01461 +** Add nicTxReleaseResource() for SDIO_STATUS_ENHANCE, and also fix the TX aggregation issue for 1x packet to TX1 port +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-04-21 09:50:47 GMT mtk01461 +** Update nicTxCmd() for moving wait RESP function call to wlanSendCommand() +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-04-17 19:56:32 GMT mtk01461 +** Move the CMD_INFO_T related function to cmd_buf.c +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-04-17 18:14:40 GMT mtk01426 +** Update OOB query for TX packet +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-04-14 15:51:32 GMT mtk01426 +** Support PKGUIO +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-04-02 17:26:40 GMT mtk01461 +** Add virtual OOB for HIF LOOPBACK SW PRETEST +** \main\maintrunk.MT6620WiFiDriver_Prj\7 2009-04-01 10:54:43 GMT mtk01461 +** Add function for SDIO_TX_ENHANCE +** \main\maintrunk.MT6620WiFiDriver_Prj\6 2009-03-23 21:53:47 GMT mtk01461 +** Add code for retransmit of rOsSendQueue, mpSendPacket(), and add code for TX Checksum offload, Loopback Test. +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-03-23 00:33:51 GMT mtk01461 +** Add code for TX Data & Cmd Packet +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-03-18 20:25:40 GMT mtk01461 +** Fix LINT warning +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-03-16 09:10:30 GMT mtk01461 +** Update TX PATH API +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:26:04 GMT mtk01426 +** Init for develop +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will initial all variables in regard to SW TX Queues and +* all free lists of MSDU_INFO_T and SW_TFCB_T. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicTxInitialize(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + PUINT_8 pucMemHandle; + P_MSDU_INFO_T prMsduInfo; + UINT_32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxInitialize"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + /* 4 <1> Initialization of Traffic Class Queue Parameters */ + nicTxResetResource(prAdapter); + +#if CFG_SDIO_TX_AGG + prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; +#endif /* CFG_SDIO_TX_AGG */ + + /* allocate MSDU_INFO_T and link it into rFreeMsduInfoList */ + QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); + + pucMemHandle = prTxCtrl->pucTxCached; + for (i = 0; i < CFG_TX_MAX_PKT_NUM; i++) { + prMsduInfo = (P_MSDU_INFO_T) pucMemHandle; + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); + } + + ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization function */ + ASSERT((UINT_32) (pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize); + + QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); + prTxCtrl->i4TxMgmtPendingNum = 0; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum = 0; + prTxCtrl->u4TotalTxPacketNum = 0; +#endif + + prTxCtrl->i4PendingFwdFrameCount = 0; + + qmInit(prAdapter); + + TX_RESET_ALL_CNTS(prTxCtrl); + +} /* end of nicTxInitialize() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will check if has enough TC Buffer for incoming +* packet and then update the value after promise to provide the resources. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] ucTC Specify the resource of TC +* +* \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. +* \retval WLAN_STATUS_RESOURCES Resource is not available. +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 u4CurrTick = 0; +WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN BOOLEAN pfgIsSecOrMgmt) +{ +#define TC4_NO_RESOURCE_DELAY_MS 5 /* exponential of 5s */ + + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; + P_QUE_MGT_T prQM; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + prQM = &prAdapter->rQM; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + +/* DbgPrint("nicTxAcquireResource prTxCtrl->rTc.aucFreeBufferCount[%d]=%d\n", + ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); */ + do { + if (pfgIsSecOrMgmt && (ucTC == TC4_INDEX)) { + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] < 2) { + DBGLOG(TX, EVENT, " aucFreeBufferCount = %d\n", + prTxCtrl->rTc.aucFreeBufferCount[ucTC]); + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) + u4CurrTick = 0; + + break; + } + } + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC]) { + + if (ucTC == TC4_INDEX) + u4CurrTick = 0; + /* get a available TX entry */ + prTxCtrl->rTc.aucFreeBufferCount[ucTC]--; + + prQM->au4ResourceUsedCounter[ucTC]++; + + DBGLOG(TX, EVENT, "Acquire: TC = %d aucFreeBufferCount = %d\n", + ucTC, prTxCtrl->rTc.aucFreeBufferCount[ucTC]); + + u4Status = WLAN_STATUS_SUCCESS; + } + } while (FALSE); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + if (ucTC == TC4_INDEX) { + if (u4CurrTick == 0) + u4CurrTick = kalGetTimeTick(); + if (CHECK_FOR_TIMEOUT(kalGetTimeTick(), u4CurrTick, + SEC_TO_SYSTIME(TC4_NO_RESOURCE_DELAY_MS))) { + wlanDumpTcResAndTxedCmd(NULL, 0); + cmdBufDumpCmdQueue(&prAdapter->rPendingCmdQueue, "waiting response CMD queue"); + glDumpConnSysCpuInfo(prAdapter->prGlueInfo); + kalSendAeeWarning("[TC4 no resource delay 5s!]", __func__); + glDoChipReset(); + u4CurrTick = 0; + } + } + return u4Status; + +} /* end of nicTxAcquireResourceAndTFCBs() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will do polling if FW has return the resource. +* Used when driver start up before enable interrupt. +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Resource is available. +* @retval WLAN_STATUS_FAILURE Resource is not available. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) +{ + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; + UINT_32 au4WTSR[2]; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + if (ucTC >= TC_NUM) + return WLAN_STATUS_FAILURE; + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) + return WLAN_STATUS_SUCCESS; + + while (i-- > 0) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); + + if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { + u4Status = WLAN_STATUS_FAILURE; + break; + } else if (nicTxReleaseResource(prAdapter, (PUINT_8) au4WTSR)) { + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] > 0) { + u4Status = WLAN_STATUS_SUCCESS; + break; + } + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + + } else { + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + } + } + + if (i <= 0 && ucTC == TC4_INDEX) { + DBGLOG(TX, ERROR, "polling Tx resource for Tc4 timeout\n"); + glDumpConnSysCpuInfo(prAdapter->prGlueInfo); + } +#if DBG + { + INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i + 1); + + if (i4Times) { + DBGLOG(TX, TRACE, "Polling MCR_WTSR delay %d times, %d msec\n", + i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)); + } + } +#endif /* DBG */ + + return u4Status; + +} /* end of nicTxPollingResource() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will release TC Buffer count according to +* the given TX_STATUS COUNTER after TX Done. +* +* \param[in] prAdapter Pointer to the Adapter structure. +* \param[in] u4TxStatusCnt Value of TX STATUS +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN unsigned char *aucTxRlsCnt) +{ + PUINT_32 pu4Tmp = (PUINT_32) aucTxRlsCnt; + P_TX_CTRL_T prTxCtrl; + BOOLEAN bStatus = FALSE; + UINT_32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + P_QUE_MGT_T prQM = &prAdapter->rQM; + prTxCtrl = &prAdapter->rTxCtrl; + + if (pu4Tmp[0] | pu4Tmp[1]) { + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + for (i = 0; i < TC_NUM; i++) + prTxCtrl->rTc.aucFreeBufferCount[i] += aucTxRlsCnt[i]; + for (i = 0; i < TC_NUM; i++) + prQM->au4QmTcResourceBackCounter[i] += aucTxRlsCnt[i]; + if (aucTxRlsCnt[TC4_INDEX] != 0) + wlanTraceReleaseTcRes(prAdapter, aucTxRlsCnt, prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX]); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); +#if 0 + for (i = 0; i < TC_NUM; i++) { + DBGLOG(TX, TRACE, "aucFreeBufferCount[%d]: %d, aucMaxNumOfBuffer[%d]: %d\n", + i, prTxCtrl->rTc.aucFreeBufferCount[i], i, + prTxCtrl->rTc.aucMaxNumOfBuffer[i]); + } + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[0]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[0]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[1]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[1]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[2]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[2]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[3]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[3]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[4]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[4]); + DbgPrint("prTxCtrl->rTc.aucFreeBufferCount[5]=%d\n", prTxCtrl->rTc.aucFreeBufferCount[5]); +#endif + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX]); + ASSERT(prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] <= prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX]); + bStatus = TRUE; + } + + return bStatus; +} /* end of nicTxReleaseResource() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Reset TC Buffer Count to initialized value +* +* \param[in] prAdapter Pointer to the Adapter structure. +* +* @return WLAN_STATUS_SUCCESS +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; + prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Driver maintain a variable that is synchronous with the usage of individual +* TC Buffer Count. This function will return the value for other component +* which needs this information for making decisions +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucTC Specify the resource of TC +* +* @retval UINT_8 The number of corresponding TC number +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) +{ + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + ASSERT(prTxCtrl); + + if (ucTC >= TC_NUM) + return 0; + else + return prTxCtrl->rTc.aucFreeBufferCount[ucTC]; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief In this function, we'll aggregate frame(PACKET_INFO_T) +* corresponding to HIF TX port +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoListHead a link list of P_MSDU_INFO_T +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T qDataPort0, qDataPort1; + WLAN_STATUS status; + BOOLEAN pfgIsSecOrMgmt = FALSE; + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prMsduInfo = prMsduInfoListHead; + + QUEUE_INITIALIZE(&qDataPort0); + QUEUE_INITIALIZE(&qDataPort1); + + /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); +#if DBG && 0 + LOG_FUNC("nicTxMsduInfoList Acquire TC %d net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prMsduInfo->ucTC, + prMsduInfo->ucNetworkType, + prMsduInfo->ucMacHeaderLength, + prMsduInfo->u2FrameLength, + prMsduInfo->ucPacketType, prMsduInfo->fgIs802_1x, prMsduInfo->fgIs802_11); + + LOG_FUNC("Dest Mac: %pM\n", prMsduInfo->aucEthDestAddr); +#endif + + /* double-check available TX resouce (need to sync with CONNSYS FW) */ + /* caller must guarantee that the TX resource is enough in the func; OR assert here */ + switch (prMsduInfo->ucTC) { + case TC0_INDEX: + case TC1_INDEX: + case TC2_INDEX: + case TC3_INDEX: + case TC5_INDEX: /* Broadcast/multicast data packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); + status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, FALSE); + ASSERT(status == WLAN_STATUS_SUCCESS) + + break; + + case TC4_INDEX: /* Command or 802.1x packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); + + if ((prMsduInfo->fgIs802_1x == TRUE) || + (prMsduInfo->fgIs802_11 == TRUE)) + pfgIsSecOrMgmt = TRUE; + + status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, pfgIsSecOrMgmt); + ASSERT(status == WLAN_STATUS_SUCCESS) + + break; + + default: + ASSERT(0); + break; + } + + prMsduInfo = prNextMsduInfo; + } + + /* send packets to HIF port0 or port1 here */ + if (qDataPort0.u4NumElem > 0) + nicTxMsduQueue(prAdapter, 0, &qDataPort0); + + if (qDataPort1.u4NumElem > 0) + nicTxMsduQueue(prAdapter, 1, &qDataPort1); + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + +#if CFG_PRINT_RTP_PROFILE +PKT_PROFILE_T rPrevRoundLastPkt; + +BOOLEAN +nicTxLifetimePrintCheckRTP(IN P_MSDU_INFO_T prPrevProfileMsduInfo, + IN P_PKT_PROFILE_T prPrevRoundLastPkt, + IN P_PKT_PROFILE_T prPktProfile, + IN OUT PBOOLEAN pfgGotFirst, IN UINT_32 u4MaxDeltaTime, IN UINT_8 ucSnToBePrinted) +{ + BOOLEAN fgPrintCurPkt = FALSE; + + if (u4MaxDeltaTime) { + /* 4 1. check delta between current round first pkt and prevous round last pkt */ + if (!*pfgGotFirst) { + *pfgGotFirst = TRUE; + + if (prPrevRoundLastPkt->fgIsValid) { + if (CHK_PROFILES_DELTA(prPktProfile, prPrevRoundLastPkt, u4MaxDeltaTime)) { + PRINT_PKT_PROFILE(prPrevRoundLastPkt, "PR"); + fgPrintCurPkt = TRUE; + } + } + } + /* 4 2. check delta between current pkt and previous pkt */ + if (prPrevProfileMsduInfo) { + if (CHK_PROFILES_DELTA(prPktProfile, &prPrevProfileMsduInfo->rPktProfile, u4MaxDeltaTime)) { + PRINT_PKT_PROFILE(&prPrevProfileMsduInfo->rPktProfile, "P"); + fgPrintCurPkt = TRUE; + } + } + /* 4 3. check delta of current pkt lifetime */ + if (CHK_PROFILE_DELTA(prPktProfile, u4MaxDeltaTime)) + fgPrintCurPkt = TRUE; + } + /* 4 4. print every X RTP packets */ +#if CFG_SUPPORT_WFD + if ((ucSnToBePrinted != 0) && (prPktProfile->u2RtpSn % ucSnToBePrinted) == 0) + fgPrintCurPkt = TRUE; +#endif + + return fgPrintCurPkt; +} + +BOOLEAN +nicTxLifetimePrintCheckSnOrder(IN P_MSDU_INFO_T prPrevProfileMsduInfo, + IN P_PKT_PROFILE_T prPrevRoundLastPkt, + IN P_PKT_PROFILE_T prPktProfile, IN OUT PBOOLEAN pfgGotFirst, IN UINT_8 ucLayer) +{ + BOOLEAN fgPrintCurPkt = FALSE; + P_PKT_PROFILE_T prTarPktProfile = NULL; + UINT_16 u2PredictSn = 0; + UINT_16 u2CurrentSn = 0; + UINT_8 aucNote[8]; + + /* 4 1. Get the target packet profile to compare */ + + /* 4 1.1 check SN between current round first pkt and prevous round last pkt */ + if ((!*pfgGotFirst) && (prPrevRoundLastPkt->fgIsValid)) { + *pfgGotFirst = TRUE; + prTarPktProfile = prPrevRoundLastPkt; + kalMemCopy(aucNote, "PR\0", 3); + } + /* 4 1.2 check SN between current pkt and previous pkt */ + else if (prPrevProfileMsduInfo) { + prTarPktProfile = &prPrevProfileMsduInfo->rPktProfile; + kalMemCopy(aucNote, "P\0", 2); + } + + if (!prTarPktProfile) + return FALSE; + /* 4 2. Check IP or RTP SN */ + switch (ucLayer) { + /* Check IP SN */ + case 0: + u2PredictSn = prTarPktProfile->u2IpSn + 1; + u2CurrentSn = prPktProfile->u2IpSn; + break; + /* Check RTP SN */ + case 1: + default: + u2PredictSn = prTarPktProfile->u2RtpSn + 1; + u2CurrentSn = prPktProfile->u2RtpSn; + break; + + } + /* 4 */ + /* 4 3. Compare SN */ + if (u2CurrentSn != u2PredictSn) { + PRINT_PKT_PROFILE(prTarPktProfile, aucNote); + fgPrintCurPkt = TRUE; + } + + return fgPrintCurPkt; +} +#endif + +VOID nicTxReturnMsduInfoProfiling(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; + P_PKT_PROFILE_T prPktProfile; + UINT_16 u2MagicCode = 0; + + UINT_8 ucDebugtMode = 0; +#if CFG_PRINT_RTP_PROFILE + P_MSDU_INFO_T prPrevProfileMsduInfo = NULL; + P_PKT_PROFILE_T prPrevRoundLastPkt = &rPrevRoundLastPkt; + + BOOLEAN fgPrintCurPkt = FALSE; + BOOLEAN fgGotFirst = FALSE; + UINT_8 ucSnToBePrinted = 0; + + UINT_32 u4MaxDeltaTime = 50; /* in ms */ +#endif + +#if CFG_ENABLE_PER_STA_STATISTICS + UINT_32 u4PktPrintPeriod = 0; +#endif + +#if CFG_SUPPORT_WFD + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + if (prAdapter->fgIsP2PRegistered) { + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + u2MagicCode = prWfdCfgSettings->u2WfdMaximumTp; + ucDebugtMode = prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting.ucWfdDebugMode; + /* if(prWfdCfgSettings->ucWfdEnable && (prWfdCfgSettings->u4WfdFlag & BIT(0))) { */ + /* u2MagicCode = 0xE040; */ + /* } */ + } +#endif + +#if CFG_PRINT_RTP_PROFILE + if ((u2MagicCode >= 0xF000)) { + ucSnToBePrinted = (UINT_8) (u2MagicCode & BITS(0, 7)); + u4MaxDeltaTime = (UINT_8) (((u2MagicCode & BITS(8, 11)) >> 8) * 10); + } else { + ucSnToBePrinted = 0; + u4MaxDeltaTime = 0; + } + +#endif + +#if CFG_ENABLE_PER_STA_STATISTICS + if ((u2MagicCode >= 0xE000) && (u2MagicCode < 0xF000)) + u4PktPrintPeriod = (UINT_32) ((u2MagicCode & BITS(0, 7)) * 32); + else + u4PktPrintPeriod = 0; +#endif + + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); + prPktProfile = &prMsduInfo->rPktProfile; + + if (prPktProfile->fgIsValid) { + + prPktProfile->rHifTxDoneTimestamp = kalGetTimeTick(); + if (ucDebugtMode > 1) { + +#if CFG_PRINT_RTP_PROFILE +#if CFG_PRINT_RTP_SN_SKIP + fgPrintCurPkt = nicTxLifetimePrintCheckSnOrder(prPrevProfileMsduInfo, + prPrevRoundLastPkt, + prPktProfile, &fgGotFirst, 0); +#else + fgPrintCurPkt = nicTxLifetimePrintCheckRTP(prPrevProfileMsduInfo, + prPrevRoundLastPkt, + prPktProfile, + &fgGotFirst, + u4MaxDeltaTime, ucSnToBePrinted); +#endif + + /* Print current pkt profile */ + if (fgPrintCurPkt && ucDebugtMode > 1) + PRINT_PKT_PROFILE(prPktProfile, "C"); + + prPrevProfileMsduInfo = prMsduInfo; + fgPrintCurPkt = FALSE; +#endif + } +#if CFG_ENABLE_PER_STA_STATISTICS + { + P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + UINT_32 u4DeltaTime; + UINT_32 u4DeltaHifTime; +#if 0 + P_QUE_MGT_T prQM = &prAdapter->rQM; +#endif + UINT_8 ucNetIndex; + + if (prStaRec) { + ucNetIndex = prStaRec->ucNetTypeIndex; + u4DeltaTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - + prPktProfile->rHardXmitArrivalTimestamp); + u4DeltaHifTime = (UINT_32) (prPktProfile->rHifTxDoneTimestamp - + prPktProfile->rDequeueTimestamp); + prStaRec->u4TotalTxPktsNumber++; + + prStaRec->u4TotalTxPktsTime += u4DeltaTime; + prStaRec->u4TotalTxPktsHifTime += u4DeltaHifTime; + + if (u4DeltaTime > prStaRec->u4MaxTxPktsTime) + prStaRec->u4MaxTxPktsTime = u4DeltaTime; + + if (u4DeltaHifTime > prStaRec->u4MaxTxPktsHifTime) + prStaRec->u4MaxTxPktsHifTime = u4DeltaHifTime; + + + if (u4DeltaTime >= NIC_TX_TIME_THRESHOLD) + prStaRec->u4ThresholdCounter++; +#if 0 + if (u4PktPrintPeriod && (prStaRec->u4TotalTxPktsNumber >= u4PktPrintPeriod)) { + + DBGLOG(TX, TRACE, "[%u]N[%4u]A[%5u]M[%4u]T[%4u]E[%4u]\n", + prStaRec->ucIndex, + prStaRec->u4TotalTxPktsNumber, + prStaRec->u4TotalTxPktsTime / prStaRec->u4TotalTxPktsNumber, + prStaRec->u4MaxTxPktsTime, + prStaRec->u4ThresholdCounter, + prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX]); + + prStaRec->u4TotalTxPktsNumber = 0; + prStaRec->u4TotalTxPktsTime = 0; + prStaRec->u4MaxTxPktsTime = 0; + prStaRec->u4ThresholdCounter = 0; + prQM->au4QmTcResourceEmptyCounter[ucNetIndex][TC2_INDEX] = 0; + } +#endif + } + + } +#endif + } + + prMsduInfo = prNextMsduInfo; + }; + +#if CFG_PRINT_RTP_PROFILE + /* 4 4. record the lifetime of current round last pkt */ + if (prPrevProfileMsduInfo) { + prPktProfile = &prPrevProfileMsduInfo->rPktProfile; + prPrevRoundLastPkt->u2IpSn = prPktProfile->u2IpSn; + prPrevRoundLastPkt->u2RtpSn = prPktProfile->u2RtpSn; + prPrevRoundLastPkt->rHardXmitArrivalTimestamp = prPktProfile->rHardXmitArrivalTimestamp; + prPrevRoundLastPkt->rEnqueueTimestamp = prPktProfile->rEnqueueTimestamp; + prPrevRoundLastPkt->rDequeueTimestamp = prPktProfile->rDequeueTimestamp; + prPrevRoundLastPkt->rHifTxDoneTimestamp = prPktProfile->rHifTxDoneTimestamp; + prPrevRoundLastPkt->ucTcxFreeCount = prPktProfile->ucTcxFreeCount; + prPrevRoundLastPkt->fgIsPrinted = prPktProfile->fgIsPrinted; + prPrevRoundLastPkt->fgIsValid = TRUE; + } +#endif + + nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); + +} + +VOID nicTxLifetimeRecordEn(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) +{ + P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; + + /* Enable packet lifetime profiling */ + prPktProfile->fgIsValid = TRUE; + + /* Packet arrival time at kernel Hard Xmit */ + prPktProfile->rHardXmitArrivalTimestamp = GLUE_GET_PKT_ARRIVAL_TIME(prPacket); + + /* Packet enqueue time */ + prPktProfile->rEnqueueTimestamp = (OS_SYSTIME) kalGetTimeTick(); + +} + +#if CFG_PRINT_RTP_PROFILE +/* + in: + data RTP packet pointer + size RTP size + return + 0:audio 1: video, -1:none +*/ +UINT8 checkRtpAV(PUINT_8 data, UINT_32 size) +{ + PUINT_8 buf = data + 12; + + while (buf + 188 <= data + size) { + int pid = ((buf[1] << 8) & 0x1F00) | (buf[2] & 0xFF); + + if (pid == 0 || pid == 0x100 || pid == 0x1000) + buf += 188; + else if (pid == 0x1100) + return 0; + else if (pid == 0x1011) + return 1; + } + return -1; +} + +VOID +nicTxLifetimeCheckRTP(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prPacket, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) +{ + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + UINT_16 u2EtherTypeLen; + PUINT_8 aucLookAheadBuf = NULL; + P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; + + /* UINT_8 ucRtpHdrOffset = 28; */ + UINT_8 ucRtpSnOffset = 30; + /* UINT_32 u4RtpSrcPort = 15550; */ + P_TX_CTRL_T prTxCtrl; +#if CFG_SUPPORT_WFD + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_WFD_DBG_CFG_SETTINGS_T prWfdDbgSettings = (P_WFD_DBG_CFG_SETTINGS_T) NULL; + + BOOLEAN fgEnProfiling = FALSE; + + if (prAdapter->fgIsP2PRegistered) { + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + prWfdDbgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdDebugSetting; +#if CFG_PRINT_RTP_SN_SKIP + if (ucNetworkType == NETWORK_TYPE_P2P_INDEX) { + fgEnProfiling = TRUE; + } else +#endif + if (((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000) || + (prWfdDbgSettings->ucWfdDebugMode > 0)) && (ucNetworkType == NETWORK_TYPE_P2P_INDEX)) { + fgEnProfiling = TRUE; + } + } + + if (fgEnProfiling == FALSE) { + /* prPktProfile->fgIsValid = FALSE; */ + return; + } +#endif + + prTxCtrl = &prAdapter->rTxCtrl; + /* prPktProfile->fgIsValid = FALSE; */ + + aucLookAheadBuf = prSkb->data; + + u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); + + if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { + PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; + UINT_16 u2tmpIpSN = 0; + UINT_8 ucIpVersion; + + ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + if (ucIpVersion == IPVERSION) { + if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { + + /* if(checkRtpAV(&pucIpHdr[ucRtpHdrOffset], + (u4PacketLen - ETH_HLEN - ucRtpHdrOffset)) == 0) { */ + + if (prPktProfile->fgIsValid == FALSE) + nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); + + prPktProfile->fgIsPrinted = FALSE; + + prPktProfile->ucTcxFreeCount = prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX]; + + /* RTP SN */ + prPktProfile->u2RtpSn = pucIpHdr[ucRtpSnOffset] << 8 | pucIpHdr[ucRtpSnOffset + 1]; + + /* IP SN */ + prPktProfile->u2IpSn = pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET] << 8 | + pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET + 1]; + u2tmpIpSN = prPktProfile->u2IpSn; + if (prWfdDbgSettings->ucWfdDebugMode == 1) { + if ((u2tmpIpSN & (prWfdDbgSettings->u2WfdSNShowPeiroid)) == 0) + DBGLOG(TX, TRACE, + "RtpSn=%d IPId=%d j=%lu\n", prPktProfile->u2RtpSn, + prPktProfile->u2IpSn, jiffies); + } + /* } */ + } + } + } + +} +#endif +#if CFG_ENABLE_PER_STA_STATISTICS +VOID +nicTxLifetimeCheckByAC(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket, IN UINT_8 ucPriorityParam) +{ + switch (ucPriorityParam) { + /* BK */ + /* case 1: */ + /* case 2: */ + + /* BE */ + /* case 0: */ + /* case 3: */ + + /* VI */ + case 4: + case 5: + + /* VO */ + case 6: + case 7: + nicTxLifetimeRecordEn(prAdapter, prMsduInfo, prPacket); + break; + default: + break; + } +} + +#endif + +VOID +nicTxLifetimeCheck(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prPacket, + IN UINT_8 ucPriorityParam, IN UINT_32 u4PacketLen, IN UINT_8 ucNetworkType) +{ + P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; + + /* Reset packet profile */ + prPktProfile->fgIsValid = FALSE; + +#if CFG_ENABLE_PER_STA_STATISTICS + nicTxLifetimeCheckByAC(prAdapter, prMsduInfo, prPacket, ucPriorityParam); +#endif + +#if CFG_PRINT_RTP_PROFILE + nicTxLifetimeCheckRTP(prAdapter, prMsduInfo, prPacket, u4PacketLen, ucNetworkType); +#endif + +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. +* +* @param prAdapter Pointer to the Adapter structure. +* @param ucPortIdx Port Number +* @param prQue a link list of P_MSDU_INFO_T +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + HIF_TX_HEADER_T rHwTxHeader; + P_NATIVE_PACKET prNativePacket; + UINT_16 u2OverallBufferLength; + UINT_8 ucEtherTypeOffsetInWord; + PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 u4TxHdrSize; + UINT_32 u4ValidBufSize; + UINT_32 u4TotalLength; + P_TX_CTRL_T prTxCtrl; + QUE_T rFreeQueue; +#if CFG_TCP_IP_CHKSUM_OFFLOAD + UINT_8 ucChksumFlag; +#endif + + ASSERT(prAdapter); + ASSERT(ucPortIdx < 2); + ASSERT(prQue); + + prTxCtrl = &prAdapter->rTxCtrl; + u4ValidBufSize = prAdapter->u4CoalescingBufCachedSize; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum++; + prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; +#endif + + QUEUE_INITIALIZE(&rFreeQueue); + + if (prQue->u4NumElem > 0) { + prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_HEAD(prQue); + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + u4TotalLength = 0; + + while (prMsduInfo) { + +#if (CFG_SUPPORT_TDLS_DBG == 1) + { + struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; + UINT8 *pkt = prSkb->data; + UINT16 u2Identifier; + + if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { + /* ip */ + u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); + DBGLOG(TX, TRACE, " %d\n", u2Identifier); + } + } +#endif +#if (CFG_SUPPORT_MET_PROFILING == 1) + kalMetProfilingFinish(prAdapter, prMsduInfo); +#endif + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + prNativePacket = prMsduInfo->prPacket; + + ASSERT(prNativePacket); + + u4TxHdrSize = TX_HDR_SIZE; + + u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & + (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + /* init TX header */ + rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; + rHwTxHeader.u2TxByteCount_UserPriority |= + ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); + + if (prMsduInfo->fgIs802_11) { + ucEtherTypeOffsetInWord = + (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; + } else { + ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; + } + + rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; + rHwTxHeader.ucResource_PktType_CSflags |= + (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & + (HIF_TX_HDR_PACKET_TYPE_MASK)); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + if (prAdapter->u4CSUMFlags & + (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP)) { + kalQueryTxChksumOffloadParam(prNativePacket, &ucChksumFlag); + + if (ucChksumFlag & TX_CS_IP_GEN) + rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_IP_CSUM; + + if (ucChksumFlag & TX_CS_TCP_UDP_GEN) + rHwTxHeader.ucResource_PktType_CSflags |= (UINT_8) HIF_TX_HDR_TCP_CSUM; + } + } +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; + rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = + (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << + HIF_TX_HDR_PS_SESSION_ID_OFFSET) + | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); + + rHwTxHeader.ucWlanHeaderLength = + (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) + | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & + HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & + HIF_TX_HDR_FLAG_1X_FRAME_MASK) + | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & + HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); + + rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; + + if (prMsduInfo->pfTxDoneHandler) { + rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; + rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; + } else { + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = 0; + } + + if (prMsduInfo->fgNeedTxDoneStatus == TRUE) + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_NEED_TX_DONE_STATUS; + + if (prMsduInfo->fgIsBIP) + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; + + if (prMsduInfo->fgIsBasicRate) + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + if (prMsduInfo->rPktProfile.fgIsValid) + prMsduInfo->rPktProfile.rDequeueTimestamp = kalGetTimeTick(); +#endif + + /* record the queue time in driver */ + STATS_TX_TIME_TO_HIF(prMsduInfo, &rHwTxHeader); + +#if CFG_SDIO_TX_AGG + /* attach to coalescing buffer */ + kalMemCopy(pucOutputBuf + u4TotalLength, &rHwTxHeader, u4TxHdrSize); + u4TotalLength += u4TxHdrSize; + + if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) + kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TotalLength); + else if (prMsduInfo->eSrc == TX_PACKET_MGMT) + kalMemCopy(pucOutputBuf + u4TotalLength, prNativePacket, prMsduInfo->u2FrameLength); + else + ASSERT(0); + + u4TotalLength += ALIGN_4(prMsduInfo->u2FrameLength); + +#else + kalMemCopy(pucOutputBuf, &rHwTxHeader, u4TxHdrSize); + + /* Copy Frame Body */ + if (prMsduInfo->eSrc == TX_PACKET_OS || prMsduInfo->eSrc == TX_PACKET_FORWARDING) + kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + u4TxHdrSize); + else if (prMsduInfo->eSrc == TX_PACKET_MGMT) + kalMemCopy(pucOutputBuf + u4TxHdrSize, prNativePacket, prMsduInfo->u2FrameLength); + else + ASSERT(0); + + ASSERT(u2OverallBufferLength <= u4ValidBufSize); + + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32) u2OverallBufferLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); + + /* send immediately */ +#endif + prNextMsduInfo = (P_MSDU_INFO_T) + QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry); + + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + if (prMsduInfo->pfTxDoneHandler == NULL) { + cnmMgtPktFree(prAdapter, prMsduInfo); + } else { + KAL_SPIN_LOCK_DECLARATION(); + DBGLOG(TX, TRACE, "Wait TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + } + } else { + /* only free MSDU when it is not a MGMT frame */ + QUEUE_INSERT_TAIL(&rFreeQueue, (P_QUE_ENTRY_T) prMsduInfo); + + if (prMsduInfo->eSrc == TX_PACKET_OS) + kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_SUCCESS); + else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) + GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + } + + prMsduInfo = prNextMsduInfo; + } + +#if CFG_SDIO_TX_AGG + ASSERT(u4TotalLength <= u4ValidBufSize); + +#if CFG_DBG_GPIO_PINS + { + /* Start port write */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_LOW); + kalUdelay(1); + mtk_wcn_stp_debug_gpio_assert(IDX_TX_PORT_WRITE, DBG_TIE_HIGH); + } +#endif + + /* send coalescing buffer */ + HAL_WRITE_TX_PORT(prAdapter, ucPortIdx, u4TotalLength, (PUINT_8) pucOutputBuf, u4ValidBufSize); +#endif + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +#if CFG_SUPPORT_WFD && CFG_PRINT_RTP_PROFILE && !CFG_ENABLE_PER_STA_STATISTICS + do { + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + + prWfdCfgSettings = &prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings; + + if ((prWfdCfgSettings->u2WfdMaximumTp >= 0xF000)) { + /* Enable profiling */ + nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); + } else { + /* Skip profiling */ + nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); + } + } while (FALSE); +#else + nicTxReturnMsduInfoProfiling(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); +#endif +#else + /* return */ + nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); +#endif + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. +* +* @param prAdapter Pointer to the Adapter structure. +* @param prPacketInfo Pointer of CMD_INFO_T +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) +{ + P_WIFI_CMD_T prWifiCmd; + UINT_16 u2OverallBufferLength; + PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_8 ucPortIdx; + HIF_TX_HEADER_T rHwTxHeader; + P_NATIVE_PACKET prNativePacket; + UINT_8 ucEtherTypeOffsetInWord; + P_MSDU_INFO_T prMsduInfo; + P_TX_CTRL_T prTxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + + /* <1> Assign Data Port */ + if (ucTC != TC4_INDEX) { + ucPortIdx = 0; + } else { + /* Broadcast/multicast data frames, 1x frames, command packets, MMPDU */ + ucPortIdx = 1; + } + wlanTraceTxCmd(prCmdInfo); + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + /* <2> Compose HIF_TX_HEADER */ + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + prNativePacket = prCmdInfo->prPacket; + + ASSERT(prNativePacket); + + u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) + & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + rHwTxHeader.u2TxByteCount_UserPriority = ((prCmdInfo->u2InfoBufLen + TX_HDR_SIZE) + & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + TX_HDR_SIZE) >> 1; + + rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET); + + rHwTxHeader.ucStaRecIdx = prCmdInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = HIF_TX_HDR_BURST_END_MASK; + + rHwTxHeader.ucWlanHeaderLength = (ETH_HLEN & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = + (((UINT_8) (prCmdInfo->eNetworkType) << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & + HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((1 << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK); + + rHwTxHeader.u2SeqNo = 0; + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_TX_DONE_STATUS; + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE /* | HIF_TX_HDR_RTS */; + + /* <2.3> Copy HIF TX HEADER */ + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); + + /* <3> Copy Frame Body Copy */ + kalCopyFrame(prAdapter->prGlueInfo, prNativePacket, pucOutputBuf + TX_HDR_SIZE); + } else if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + prMsduInfo = (P_MSDU_INFO_T) prCmdInfo->prPacket; + + ASSERT(prMsduInfo->fgIs802_11 == TRUE); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + /* <2> Compose HIF_TX_HEADER */ + kalMemZero(&rHwTxHeader, sizeof(rHwTxHeader)); + + u2OverallBufferLength = ((prMsduInfo->u2FrameLength + TX_HDR_SIZE) & + (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + rHwTxHeader.u2TxByteCount_UserPriority = u2OverallBufferLength; + rHwTxHeader.u2TxByteCount_UserPriority |= + ((UINT_16) prMsduInfo->ucUserPriority << HIF_TX_HDR_USER_PRIORITY_OFFSET); + + ucEtherTypeOffsetInWord = (TX_HDR_SIZE + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; + + rHwTxHeader.ucEtherTypeOffset = ucEtherTypeOffsetInWord & HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK; + + rHwTxHeader.ucResource_PktType_CSflags = (prMsduInfo->ucTC) << HIF_TX_HDR_RESOURCE_OFFSET; + rHwTxHeader.ucResource_PktType_CSflags |= + (UINT_8) (((prMsduInfo->ucPacketType) << HIF_TX_HDR_PACKET_TYPE_OFFSET) & + (HIF_TX_HDR_PACKET_TYPE_MASK)); + + rHwTxHeader.u2LLH = prMsduInfo->u2PalLLH; + rHwTxHeader.ucStaRecIdx = prMsduInfo->ucStaRecIndex; + rHwTxHeader.ucForwardingType_SessionID_Reserved = + (prMsduInfo->ucPsForwardingType) | ((prMsduInfo->ucPsSessionID) << HIF_TX_HDR_PS_SESSION_ID_OFFSET) + | ((prMsduInfo->fgIsBurstEnd) ? HIF_TX_HDR_BURST_END_MASK : 0); + + rHwTxHeader.ucWlanHeaderLength = (prMsduInfo->ucMacHeaderLength & HIF_TX_HDR_WLAN_HEADER_LEN_MASK); + rHwTxHeader.ucPktFormtId_Flags = (prMsduInfo->ucFormatID & HIF_TX_HDR_FORMAT_ID_MASK) + | ((prMsduInfo->ucNetworkType << HIF_TX_HDR_NETWORK_TYPE_OFFSET) & HIF_TX_HDR_NETWORK_TYPE_MASK) + | ((prMsduInfo->fgIs802_1x << HIF_TX_HDR_FLAG_1X_FRAME_OFFSET) & HIF_TX_HDR_FLAG_1X_FRAME_MASK) + | ((prMsduInfo->fgIs802_11 << HIF_TX_HDR_FLAG_802_11_FORMAT_OFFSET) & + HIF_TX_HDR_FLAG_802_11_FORMAT_MASK); + + rHwTxHeader.u2SeqNo = prMsduInfo->u2AclSN; + + if (prMsduInfo->pfTxDoneHandler) { + rHwTxHeader.ucPacketSeqNo = prMsduInfo->ucTxSeqNum; + rHwTxHeader.ucAck_BIP_BasicRate = HIF_TX_HDR_NEED_ACK; + } else { + rHwTxHeader.ucPacketSeqNo = 0; + rHwTxHeader.ucAck_BIP_BasicRate = 0; + } + + if (prMsduInfo->fgIsBIP) + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BIP; + + if (prMsduInfo->fgIsBasicRate) + rHwTxHeader.ucAck_BIP_BasicRate |= HIF_TX_HDR_BASIC_RATE; + /* <2.3> Copy HIF TX HEADER */ + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID)&rHwTxHeader, TX_HDR_SIZE); + + /* <3> Copy Frame Body */ + kalMemCopy(pucOutputBuf + TX_HDR_SIZE, prMsduInfo->prPacket, prMsduInfo->u2FrameLength); + + /* <4> Management Frame Post-Processing */ + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + if (prMsduInfo->pfTxDoneHandler == NULL) { + cnmMgtPktFree(prAdapter, prMsduInfo); + } else { + + DBGLOG(TX, TRACE, "Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + } + } else { + prWifiCmd = (P_WIFI_CMD_T) prCmdInfo->pucInfoBuffer; + + /* <2> Compose the Header of Transmit Data Structure for CMD Packet */ + u2OverallBufferLength = + TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + prWifiCmd->u2TxByteCount_UserPriority = u2OverallBufferLength; + prWifiCmd->ucEtherTypeOffset = 0; + prWifiCmd->ucResource_PktType_CSflags = (ucTC << HIF_TX_HDR_RESOURCE_OFFSET) + | (UINT_8) ((HIF_TX_PKT_TYPE_CMD << HIF_TX_HDR_PACKET_TYPE_OFFSET) & (HIF_TX_HDR_PACKET_TYPE_MASK)); + + /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); + + ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); + + if ((prCmdInfo->ucCID == CMD_ID_SCAN_REQ) || + (prCmdInfo->ucCID == CMD_ID_SCAN_CANCEL) || + (prCmdInfo->ucCID == CMD_ID_SCAN_REQ_V2)) + DBGLOG(TX, INFO, "ucCmdSeqNum =%d, ucCID =%d\n", prCmdInfo->ucCmdSeqNum, prCmdInfo->ucCID); + } + + /* <4> Write frame to data port */ + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32) u2OverallBufferLength, + (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); + + return WLAN_STATUS_SUCCESS; +} /* end of nicTxCmd() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function will clean up all the pending frames in internal SW Queues +* by return the pending TX packet to the system. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicTxRelease(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + nicTxFlush(prAdapter); + + /* free MSDU_INFO_T from rTxMgmtMsduInfoList */ + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + if (prMsduInfo) { + /* the packet must be mgmt frame with tx done callback */ + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + /* invoke done handler */ + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_LIFE_TIMEOUT); + + cnmMgtPktFree(prAdapter, prMsduInfo); + } else { + break; + } + } while (TRUE); + +} /* end of nicTxRelease() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Process the TX Done interrupt and pull in more pending frames in SW +* Queues for transmission. +* +* @param prAdapter Pointer to the Adapter structure. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; +#if CFG_SDIO_INTR_ENHANCE + P_SDIO_CTRL_T prSDIOCtrl; +#else + UINT_32 au4TxCount[2]; +#endif /* CFG_SDIO_INTR_ENHANCE */ + + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + prGlueInfo->IsrTxCnt++; + + /* Get the TX STATUS */ +#if CFG_SDIO_INTR_ENHANCE + + prSDIOCtrl = prAdapter->prSDIOCtrl; +#if DBG + /* dumpMemory8((PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T)); */ +#endif + + nicTxReleaseResource(prAdapter, (PUINT_8) &prSDIOCtrl->rTxInfo); + kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); + +#else + + HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); + HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); + DBGLOG(EMU, TRACE, "MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1]); + + nicTxReleaseResource(prAdapter, (PUINT_8) au4TxCount); + +#endif /* CFG_SDIO_INTR_ENHANCE */ + + nicTxAdjustTcq(prAdapter); + + /* Indicate Service Thread */ + if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) + kalSetEvent(prAdapter->prGlueInfo); + +} /* end of nicProcessTxInterrupt() */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function frees packet of P_MSDU_INFO_T linked-list +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoList a link list of P_MSDU_INFO_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_NATIVE_PACKET prNativePacket; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + + while (prMsduInfo) { + prNativePacket = prMsduInfo->prPacket; + + if (prMsduInfo->eSrc == TX_PACKET_OS) { + kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_FAILURE); + } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + P_MSDU_INFO_T prTempMsduInfo = prMsduInfo; + + if (prMsduInfo->pfTxDoneHandler) + prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); + prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); + cnmMgtPktFree(prAdapter, prTempMsduInfo); + continue; + } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + } + + prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfoList a link list of P_MSDU_INFO_T +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); + + switch (prMsduInfo->eSrc) { + case TX_PACKET_FORWARDING: + wlanReturnPacket(prAdapter, prMsduInfo->prPacket); + break; + case TX_PACKET_OS: + case TX_PACKET_OS_OID: + case TX_PACKET_MGMT: + default: + break; + } + + /* Reset MSDU_INFO fields */ + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = prNextMsduInfo; + }; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function fills packet information to P_MSDU_INFO_T +* +* @param prAdapter Pointer to the Adapter structure. +* @param prMsduInfo P_MSDU_INFO_T +* @param prPacket P_NATIVE_PACKET +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) +{ + P_GLUE_INFO_T prGlueInfo; + UINT_8 ucPriorityParam; + UINT_8 ucMacHeaderLen; + UINT_8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; + BOOLEAN fgIs1x = FALSE; + BOOLEAN fgIsPAL = FALSE; + UINT_32 u4PacketLen; + ULONG u4SysTime; + UINT_8 ucNetworkType; + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + if (kalQoSFrameClassifierAndPacketInfo(prGlueInfo, + prPacket, + &ucPriorityParam, + &u4PacketLen, + aucEthDestAddr, + &fgIs1x, &fgIsPAL, &ucNetworkType, + NULL) == FALSE) { + return FALSE; + } +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + nicTxLifetimeCheck(prAdapter, prMsduInfo, prPacket, ucPriorityParam, u4PacketLen, ucNetworkType); +#endif + + /* Save the value of Priority Parameter */ + GLUE_SET_PKT_TID(prPacket, ucPriorityParam); + + if (fgIs1x) + GLUE_SET_PKT_FLAG_1X(prPacket); + + if (fgIsPAL) + GLUE_SET_PKT_FLAG_PAL(prPacket); + + ucMacHeaderLen = ETH_HLEN; + + /* Save the value of Header Length */ + GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen); + + /* Save the value of Frame Length */ + GLUE_SET_PKT_FRAME_LEN(prPacket, (UINT_16) u4PacketLen); + + /* Save the value of Arrival Time */ + u4SysTime = (OS_SYSTIME) kalGetTimeTick(); + GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); + + prMsduInfo->prPacket = prPacket; + prMsduInfo->fgIs802_1x = fgIs1x; + prMsduInfo->fgIs802_11 = FALSE; + prMsduInfo->ucNetworkType = ucNetworkType; + prMsduInfo->ucUserPriority = ucPriorityParam; + prMsduInfo->ucMacHeaderLength = ucMacHeaderLen; + prMsduInfo->u2FrameLength = (UINT_16) u4PacketLen; + COPY_MAC_ADDR(prMsduInfo->aucEthDestAddr, aucEthDestAddr); + + if (prSkb->len > ETH_HLEN) + STATS_TX_PKT_CALLBACK(prSkb->data, prMsduInfo); + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function update TCQ values by passing current status to txAdjustTcQuotas +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Updated successfully +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4Num; + TX_TCQ_ADJUST_T rTcqAdjust; + P_TX_CTRL_T prTxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + for (u4Num = 0; u4Num < TC_NUM; u4Num++) { + prTxCtrl->rTc.aucFreeBufferCount[u4Num] += rTcqAdjust.acVariation[u4Num]; + prTxCtrl->rTc.aucMaxNumOfBuffer[u4Num] += rTcqAdjust.acVariation[u4Num]; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief this function flushes all packets queued in STA/AC queue +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Flushed successfully +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter) +{ + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + /* ask Per STA/AC queue to be fllushed and return all queued packets */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmFlushTxQueues(prAdapter); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prMsduInfo != NULL) { + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_ENABLE_FW_DOWNLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll write Command(CMD_INFO_T) into HIF. +* However this function is used for INIT_CMD. +* +* In order to avoid further maintenance issues, these 2 functions are separated +* +* @param prAdapter Pointer to the Adapter structure. +* @param prPacketInfo Pointer of CMD_INFO_T +* @param ucTC Specify the resource of TC +* +* @retval WLAN_STATUS_SUCCESS Bus access ok. +* @retval WLAN_STATUS_FAILURE Bus access fail. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) +{ + P_INIT_HIF_TX_HEADER_T prInitTxHeader; + UINT_16 u2OverallBufferLength; + PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ + UINT_32 ucPortIdx; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(ucTC == TC0_INDEX); + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + prInitTxHeader = (P_INIT_HIF_TX_HEADER_T) prCmdInfo->pucInfoBuffer; + + /* <1> Compose the Header of Transmit Data Structure for CMD Packet */ + u2OverallBufferLength = + TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + prInitTxHeader->u2TxByteCount = u2OverallBufferLength; + prInitTxHeader->ucEtherTypeOffset = 0; + prInitTxHeader->ucCSflags = 0; + + /* <2> Assign Data Port */ + if (ucTC != TC4_INDEX) { + ucPortIdx = 0; + } else { /* Broadcast/multicast data packets */ + ucPortIdx = 1; + } + + /* <3> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ + kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); + + ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); + + /* <4> Write frame to data port */ + HAL_WRITE_TX_PORT(prAdapter, + ucPortIdx, + (UINT_32) u2OverallBufferLength, + (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief In this function, we'll reset TX resource counter to initial value used +* in F/W download state +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + + DEBUGFUNC("nicTxInitResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; + prTxCtrl->rTc.aucFreeBufferCount[TC0_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC0; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; + prTxCtrl->rTc.aucFreeBufferCount[TC1_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC1; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; + prTxCtrl->rTc.aucFreeBufferCount[TC2_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC2; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; + prTxCtrl->rTc.aucFreeBufferCount[TC3_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC3; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; + prTxCtrl->rTc.aucFreeBufferCount[TC4_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC4; + + prTxCtrl->rTc.aucMaxNumOfBuffer[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; + prTxCtrl->rTc.aucFreeBufferCount[TC5_INDEX] = NIC_TX_INIT_BUFF_COUNT_TC5; + + return WLAN_STATUS_SUCCESS; + +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function enqueues MSDU_INFO_T into queue management, +* or command queue +* +* @param prAdapter Pointer to the Adapter structure. +* prMsduInfo Pointer to MSDU +* +* @retval WLAN_STATUS_SUCCESS Reset is done successfully. +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; + QUE_T qDataPort0, qDataPort1; + P_CMD_INFO_T prCmdInfo; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + QUEUE_INITIALIZE(&qDataPort0); + QUEUE_INITIALIZE(&qDataPort1); + + /* check how many management frame are being queued */ + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); + + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; + + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + /* MMPDU: force stick to TC4 */ + prMsduInfo->ucTC = TC4_INDEX; + + QUEUE_INSERT_TAIL(&qDataPort1, (P_QUE_ENTRY_T) prMsduInfo); + } else { + QUEUE_INSERT_TAIL(&qDataPort0, (P_QUE_ENTRY_T) prMsduInfo); + } + + prMsduInfo = prNextMsduInfo; + } + + if (qDataPort0.u4NumElem) { + /* send to QM: queue the packet to different TX queue by policy */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort0)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + /* post-process for "dropped" packets */ + if (prRetMsduInfo != NULL) { /* unable to enqueue */ + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); + } + } + + if (qDataPort1.u4NumElem) { + prMsduInfoHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&qDataPort1); + + if (qDataPort1.u4NumElem > nicTxGetFreeCmdCount(prAdapter)) { + /* not enough descriptors for sending */ + u4Status = WLAN_STATUS_FAILURE; + + /* free all MSDUs */ + while (prMsduInfoHead) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); + + if (prMsduInfoHead->pfTxDoneHandler != NULL) { + prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, + TX_RESULT_DROPPED_IN_DRIVER); + } + + cnmMgtPktFree(prAdapter, prMsduInfoHead); + + prMsduInfoHead = prNextMsduInfo; + } + } else { + /* send to command queue */ + while (prMsduInfoHead) { + prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); + + prCmdInfo->eCmdType = COMMAND_TYPE_MANAGEMENT_FRAME; + prCmdInfo->u2InfoBufLen = prMsduInfoHead->u2FrameLength; + prCmdInfo->pucInfoBuffer = NULL; + prCmdInfo->prPacket = (P_NATIVE_PACKET) prMsduInfoHead; + prCmdInfo->ucStaRecIndex = prMsduInfoHead->ucStaRecIndex; + prCmdInfo->eNetworkType = prMsduInfoHead->ucNetworkType; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = FALSE; + prCmdInfo->fgSetQuery = TRUE; + prCmdInfo->fgNeedResp = FALSE; + + kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); + } else { + /* Cmd free count is larger than expected, but allocation fail. */ + ASSERT(0); + + u4Status = WLAN_STATUS_FAILURE; + cnmMgtPktFree(prAdapter, prMsduInfoHead); + } + + prMsduInfoHead = prNextMsduInfo; + } + } + } + + /* indicate service thread for sending */ + if (prTxCtrl->i4TxMgmtPendingNum > 0 || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) + kalSetEvent(prAdapter->prGlueInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief this function returns available count in command queue +* +* @param prAdapter Pointer to the Adapter structure. +* +* @retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->rFreeCmdList.u4NumElem; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c new file mode 100644 index 0000000000000..38e4569bc04f9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/p2p_nic.c @@ -0,0 +1,192 @@ +/* +** Id: @(#) p2p_nic.c@@ +*/ + +/*! \file p2p_nic.c + \brief Wi-Fi Direct Functions that provide operation in NIC's (Network Interface Card) point of view. + + This file includes functions which unite multiple hal(Hardware) operations + and also take the responsibility of Software Resource Management in order + to keep the synchronization with Hardware Manipulation. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief When Probe Rsp & Beacon frame is received and decide a P2P device, +* this function will be invoked to buffer scan result +* +* @param prAdapter Pointer to the Adapter structure. +* @param prEventScanResult Pointer of EVENT_SCAN_RESULT_T. +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELength) +{ + P_P2P_INFO_T prP2pInfo = (P_P2P_INFO_T) NULL; + P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; + UINT_32 u4Idx = 0; + BOOLEAN bUpdate = FALSE; + + PUINT_8 pucIeBuf = (PUINT_8) NULL; + UINT_16 u2IELength = 0; + UINT_8 zeroMac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + ASSERT(prAdapter); + + prP2pInfo = prAdapter->prP2pInfo; + + for (u4Idx = 0; u4Idx < prP2pInfo->u4DeviceNum; u4Idx++) { + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + if (EQUAL_MAC_ADDR(prTargetResult->aucDeviceAddr, prP2pResult->aucDeviceAddr)) { + bUpdate = TRUE; + + /* Backup OLD buffer result. */ + pucIeBuf = prTargetResult->pucIeBuf; + u2IELength = prTargetResult->u2IELength; + + /* Update Device Info. */ + /* zero */ + kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* then buffer */ + kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* See if new IE length is longer or not. */ + if ((u2RxIELength > u2IELength) && (u2IELength != 0)) { + /* Buffer is not enough. */ + u2RxIELength = u2IELength; + } else if ((u2IELength == 0) && (u2RxIELength != 0)) { + /* RX new IE buf. */ + ASSERT(pucIeBuf == NULL); + pucIeBuf = prP2pInfo->pucCurrIePtr; + + if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > + (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2RxIELength = + (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - + (ULONG) prP2pInfo->pucCurrIePtr); + } + + /* Step to next buffer address. */ + prP2pInfo->pucCurrIePtr = + (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength); + } + + /* Restore buffer pointer. */ + prTargetResult->pucIeBuf = pucIeBuf; + + if (pucRxIEBuf) { + /* If new received IE is available. + * Replace the old one & update new IE length. + */ + kalMemCopy(pucIeBuf, pucRxIEBuf, u2RxIELength); + prTargetResult->u2IELength = u2RxIELength; + } else { + /* There is no new IE information, keep the old one. */ + prTargetResult->u2IELength = u2IELength; + } + } + } + + if (!bUpdate) { + /* We would flush the whole scan result after each scan request is issued. + * If P2P device is too many, it may over the scan list. + */ + if ((u4Idx < CFG_MAX_NUM_BSS_LIST) && (UNEQUAL_MAC_ADDR(zeroMac, prP2pResult->aucDeviceAddr))) { + /* whsu:XXX */ + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + /* zero */ + kalMemZero(prTargetResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* then buffer */ + kalMemCopy(prTargetResult, (PVOID) prP2pResult, sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* printk("DVC FND %d %pM, %pM\n", + prP2pInfo->u4DeviceNum, + prP2pResult->aucDeviceAddr, + prTargetResult->aucDeviceAddr); */ + + if (u2RxIELength) { + prTargetResult->pucIeBuf = prP2pInfo->pucCurrIePtr; + + if (((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2RxIELength) > + (ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2IELength = + (UINT_16) ((ULONG)&prP2pInfo->aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN] - + (ULONG) prP2pInfo->pucCurrIePtr); + } else { + u2IELength = u2RxIELength; + } + + prP2pInfo->pucCurrIePtr = + (PUINT_8) ((ULONG) prP2pInfo->pucCurrIePtr + (ULONG) u2IELength); + + kalMemCopy((PVOID) prTargetResult->pucIeBuf, (PVOID) pucRxIEBuf, (UINT_32) u2IELength); + prTargetResult->u2IELength = u2IELength; + } else { + prTargetResult->pucIeBuf = NULL; + prTargetResult->u2IELength = 0; + } + + prP2pInfo->u4DeviceNum++; + + } else { + /* TODO: Fixme to replace an old one. (?) */ + ASSERT(FALSE); + } + } +} /* nicRxAddP2pDevice */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c new file mode 100644 index 0000000000000..dd00859d46082 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/nic/que_mgt.c @@ -0,0 +1,5038 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/que_mgt.c#1 +*/ + +/*! \file "que_mgt.c" + \brief TX/RX queues management + + The main tasks of queue management include TC-based HIF TX flow control, + adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + forwarding control, RX packet reordering, and RX BA agreement management. +*/ + +/* +** Log: que_mgt.c +** +** 04 11 2013 yuche.tsai +** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. +** Drop the probe response packet when absent. +** +** 04 09 2013 yuche.tsai +** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. +** Fix CMD buffer short issue. +** +** 04 09 2013 yuche.tsai +** [ALPS00542142] [Pre-SQC][6627][W]use wifi direct press cancel connect, phone all stop. +** Fix CMD buffer short issue. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 02 23 2012 eddie.chen + * [WCXRP00001194] [MT6620][DRV/FW] follow admission control bit to change the enqueue rule + * Change the enqueue policy when ACM = 1. + * + * 11 22 2011 yuche.tsai + * NULL + * Code refine, remove one #if 0 code. + * + * 11 19 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog for tx + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 18 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Fix xlog format to hex format + * + * 11 17 2011 tsaiyuan.hsu + * [WCXRP00001115] [MT6620 Wi-Fi][DRV] avoid deactivating staRec when changing state 3 to 3. + * avoid deactivating staRec when changing state from 3 to 3. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug msg for xlog. + * + * 11 11 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters of bb and ar for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Use short name for xlog. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 10 2011 chinglan.wang + * NULL + * [WiFi WPS]Can't switch to new AP via WPS PBC when there existing a connection to another AP. + * + * 11 09 2011 chinglan.wang + * NULL + * [WiFi direct]Can't make P2P connect via PBC. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 11 01 2011 chinglan.wang + * NULL + * Modify the Wi-Fi method of the flush TX queue when disconnect the AP. + * If disconnect the AP and flush all the data frame in the TX queue, WPS cannot do the 4-way handshake to connect to + * the AP.. + * + * 10 25 2011 wh.su + * [WCXRP00001059] [MT6620 Wi-Fi][Driver][P2P] Fixed sometimes data (1x) will not indicate to upper layer due ba check + * un-expect + * let the Rx BA accept even the sta not valid. + * + * 09 28 2011 tsaiyuan.hsu + * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX + * enlarge window size only by 4. + * + * 09 01 2011 tsaiyuan.hsu + * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX + * set rx window size as twice buffer size. + * + * 08 23 2011 yuche.tsai + * NULL + * Fix multicast address list issue. + * + * 08 03 2011 tsaiyuan.hsu + * [WCXRP00000900] [MT5931 Wi-Fi] Improve balance of TX and RX + * force window size at least 16. + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting device + * issue. + * Fix GO send deauth frame issue. + * + * 07 26 2011 eddie.chen + * [WCXRP00000874] [MT5931][DRV] API for query the RX reorder queued packets counter + * API for query the RX reorder queued packets counter. + * + * 07 07 2011 eddie.chen + * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. + * Add setEvent when free quota is updated. + * + * 07 05 2011 eddie.chen + * [WCXRP00000834] [MT6620 Wi-Fi][DRV] Send 1x packet when peer STA is in PS. + * Send 1x when peer STA is in PS. + * + * 05 31 2011 eddie.chen + * [WCXRP00000753] [MT5931 Wi-Fi][DRV] Adjust QM for MT5931 + * Fix the QM quota in MT5931. + * + * 05 11 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Fix dest type when GO packet copying. + * + * 05 09 2011 yuche.tsai + * [WCXRP00000712] [Volunteer Patch][MT6620][Driver] Sending deauth issue when Hot spot is disabled. (GO is dissolved) + * Deauthentication frame is not bound to network active status. + * + * 05 09 2011 eddie.chen + * [WCXRP00000709] [MT6620 Wi-Fi][Driver] Check free number before copying broadcast packet + * Check free number before copying broadcast packet. + * + * 04 14 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Check the SW RFB free. Fix the compile warning.. + * + * 04 12 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix the sta index in processing security frame + * Simple flow control for TC4 to avoid mgt frames for PS STA to occupy the TC4 + * Add debug message. + * + * 04 11 2011 yuche.tsai + * [WCXRP00000627] [Volunteer Patch][MT6620][Driver] Pending MMPUD of P2P Network may crash system issue. + * Fix kernel panic issue when MMPDU of P2P is pending in driver. + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 03 28 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Fix Klockwork warning. + * + * 03 28 2011 eddie.chen + * [WCXRP00000602] [MT6620 Wi-Fi][DRV] Fix wmm parameters in beacon for BOW + * Fix wmm parameters in beacon for BOW. + * + * 03 15 2011 eddie.chen + * [WCXRP00000554] [MT6620 Wi-Fi][DRV] Add sw control debug counter + * Add sw debug counter for QM. + * + * 02 23 2011 eddie.chen + * [WCXRP00000463] [MT6620 Wi-Fi][FW/Driver][Hotspot] Cannot update WMM PS STA's partital bitmap + * Fix parsing WMM INFO and bmp delivery bitmap definition. + * + * 02 17 2011 eddie.chen + * [WCXRP00000458] [MT6620 Wi-Fi][Driver] BOW Concurrent - ProbeResp was exist in other channel + * 1) Change GetFrameAction decision when BSS is absent. + * 2) Check channel and resource in processing ProbeRequest + * + * 02 08 2011 eddie.chen + * [WCXRP00000426] [MT6620 Wi-Fi][FW/Driver] Add STA aging timeout and defualtHwRatein AP mode + * Add event STA agint timeout + * + * 01 27 2011 tsaiyuan.hsu + * [WCXRP00000392] [MT6620 Wi-Fi][Driver] Add Roaming Support + * add roaming fsm + * 1. not support 11r, only use strength of signal to determine roaming. + * 2. not enable CFG_SUPPORT_ROAMING until completion of full test. + * 3. in 6620, adopt work-around to avoid sign extension problem of cck of hw + * 4. assume that change of link quality in smooth way. + * + * 01 25 2011 yuche.tsai + * [WCXRP00000388] [Volunteer Patch][MT6620][Driver/Fw] change Station Type in station record. + * Change Station Type in Station Record, Modify MACRO definition for getting station type & network type index & Role. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Remove comments. + * + * 01 24 2011 eddie.chen + * [WCXRP00000385] [MT6620 Wi-Fi][DRV] Add destination decision for forwarding packets + * Add destination decision in AP mode. + * + * 01 14 2011 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out[WCXRP00000326] + * [MT6620][Wi-Fi][Driver] check in the binary format gl_sec.o.new instead of use change type!!! + * Allow 802.1x can be send even the net is not active due the drver / fw sync issue. + * + * 01 13 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * Fix typo and compile error. + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * Fix WMM parameter condition for STA + * + * 01 12 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + * 1) Check Bss if support QoS before adding WMMIE + * 2) Check if support prAdapter->rWifiVar QoS and uapsd in flow control + * + * 01 12 2011 george.huang + * [WCXRP00000355] [MT6620 Wi-Fi] Set WMM-PS related setting with qualifying AP capability + * Update MQM for WMM IE generation method + * + * 01 11 2011 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add per STA flow control when STA is in PS mode + * + * 01 03 2011 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * update prStaRec->fgIsUapsdSupported flag. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * Add WMM parameter for broadcast. + * + * 12 29 2010 eddie.chen + * [WCXRP00000322] Add WMM IE in beacon, +Add per station flow control when STA is in PS + + * 1) PS flow control event + * + * 2) WMM IE in beacon, assoc resp, probe resp + * + * 12 23 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * 1. update WMM IE parsing, with ASSOC REQ handling + * 2. extend U-APSD parameter passing from driver to FW + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * use the #14 and modify the add code for check MMPDU. + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * only MMPDU not check the netActive flag. + * + * 10 14 2010 wh.su + * [WCXRP00000099] [MT6620 Wi-Fi] [Driver] workaround to let the de-authentication can be send out + * not check the netActive flag for mgmt . + * + * 10 04 2010 cp.wu + * [WCXRP00000077] [MT6620 Wi-Fi][Driver][FW] Eliminate use of ENUM_NETWORK_TYPE_T and replaced by + * ENUM_NETWORK_TYPE_INDEX_T only + * remove ENUM_NETWORK_TYPE_T definitions + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 08 30 2010 yarco.yang + * NULL + * Fixed klockwork error message + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 10 2010 yarco.yang + * NULL + * Code refine + * + * 08 06 2010 yarco.yang + * NULL + * Update qmGetFrameAction() to allow P2P MGMT frame w/o STA_Record still can perform TX action + * + * 07 26 2010 cp.wu + * + * AIS-FSM FIX: return channel privilege even when the privilege is not granted yet + * QM: qmGetFrameAction() won't assert when corresponding STA-REC index is not found + * + * 07 20 2010 yarco.yang + * + * Add to SetEvent when BSS is from Absent to Present or STA from PS to Awake + * + * 07 16 2010 yarco.yang + * + * 1. Support BSS Absence/Presence Event + * 2. Support STA change PS mode Event + * 3. Support BMC forwarding for AP mode. + * + * 07 14 2010 yarco.yang + * + * 1. Remove CFG_MQM_MIGRATION + * 2. Add CMD_UPDATE_WMM_PARMS command + * + * 07 13 2010 yarco.yang + * + * [WPD00003849] + * [MT6620 and MT5931] SW Migration, add qmGetFrameAction() API for CMD Queue Processing + * + * 07 09 2010 yarco.yang + * + * [MT6620 and MT5931] SW Migration: Add ADDBA support + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 07 08 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * . + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Use fgInUse instead of fgIsValid for De-queue judgement + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * For MMPDU, STA_REC will be decided by caller module + * + * 07 06 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Add MGMT Packet type for HIF_TX_HEADER + * + * 06 29 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * replace g_rQM with Adpater->rQM + * + * 06 25 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * add API in que_mgt to retrieve sta-rec index for security frames. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Support CFG_MQM_MIGRATION flag + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Refined the debug msg + * + * 03 30 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * comment out one assertion which refer to undefined data member. + * + * 03 30 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled adaptive TC resource control + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port + * +* 03 17 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Changed STA_REC index determination rules (DA=BMCAST always --> STA_REC_INDEX_BMCAST) + * + * 03 11 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed buffer leak when processing BAR frames + * + * 03 02 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * For TX packets with STA_REC index = STA_REC_INDEX_NOT_FOUND, use TC5 + * + * 03 01 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Fixed STA_REC index determination bug (fgIsValid shall be checked) + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Refined function qmDetermineStaRecIndex() for BMCAST packets + * + * 02 25 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled multi-STA TX path with fairness + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled dynamically activating and deactivating STA_RECs + * + * 02 24 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Added code for dynamic activating and deactivating STA_RECs. + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the 802.1x path + * + * 01 13 2010 tehuang.liu + * [WPD00001943]Create WiFi test driver framework on WinXP + * Enabled the Burst_End Indication mechanism +** \main\maintrunk.MT6620WiFiDriver_Prj\13 2009-12-14 15:01:37 GMT MTK02468 +** Fixed casting for qmAddRxBaEntry() +** \main\maintrunk.MT6620WiFiDriver_Prj\12 2009-12-10 16:51:03 GMT mtk02752 +** remove SD1_SD3.. flag +** \main\maintrunk.MT6620WiFiDriver_Prj\11 2009-12-09 14:07:25 GMT MTK02468 +** Added RX buffer reordering functions +** \main\maintrunk.MT6620WiFiDriver_Prj\10 2009-12-04 13:34:16 GMT MTK02468 +** Modified Flush Queue function to let queues be reinitialized +** \main\maintrunk.MT6620WiFiDriver_Prj\9 2009-12-04 13:18:25 GMT MTK02468 +** Added flushing per-Type queues code +** \main\maintrunk.MT6620WiFiDriver_Prj\8 2009-12-02 23:39:49 GMT MTK02468 +** Added Debug msgs and fixed incorrect assert +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-26 23:50:27 GMT MTK02468 +** Bug fixing (qmDequeueTxPackets local variable initialization) +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-26 09:39:25 GMT mtk02752 +** correct and surpress PREfast warning +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-11-23 22:10:55 GMT mtk02468 +** Used SD1_SD3_DATAPATH_INTEGRATION +** \main\maintrunk.MT6620WiFiDriver_Prj\1 2009-11-23 22:02:30 GMT mtk02468 +** Initial version +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +OS_SYSTIME g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM]; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if ARP_MONITER_ENABLE +static UINT_16 arpMoniter; +static UINT_8 apIp[4]; +#endif +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static inline VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +static inline VOID +qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN UINT_8 ucTC, IN UINT_8 ucCurrentAvailableQuota, IN UINT_8 ucTotalQuota); + +static inline VOID +qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init Queue Management for TX +* +* \param[in] (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmInit(IN P_ADAPTER_T prAdapter) +{ + UINT_32 u4QueArrayIdx; + UINT_32 i; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* DbgPrint("QM: Enter qmInit()\n"); */ +#if CFG_SUPPORT_QOS + prAdapter->rWifiVar.fgSupportQoS = TRUE; +#else + prAdapter->rWifiVar.fgSupportQoS = FALSE; +#endif + +#if CFG_SUPPORT_AMPDU_RX + prAdapter->rWifiVar.fgSupportAmpduRx = TRUE; +#else + prAdapter->rWifiVar.fgSupportAmpduRx = FALSE; +#endif + +#if CFG_SUPPORT_AMPDU_TX + prAdapter->rWifiVar.fgSupportAmpduTx = TRUE; +#else + prAdapter->rWifiVar.fgSupportAmpduTx = FALSE; +#endif + +#if CFG_SUPPORT_TSPEC + prAdapter->rWifiVar.fgSupportTspec = TRUE; +#else + prAdapter->rWifiVar.fgSupportTspec = FALSE; +#endif + +#if CFG_SUPPORT_UAPSD + prAdapter->rWifiVar.fgSupportUAPSD = TRUE; +#else + prAdapter->rWifiVar.fgSupportUAPSD = FALSE; +#endif + +#if CFG_SUPPORT_UL_PSMP + prAdapter->rWifiVar.fgSupportULPSMP = TRUE; +#else + prAdapter->rWifiVar.fgSupportULPSMP = FALSE; +#endif + +#if CFG_SUPPORT_RX_SGI + prAdapter->rWifiVar.u8SupportRxSgi20 = 0; + prAdapter->rWifiVar.u8SupportRxSgi40 = 0; +#else + prAdapter->rWifiVar.u8SupportRxSgi20 = 2; + prAdapter->rWifiVar.u8SupportRxSgi40 = 2; +#endif + +#if CFG_SUPPORT_RX_HT_GF + prAdapter->rWifiVar.u8SupportRxGf = 0; +#else + prAdapter->rWifiVar.u8SupportRxGf = 2; +#endif + + /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */ + for (u4QueArrayIdx = 0; u4QueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; u4QueArrayIdx++) + QUEUE_INITIALIZE(&(prQM->arTxQueue[u4QueArrayIdx])); + + /* 4 <3> Initialize the RX BA table and RX queues */ + /* Initialize the RX Reordering Parameters and Queues */ + for (u4QueArrayIdx = 0; u4QueArrayIdx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4QueArrayIdx++) { + prQM->arRxBaTable[u4QueArrayIdx].fgIsValid = FALSE; + QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4QueArrayIdx].rReOrderQue)); + prQM->arRxBaTable[u4QueArrayIdx].u2WinStart = 0xFFFF; + prQM->arRxBaTable[u4QueArrayIdx].u2WinEnd = 0xFFFF; + + prQM->arRxBaTable[u4QueArrayIdx].fgIsWaitingForPktWithSsn = FALSE; + + } + prQM->ucRxBaCount = 0; + + kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout)); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* 4 <4> Initialize TC resource control variables */ + for (i = 0; i < TC_NUM; i++) + prQM->au4AverageQueLen[i] = 0; + prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; + prQM->u4TxNumOfVi = 0; + prQM->u4TxNumOfVo = 0; + +/* ASSERT(prQM->u4TimeToAdjust && prQM->u4TimeToUpdateQueLen); */ + + /* 1 20 1 1 4 1 */ + prQM->au4CurrentTcResource[TC0_INDEX] = NIC_TX_BUFF_COUNT_TC0; + prQM->au4CurrentTcResource[TC1_INDEX] = NIC_TX_BUFF_COUNT_TC1; + prQM->au4CurrentTcResource[TC2_INDEX] = NIC_TX_BUFF_COUNT_TC2; + prQM->au4CurrentTcResource[TC3_INDEX] = NIC_TX_BUFF_COUNT_TC3; + prQM->au4CurrentTcResource[TC4_INDEX] = NIC_TX_BUFF_COUNT_TC4; /* Not adjustable (TX port 1) */ + prQM->au4CurrentTcResource[TC5_INDEX] = NIC_TX_BUFF_COUNT_TC5; + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC0 = %d\n", NIC_TX_BUFF_COUNT_TC0); + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC1 = %d\n", NIC_TX_BUFF_COUNT_TC1); + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC2 = %d\n", NIC_TX_BUFF_COUNT_TC2); + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC3 = %d\n", NIC_TX_BUFF_COUNT_TC3); + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC4 = %d\n", NIC_TX_BUFF_COUNT_TC4); + DBGLOG(QM, TRACE, "QM: NIC_TX_BUFF_COUNT_TC5 = %d\n", NIC_TX_BUFF_COUNT_TC5); + + /* 1 1 1 1 2 1 */ + prQM->au4MinReservedTcResource[TC0_INDEX] = QM_MIN_RESERVED_TC0_RESOURCE; + prQM->au4MinReservedTcResource[TC1_INDEX] = QM_MIN_RESERVED_TC1_RESOURCE; + prQM->au4MinReservedTcResource[TC2_INDEX] = QM_MIN_RESERVED_TC2_RESOURCE; + prQM->au4MinReservedTcResource[TC3_INDEX] = QM_MIN_RESERVED_TC3_RESOURCE; + prQM->au4MinReservedTcResource[TC4_INDEX] = QM_MIN_RESERVED_TC4_RESOURCE; /* Not adjustable (TX port 1) */ + prQM->au4MinReservedTcResource[TC5_INDEX] = QM_MIN_RESERVED_TC5_RESOURCE; + + /* 4 4 6 6 2 4 */ + prQM->au4GuaranteedTcResource[TC0_INDEX] = QM_GUARANTEED_TC0_RESOURCE; + prQM->au4GuaranteedTcResource[TC1_INDEX] = QM_GUARANTEED_TC1_RESOURCE; + prQM->au4GuaranteedTcResource[TC2_INDEX] = QM_GUARANTEED_TC2_RESOURCE; + prQM->au4GuaranteedTcResource[TC3_INDEX] = QM_GUARANTEED_TC3_RESOURCE; + prQM->au4GuaranteedTcResource[TC4_INDEX] = QM_GUARANTEED_TC4_RESOURCE; + prQM->au4GuaranteedTcResource[TC5_INDEX] = QM_GUARANTEED_TC5_RESOURCE; + + prQM->fgTcResourcePostAnnealing = FALSE; + + ASSERT(QM_INITIAL_RESIDUAL_TC_RESOURCE < 64); +#endif + +#if QM_TEST_MODE + prQM->u4PktCount = 0; + +#if QM_TEST_FAIR_FORWARDING + + prQM->u4CurrentStaRecIndexToEnqueue = 0; + { + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + P_STA_RECORD_T prStaRec; + + /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + prStaRec = &prAdapter->arStaRec[1]; + ASSERT(prStaRec); + + prStaRec->fgIsValid = TRUE; + prStaRec->fgIsQoS = TRUE; + prStaRec->fgIsInPS = FALSE; + prStaRec->ucPsSessionID = 0xFF; + prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + prStaRec->fgIsAp = TRUE; + COPY_MAC_ADDR((prStaRec)->aucMacAddr, aucMacAddr); + + } + +#endif + +#endif + +#if QM_FORWARDING_FAIRNESS + { + UINT_32 i; + + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { + prQM->au4ForwardCount[i] = 0; + prQM->au4HeadStaRecIndex[i] = 0; + } + } +#endif + +#if QM_TC_RESOURCE_EMPTY_COUNTER + kalMemZero(prQM->au4QmTcResourceEmptyCounter, sizeof(prQM->au4QmTcResourceEmptyCounter)); +#endif + +} + +#if QM_TEST_MODE +VOID qmTestCases(IN P_ADAPTER_T prAdapter) +{ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DbgPrint("QM: ** TEST MODE **\n"); + + if (QM_TEST_STA_REC_DETERMINATION) { + if (prAdapter->arStaRec[0].fgIsValid) { + prAdapter->arStaRec[0].fgIsValid = FALSE; + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + } else { + prAdapter->arStaRec[0].fgIsValid = TRUE; + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + } + } + + if (QM_TEST_STA_REC_DEACTIVATION) { + /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this test */ + + if (prAdapter->arStaRec[0].fgIsValid) { + + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + qmDeactivateStaRec(prAdapter, 0); + } else { + + UINT_8 aucMacAddr[MAC_ADDR_LEN]; + + /* Irrelevant in case this STA is an AIS AP (see qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + qmActivateStaRec(prAdapter, /* Adapter pointer */ + 0, /* STA_REC index from FW */ + TRUE, /* fgIsQoS */ + NETWORK_TYPE_AIS_INDEX, /* Network type */ + TRUE, /* fgIsAp */ + aucMacAddr /* MAC address */ + ); + } + } + + if (QM_TEST_FAIR_FORWARDING) { + if (prAdapter->arStaRec[1].fgIsValid) { + prQM->u4CurrentStaRecIndexToEnqueue++; + prQM->u4CurrentStaRecIndexToEnqueue %= 2; + DbgPrint("QM: (Test) Switch to STA_REC[%u]\n", prQM->u4CurrentStaRecIndexToEnqueue); + } + } + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Activate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the STA_REC +* \param[in] fgIsQoS Set to TRUE if this is a QoS STA +* \param[in] pucMacAddr The MAC address of the STA +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + + /* 4 <1> Deactivate first */ + ASSERT(prStaRec); + + if (prStaRec->fgIsValid) { /* The STA_REC has been activated */ + DBGLOG(QM, WARN, "QM: (WARNING) Activating a STA_REC which has been activated\n"); + DBGLOG(QM, WARN, "QM: (WARNING) Deactivating a STA_REC before re-activating\n"); + /* To flush TX/RX queues and del RX BA agreements */ + qmDeactivateStaRec(prAdapter, prStaRec->ucIndex); + } + /* 4 <2> Activate the STA_REC */ + /* Init the STA_REC */ + prStaRec->fgIsValid = TRUE; + prStaRec->fgIsInPS = FALSE; + prStaRec->ucPsSessionID = 0xFF; + prStaRec->fgIsAp = (IS_AP_STA(prStaRec)) ? TRUE : FALSE; + + /* Done in qmInit() or qmDeactivateStaRec() */ +#if 0 + /* At the beginning, no RX BA agreements have been established */ + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) + (prStaRec->aprRxReorderParamRefTbl)[i] = NULL; +#endif + + DBGLOG(QM, TRACE, "QM: +STA[%u]\n", (UINT_32) prStaRec->ucIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Deactivate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the STA_REC +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) +{ + P_STA_RECORD_T prStaRec; + UINT_32 i; + P_MSDU_INFO_T prFlushedTxPacketList = NULL; + + ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* 4<1> Flush TX queues */ + prFlushedTxPacketList = qmFlushStaTxQueues(prAdapter, u4StaRecIdx); + + if (prFlushedTxPacketList) + wlanProcessQueuedMsduInfo(prAdapter, prFlushedTxPacketList); + /* 4 <2> Flush RX queues and delete RX BA agreements */ + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { + /* Delete the RX BA entry with TID = i */ + qmDelRxBaEntry(prAdapter, (UINT_8) u4StaRecIdx, (UINT_8) i, FALSE); + } + + /* 4 <3> Deactivate the STA_REC */ + prStaRec->fgIsValid = FALSE; + prStaRec->fgIsInPS = FALSE; + + /* To reduce printk for IOT sta to connect all the time, */ + /* DBGLOG(QM, INFO, ("QM: -STA[%ld]\n", u4StaRecIdx)); */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Deactivate a STA_REC +* +* \param[in] prAdapter Pointer to the Adapter instance +* \param[in] u4StaRecIdx The index of the network +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +VOID qmFreeAllByNetType(IN P_ADAPTER_T prAdapter, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + + P_QUE_MGT_T prQM; + P_QUE_T prQue; + QUE_T rNeedToFreeQue; + QUE_T rTempQue; + P_QUE_T prNeedToFreeQue; + P_QUE_T prTempQue; + P_MSDU_INFO_T prMsduInfo; + + prQM = &prAdapter->rQM; + prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + + QUEUE_INITIALIZE(&rNeedToFreeQue); + QUEUE_INITIALIZE(&rTempQue); + + prNeedToFreeQue = &rNeedToFreeQue; + prTempQue = &rTempQue; + + QUEUE_MOVE_ALL(prTempQue, prQue); + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + while (prMsduInfo) { + + if (prMsduInfo->ucNetworkType == eNetworkTypeIdx) { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(prNeedToFreeQue, (P_QUE_ENTRY_T) prMsduInfo); + } else { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); + } + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + } + if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) + wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush all TX queues +* +* \param[in] (none) +* +* \return The flushed packets (in a list of MSDU_INFOs) +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter) +{ + UINT_8 ucStaArrayIdx; + UINT_8 ucQueArrayIdx; + + P_MSDU_INFO_T prMsduInfoListHead; + P_MSDU_INFO_T prMsduInfoListTail; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushTxQueues()\n"); + + prMsduInfoListHead = NULL; + prMsduInfoListTail = NULL; + + /* Concatenate all MSDU_INFOs in per-STA queues */ + for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_NUM_OF_STA_RECORD; ucStaArrayIdx++) { + + /* Always check each STA_REC when flushing packets no matter it is inactive or active */ +#if 0 + if (!prAdapter->arStaRec[ucStaArrayIdx].fgIsValid) + continue; /* Continue to check the next STA_REC */ +#endif + + for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { + if (QUEUE_IS_EMPTY(&(prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]))) + continue; /* Continue to check the next TX queue of the same STA */ + + if (!prMsduInfoListHead) { + + /* The first MSDU_INFO is found */ + prMsduInfoListHead = (P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } else { + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, + QUEUE_GET_HEAD(&prAdapter-> + arStaRec[ucStaArrayIdx].arTxQueue + [ucQueArrayIdx])); + + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prAdapter->arStaRec[ucStaArrayIdx].arTxQueue[ucQueArrayIdx]); + } + } + + /* Flush per-Type queues */ + for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; ucQueArrayIdx++) { + + if (QUEUE_IS_EMPTY(&(prQM->arTxQueue[ucQueArrayIdx]))) + continue; /* Continue to check the next TX queue of the same STA */ + + if (!prMsduInfoListHead) { + + /* The first MSDU_INFO is found */ + prMsduInfoListHead = (P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); + } else { + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, QUEUE_GET_HEAD(&prQM->arTxQueue[ucQueArrayIdx])); + + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prQM->arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prQM->arTxQueue[ucQueArrayIdx]); + + } + + if (prMsduInfoListTail) { + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, NULL); + } + + return prMsduInfoListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush TX packets for a particular STA +* +* \param[in] u4StaRecIdx STA_REC index +* +* \return The flushed packets (in a list of MSDU_INFOs) +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx) +{ + UINT_8 ucQueArrayIdx; + P_MSDU_INFO_T prMsduInfoListHead; + P_MSDU_INFO_T prMsduInfoListTail; + P_STA_RECORD_T prStaRec; + + /* To reduce printk for IOT sta to connect all the time, */ + /* DBGLOG(QM, TRACE, ("QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx)); */ + + ASSERT(u4StaRecIdx < CFG_NUM_OF_STA_RECORD); + + prMsduInfoListHead = NULL; + prMsduInfoListTail = NULL; + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* No matter whether this is an activated STA_REC, do flush */ +#if 0 + if (!prStaRec->fgIsValid) + return NULL; +#endif + + /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */ + for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; ucQueArrayIdx++) { + if (QUEUE_IS_EMPTY(&(prStaRec->arTxQueue[ucQueArrayIdx]))) + continue; + + if (!prMsduInfoListHead) { + /* The first MSDU_INFO is found */ + prMsduInfoListHead = (P_MSDU_INFO_T) + QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx]); + prMsduInfoListTail = (P_MSDU_INFO_T) + QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); + } else { + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, + QUEUE_GET_HEAD(&prStaRec->arTxQueue[ucQueArrayIdx])); + + prMsduInfoListTail = (P_MSDU_INFO_T) QUEUE_GET_TAIL(&prStaRec->arTxQueue[ucQueArrayIdx]); + } + + QUEUE_INITIALIZE(&prStaRec->arTxQueue[ucQueArrayIdx]); + + } + +#if 0 + if (prMsduInfoListTail) { + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx)); + } else { + prMsduInfoListHead = nicGetPendingStaMMPDU(prAdapter, (UINT_8) u4StaRecIdx); + } +#endif + + return prMsduInfoListHead; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush RX packets +* +* \param[in] (none) +* +* \return The flushed packets (in a list of SW_RFBs) +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i; + P_SW_RFB_T prSwRfbListHead; + P_SW_RFB_T prSwRfbListTail; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + prSwRfbListHead = prSwRfbListTail = NULL; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushRxQueues()\n"); + + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) { + if (!prSwRfbListHead) { + + /* The first MSDU_INFO is found */ + prSwRfbListHead = (P_SW_RFB_T) + QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue)); + prSwRfbListTail = (P_SW_RFB_T) + QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); + } else { + /* Concatenate the MSDU_INFO list with the existing list */ + QM_TX_SET_NEXT_MSDU_INFO(prSwRfbListTail, + QUEUE_GET_HEAD(&(prQM->arRxBaTable[i].rReOrderQue))); + + prSwRfbListTail = (P_SW_RFB_T) + QUEUE_GET_TAIL(&(prQM->arRxBaTable[i].rReOrderQue)); + } + + QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue)); + + } else { + continue; + } + } + + if (prSwRfbListTail) { + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Flush RX packets with respect to a particular STA +* +* \param[in] u4StaRecIdx STA_REC index +* \param[in] u4Tid TID +* +* \return The flushed packets (in a list of SW_RFBs) +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN UINT_32 u4StaRecIdx, IN UINT_32 u4Tid) +{ + /* UINT_32 i; */ + P_SW_RFB_T prSwRfbListHead; + P_SW_RFB_T prSwRfbListTail; + P_RX_BA_ENTRY_T prReorderQueParm; + P_STA_RECORD_T prStaRec; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushStaRxQueues(%u)\n", u4StaRecIdx); + + prSwRfbListHead = prSwRfbListTail = NULL; + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* No matter whether this is an activated STA_REC, do flush */ +#if 0 + if (!prStaRec->fgIsValid) + return NULL; +#endif + + /* Obtain the RX BA Entry pointer */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]); + + /* Note: For each queued packet, prCurrSwRfb->eDst equals RX_PKT_DESTINATION_HOST */ + if (prReorderQueParm) { + + if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) { + + prSwRfbListHead = (P_SW_RFB_T) + QUEUE_GET_HEAD(&(prReorderQueParm->rReOrderQue)); + prSwRfbListTail = (P_SW_RFB_T) + QUEUE_GET_TAIL(&(prReorderQueParm->rReOrderQue)); + + QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue)); + + } + } + + if (prSwRfbListTail) { + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Enqueue TX packets +* +* \param[in] prMsduInfoListHead Pointer to the list of TX packets +* +* \return The freed packets, which are not enqueued +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfoReleaseList; + P_MSDU_INFO_T prCurrentMsduInfo; + P_MSDU_INFO_T prNextMsduInfo; + + P_STA_RECORD_T prStaRec; + QUE_T rNotEnqueuedQue; + P_QUE_T prTxQue = &rNotEnqueuedQue; + + UINT_8 ucPacketType; + UINT_8 ucTC; + P_QUE_MGT_T prQM = &prAdapter->rQM; + UINT_8 aucNextUP[WMM_AC_INDEX_NUM] = { 1 /* BEtoBK */ , 1 /*na */ , 0 /*VItoBE */ , 4 /*VOtoVI */ }; + + DBGLOG(QM, LOUD, "Enter qmEnqueueTxPackets\n"); + + ASSERT(prMsduInfoListHead); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + { + /* UINT_32 i; */ + /* 4 <0> Update TC resource control related variables */ + /* Keep track of the queue length */ + if (--prQM->u4TimeToUpdateQueLen == 0) { /* -- only here */ + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; + qmUpdateAverageTxQueLen(prAdapter); + } + } +#endif + + /* Push TX packets into STA_REC (for UNICAST) or prAdapter->rQM (for BMCAST) */ + prStaRec = NULL; + prMsduInfoReleaseList = NULL; + prCurrentMsduInfo = NULL; + QUEUE_INITIALIZE(&rNotEnqueuedQue); + prNextMsduInfo = prMsduInfoListHead; + + do { + P_BSS_INFO_T prBssInfo; + BOOLEAN fgCheckACMAgain; + ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; + + prCurrentMsduInfo = prNextMsduInfo; + prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo); + ucTC = TC1_INDEX; + + /* 4 <1> Lookup the STA_REC index */ + /* The ucStaRecIndex will be set in this function */ + qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo); + ucPacketType = HIF_TX_PACKET_TYPE_DATA; + + STATS_ENV_REPORT_DETECT(prAdapter, prCurrentMsduInfo->ucStaRecIndex); + + DBGLOG(QM, LOUD, "***** ucStaRecIndex = %d *****\n", prCurrentMsduInfo->ucStaRecIndex); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prCurrentMsduInfo->ucNetworkType]); + +#if (CONF_HIF_LOOPBACK_AUTO == 0) + if (IS_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType)) { +#else + /* force to send the loopback test packet */ + if (1) { + SET_NET_ACTIVE(prAdapter, prCurrentMsduInfo->ucNetworkType); + prCurrentMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; + ucPacketType = HIF_TX_PKT_TYPE_HIF_LOOPBACK; +#endif /* End of CONF_HIF_LOOPBACK_AUTO */ + + switch (prCurrentMsduInfo->ucStaRecIndex) { + case STA_REC_INDEX_BMCAST: + prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + ucTC = TC5_INDEX; +#if 0 + if (prCurrentMsduInfo->ucNetworkType == NETWORK_TYPE_P2P_INDEX + && prCurrentMsduInfo->eSrc != TX_PACKET_MGMT) { + if (LINK_IS_EMPTY + (&prAdapter->rWifiVar. + arBssInfo[NETWORK_TYPE_P2P_INDEX].rStaRecOfClientList)) { + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl, TX_AP_BORADCAST_DROP); + } + } +#endif + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); + break; + + case STA_REC_INDEX_NOT_FOUND: + ucTC = TC5_INDEX; + + if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { + + /* if the packet is the forward type. the packet should be freed */ + DBGLOG(QM, TRACE, "Forwarding packet but Sta is STA_REC_INDEX_NOT_FOUND\n"); + /* prTxQue = &rNotEnqueuedQue; */ + } + prTxQue = &prQM->arTxQueue[TX_QUEUE_INDEX_NO_STA_REC]; + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); + + break; + + default: + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prCurrentMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + DBGLOG(QM, ERROR, "prStaRec is NULL\n"); + break; + } + ASSERT(prStaRec->fgIsValid); + + if (prCurrentMsduInfo->ucUserPriority < 8) { + QM_DBG_CNT_INC(prQM, prCurrentMsduInfo->ucUserPriority + 15); + /* QM_DBG_CNT_15 *//* QM_DBG_CNT_16 *//* QM_DBG_CNT_17 *//* QM_DBG_CNT_18 */ + /* QM_DBG_CNT_19 *//* QM_DBG_CNT_20 *//* QM_DBG_CNT_21 *//* QM_DBG_CNT_22 */ + } + + eAci = WMM_AC_BE_INDEX; + do { + fgCheckACMAgain = FALSE; + if (!prStaRec->fgIsQoS) { + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + break; + } + + switch (prCurrentMsduInfo->ucUserPriority) { + case 1: + case 2: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC0]; + ucTC = TC0_INDEX; + eAci = WMM_AC_BK_INDEX; + break; + case 0: + case 3: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + eAci = WMM_AC_BE_INDEX; + break; + case 4: + case 5: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC2]; + ucTC = TC2_INDEX; + eAci = WMM_AC_VI_INDEX; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + prQM->u4TxNumOfVi++; +#endif + break; + case 6: + case 7: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC3]; + ucTC = TC3_INDEX; + eAci = WMM_AC_VO_INDEX; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + prQM->u4TxNumOfVo++; +#endif + break; + default: + prTxQue = &prStaRec->arTxQueue[TX_QUEUE_INDEX_AC1]; + ucTC = TC1_INDEX; + eAci = WMM_AC_BE_INDEX; + ASSERT(0); + break; + } + if (prBssInfo->arACQueParms[eAci].fgIsACMSet && eAci + != WMM_AC_BK_INDEX) { + prCurrentMsduInfo->ucUserPriority = aucNextUP[eAci]; + fgCheckACMAgain = TRUE; + } + } while (fgCheckACMAgain); + + /* LOG_FUNC ("QoS %u UP %u TC %u", */ + /* prStaRec->fgIsQoS,prCurrentMsduInfo->ucUserPriority, ucTC); */ + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* + In TDLS or AP mode, peer maybe enter "sleep mode". + + If QM_INIT_TIME_TO_UPDATE_QUE_LEN = 60 when peer is in sleep mode, + we need to wait 60 * u4TimeToAdjustTcResource = 180 packets + u4TimeToAdjustTcResource = 3, + then we will adjust TC resouce for VI or VO. + + But in TDLS test case, the throughput is very low, only 0.8Mbps in 5.7, + we will to wait about 12 seconds to collect 180 packets. + but the test time is only 20 seconds. + */ + if ((prQM->u4TxNumOfVi == 10) || (prQM->u4TxNumOfVo == 10)) { + /* force to do TC resouce update */ + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN_MIN; + prQM->u4TimeToAdjustTcResource = 1; + } +#endif +#if ARP_MONITER_ENABLE + if (IS_STA_IN_AIS(prStaRec) && prCurrentMsduInfo->eSrc == TX_PACKET_OS) + qmDetectArpNoResponse(prAdapter, prCurrentMsduInfo); +#endif + + break; /*default */ + } /* switch (prCurrentMsduInfo->ucStaRecIndex) */ + + if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { + if (prTxQue->u4NumElem > 32) { + DBGLOG(QM, WARN, + "Drop the Packet for full Tx queue (forwarding) Bss %u\n", + prCurrentMsduInfo->ucNetworkType); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl, TX_FORWARD_OVERFLOW_DROP); + } + } + + } else { + + DBGLOG(QM, WARN, "Drop the Packet for inactive Bss %u\n", prCurrentMsduInfo->ucNetworkType); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); + } + + /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */ + + /* TODO: Fill MSDU_INFO according to the network type, + * EtherType, and STA status (for PS forwarding control). + */ + + /* Note that the Network Type Index and STA_REC index are determined in + * qmDetermineStaRecIndex(prCurrentMsduInfo). + */ + QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(prCurrentMsduInfo, /* MSDU_INFO ptr */ + ucTC, /* TC tag */ + ucPacketType, /* Packet Type */ + 0, /* Format ID */ + prCurrentMsduInfo->fgIs802_1x, /* Flag 802.1x */ + prCurrentMsduInfo->fgIs802_11, /* Flag 802.11 */ + 0, /* PAL LLH */ + 0, /* ACL SN */ + PS_FORWARDING_TYPE_NON_PS, /* PS Forwarding Type */ + 0 /* PS Session ID */ + ); + + /* 4 <4> Enqueue the packet to different AC queue (max 5 AC queues) */ + QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T) prCurrentMsduInfo); + + if (prTxQue != &rNotEnqueuedQue) { + prQM->u4EnqeueuCounter++; + prQM->au4ResourceWantedCounter[ucTC]++; + } + if (prStaRec) + prStaRec->u4EnqeueuCounter++; + +#if QM_TC_RESOURCE_EMPTY_COUNTER + { + P_TX_CTRL_T prTxCtrl = &prAdapter->rTxCtrl; + + if (prTxCtrl->rTc.aucFreeBufferCount[ucTC] == 0) { + prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC]++; + /* + DBGLOG(QM, TRACE, ("TC%d Q Empty Count: [%d]%ld\n", + ucTC, + prCurrentMsduInfo->ucNetworkType, + prQM->au4QmTcResourceEmptyCounter[prCurrentMsduInfo->ucNetworkType][ucTC])); + */ + } + + } +#endif + +#if QM_TEST_MODE + if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) { + prQM->u4PktCount = 0; + qmTestCases(prAdapter); + } +#endif + + DBGLOG(QM, LOUD, "Current queue length = %u\n", prTxQue->u4NumElem); + } while (prNextMsduInfo); + + if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue)) { + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL); + prMsduInfoReleaseList = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rNotEnqueuedQue); + } + + return prMsduInfoReleaseList; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Determine the STA_REC index for a packet +* +* \param[in] prMsduInfo Pointer to the packet +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + UINT_32 i; + + P_STA_RECORD_T prTempStaRec; + /* P_QUE_MGT_T prQM = &prAdapter->rQM; */ + + prTempStaRec = NULL; + + ASSERT(prMsduInfo); + + /* 4 <1> DA = BMCAST */ + if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) { + /* For intrastructure mode and P2P (playing as a GC), BMCAST frames shall be sent to the AP. + * FW shall take care of this. The host driver is not able to distinguish these cases. */ + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_BMCAST; + DBGLOG(QM, LOUD, "TX with DA = BMCAST\n"); + return; + } +#if (CFG_SUPPORT_TDLS == 1) + /* Check if the peer is TDLS one */ + if (TdlsexStaRecIdxGet(prAdapter, prMsduInfo) == TDLS_STATUS_SUCCESS) + return; /* find a TDLS record */ +#endif /* CFG_SUPPORT_TDLS */ + + /* 4 <2> Check if an AP STA is present */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { + prTempStaRec = &(prAdapter->arStaRec[i]); + + if ((prTempStaRec->ucNetTypeIndex == prMsduInfo->ucNetworkType) + && (prTempStaRec->fgIsAp) + && (prTempStaRec->fgIsValid)) { + prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; + return; + } + } + + /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { + prTempStaRec = &(prAdapter->arStaRec[i]); + if (prTempStaRec->fgIsValid) { + if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, prMsduInfo->aucEthDestAddr)) { + prMsduInfo->ucStaRecIndex = prTempStaRec->ucIndex; + return; + } + } + } + + /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + DBGLOG(QM, LOUD, "QM: TX with STA_REC_INDEX_NOT_FOUND\n"); + +#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING) + prMsduInfo->ucStaRecIndex = (UINT_8) prQM->u4CurrentStaRecIndexToEnqueue; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets from a STA_REC for a particular TC +* +* \param[out] prQue The queue to put the dequeued packets +* \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX) +* \param[in] ucMaxNum The maximum amount of dequeued packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucCurrentQuota, IN UINT_8 ucTotalQuota) +{ + +#if QM_FORWARDING_FAIRNESS + UINT_32 i; /* Loop for */ + + PUINT_32 pu4HeadStaRecIndex; /* The Head STA index */ + PUINT_32 pu4HeadStaRecForwardCount; /* The total forwarded packets for the head STA */ + + P_STA_RECORD_T prStaRec; /* The current focused STA */ + P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */ + P_QUE_T prCurrQueue; /* The current TX queue to dequeue */ + P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */ + + UINT_32 u4ForwardCount; /* To remember the total forwarded packets for a STA */ + UINT_32 u4MaxForwardCount; /* The maximum number of packets a STA can forward */ + UINT_32 u4Resource; /* The TX resource amount */ + + BOOLEAN fgChangeHeadSta; /* Whether a new head STA shall be determined at the end of the function */ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + PUINT_8 pucFreeQuota = NULL; +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = &prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; + /*NFC Beam + Indication */ +#endif + DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); + + ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); + + if (!ucCurrentQuota) { + prQM->au4DequeueNoTcResourceCounter[ucTC]++; + DBGLOG(TX, LOUD, "@@@@@ TC = %u ucCurrentQuota = %u @@@@@\n", ucTC, ucCurrentQuota); + return; + } + + u4Resource = ucCurrentQuota; + + /* 4 <1> Determine the head STA */ + /* The head STA shall be an active STA */ + + pu4HeadStaRecIndex = &(prQM->au4HeadStaRecIndex[ucTC]); + pu4HeadStaRecForwardCount = &(prQM->au4ForwardCount[ucTC]); + + DBGLOG(QM, LOUD, "(Fairness) TID = %u Init Head STA = %u Resource = %u\n", + ucTC, *pu4HeadStaRecIndex, u4Resource); + + /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD + 1; i++) { + prStaRec = &prAdapter->arStaRec[(*pu4HeadStaRecIndex)]; + ASSERT(prStaRec); + + /* Only Data frame (1x was not included) will be queued in */ + if (prStaRec->fgIsValid) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + + /* Determine how many packets the head STA is allowed to send in a round */ + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_25); + u4MaxForwardCount = ucTotalQuota; +#if CFG_ENABLE_WIFI_DIRECT + + pucFreeQuota = NULL; + if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { + /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ + /* u4MaxForwardCount = ucTotalQuota; */ + /* Per STA flow control when STA in PS mode */ + /* The PHASE 1: only update from ucFreeQuota (now) */ + /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ + /* aucFreeQuotaPerQueue[] */ + /* NOTE: other method to set u4Resource */ + + if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD */) { + + if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { + u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; + } else { + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } else { + ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } /* fgIsInPS */ +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_WIFI_DIRECT + + /*NFC Beam + Indication */ + + if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + if ((prChnlReqInfo->NFC_BEAM != 1) && + (u4MaxForwardCount > prBssInfo->ucBssFreeQuota)) + u4MaxForwardCount = prBssInfo->ucBssFreeQuota; + } else { + if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) + u4MaxForwardCount = prBssInfo->ucBssFreeQuota; + } + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + /* Determine whether the head STA can continue to forward packets in this round */ + if ((*pu4HeadStaRecForwardCount) < u4MaxForwardCount) + break; + + } /* prStaRec->fgIsValid */ + else { + /* The current Head STA has been deactivated, so search for a new head STA */ + prStaRec = NULL; + prBssInfo = NULL; + (*pu4HeadStaRecIndex)++; + (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; + + /* Reset the forwarding count before searching (since this is for a new selected STA) */ + (*pu4HeadStaRecForwardCount) = 0; + } + } /* i < CFG_NUM_OF_STA_RECORD + 1 */ + + /* All STA_RECs are inactive, so exit */ + if (!prStaRec) { + /* Under concurrent, it is possible that there is no candidcated STA. */ + /* DBGLOG(TX, EVENT, ("All STA_RECs are inactive\n")); */ + return; + } + + DBGLOG(QM, LOUD, "(Fairness) TID = %u Round Head STA = %u\n", ucTC, *pu4HeadStaRecIndex); + + /* 4 <2> Dequeue packets from the head STA */ + + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + prDequeuedPkt = NULL; + fgChangeHeadSta = FALSE; + +#if (CFG_SUPPORT_TDLS == 1) + if (pucFreeQuota != NULL) + TdlsexTxQuotaCheck(prAdapter->prGlueInfo, prStaRec, *pucFreeQuota); +#endif /* CFG_SUPPORT_TDLS */ + + while (prCurrQueue) { + +#if QM_DEBUG_COUNTER + + if (ucTC <= TC4_INDEX) { + if (QUEUE_IS_EMPTY(prCurrQueue)) { + QM_DBG_CNT_INC(prQM, ucTC); + /* QM_DBG_CNT_00 *//* QM_DBG_CNT_01 *//* QM_DBG_CNT_02 */ + /* QM_DBG_CNT_03 *//* QM_DBG_CNT_04 */ + } + if (u4Resource == 0) { + QM_DBG_CNT_INC(prQM, ucTC + 5); + /* QM_DBG_CNT_05 *//* QM_DBG_CNT_06 *//* QM_DBG_CNT_07 */ + /* QM_DBG_CNT_08 *//* QM_DBG_CNT_09 */ + } + if (((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { + QM_DBG_CNT_INC(prQM, ucTC + 10); + /* QM_DBG_CNT_10 *//* QM_DBG_CNT_11 *//* QM_DBG_CNT_12 */ + /* QM_DBG_CNT_13 *//* QM_DBG_CNT_14 */ + } + } +#endif + + /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ + if (QUEUE_IS_EMPTY(prCurrQueue) || ((*pu4HeadStaRecForwardCount) >= u4MaxForwardCount)) { + fgChangeHeadSta = TRUE; + break; + } else if (u4Resource == 0) { +#if (CFG_SUPPORT_STATISTICS == 1) + prStaRec->u4NumOfNoTxQuota++; +#endif /* CFG_SUPPORT_STATISTICS */ + break; + } + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + prStaRec->u4DeqeueuCounter++; + prQM->u4DequeueCounter++; + +#if (CFG_SUPPORT_TDLS_DBG == 1) + if (prDequeuedPkt != NULL) { + struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; + UINT8 *pkt = prSkb->data; + UINT16 u2Identifier; + + if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { + /* ip */ + u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); + DBGLOG(QM, LOUD, " %d\n", u2Identifier); + } + } +#endif +#if DBG && 0 + LOG_FUNC("Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, + prCurrQueue->u4NumElem, + prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, + prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11); + + LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; + + dumpMemory8((PUINT_8) prSkb->data, prSkb->len); + } +#endif + +#endif + + ASSERT(prDequeuedPkt->ucTC == ucTC); + + if (!QUEUE_IS_EMPTY(prCurrQueue)) { + /* XXX: check all queues for STA */ + prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; + } + + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); + u4Resource--; + (*pu4HeadStaRecForwardCount)++; + +#if CFG_ENABLE_WIFI_DIRECT + /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ + if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { + if ((pucFreeQuota) && (*pucFreeQuota > 0)) + *pucFreeQuota = *pucFreeQuota - 1; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { + if (prBssInfo->ucBssFreeQuota > 0) + prBssInfo->ucBssFreeQuota--; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + } + + if (*pu4HeadStaRecForwardCount) { + DBGLOG(QM, LOUD, + "TC = %u Round Head STA = %u, u4HeadStaRecForwardCount = %u\n", ucTC, *pu4HeadStaRecIndex, + (*pu4HeadStaRecForwardCount)); + } +#if QM_BURST_END_INFO_ENABLED + /* Let FW know which packet is the last one dequeued from the STA */ + if (prDequeuedPkt) + prDequeuedPkt->fgIsBurstEnd = TRUE; +#endif + + /* 4 <3> Dequeue from the other STAs if there is residual TX resource */ + + /* Check all of the STAs to continue forwarding packets (including the head STA) */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { + /* Break in case no reasource is available */ + if (u4Resource == 0) { + prQM->au4DequeueNoTcResourceCounter[ucTC]++; + break; + } + + /* The current head STA will be examined when i = CFG_NUM_OF_STA_RECORD-1 */ + prStaRec = &prAdapter->arStaRec[((*pu4HeadStaRecIndex) + i + 1) % CFG_NUM_OF_STA_RECORD]; + ASSERT(prStaRec); + + if (prStaRec->fgIsValid) { + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + + DBGLOG(QM, LOUD, "(Fairness) TID = %u Sharing STA = %u Resource = %u\n", + ucTC, prStaRec->ucIndex, u4Resource); + + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + u4ForwardCount = 0; + u4MaxForwardCount = ucTotalQuota; + +#if CFG_ENABLE_WIFI_DIRECT + pucFreeQuota = NULL; + if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { + /* TODO: Change the threshold in coorperation with the PS forwarding mechanism */ + /* u4MaxForwardCount = ucTotalQuota; */ + /* Per STA flow control when STA in PS mode */ + /* The PHASE 1: only update from ucFreeQuota (now) */ + /* XXX The PHASE 2: Decide by ucFreeQuota and ucBmpDeliveryAC (per queue ) */ + /* aucFreeQuotaPerQueue[] */ + /* NOTE: other method to set u4Resource */ + if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD */) { + + if (prStaRec->ucBmpTriggerAC & BIT(ucTC)) { + u4MaxForwardCount = prStaRec->ucFreeQuotaForDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForDelivery; + } else { + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } else { + ASSERT(prStaRec->ucFreeQuotaForDelivery == 0); + u4MaxForwardCount = prStaRec->ucFreeQuotaForNonDelivery; + pucFreeQuota = &prStaRec->ucFreeQuotaForNonDelivery; + } + + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { + if (u4MaxForwardCount > prBssInfo->ucBssFreeQuota) + u4MaxForwardCount = prBssInfo->ucBssFreeQuota; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + } /* prStaRec->fgIsValid */ + else { + prBssInfo = NULL; + /* Invalid STA, so check the next STA */ + continue; + } + + while (prCurrQueue) { + /* Three cases to break: (1) No resource (2) No packets (3) Fairness */ + if ((u4Resource == 0) || QUEUE_IS_EMPTY(prCurrQueue) || (u4ForwardCount >= u4MaxForwardCount)) + break; + + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + +#if DBG && 0 + DBGLOG(QM, LOUD, "Deq0 TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, + prCurrQueue->u4NumElem, + prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, + prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, + prDequeuedPkt->fgIs802_1x, prDequeuedPkt->fgIs802_11)); + + DBGLOG(QM, LOUD, "Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; + + dumpMemory8((PUINT_8) prSkb->data, prSkb->len); + } +#endif + +#endif + + ASSERT(prDequeuedPkt->ucTC == ucTC); + + if (!QUEUE_IS_EMPTY(prCurrQueue)) + /* more data field ? */ + prDequeuedPkt->ucPsForwardingType = PS_FORWARDING_MORE_DATA_ENABLED; + + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); + if (prStaRec) + prStaRec->u4DeqeueuCounter++; + prQM->u4DequeueCounter++; + u4Resource--; + u4ForwardCount++; + +#if CFG_ENABLE_WIFI_DIRECT + /* XXX The PHASE 2: decrease from aucFreeQuotaPerQueue[] */ + if (prStaRec->fgIsInPS && (ucTC != TC4_INDEX)) { + ASSERT(pucFreeQuota); + ASSERT(*pucFreeQuota > 0); + if (*pucFreeQuota > 0) + *pucFreeQuota = *pucFreeQuota - 1; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + +#if CFG_ENABLE_WIFI_DIRECT + ASSERT(prBssInfo->ucNetTypeIndex == prStaRec->ucNetTypeIndex); + if (prBssInfo->fgIsNetAbsent && (ucTC != TC4_INDEX)) { + if (prBssInfo->ucBssFreeQuota > 0) + prBssInfo->ucBssFreeQuota--; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + + } + +#if QM_BURST_END_INFO_ENABLED + /* Let FW know which packet is the last one dequeued from the STA */ + if (u4ForwardCount) + prDequeuedPkt->fgIsBurstEnd = TRUE; +#endif + } + + if (fgChangeHeadSta) { + (*pu4HeadStaRecIndex)++; + (*pu4HeadStaRecIndex) %= CFG_NUM_OF_STA_RECORD; + (*pu4HeadStaRecForwardCount) = 0; + DBGLOG(QM, LOUD, "(Fairness) TID = %u Scheduled Head STA = %u Left Resource = %u\n", + ucTC, (*pu4HeadStaRecIndex), u4Resource); + } + +/***************************************************************************************/ +#else + UINT_8 ucStaRecIndex; + P_STA_RECORD_T prStaRec; + P_QUE_T prCurrQueue; + UINT_8 ucPktCount; + P_MSDU_INFO_T prDequeuedPkt; + + DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerStaQueues (TC = %u)\n", ucTC); + + if (ucCurrentQuota == 0) + return; + /* 4 <1> Determine the queue index and the head STA */ + + /* The head STA */ + ucStaRecIndex = 0; /* TODO: Get the current head STA */ + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIndex); + ASSERT(prStaRec); + + if (prStaRec == NULL) + return; + + /* The queue to pull out packets */ + ASSERT(ucTC == TC0_INDEX || ucTC == TC1_INDEX || ucTC == TC2_INDEX || ucTC == TC3_INDEX || ucTC == TC4_INDEX); + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + + ucPktCount = ucCurrentQuota; + prDequeuedPkt = NULL; + + /* 4 <2> Dequeue packets for the head STA */ + while (TRUE) { + if (!(prStaRec->fgIsValid) || ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) { + break; + + } else { + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + /* DbgPrint("QM: Remove Queue Head, TC= %d\n", prDequeuedPkt->ucTC); */ + ASSERT(prDequeuedPkt->ucTC == ucTC); + + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); + ucPktCount--; + } + } + + /* DbgPrint("QM: Remaining number of queued packets = %d\n", prCurrQueue->u4NumElem); */ + +#if QM_BURST_END_INFO_ENABLED + if (prDequeuedPkt) + prDequeuedPkt->fgIsBurstEnd = TRUE; +#endif + + /* 4 <3> Update scheduling info */ + /* TODO */ + + /* 4 <4> Utilize the remainaing TX opportunities for non-head STAs */ + /* TODO */ +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets from a per-Type-based Queue for a particular TC +* +* \param[out] prQue The queue to put the dequeued packets +* \param[in] ucTC The TC index (Shall always be TC5_INDEX) +* \param[in] ucMaxNum The maximum amount of dequeued packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID +qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, OUT P_QUE_T prQue, IN UINT_8 ucTC, IN UINT_8 ucMaxNum) +{ + /* UINT_8 ucQueIndex; */ + /* UINT_8 ucStaRecIndex; */ + P_BSS_INFO_T prBssInfo; + P_BSS_INFO_T parBssInfo; + P_QUE_T prCurrQueue; + UINT_8 ucPktCount; + P_MSDU_INFO_T prDequeuedPkt; + P_MSDU_INFO_T prBurstEndPkt; + QUE_T rMergeQue; + P_QUE_T prMergeQue; + P_QUE_MGT_T prQM; + + DBGLOG(QM, LOUD, "Enter qmDequeueTxPacketsFromPerTypeQueues (TC = %d, Max = %d)\n", ucTC, ucMaxNum); + + /* TC5: Broadcast/Multicast data packets */ + ASSERT(ucTC == TC5_INDEX); + + if (ucMaxNum == 0) + return; + + prQM = &prAdapter->rQM; + /* 4 <1> Determine the queue */ + + prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + ucPktCount = ucMaxNum; + prDequeuedPkt = NULL; + prBurstEndPkt = NULL; + + parBssInfo = prAdapter->rWifiVar.arBssInfo; + + QUEUE_INITIALIZE(&rMergeQue); + prMergeQue = &rMergeQue; + + /* 4 <2> Dequeue packets */ + while (TRUE) { + if (ucPktCount == 0 || QUEUE_IS_EMPTY(prCurrQueue)) + break; + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + ASSERT(prDequeuedPkt->ucTC == ucTC); + + ASSERT(prDequeuedPkt->ucNetworkType < NETWORK_TYPE_INDEX_NUM); + + prBssInfo = &parBssInfo[prDequeuedPkt->ucNetworkType]; + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (!prBssInfo->fgIsNetAbsent) { + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prDequeuedPkt); + prQM->u4DequeueCounter++; + prBurstEndPkt = prDequeuedPkt; + ucPktCount--; + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26); +#if DBG && 0 + LOG_FUNC + ("DeqType TC %d queued %u net %u mac len %u len %u Type %u 1x %u 11 %u\n", + prDequeuedPkt->ucTC, prCurrQueue->u4NumElem, prDequeuedPkt->ucNetworkType, + prDequeuedPkt->ucMacHeaderLength, prDequeuedPkt->u2FrameLength, + prDequeuedPkt->ucPacketType, prDequeuedPkt->fgIs802_1x, + prDequeuedPkt->fgIs802_11); + + LOG_FUNC("Dest Mac: %pM\n", prDequeuedPkt->aucEthDestAddr); + +#if LINUX + { + struct sk_buff *prSkb = (struct sk_buff *)prDequeuedPkt->prPacket; + + dumpMemory8((PUINT_8) prSkb->data, prSkb->len); + } +#endif + +#endif + } else { + QUEUE_INSERT_TAIL(prMergeQue, (P_QUE_ENTRY_T) prDequeuedPkt); + } + } else { + QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL); + wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt); + } + } + + if (QUEUE_IS_NOT_EMPTY(prMergeQue)) { + QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue); + QUEUE_MOVE_ALL(prCurrQueue, prMergeQue); + if (QUEUE_GET_TAIL(prCurrQueue)) + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(prCurrQueue), NULL); + } +#if QM_BURST_END_INFO_ENABLED + if (prBurstEndPkt) + prBurstEndPkt->fgIsBurstEnd = TRUE; +#endif +} /* qmDequeueTxPacketsFromPerTypeQueues */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dequeue TX packets to send to HIF TX +* +* \param[in] prTcqStatus Info about the maximum amount of dequeued packets +* +* \return The list of dequeued TX packets +*/ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, IN P_TX_TCQ_STATUS_T prTcqStatus) +{ + + INT32 i; + P_MSDU_INFO_T prReturnedPacketListHead; + QUE_T rReturnedQue; + + DBGLOG(QM, LOUD, "Enter qmDequeueTxPackets\n"); + + QUEUE_INITIALIZE(&rReturnedQue); + + prReturnedPacketListHead = NULL; + + /* dequeue packets from different AC queue based on available aucFreeBufferCount */ + /* TC0 to TC4: AC0~AC3, 802.1x (commands packets are not handled by QM) */ + for (i = TC4_INDEX; i >= TC0_INDEX; i--) { + DBGLOG(QM, LOUD, "Dequeue packets from Per-STA queue[%d]\n", i); + + /* + in the function, we will re-calculate the ucFreeQuota. + If any packet with any priority for the station will be sent, ucFreeQuota -- + + Note1: ucFreeQuota will be decrease only when station is in power save mode. + In active mode, we will sent the packet to the air directly. + + if(prStaRec->fgIsInPS && (ucTC!=TC4_INDEX)) { + ASSERT(pucFreeQuota); + ASSERT(*pucFreeQuota>0); + if ((pucFreeQuota) && (*pucFreeQuota>0)) { + *pucFreeQuota = *pucFreeQuota - 1; + } + } + + Note2: maximum queued number for a station is 10, TXM_MAX_BUFFER_PER_STA_DEF in fw + i.e. default prStaRec->ucFreeQuota = 10 + + Note3: In qmUpdateFreeQuota(), we will adjust + ucFreeQuotaForNonDelivery = ucFreeQuota>>1; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + */ + qmDequeueTxPacketsFromPerStaQueues(prAdapter, + &rReturnedQue, + (UINT_8) i, + prTcqStatus->aucFreeBufferCount[i], /* maximum dequeue number */ + prTcqStatus->aucMaxNumOfBuffer[i]); + + /* The aggregate number of dequeued packets */ + DBGLOG(QM, LOUD, "DQA)[%u](%u)\n", i, rReturnedQue.u4NumElem); + } + + /* TC5 (BMCAST or STA-NOT-FOUND packets) */ + qmDequeueTxPacketsFromPerTypeQueues(prAdapter, + &rReturnedQue, TC5_INDEX, prTcqStatus->aucFreeBufferCount[TC5_INDEX] + ); + + DBGLOG(QM, LOUD, "Current total number of dequeued packets = %u\n", rReturnedQue.u4NumElem); + + if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) { + prReturnedPacketListHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rReturnedQue); + QM_TX_SET_NEXT_MSDU_INFO((P_MSDU_INFO_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); + } + + return prReturnedPacketListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Adjust the TC quotas according to traffic demands +* +* \param[out] prTcqAdjust The resulting adjustment +* \param[in] prTcqStatus Info about the current TC quotas and counters +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, IN P_TX_TCQ_STATUS_T prTcqStatus) +{ +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + UINT_32 i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Must reset */ + for (i = 0; i < TC_NUM; i++) + prTcqAdjust->acVariation[i] = 0; + + /* 4 <1> If TC resource is not just adjusted, exit directly */ + if (!prQM->fgTcResourcePostAnnealing) + return; + /* 4 <2> Adjust TcqStatus according to the updated prQM->au4CurrentTcResource */ + else { + INT_32 i4TotalExtraQuota = 0; + INT_32 ai4ExtraQuota[TC_NUM]; + BOOLEAN fgResourceRedistributed = TRUE; + + /* Obtain the free-to-distribute resource */ + for (i = 0; i < TC_NUM; i++) { + ai4ExtraQuota[i] = + (INT_32) prTcqStatus->aucMaxNumOfBuffer[i] - (INT_32) prQM->au4CurrentTcResource[i]; + + if (ai4ExtraQuota[i] > 0) { /* The resource shall be reallocated to other TCs */ + + if (ai4ExtraQuota[i] > prTcqStatus->aucFreeBufferCount[i]) { + /* + we have residunt TC resources for the TC: + EX: aucMaxNumOfBuffer[] = 20, au4CurrentTcResource[] = 5 + ai4ExtraQuota[] = 15, aucFreeBufferCount[] = 10 + + so ai4ExtraQuota[] = aucFreeBufferCount[] = 10 + because we available TC resources actually is 10, not 20 + */ + ai4ExtraQuota[i] = prTcqStatus->aucFreeBufferCount[i]; + + /* + FALSE means we can re-do TC resource adjustment in tx done + at next time, maybe more tx done is finished + */ + fgResourceRedistributed = FALSE; + } + + /* accumulate current all available TC resources */ + i4TotalExtraQuota += ai4ExtraQuota[i]; + + /* deduce unused TC resources for the TC */ + prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); + } + } + + /* Distribute quotas to TCs which need extra resource according to prQM->au4CurrentTcResource */ + for (i = 0; i < TC_NUM; i++) { + if (ai4ExtraQuota[i] < 0) { + + /* The TC needs extra resources */ + if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) { + /* the number of needed extra resources is larger than total available */ + ai4ExtraQuota[i] = (-i4TotalExtraQuota); + + /* wait for next tx done to do adjustment */ + fgResourceRedistributed = FALSE; + } + + /* decrease the total available */ + i4TotalExtraQuota += ai4ExtraQuota[i]; + + /* mark to increase TC resources for the TC */ + prTcqAdjust->acVariation[i] = (INT_8) (-ai4ExtraQuota[i]); + } + } + + /* In case some TC is waiting for TX Done, continue to adjust TC quotas upon TX Done */ + + /* + if fgResourceRedistributed == TRUE, it means we will adjust at this time so + we need to re-adjust TC resources (fgTcResourcePostAnnealing = FALSE). + */ + prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); + +#if QM_PRINT_TC_RESOURCE_CTRL + DBGLOG(QM, LOUD, "QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n", + prTcqStatus->aucFreeBufferCount[0], + prTcqStatus->aucFreeBufferCount[1], + prTcqStatus->aucFreeBufferCount[2], + prTcqStatus->aucFreeBufferCount[3], + prTcqStatus->aucFreeBufferCount[4], prTcqStatus->aucFreeBufferCount[5] + )); +#endif + } + +#else + UINT_32 i; + + for (i = 0; i < TC_NUM; i++) + prTcqAdjust->acVariation[i] = 0; + +#endif +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update the average TX queue length for the TC resource control mechanism +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter) +{ + INT_32 u4CurrQueLen, i, k; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ + /* use moving average algorithm to calculate au4AverageQueLen for every TC queue */ + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES - 1; i++) { + u4CurrQueLen = 0; + + for (k = 0; k < CFG_NUM_OF_STA_RECORD; k++) { + prStaRec = &prAdapter->arStaRec[k]; + ASSERT(prStaRec); + + /* If the STA is activated, get the queue length */ + if (prStaRec->fgIsValid && + (!prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex].fgIsNetAbsent) + ) { + + u4CurrQueLen += (prStaRec->arTxQueue[i].u4NumElem); + } + } + + if (prQM->au4AverageQueLen[i] == 0) { + prQM->au4AverageQueLen[i] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); /* *8 */ + } else { + /* len => len - len/8 = 7/8 * len + new len */ + prQM->au4AverageQueLen[i] -= (prQM->au4AverageQueLen[i] >> QM_QUE_LEN_MOVING_AVE_FACTOR); + prQM->au4AverageQueLen[i] += (u4CurrQueLen); + } + + } + + /* Update the queue length for TC5 (BMCAST) */ + u4CurrQueLen = prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem; + + if (prQM->au4AverageQueLen[TC_NUM - 1] == 0) { + prQM->au4AverageQueLen[TC_NUM - 1] = (u4CurrQueLen << QM_QUE_LEN_MOVING_AVE_FACTOR); + } else { + prQM->au4AverageQueLen[TC_NUM - 1] -= + (prQM->au4AverageQueLen[TC_NUM - 1] >> QM_QUE_LEN_MOVING_AVE_FACTOR); + prQM->au4AverageQueLen[TC_NUM - 1] += (u4CurrQueLen); + } + + /* 4 <2> Adjust TC resource assignment every 3 times */ + /* Check whether it is time to adjust the TC resource assignment */ + if (--prQM->u4TimeToAdjustTcResource == 0) { /* u4TimeToAdjustTcResource = 3 */ + + /* The last assignment has not been completely applied */ + if (prQM->fgTcResourcePostAnnealing) { + /* Upon the next qmUpdateAverageTxQueLen function call, do this check again */ + + /* wait for next time to do qmReassignTcResource */ + prQM->u4TimeToAdjustTcResource = 1; + } else { /* The last assignment has been applied */ + prQM->u4TimeToAdjustTcResource = QM_INIT_TIME_TO_ADJUST_TC_RSC; + qmReassignTcResource(prAdapter); + } + } + + /* Debug */ +#if QM_PRINT_TC_RESOURCE_CTRL + for (i = 0; i < TC_NUM; i++) { + if (QM_GET_TX_QUEUE_LEN(prAdapter, i) >= 100) { + DBGLOG(QM, LOUD, "QM: QueLen [%u %u %u %u %u %u]\n", + QM_GET_TX_QUEUE_LEN(prAdapter, 0), + QM_GET_TX_QUEUE_LEN(prAdapter, 1), + QM_GET_TX_QUEUE_LEN(prAdapter, 2), + QM_GET_TX_QUEUE_LEN(prAdapter, 3), + QM_GET_TX_QUEUE_LEN(prAdapter, 4), QM_GET_TX_QUEUE_LEN(prAdapter, 5) + )); + break; + } + } +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Assign TX resource for each TC according to TX queue length and current assignment +* +* \param (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmReassignTcResource(IN P_ADAPTER_T prAdapter) +{ + INT_32 i4TotalResourceDemand = 0; + UINT_32 u4ResidualResource = 0; + UINT_32 i; + INT_32 ai4PerTcResourceDemand[TC_NUM]; + UINT_32 u4ShareCount = 0; + UINT_32 u4Share = 0; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Note: After the new assignment is obtained, set prQM->fgTcResourcePostAnnealing to TRUE to + * start the TC-quota adjusting procedure, which will be invoked upon every TX Done + */ + /* tx done -> nicProcessTxInterrupt() -> nicTxAdjustTcq() + * -> qmAdjustTcQuotas() -> check fgTcResourcePostAnnealing */ + + /* 4 <1> Determine the demands */ + /* Determine the amount of extra resource to fulfill all of the demands */ + for (i = 0; i < TC_NUM; i++) { + /* Skip TC4, which is not adjustable */ + if (i == TC4_INDEX) + continue; + + /* + Define: extra_demand = average que_length (includes all station records) + + min_reserved_quota - + current available TC resources + + extra_demand means we need extra TC resources to transmit; other TCs can + borrow their resources to us? + */ + ai4PerTcResourceDemand[i] = + ((UINT_32) (QM_GET_TX_QUEUE_LEN(prAdapter, i)) + + prQM->au4MinReservedTcResource[i] - prQM->au4CurrentTcResource[i]); + + /* If there are queued packets, allocate extra resource for the TC (for TCP consideration) */ + if (QM_GET_TX_QUEUE_LEN(prAdapter, i)) + ai4PerTcResourceDemand[i] += QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY; /* 0 */ + + /* + accumulate all needed extra TC resources + maybe someone need + resource, maybe someone need - resource + */ + i4TotalResourceDemand += ai4PerTcResourceDemand[i]; + } + + /* 4 <2> Case 1: Demand <= Total Resource */ + if (i4TotalResourceDemand <= 0) { + /* 4 <2.1> Satisfy every TC */ + /* total TC resources are enough, no extra TC resources is needed */ + + /* adjust used TC resources to average TC resources + min reserve TC resources */ + for (i = 0; i < TC_NUM; i++) { + /* Skip TC4 (not adjustable) */ + if (i == TC4_INDEX) + continue; + + /* + the number of resources that one TC releases can be used for + other TCs + + EX: TC0 au4CurrentTcResource[0] = 10 ai4PerTcResourceDemand[0] = -5 + TC1 au4CurrentTcResource[1] = 5 ai4PerTcResourceDemand[0] = +5 + => TC0 au4CurrentTcResource[0] = 10 + (-5) = 5 + TC1 au4CurrentTcResource[1] = 5 + (+5) = 10 + */ + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + } + + /* 4 <2.2> Share the residual resource evenly */ + u4ShareCount = (TC_NUM - 1); /* 5, excluding TC4 */ + + /* + EX: i4TotalResourceDemand = -10 + means we have 10 available resources can be used. + */ + u4ResidualResource = (UINT_32) (-i4TotalResourceDemand); + u4Share = (u4ResidualResource / u4ShareCount); + + /* share available TC resources to all TCs averagely */ + for (i = 0; i < TC_NUM; i++) { + /* Skip TC4 (not adjustable) */ + if (i == TC4_INDEX) + continue; + + /* allocate residual average resources to the TC */ + prQM->au4CurrentTcResource[i] += u4Share; + + /* Every TC is fully satisfied so no need extra resources */ + ai4PerTcResourceDemand[i] = 0; + + /* decrease the allocated resources */ + u4ResidualResource -= u4Share; + } + + /* if still have available resources, we decide to give them to VO (TC3) queue */ + /* 4 <2.3> Allocate the left resource to TC3 (VO) */ + prQM->au4CurrentTcResource[TC3_INDEX] += (u4ResidualResource); + + } + /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount of resource for each TC */ + else { + /* + u4ResidualResource means we at least need to keep + QM_INITIAL_RESIDUAL_TC_RESOURCE available TC resources + + in 6628, u4ResidualResource = 26, max 28 + */ + u4ResidualResource = QM_INITIAL_RESIDUAL_TC_RESOURCE; + + /* 4 <3.1> Allocated resource amount = minimum of (guaranteed, total demand) */ + for (i = 0; i < TC_NUM; i++) { + + if (i == TC4_INDEX) + continue; /* Skip TC4 (not adjustable) */ + + /* The demand can be fulfilled with the guaranteed resource amount 4 4 6 6 2 4 */ + + /* + ai4PerTcResourceDemand[i] = + ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + + prQM->au4MinReservedTcResource[i] - + prQM->au4CurrentTcResource[i]); + + so au4CurrentTcResource + ai4PerTcResourceDemand = + + ((UINT_32)(QM_GET_TX_QUEUE_LEN(prAdapter, i)) + + prQM->au4MinReservedTcResource[i] = + + current average queue len + min TC resources + */ + if (prQM->au4CurrentTcResource[i] + ai4PerTcResourceDemand[i] < + prQM->au4GuaranteedTcResource[i]) { + + /* avg queue len + min reserve still smaller than guarantee so enough */ + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + + /* accumulate available TC resources from the TC */ + u4ResidualResource += + (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); + ai4PerTcResourceDemand[i] = 0; + } + + /* The demand can not be fulfilled with the guaranteed resource amount */ + else { + + /* means even we use all guarantee resources for the TC is still not enough */ + + /* + guarantee number is always for the TC so extra resource number cannot + include the guarantee number. + + EX: au4GuaranteedTcResource = 10, au4CurrentTcResource = 5 + ai4PerTcResourceDemand = 6 + + ai4PerTcResourceDemand -= (10 - 5) ==> 1 + only need extra 1 TC resouce is enough. + */ + ai4PerTcResourceDemand[i] -= + (prQM->au4GuaranteedTcResource[i] - prQM->au4CurrentTcResource[i]); + + /* update current avg TC resource to guarantee number */ + prQM->au4CurrentTcResource[i] = prQM->au4GuaranteedTcResource[i]; + + /* count how many TC queues need to get extra resources */ + u4ShareCount++; + } + } + + /* 4 <3.2> Allocate the residual resource */ + do { + /* If there is no resource left, exit directly */ + if (u4ResidualResource == 0) + break; + + /* This shall not happen */ + if (u4ShareCount == 0) { + prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource; + DBGLOG(QM, ERROR, "QM: (Error) u4ShareCount = 0\n"); + break; + } + + /* Share the residual resource evenly */ + u4Share = (u4ResidualResource / u4ShareCount); + + if (u4Share) { + for (i = 0; i < TC_NUM; i++) { + /* Skip TC4 (not adjustable) */ + if (i == TC4_INDEX) + continue; + + if (ai4PerTcResourceDemand[i] == 0) + continue; + + if (ai4PerTcResourceDemand[i] - u4Share) { + /* still not enough but we just can give it u4Share resources */ + prQM->au4CurrentTcResource[i] += u4Share; + u4ResidualResource -= u4Share; + ai4PerTcResourceDemand[i] -= u4Share; + } else { + /* enough */ + prQM->au4CurrentTcResource[i] += ai4PerTcResourceDemand[i]; + u4ResidualResource -= ai4PerTcResourceDemand[i]; + ai4PerTcResourceDemand[i] = 0; + } + } + } + + if (u4ResidualResource == 0) + break; + /* By priority, allocate the left resource that is not divisible by u4Share */ + + if (ai4PerTcResourceDemand[TC3_INDEX]) { /* VO */ + prQM->au4CurrentTcResource[TC3_INDEX]++; + if (--u4ResidualResource == 0) + break; + } + + if (ai4PerTcResourceDemand[TC2_INDEX]) { /* VI */ + prQM->au4CurrentTcResource[TC2_INDEX]++; + if (--u4ResidualResource == 0) + break; + } + + if (ai4PerTcResourceDemand[TC5_INDEX]) { /* BMCAST */ + prQM->au4CurrentTcResource[TC5_INDEX]++; + if (--u4ResidualResource == 0) + break; + } + + if (ai4PerTcResourceDemand[TC1_INDEX]) { /* BE */ + prQM->au4CurrentTcResource[TC1_INDEX]++; + if (--u4ResidualResource == 0) + break; + } + + if (ai4PerTcResourceDemand[TC0_INDEX]) { /* BK */ + prQM->au4CurrentTcResource[TC0_INDEX]++; + if (--u4ResidualResource == 0) + break; + } + + /* Allocate the left resource */ + prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource; + + } while (FALSE); + } + + /* mark the flag that we can start to do TC resource adjustment after TX done handle */ + prQM->fgTcResourcePostAnnealing = TRUE; + +#if QM_PRINT_TC_RESOURCE_CTRL + /* Debug print */ + DBGLOG(QM, LOUD, "QM: TC Rsc %u %u %u %u %u %u\n", + prQM->au4CurrentTcResource[0], + prQM->au4CurrentTcResource[1], + prQM->au4CurrentTcResource[2], + prQM->au4CurrentTcResource[3], prQM->au4CurrentTcResource[4], prQM->au4CurrentTcResource[5] + )); +#endif + +} + +#endif + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief Init Queue Management for RX +* +* \param[in] (none) +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmInitRxQueues(IN P_ADAPTER_T prAdapter) +{ + /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */ + /* TODO */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle RX packets (buffer reordering) +* +* \param[in] prSwRfbListHead The list of RX packets +* +* \return The list of packets which are not buffered for reordering +*/ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfbListHead) +{ + +#if CFG_RX_REORDERING_ENABLED + /* UINT_32 i; */ + P_SW_RFB_T prCurrSwRfb; + P_SW_RFB_T prNextSwRfb; + P_HIF_RX_HEADER_T prHifRxHdr; + QUE_T rReturnedQue; + PUINT_8 pucEthDestAddr; + BOOLEAN fgIsBMC; + + /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ + + DEBUGFUNC("qmHandleRxPackets"); + + ASSERT(prSwRfbListHead); + + QUEUE_INITIALIZE(&rReturnedQue); + prNextSwRfb = prSwRfbListHead; + + do { + prCurrSwRfb = prNextSwRfb; + prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb); + + prHifRxHdr = prCurrSwRfb->prHifRxHdr; /* TODO: (Tehuang) Use macro to obtain the pointer */ + + /* TODO: (Tehuang) Check if relaying */ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST; + + /* Decide the Destination */ +#if CFG_RX_PKTS_DUMP + if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & BIT(HIF_RX_PKT_TYPE_DATA)) { + DBGLOG(SW4, INFO, "QM RX DATA: net %u sta idx %u wlan idx %u ssn %u tid %u ptype %u 11 %u\n", + (UINT_32) HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr), + prHifRxHdr->ucStaRecIdx, prCurrSwRfb->ucWlanIdx, + (UINT_32) HIF_RX_HDR_GET_SN(prHifRxHdr), /* The new SN of the frame */ + (UINT_32) HIF_RX_HDR_GET_TID(prHifRxHdr), + prCurrSwRfb->ucPacketType, + (UINT_32) HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)); + + DBGLOG_MEM8(SW4, TRACE, (PUINT_8) prCurrSwRfb->pvHeader, prCurrSwRfb->u2PacketLen); + } +#endif + + fgIsBMC = FALSE; + if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { + + UINT_8 ucNetTypeIdx; + P_BSS_INFO_T prBssInfo; + + pucEthDestAddr = prCurrSwRfb->pvHeader; + ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); + /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, 16); */ + /* */ + + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) && (OP_MODE_ACCESS_POINT != prBssInfo->eCurrentOPMode)) + fgIsBMC = TRUE; + + if (prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem > + (CFG_RX_MAX_PKT_NUM - CFG_NUM_OF_QM_RX_PKT_NUM)) { + + if (!IS_BSS_ACTIVE(prBssInfo)) { + DBGLOG(QM, WARN, "Mark NULL the Packet for inactive Bss %u\n", ucNetTypeIdx); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); + continue; + } + + if (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode) { + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; + else if (UNEQUAL_MAC_ADDR(prBssInfo->aucOwnMacAddr, pucEthDestAddr) && + bssGetClientByAddress(prBssInfo, pucEthDestAddr)) + prCurrSwRfb->eDst = RX_PKT_DESTINATION_FORWARD; + /* TODO : need to check the dst mac is valid */ + /* If src mac is invalid, the packet will be freed in fw */ + } /* OP_MODE_ACCESS_POINT */ +#if CFG_SUPPORT_HOTSPOT_2_0 + else if (hs20IsFrameFilterEnabled(prAdapter, prBssInfo) && + hs20IsUnsecuredFrame(prAdapter, prBssInfo, prCurrSwRfb)) { + DBGLOG(QM, WARN, + "Mark NULL the Packet for Dropped Packet %u\n", ucNetTypeIdx); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); + continue; + } +#endif + } else { + /* Dont not occupy other SW RFB */ + DBGLOG(QM, WARN, "Mark NULL the Packet for less Free Sw Rfb\n"); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); + continue; + } + + } +#if CFG_SUPPORT_WAPI + if (prCurrSwRfb->u2PacketLen > ETHER_HEADER_LEN) { + PUINT_8 pc = (PUINT_8) prCurrSwRfb->pvHeader; + UINT_16 u2Etype = 0; + + u2Etype = (pc[ETH_TYPE_LEN_OFFSET] << 8) | (pc[ETH_TYPE_LEN_OFFSET + 1]); + + /* for wapi integrity test. WPI_1x packet should be always in non-encrypted mode. + if we received any WPI(0x88b4) packet that is encrypted, drop here. */ + if (u2Etype == ETH_WPI_1X && HIF_RX_HDR_GET_SEC_MODE(prHifRxHdr) != 0) { + DBGLOG(QM, INFO, "drop wpi packet with sec mode\n"); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); + continue; + } + } +#endif + /* BAR frame */ + if (HIF_RX_HDR_GET_BAR_FLAG(prHifRxHdr)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + qmProcessBarFrame(prAdapter, prCurrSwRfb, &rReturnedQue); + } + /* Reordering is not required for this packet, return it without buffering */ + else if (!HIF_RX_HDR_GET_REORDER_FLAG(prHifRxHdr) || fgIsBMC) { +#if 0 + if (!HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr)) { + UINT_8 ucNetTypeIdx; + P_BSS_INFO_T prBssInfo; + + pucEthDestAddr = prCurrSwRfb->pvHeader; + ucNetTypeIdx = HIF_RX_HDR_GET_NETWORK_IDX(prHifRxHdr); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[ucNetTypeIdx]); + + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr) + && (OP_MODE_ACCESS_POINT == prBssInfo->eCurrentOPMode)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST_WITH_FORWARD; + } + } +#endif + QUEUE_INSERT_TAIL(&rReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb); + } + /* Reordering is required for this packet */ + else { + /* If this packet should dropped or indicated to the host immediately, + * it should be enqueued into the rReturnedQue with specific flags. If + * this packet should be buffered for reordering, it should be enqueued + * into the reordering queue in the STA_REC rather than into the + * rReturnedQue. + */ + qmProcessPktWithReordering(prAdapter, prCurrSwRfb, &rReturnedQue); + + } + } while (prNextSwRfb); + + /* RX_PKT_DESTINATION_HOST_WITH_FORWARD or RX_PKT_DESTINATION_FORWARD */ + /* The returned list of SW_RFBs must end with a NULL pointer */ + if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) + QM_TX_SET_NEXT_MSDU_INFO((P_SW_RFB_T) QUEUE_GET_TAIL(&rReturnedQue), NULL); + + return (P_SW_RFB_T) QUEUE_GET_HEAD(&rReturnedQue); + +#else + + /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ + return prSwRfbListHead; + +#endif + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Reorder the received packet +* +* \param[in] prSwRfb The RX packet to process +* \param[out] prReturnedQue The queue for indicating packets +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) +{ + + P_STA_RECORD_T prStaRec; + P_HIF_RX_HEADER_T prHifRxHdr; + P_RX_BA_ENTRY_T prReorderQueParm; + + UINT_32 u4SeqNo; + UINT_32 u4WinStart; + UINT_32 u4WinEnd; + P_QUE_T prReorderQue; + /* P_SW_RFB_T prReorderedSwRfb; */ + BOOLEAN fgIsBaTimeout; + + DEBUGFUNC("qmProcessPktWithReordering"); + + if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { + ASSERT(FALSE); + return; + } + + prHifRxHdr = prSwRfb->prHifRxHdr; + prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; + prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SN of the frame */ + prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); + /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ + + /* Incorrect STA_REC index */ + if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + DBGLOG(QM, WARN, "Reordering for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); + /* ASSERT(0); */ + return; + } + + /* Check whether the STA_REC is activated */ + prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); + ASSERT(prStaRec); + +#if 0 + if (!(prStaRec->fgIsValid)) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + DBGLOG(QM, WARN, "Reordering for an invalid STA_REC\n"); + /* ASSERT(0); */ + return; + } +#endif + + /* Check whether the BA agreement exists */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); + if (!prReorderQueParm) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + DBGLOG(QM, WARN, "Reordering for a NULL ReorderQueParm\n"); + /* ASSERT(0); */ + return; + } + + /* Start to reorder packets */ + u4SeqNo = (UINT_32) (prSwRfb->u2SSN); + prReorderQue = &(prReorderQueParm->rReOrderQue); + u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); + u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); + + /* Debug */ + /* DbgPrint("QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ + + /* Case 1: Fall within */ + if /* 0 - start - sn - end - 4095 */ + (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd)) + /* 0 - end - start - sn - 4095 */ + || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo)) + /* 0 - sn - end - start - 4095 */ + || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) { + + qmInsertFallWithinReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if (prReorderQueParm->fgIsWaitingForPktWithSsn) { + /* Let the first received packet pass the reorder check */ + DBGLOG(QM, LOUD, "QM:(A)[%d](%u){%u,%u}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + + prReorderQueParm->u2WinStart = (UINT_16) u4SeqNo; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; + prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; + } +#endif + + if (qmPopOutDueToFallWithin(prReorderQueParm, prReturnedQue, &fgIsBaTimeout) == FALSE) + STATS_RX_REORDER_HOLE_INC(prStaRec); /* record hole count */ + STATS_RX_REORDER_HOLE_TIMEOUT_INC(prStaRec, fgIsBaTimeout); + } + /* Case 2: Fall ahead */ + else if + /* 0 - start - end - sn - (start+2048) - 4095 */ + (((u4WinStart < u4WinEnd) + && (u4WinEnd < u4SeqNo) + && (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - sn - (start+2048) - start - end - 4095 */ + || ((u4SeqNo < u4WinStart) + && (u4WinStart < u4WinEnd) + && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - end - sn - (start+2048) - start - 4095 */ + || ((u4WinEnd < u4SeqNo) + && (u4SeqNo < u4WinStart) + && ((u4SeqNo + MAX_SEQ_NO_COUNT) < (u4WinStart + HALF_SEQ_NO_COUNT)))) { + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if (prReorderQueParm->fgIsWaitingForPktWithSsn) + prReorderQueParm->fgIsWaitingForPktWithSsn = FALSE; +#endif + + qmInsertFallAheadReorderPkt(prSwRfb, prReorderQueParm, prReturnedQue); + + /* Advance the window after inserting a new tail */ + prReorderQueParm->u2WinEnd = (UINT_16) u4SeqNo; + prReorderQueParm->u2WinStart = + (((prReorderQueParm->u2WinEnd) - (prReorderQueParm->u2WinSize) + MAX_SEQ_NO_COUNT + 1) + % MAX_SEQ_NO_COUNT); + + qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); + + STATS_RX_REORDER_FALL_AHEAD_INC(prStaRec); + + } + /* Case 3: Fall behind */ + else { + +#if QM_RX_WIN_SSN_AUTO_ADVANCING +#if QM_RX_INIT_FALL_BEHIND_PASS + if (prReorderQueParm->fgIsWaitingForPktWithSsn) { + /* ?? prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + /* DbgPrint("QM:(P)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ + return; + } +#endif +#endif + + STATS_RX_REORDER_FALL_BEHIND_INC(prStaRec); + /* An erroneous packet */ + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + /* DbgPrint("QM:(D)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); */ + return; + } + + return; + +} + +VOID qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, OUT P_QUE_T prReturnedQue) +{ + + P_STA_RECORD_T prStaRec; + P_HIF_RX_HEADER_T prHifRxHdr; + P_RX_BA_ENTRY_T prReorderQueParm; + + UINT_32 u4SSN; + UINT_32 u4WinStart; + UINT_32 u4WinEnd; + P_QUE_T prReorderQue; + /* P_SW_RFB_T prReorderedSwRfb; */ + + if ((prSwRfb == NULL) || (prReturnedQue == NULL) || (prSwRfb->prHifRxHdr == NULL)) { + ASSERT(FALSE); + return; + } + + prHifRxHdr = prSwRfb->prHifRxHdr; + prSwRfb->ucStaRecIdx = prHifRxHdr->ucStaRecIdx; + prSwRfb->u2SSN = HIF_RX_HDR_GET_SN(prHifRxHdr); /* The new SSN */ + prSwRfb->ucTid = (UINT_8) (HIF_RX_HDR_GET_TID(prHifRxHdr)); + + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + + /* Incorrect STA_REC index */ + if (prSwRfb->ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { + DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n", prSwRfb->ucStaRecIdx); + /* ASSERT(0); */ + return; + } + + /* Check whether the STA_REC is activated */ + prStaRec = &(prAdapter->arStaRec[prSwRfb->ucStaRecIdx]); + ASSERT(prStaRec); + +#if 0 + if (!(prStaRec->fgIsValid)) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + DbgPrint("QM: (Warning) BAR for an invalid STA_REC\n"); + /* ASSERT(0); */ + return; + } +#endif + + /* Check whether the BA agreement exists */ + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); + if (!prReorderQueParm) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + DBGLOG(QM, WARN, "QM: (Warning) BAR for a NULL ReorderQueParm\n"); + /* ASSERT(0); */ + return; + } + + u4SSN = (UINT_32) (prSwRfb->u2SSN); + prReorderQue = &(prReorderQueParm->rReOrderQue); + u4WinStart = (UINT_32) (prReorderQueParm->u2WinStart); + u4WinEnd = (UINT_32) (prReorderQueParm->u2WinEnd); + + if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) { + prReorderQueParm->u2WinStart = (UINT_16) u4SSN; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT; + DBGLOG(QM, TRACE, + "QM:(BAR)[%d](%u){%d,%d}\n", prSwRfb->ucTid, u4SSN, prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + qmPopOutDueToFallAhead(prReorderQueParm, prReturnedQue); + } else { + DBGLOG(QM, TRACE, "QM:(BAR)(%d)(%u){%u,%u}\n", prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd); + } +} + +VOID qmInsertFallWithinReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prExaminedQueuedSwRfb; + P_QUE_T prReorderQue; + + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); + + prReorderQue = &(prReorderQueParm->rReOrderQue); + prExaminedQueuedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); + + /* There are no packets queued in the Reorder Queue */ + if (prExaminedQueuedSwRfb == NULL) { + ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; + prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; + prReorderQue->u4NumElem++; + } + + /* Determine the insert position */ + else { + do { + /* Case 1: Terminate. A duplicate packet */ + if (((prExaminedQueuedSwRfb->u2SSN) == (prSwRfb->u2SSN))) { + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prSwRfb); + return; + } + + /* Case 2: Terminate. The insert point is found */ + else if (qmCompareSnIsLessThan((prSwRfb->u2SSN), (prExaminedQueuedSwRfb->u2SSN))) + break; + + /* Case 3: Insert point not found. Check the next SW_RFB in the Reorder Queue */ + else + prExaminedQueuedSwRfb = (P_SW_RFB_T) (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prNext); + } while (prExaminedQueuedSwRfb); + + /* Update the Reorder Queue Parameters according to the found insert position */ + if (prExaminedQueuedSwRfb == NULL) { + /* The received packet shall be placed at the tail */ + ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); + prReorderQue->prTail = (P_QUE_ENTRY_T) (prSwRfb); + } else { + ((P_QUE_ENTRY_T) prSwRfb)->prPrev = ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev; + ((P_QUE_ENTRY_T) prSwRfb)->prNext = (P_QUE_ENTRY_T) prExaminedQueuedSwRfb; + if (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb) == (prReorderQue->prHead)) { + /* The received packet will become the head */ + prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; + } else { + (((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev)->prNext = (P_QUE_ENTRY_T) prSwRfb; + } + ((P_QUE_ENTRY_T) prExaminedQueuedSwRfb)->prPrev = (P_QUE_ENTRY_T) prSwRfb; + } + + prReorderQue->u4NumElem++; + + } + +} + +VOID qmInsertFallAheadReorderPkt(IN P_SW_RFB_T prSwRfb, IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) +{ + P_QUE_T prReorderQue; + + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* There are no packets queued in the Reorder Queue */ + if (QUEUE_IS_EMPTY(prReorderQue)) { + ((P_QUE_ENTRY_T) prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T) prSwRfb; + } else { + ((P_QUE_ENTRY_T) prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T) prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T) (prSwRfb); + } + prReorderQue->prTail = (P_QUE_ENTRY_T) prSwRfb; + prReorderQue->u4NumElem++; + +} + +BOOLEAN +qmPopOutDueToFallWithin(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue, OUT BOOLEAN *fgIsTimeout) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + BOOLEAN fgDequeuHead, fgMissing; + OS_SYSTIME rCurrentTime, *prMissTimeout; + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + *fgIsTimeout = FALSE; + fgMissing = FALSE; + rCurrentTime = 0; + prMissTimeout = &(g_arMissTimeout[prReorderQueParm->ucStaRecIdx][prReorderQueParm->ucTid]); + if ((*prMissTimeout)) { + fgMissing = TRUE; + GET_CURRENT_SYSTIME(&rCurrentTime); + } + + /* Check whether any packet can be indicated to the higher layer */ + while (TRUE) { + if (QUEUE_IS_EMPTY(prReorderQue)) + break; + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = FALSE; + + /* SN == WinStart, so the head packet shall be indicated (advance the window) */ + if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { + + fgDequeuHead = TRUE; + prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); + } + /* SN > WinStart, break to update WinEnd */ + else { + if ((fgMissing == TRUE) && + CHECK_FOR_TIMEOUT(rCurrentTime, (*prMissTimeout), + MSEC_TO_SYSTIME(QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) { + DBGLOG(QM, TRACE, + "QM:RX BA Timout Next Tid %d SSN %d\n", prReorderQueParm->ucTid, + prReorderedSwRfb->u2SSN); + fgDequeuHead = TRUE; + prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); + + fgMissing = FALSE; + *fgIsTimeout = TRUE; + } else + break; + } + + /* Dequeue the head packet */ + if (fgDequeuHead) { + + if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } else { + prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; + (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; + } + prReorderQue->u4NumElem--; + /* DbgPrint("QM: [%d] %d (%d)\n", + prReorderQueParm->ucTid, + prReorderedSwRfb->u2PacketLen, + prReorderedSwRfb->u2SSN); */ + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); + } + } + + if (QUEUE_IS_EMPTY(prReorderQue)) + *prMissTimeout = 0; + else { + if (fgMissing == FALSE) + GET_CURRENT_SYSTIME(prMissTimeout); + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = + (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); + return QUEUE_IS_EMPTY(prReorderQue); +} + +VOID qmPopOutDueToFallAhead(IN P_RX_BA_ENTRY_T prReorderQueParm, OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + BOOLEAN fgDequeuHead; + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* Check whether any packet can be indicated to the higher layer */ + while (TRUE) { + if (QUEUE_IS_EMPTY(prReorderQue)) + break; + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T) QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = FALSE; + + /* SN == WinStart, so the head packet shall be indicated (advance the window) */ + if ((prReorderedSwRfb->u2SSN) == (prReorderQueParm->u2WinStart)) { + + fgDequeuHead = TRUE; + prReorderQueParm->u2WinStart = (((prReorderedSwRfb->u2SSN) + 1) % MAX_SEQ_NO_COUNT); + } + + /* SN < WinStart, so the head packet shall be indicated (do not advance the window) */ + else if (qmCompareSnIsLessThan((UINT_32) (prReorderedSwRfb->u2SSN), + (UINT_32) (prReorderQueParm->u2WinStart))) + fgDequeuHead = TRUE; + + /* SN > WinStart, break to update WinEnd */ + else + break; + + /* Dequeue the head packet */ + if (fgDequeuHead) { + + if (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext == NULL) { + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } else { + prReorderQue->prHead = ((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext; + (((P_QUE_ENTRY_T) prReorderedSwRfb)->prNext)->prPrev = NULL; + } + prReorderQue->u4NumElem--; + /* DbgPrint("QM: [%d] %d (%d)\n", */ + /* prReorderQueParm->ucTid, prReorderedSwRfb->u2PacketLen, prReorderedSwRfb->u2SSN); */ + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prReorderedSwRfb); + } + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = + (((prReorderQueParm->u2WinStart) + (prReorderQueParm->u2WinSize) - 1) % MAX_SEQ_NO_COUNT); + +} + +BOOLEAN qmCompareSnIsLessThan(IN UINT_32 u4SnLess, IN UINT_32 u4SnGreater) +{ + /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */ + if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) /* Shall be <= */ + return FALSE; + + /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */ + else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) + return TRUE; + + /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */ + /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */ + else if (u4SnLess < u4SnGreater) + return TRUE; + else + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle Mailbox RX messages +* +* \param[in] prMailboxRxMsg The received Mailbox message from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg) +{ + /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */ + /* TODO */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle ADD RX BA Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) +{ + P_EVENT_RX_ADDBA_T prEventRxAddBa; + P_STA_RECORD_T prStaRec; + UINT_32 u4Tid; + UINT_32 u4WinSize; + + DBGLOG(QM, INFO, "QM:Event +RxBa\n"); + + prEventRxAddBa = (P_EVENT_RX_ADDBA_T) prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxAddBa->ucStaRecIdx); + + if (!prStaRec) { + /* Invalid STA_REC index, discard the event packet */ + /* ASSERT(0); */ + DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"); + return; + } +#if 0 + if (!(prStaRec->fgIsValid)) { + /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ + DBGLOG(QM, WARN, "QM: (Warning) RX ADDBA Event for an invalid STA_REC\n"); + /* ASSERT(0); */ + /* return; */ + } +#endif + + u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK) + >> BA_PARAM_SET_TID_MASK_OFFSET); + + u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_BUFFER_SIZE_MASK) + >> BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET); + + if (!qmAddRxBaEntry(prAdapter, + prStaRec->ucIndex, + (UINT_8) u4Tid, + (prEventRxAddBa->u2BAStartSeqCtrl >> OFFSET_BAR_SSC_SN), (UINT_16) u4WinSize)) { + + /* FW shall ensure the availabiilty of the free-to-use BA entry */ + DBGLOG(QM, ERROR, "QM: (Error) qmAddRxBaEntry() failure\n"); + ASSERT(0); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle DEL RX BA Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) +{ + P_EVENT_RX_DELBA_T prEventRxDelBa; + P_STA_RECORD_T prStaRec; + + /* DbgPrint("QM:Event -RxBa\n"); */ + + prEventRxDelBa = (P_EVENT_RX_DELBA_T) prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventRxDelBa->ucStaRecIdx); + + if (!prStaRec) + /* Invalid STA_REC index, discard the event packet */ + /* ASSERT(0); */ + return; +#if 0 + if (!(prStaRec->fgIsValid)) + /* TODO: (Tehuang) Handle the Host-FW synchronization issue */ + /* ASSERT(0); */ + return; +#endif + + qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, TRUE); + +} + +P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIdx, UINT_8 ucTid) +{ + int i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */ + + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (prQM->arRxBaTable[i].fgIsValid) { + if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) && (prQM->arRxBaTable[i].ucTid == ucTid)) + return &prQM->arRxBaTable[i]; + } + } + return NULL; +} + +BOOLEAN +qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, + IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN UINT_16 u2WinStart, IN UINT_16 u2WinSize) +{ + int i; + P_RX_BA_ENTRY_T prRxBaEntry = NULL; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); + + if (ucStaRecIdx >= CFG_NUM_OF_STA_RECORD) { + /* Invalid STA_REC index, discard the event packet */ + DBGLOG(QM, WARN, "QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d\n", ucStaRecIdx); + return FALSE; + } + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + + /* if(!(prStaRec->fgIsValid)){ */ + /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */ + /* return FALSE; */ + /* } */ + + /* 4 <1> Delete before adding */ + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) + qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, TRUE); /* prQM->ucRxBaCount-- */ + /* 4 <2> Add a new BA entry */ + /* No available entry to store the BA agreement info. Retrun FALSE. */ + if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) { + DBGLOG(QM, ERROR, "QM: **failure** (limited resource, ucRxBaCount=%d)\n", prQM->ucRxBaCount); + return FALSE; + } + /* Find the free-to-use BA entry */ + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (!prQM->arRxBaTable[i].fgIsValid) { + prRxBaEntry = &(prQM->arRxBaTable[i]); + prQM->ucRxBaCount++; + DBGLOG(QM, LOUD, "QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); + break; + } + } + /* If a free-to-use entry is found, configure it and associate it with the STA_REC */ + u2WinSize += CFG_RX_BA_INC_SIZE; + if (prRxBaEntry) { + prRxBaEntry->ucStaRecIdx = ucStaRecIdx; + prRxBaEntry->ucTid = ucTid; + prRxBaEntry->u2WinStart = u2WinStart; + prRxBaEntry->u2WinSize = u2WinSize; + prRxBaEntry->u2WinEnd = ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT); + prRxBaEntry->fgIsValid = TRUE; + prRxBaEntry->fgIsWaitingForPktWithSsn = TRUE; + + g_arMissTimeout[ucStaRecIdx][ucTid] = 0; + + DBGLOG(QM, INFO, "QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n", + ucStaRecIdx, ucTid, + prRxBaEntry->u2WinStart, prRxBaEntry->u2WinEnd, prRxBaEntry->u2WinSize); + + /* Update the BA entry reference table for per-packet lookup */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry; + } else { + /* This shall not happen because FW should keep track of the usage of RX BA entries */ + DBGLOG(QM, ERROR, "QM: **AddBA Error** (ucRxBaCount=%d)\n", prQM->ucRxBaCount); + return FALSE; + } + return TRUE; +} + +VOID qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucStaRecIdx, IN UINT_8 ucTid, IN BOOLEAN fgFlushToHost) +{ + P_RX_BA_ENTRY_T prRxBaEntry; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prFlushedPacketList = NULL; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_NUM_OF_STA_RECORD); + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + +#if 0 + if (!(prStaRec->fgIsValid)) { + DbgPrint("QM: (WARNING) Invalid STA when deleting an RX BA\n"); + return; + } +#endif + + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid]; + + if (prRxBaEntry) { + + prFlushedPacketList = qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid); + + if (prFlushedPacketList) { + + if (fgFlushToHost) { + wlanProcessQueuedSwRfb(prAdapter, prFlushedPacketList); + } else { + + P_SW_RFB_T prSwRfb; + P_SW_RFB_T prNextSwRfb; + + prSwRfb = prFlushedPacketList; + + do { + prNextSwRfb = (P_SW_RFB_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + prSwRfb = prNextSwRfb; + } while (prSwRfb); + + } + + } +#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0)) + /* Update RX BA entry state. Note that RX queue flush is not done here */ + prRxBaEntry->fgIsValid = FALSE; + prQM->ucRxBaCount--; + + /* Debug */ +#if 0 + DbgPrint("QM: ucRxBaCount=%d\n", prQM->ucRxBaCount); +#endif + + /* Update STA RX BA table */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL; +#endif + + DBGLOG(QM, INFO, "QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, ucTid); + + } + + /* Debug */ +#if CFG_HIF_RX_STARVATION_WARNING + { + P_RX_CTRL_T prRxCtrl; + + prRxCtrl = &prAdapter->rRxCtrl; + DBGLOG(QM, TRACE, + "QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", prRxCtrl->u4QueuedCnt, + prRxCtrl->u4DequeuedCnt); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To process WMM related IEs in ASSOC_RSP +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + PUINT_8 pucIEStart; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_IE_WMM_INFO_T prIeWmmInfo; + UINT_8 ucQosInfo; + UINT_8 ucQosInfoAC; + UINT_8 ucBmpAC; + + DEBUGFUNC("mqmProcessAssocReq"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec == NULL) + return; + + prStaRec->fgIsQoS = FALSE; + prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; + + pucIEStart = pucIE; + + /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ + if (!prAdapter->rWifiVar.fgSupportQoS) + return; + + /* Determine whether QoS is enabled with the association */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) + break; /* WMM Info IE with a wrong length */ + prStaRec->fgIsQoS = TRUE; + prStaRec->fgIsWmmSupported = TRUE; + + prIeWmmInfo = (P_IE_WMM_INFO_T) pucIE; + ucQosInfo = prIeWmmInfo->ucQosInfo; + ucQosInfoAC = ucQosInfo & BITS(0, 3); + + prStaRec->fgIsUapsdSupported = ((ucQosInfoAC) ? TRUE : FALSE) & + prAdapter->rWifiVar.fgSupportUAPSD; + + ucBmpAC = 0; + + if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) + ucBmpAC |= BIT(ACI_VO); + if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) + ucBmpAC |= BIT(ACI_VI); + if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) + ucBmpAC |= BIT(ACI_BE); + if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) + ucBmpAC |= BIT(ACI_BK); + + prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = ucBmpAC; + + prStaRec->ucUapsdSp = + (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5; + break; + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ + + break; + + case ELEM_ID_HT_CAP: + /* Some client won't put the WMM IE if client is 802.11n */ + if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) + prStaRec->fgIsQoS = TRUE; + break; + default: + break; + } + } + + DBGLOG(QM, TRACE, "MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To process WMM related IEs in ASSOC_RSP +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + PUINT_8 pucIEStart; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + DEBUGFUNC("mqmProcessAssocRsp"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec == NULL) + return; + + prStaRec->fgIsQoS = FALSE; + + pucIEStart = pucIE; + + DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n", + prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.fgSupportQoS); + + /* If the device does not support QoS or if WMM is not supported by the peer, exit. */ + /* if((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported)) */ + if ((!prAdapter->rWifiVar.fgSupportQoS)) + return; + + /* Determine whether QoS is enabled with the association */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if (IE_LEN(pucIE) != 24) + break; /* WMM Info IE with a wrong length */ + prStaRec->fgIsQoS = TRUE; + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) + break; /* WMM Info IE with a wrong length */ + prStaRec->fgIsQoS = TRUE; + break; + + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS */ + break; + + case ELEM_ID_HT_CAP: + /* Some AP won't put the WMM IE if client is 802.11n */ + if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) + prStaRec->fgIsQoS = TRUE; + break; + default: + break; + } + } + + /* Parse AC parameters and write to HW CRs */ + if ((prStaRec->fgIsQoS) && (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) { + mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, u2IELength, TRUE); +#if ARP_MONITER_ENABLE + qmResetArpDetect(); +#endif + } + + DBGLOG(QM, TRACE, "MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", prStaRec->fgIsQoS); + if (prStaRec->fgIsWmmSupported) + nicQmUpdateWmmParms(prAdapter, prStaRec->ucNetTypeIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp) +* +* \param[in] prAdapter Adapter pointer +* \param[in] prSwRfb The received frame +* \param[in] pucIE The pointer to the first IE in the frame +* \param[in] u2IELength The total length of IEs in the frame +* \param[in] fgForceOverride TRUE: If EDCA parameters are found, always set to HW CRs. +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN PUINT_8 pucIE, IN UINT_16 u2IELength, IN BOOLEAN fgForceOverride) +{ + P_STA_RECORD_T prStaRec; + UINT_16 u2Offset; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + P_BSS_INFO_T prBssInfo; + P_AC_QUE_PARMS_T prAcQueParams; + P_IE_WMM_PARAM_T prIeWmmParam; + ENUM_WMM_ACI_T eAci; + PUINT_8 pucWmmParamSetCount; + + DEBUGFUNC("mqmParseEdcaParameters"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + if (prStaRec == NULL) + return; + + DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n", prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS); + + if ((!prAdapter->rWifiVar.fgSupportQoS) || (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)) + return; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + /* Goal: Obtain the EDCA parameters */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + if ((WMM_IE_OUI_TYPE(pucIE) != VENDOR_OUI_TYPE_WMM) || + (kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) + break; + + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if (IE_LEN(pucIE) != 24) + break; /* WMM Param IE with a wrong length */ + + pucWmmParamSetCount = &(prBssInfo->ucWmmParamSetCount); + prIeWmmParam = (P_IE_WMM_PARAM_T) pucIE; + + /* Check the Parameter Set Count to determine whether EDCA parameters */ + /* have been changed */ + if (!fgForceOverride && (*pucWmmParamSetCount + == (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT))) + break; /* Ignore the IE without updating HW CRs */ + + /* Update Parameter Set Count */ + *pucWmmParamSetCount = + (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT); + + /* Update EDCA parameters */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + prAcQueParams = &prBssInfo->arACQueParms[eAci]; + mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams); + + prAcQueParams->fgIsACMSet = + (prAcQueParams->u2Aifsn & WMM_ACIAIFSN_ACM) ? TRUE : FALSE; + prAcQueParams->u2Aifsn &= WMM_ACIAIFSN_AIFSN; + + DBGLOG(QM, LOUD, + "eAci:%d, ACM:%d, Aifsn:%d, CWmin:%d, CWmax:%d, TxopLmt:%d\n", + eAci, prAcQueParams->fgIsACMSet, prAcQueParams->u2Aifsn, + prAcQueParams->u2CWmin, prAcQueParams->u2CWmax, + prAcQueParams->u2TxopLimit); + } + break; + default: + /* Other WMM QoS IEs. Ignore */ + break; + } + + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ + break; + default: + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used for parsing EDCA parameters specified in the WMM Parameter IE +* +* \param[in] prAdapter Adapter pointer +* \param[in] prIeWmmParam The pointer to the WMM Parameter IE +* \param[in] u4AcOffset The offset specifying the AC queue for parsing +* \param[in] prHwAcParams The parameter structure used to configure the HW CRs +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN UINT_32 u4AcOffset, OUT P_AC_QUE_PARMS_T prAcQueParams) +{ + prAcQueParams->u2Aifsn = *((PUINT_8) (&(prIeWmmParam->ucAciAifsn_BE)) + (u4AcOffset * 4)); + + prAcQueParams->u2CWmax = BIT(((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMAX_MASK) + >> WMM_ECW_WMAX_OFFSET) - 1; + + prAcQueParams->u2CWmin = + BIT((*((PUINT_8) (&(prIeWmmParam->ucEcw_BE)) + (u4AcOffset * 4))) & WMM_ECW_WMIN_MASK) - 1; + + WLAN_GET_FIELD_16(((PUINT_8) (&(prIeWmmParam->aucTxopLimit_BE)) + (u4AcOffset * 4)), + &(prAcQueParams->u2TxopLimit)); + + prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To parse WMM/11n related IEs in scan results (only for AP peers) +* +* \param[in] prAdapter Adapter pointer +* \param[in] prScanResult The scan result which shall be parsed to obtain needed info +* \param[out] prStaRec The obtained info is stored in the STA_REC +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +#if (CFG_SUPPORT_TDLS == 1) /* for test purpose */ +BOOLEAN flgTdlsTestExtCapElm = FALSE; +UINT8 aucTdlsTestExtCapElm[7]; +#endif /* CFG_SUPPORT_TDLS */ +VOID mqmProcessScanResult(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prScanResult, OUT P_STA_RECORD_T prStaRec) +{ + PUINT_8 pucIE; + UINT_16 u2IELength; + UINT_16 u2Offset; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + DEBUGFUNC("mqmProcessScanResult"); + + ASSERT(prScanResult); + ASSERT(prStaRec); + + /* Reset the flag before parsing */ + prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = FALSE; + + if (!prAdapter->rWifiVar.fgSupportQoS) + return; + + u2IELength = prScanResult->u2IELength; + pucIE = prScanResult->aucIEBuf; + +#if (CFG_SUPPORT_TDLS == 1) + /* TDLS test purpose */ + if (flgTdlsTestExtCapElm == TRUE) + TdlsexBssExtCapParse(prStaRec, aucTdlsTestExtCapElm); +#endif /* CFG_SUPPORT_TDLS */ + + /* Goal: Determine whether the peer supports WMM/QoS and UAPSDU */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_EXTENDED_CAP: +#if (CFG_SUPPORT_TDLS == 1) + TdlsexBssExtCapParse(prStaRec, pucIE); +#endif /* CFG_SUPPORT_TDLS */ + break; + + case ELEM_ID_WMM: + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if (IE_LEN(pucIE) != 24) + break; /* WMM Param IE with a wrong length */ + + prStaRec->fgIsWmmSupported = TRUE; + prStaRec->fgIsUapsdSupported = + (((((P_IE_WMM_PARAM_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? + TRUE : FALSE); + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) + break; /* WMM Info IE with a wrong length */ + + prStaRec->fgIsWmmSupported = TRUE; + prStaRec->fgIsUapsdSupported = + (((((P_IE_WMM_INFO_T) pucIE)->ucQosInfo) & WMM_QOS_INFO_UAPSD) ? + TRUE : FALSE); + break; + + default: + /* A WMM QoS IE that doesn't matter. Ignore it. */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... (not cared) */ + + break; + + default: + /* A WMM IE that doesn't matter. Ignore it. */ + break; + } + } + DBGLOG(QM, LOUD, "MQM: Scan Result Parsing (WMM=%d, UAPSD=%d)\n", + prStaRec->fgIsWmmSupported, prStaRec->fgIsUapsdSupported); + +} + +UINT_8 qmGetStaRecIdx(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucEthDestAddr, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType) +{ + UINT_32 i; + P_STA_RECORD_T prTempStaRec; + + prTempStaRec = NULL; + + ASSERT(prAdapter); + + /* 4 <1> DA = BMCAST */ + if (IS_BMCAST_MAC_ADDR(pucEthDestAddr)) + return STA_REC_INDEX_BMCAST; + /* 4 <2> Check if an AP STA is present */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { + prTempStaRec = &(prAdapter->arStaRec[i]); + if ((prTempStaRec->ucNetTypeIndex == eNetworkType) + && (prTempStaRec->fgIsAp) + && (prTempStaRec->fgIsValid)) { + return prTempStaRec->ucIndex; + } + } + + /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is a unicast frame to a client) */ + for (i = 0; i < CFG_NUM_OF_STA_RECORD; i++) { + prTempStaRec = &(prAdapter->arStaRec[i]); + if (prTempStaRec->fgIsValid) { + if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucEthDestAddr)) + return prTempStaRec->ucIndex; + } + } + + /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ + return STA_REC_INDEX_NOT_FOUND; +} + +UINT_32 +mqmGenerateWmmInfoIEByParam(BOOLEAN fgSupportUAPSD, + UINT_8 ucBmpDeliveryAC, UINT_8 ucBmpTriggerAC, UINT_8 ucUapsdSp, UINT_8 *pOutBuf) +{ + P_IE_WMM_INFO_T prIeWmmInfo; + UINT_32 ucUapsd[] = { + WMM_QOS_INFO_BE_UAPSD, + WMM_QOS_INFO_BK_UAPSD, + WMM_QOS_INFO_VI_UAPSD, + WMM_QOS_INFO_VO_UAPSD + }; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + ASSERT(pOutBuf); + + prIeWmmInfo = (P_IE_WMM_INFO_T) pOutBuf; + + prIeWmmInfo->ucId = ELEM_ID_WMM; + prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmInfo->aucOui[0] = aucWfaOui[0]; + prIeWmmInfo->aucOui[1] = aucWfaOui[1]; + prIeWmmInfo->aucOui[2] = aucWfaOui[2]; + prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; + + prIeWmmInfo->ucVersion = VERSION_WMM; + prIeWmmInfo->ucQosInfo = 0; + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (fgSupportUAPSD) { + + UINT_8 ucQosInfo = 0; + UINT_8 i; + + /* Static U-APSD setting */ + for (i = ACI_BE; i <= ACI_VO; i++) { + if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) + ucQosInfo |= (UINT_8) ucUapsd[i]; + } + + if (ucBmpDeliveryAC & ucBmpTriggerAC) { + switch (ucUapsdSp) { + case WMM_MAX_SP_LENGTH_ALL: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; + break; + + case WMM_MAX_SP_LENGTH_2: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + + case WMM_MAX_SP_LENGTH_4: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; + break; + + case WMM_MAX_SP_LENGTH_6: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; + break; + + default: + DBGLOG(QM, WARN, "MQM: Incorrect SP length\n"); + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + } + } + prIeWmmInfo->ucQosInfo = ucQosInfo; + + } + + /* Increment the total IE length for the Element ID and Length fields. */ + return IE_SIZE(prIeWmmInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Generate the WMM Info IE +* +* \param[in] prAdapter Adapter pointer +* @param prMsduInfo The TX MMPDU +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_IE_WMM_INFO_T prIeWmmInfo; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("mqmGenerateWmmInfoIE"); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if (!prAdapter->rWifiVar.fgSupportQoS) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (prStaRec == NULL) + return; + + if (!prStaRec->fgIsWmmSupported) + return; + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prStaRec->ucNetTypeIndex]); + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + prIeWmmInfo = (P_IE_WMM_INFO_T) + ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); + +#if 0 + prIeWmmInfo->ucId = ELEM_ID_WMM; + prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmInfo->aucOui[0] = aucWfaOui[0]; + prIeWmmInfo->aucOui[1] = aucWfaOui[1]; + prIeWmmInfo->aucOui[2] = aucWfaOui[2]; + prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; + + prIeWmmInfo->ucVersion = VERSION_WMM; + prIeWmmInfo->ucQosInfo = 0; + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ +/* if(prAdapter->rWifiVar.fgSupportUAPSD){ */ + if (prAdapter->rWifiVar.fgSupportUAPSD && prStaRec->fgIsUapsdSupported) { + + UINT_8 ucQosInfo = 0; + UINT_8 i; + + /* Static U-APSD setting */ + for (i = ACI_BE; i <= ACI_VO; i++) { + if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC & BIT(i)) + ucQosInfo |= (UINT_8) ucUapsd[i]; + } + + if (prPmProfSetupInfo->ucBmpDeliveryAC & prPmProfSetupInfo->ucBmpTriggerAC) { + switch (prPmProfSetupInfo->ucUapsdSp) { + case WMM_MAX_SP_LENGTH_ALL: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; + break; + + case WMM_MAX_SP_LENGTH_2: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + + case WMM_MAX_SP_LENGTH_4: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; + break; + + case WMM_MAX_SP_LENGTH_6: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; + break; + + default: + DBGLOG(QM, INFO, "MQM: Incorrect SP length\n"); + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + } + } + prIeWmmInfo->ucQosInfo = ucQosInfo; + + } + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmInfo); +#else + + prMsduInfo->u2FrameLength += mqmGenerateWmmInfoIEByParam((prAdapter->rWifiVar.fgSupportUAPSD + && prStaRec->fgIsUapsdSupported), + prPmProfSetupInfo->ucBmpDeliveryAC, + prPmProfSetupInfo->ucBmpTriggerAC, + prPmProfSetupInfo->ucUapsdSp, (UINT_8 *) prIeWmmInfo); +#endif +} + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* @brief log2 calculation for CW +* +* @param[in] val value +* +* @return log2(val) +*/ +/*----------------------------------------------------------------------------*/ + +UINT_32 cwlog2(UINT_32 val) +{ + + UINT_32 n; + + n = 0; + + while (val >= 512) { + n += 9; + val = val >> 9; + } + while (val >= 16) { + n += 4; + val >>= 4; + } + while (val >= 2) { + n += 1; + val >>= 1; + } + return n; +} +#endif + +UINT_32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, UINT_8 *pOutBuf, ENUM_OP_MODE_T ucOpMode) +{ + P_IE_WMM_PARAM_T prIeWmmParam; + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + UINT_8 aucACI[] = { + WMM_ACI_AC_BE, + WMM_ACI_AC_BK, + WMM_ACI_AC_VI, + WMM_ACI_AC_VO + }; + ENUM_WMM_ACI_T eAci; + UCHAR *pucAciAifsn, *pucEcw, *pucTxopLimit; + + ASSERT(pOutBuf); + + prIeWmmParam = (P_IE_WMM_PARAM_T) pOutBuf; + + prIeWmmParam->ucId = ELEM_ID_WMM; + prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmParam->aucOui[0] = aucWfaOui[0]; + prIeWmmParam->aucOui[1] = aucWfaOui[1]; + prIeWmmParam->aucOui[2] = aucWfaOui[2]; + prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; + + prIeWmmParam->ucVersion = VERSION_WMM; + prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (prAdapter->rWifiVar.fgSupportUAPSD) { + if (ucOpMode == OP_MODE_INFRASTRUCTURE) + prIeWmmParam->ucQosInfo = 0xf; + else + prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; + } + + /* EDCA parameter */ + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + /* DBGLOG(QM, LOUD, */ + /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ + /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ + +#if 0 + *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] + | + (prBssInfo->arACQueParmsForBcast + [eAci].fgIsACMSet ? + WMM_ACIAIFSN_ACM : 0) + | + (prBssInfo->arACQueParmsForBcast + [eAci].u2Aifsn & + (WMM_ACIAIFSN_AIFSN))); +#else + /* avoid compile warnings in Klockwork tool */ + if (eAci == WMM_AC_BE_INDEX) { + pucAciAifsn = &prIeWmmParam->ucAciAifsn_BE; + pucEcw = &prIeWmmParam->ucEcw_BE; + pucTxopLimit = prIeWmmParam->aucTxopLimit_BE; + } else if (eAci == WMM_AC_BK_INDEX) { + pucAciAifsn = &prIeWmmParam->ucAciAifsn_BG; + pucEcw = &prIeWmmParam->ucEcw_BG; + pucTxopLimit = prIeWmmParam->aucTxopLimit_BG; + } else if (eAci == WMM_AC_VI_INDEX) { + pucAciAifsn = &prIeWmmParam->ucAciAifsn_VI; + pucEcw = &prIeWmmParam->ucEcw_VI; + pucTxopLimit = prIeWmmParam->aucTxopLimit_VI; + } else if (eAci == WMM_AC_VO_INDEX) { + pucAciAifsn = &prIeWmmParam->ucAciAifsn_VO; + pucEcw = &prIeWmmParam->ucEcw_VO; + pucTxopLimit = prIeWmmParam->aucTxopLimit_VO; + } + + *pucAciAifsn = (UINT_8) (aucACI[eAci] + | (prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet ? WMM_ACIAIFSN_ACM : 0) + | (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & (WMM_ACIAIFSN_AIFSN))); +#endif + +#if 1 +/* *( ((PUINT_8)(&prIeWmmParam->ucEcw_BE)) + (eAci <<2) ) = (UINT_8) (0 */ + *pucEcw = (UINT_8) (0 | (((prBssInfo->aucCWminLog2ForBcast[eAci])) & WMM_ECW_WMIN_MASK) + | ((((prBssInfo->aucCWmaxLog2ForBcast[eAci])) << WMM_ECW_WMAX_OFFSET) & + WMM_ECW_WMAX_MASK) + ); +#else + *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 + | + (cwlog2 + ((prBssInfo->arACQueParmsForBcast + [eAci].u2CWmin + + 1)) & WMM_ECW_WMIN_MASK) + | + ((cwlog2 + ((prBssInfo->arACQueParmsForBcast + [eAci].u2CWmax + + 1)) << WMM_ECW_WMAX_OFFSET) & + WMM_ECW_WMAX_MASK) + ); +#endif + +#if 0 + WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) + , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); +#else + WLAN_SET_FIELD_16(pucTxopLimit, prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); +#endif + } + + /* Increment the total IE length for the Element ID and Length fields. */ + return IE_SIZE(prIeWmmParam); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Generate the WMM Param IE +* +* \param[in] prAdapter Adapter pointer +* @param prMsduInfo The TX MMPDU +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_IE_WMM_PARAM_T prIeWmmParam; + +#if 0 + UINT_8 aucWfaOui[] = VENDOR_OUI_WFA; + + UINT_8 aucACI[] = { + WMM_ACI_AC_BE, + WMM_ACI_AC_BK, + WMM_ACI_AC_VI, + WMM_ACI_AC_VO + }; + ENUM_WMM_ACI_T eAci; +#endif + + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("mqmGenerateWmmParamIE"); + DBGLOG(QM, LOUD, "\n"); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if (!prAdapter->rWifiVar.fgSupportQoS) + return; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec) { + if (!prStaRec->fgIsQoS) + return; + } + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prMsduInfo->ucNetworkType]); + + if (!prBssInfo->fgIsQBSS) + return; +/* 20120220 frog: update beacon content & change OP mode is a separate event for P2P network. */ +#if 0 + if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT && prBssInfo->eCurrentOPMode != OP_MODE_BOW) + return; +#endif + + prIeWmmParam = (P_IE_WMM_PARAM_T) + ((PUINT_8) prMsduInfo->prPacket + prMsduInfo->u2FrameLength); + +#if 0 + prIeWmmParam->ucId = ELEM_ID_WMM; + prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmParam->aucOui[0] = aucWfaOui[0]; + prIeWmmParam->aucOui[1] = aucWfaOui[1]; + prIeWmmParam->aucOui[2] = aucWfaOui[2]; + prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; + + prIeWmmParam->ucVersion = VERSION_WMM; + prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (prAdapter->rWifiVar.fgSupportUAPSD) + prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; + + /* EDCA parameter */ + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + + /* DBGLOG(QM, LOUD, */ + /* ("MQM: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", */ + /* eAci,prBssInfo->arACQueParmsForBcast[eAci].fgIsACMSet , */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ + + *(((PUINT_8) (&prIeWmmParam->ucAciAifsn_BE)) + (eAci << 2)) = (UINT_8) (aucACI[eAci] + | + (prBssInfo->arACQueParmsForBcast + [eAci].fgIsACMSet ? + WMM_ACIAIFSN_ACM : 0) + | + (prBssInfo->arACQueParmsForBcast + [eAci].u2Aifsn & + (WMM_ACIAIFSN_AIFSN))); +#if 1 + *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 + | + (((prBssInfo->aucCWminLog2ForBcast + [eAci])) & WMM_ECW_WMIN_MASK) + | + ((((prBssInfo->aucCWmaxLog2ForBcast + [eAci])) << WMM_ECW_WMAX_OFFSET) + & WMM_ECW_WMAX_MASK) + ); +#else + *(((PUINT_8) (&prIeWmmParam->ucEcw_BE)) + (eAci << 2)) = (UINT_8) (0 + | + (cwlog2 + ((prBssInfo->arACQueParmsForBcast + [eAci].u2CWmin + + 1)) & WMM_ECW_WMIN_MASK) + | + ((cwlog2 + ((prBssInfo->arACQueParmsForBcast + [eAci].u2CWmax + + 1)) << WMM_ECW_WMAX_OFFSET) & + WMM_ECW_WMAX_MASK) + ); +#endif + + WLAN_SET_FIELD_16(((PUINT_8) (prIeWmmParam->aucTxopLimit_BE)) + (eAci << 2) + , prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); + + } + + /* Increment the total IE length for the Element ID and Length fields. */ + prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam); +#else + + prMsduInfo->u2FrameLength += mqmGenerateWmmParamIEByParam(prAdapter, + prBssInfo, (UINT_8 *) prIeWmmParam, OP_MODE_ACCESS_POINT); +#endif +} + +ENUM_FRAME_ACTION_T +qmGetFrameAction(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_INDEX_T eNetworkType, + IN UINT_8 ucStaRecIdx, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + P_WLAN_MAC_HEADER_T prWlanFrame; + UINT_16 u2TxFrameCtrl; + + DEBUGFUNC("qmGetFrameAction"); + +#if (NIC_TX_BUFF_COUNT_TC4 > 2) +#define QM_MGMT_QUUEUD_THRESHOLD 2 +#else +#define QM_MGMT_QUUEUD_THRESHOLD 1 +#endif + + DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD <= (NIC_TX_BUFF_COUNT_TC4)); + DATA_STRUCT_INSPECTING_ASSERT(QM_MGMT_QUUEUD_THRESHOLD > 0); + + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[eNetworkType]); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx); + + /* XXX Check BOW P2P AIS time ot set active */ + if (!IS_BSS_ACTIVE(prBssInfo)) { + if (eFrameType == FRAME_TYPE_MMPDU) { + prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; + u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ + if (((u2TxFrameCtrl == MAC_FRAME_DEAUTH) + && (prMsduInfo->pfTxDoneHandler == NULL)) + || (u2TxFrameCtrl == MAC_FRAME_ACTION)) /* whsu */ + return FRAME_ACTION_TX_PKT; + } + + DBGLOG(QM, WARN, "Drop packets Action, eFrameType: %d (Bss Index %u).\n", + eFrameType, prBssInfo->ucNetTypeIndex); + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); + return FRAME_ACTION_DROP_PKT; + } + + /* TODO Handle disconnect issue */ + + /* P2P probe Request frame */ + do { + if (eFrameType == FRAME_TYPE_MMPDU) { + prWlanFrame = (P_WLAN_MAC_HEADER_T) prMsduInfo->prPacket; + u2TxFrameCtrl = (prWlanFrame->u2FrameCtrl) & MASK_FRAME_TYPE; /* Optimized for ARM */ + + if (u2TxFrameCtrl == MAC_FRAME_BEACON) { + if (prBssInfo->fgIsNetAbsent) + return FRAME_ACTION_DROP_PKT; + } else if (u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { + if (prBssInfo->fgIsNetAbsent) + return FRAME_ACTION_DROP_PKT; + } else if (u2TxFrameCtrl == MAC_FRAME_DEAUTH) { + if (prBssInfo->fgIsNetAbsent) + break; + DBGLOG(P2P, LOUD, "Sending DEAUTH Frame\n"); + return FRAME_ACTION_TX_PKT; + } + /* MMPDU with prStaRec && fgIsInUse not check fgIsNetActive */ + else if (u2TxFrameCtrl == MAC_FRAME_ASSOC_REQ + || u2TxFrameCtrl == MAC_FRAME_AUTH + || u2TxFrameCtrl == MAC_FRAME_REASSOC_REQ + || u2TxFrameCtrl == MAC_FRAME_PROBE_REQ || u2TxFrameCtrl == MAC_FRAME_ACTION) { + + if ((prStaRec) && (prStaRec->fgIsInPS)) { + if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) + return FRAME_ACTION_TX_PKT; + else + return FRAME_ACTION_QUEUE_PKT; + } + return FRAME_ACTION_TX_PKT; + } + + if (!prStaRec) + return FRAME_ACTION_TX_PKT; + + if (!prStaRec->fgIsInUse) + return FRAME_ACTION_DROP_PKT; + + } /* FRAME_TYPE_MMPDU */ + else if (eFrameType == FRAME_TYPE_802_1X) { + + if (!prStaRec) + return FRAME_ACTION_TX_PKT; + + if (!prStaRec->fgIsInUse) + return FRAME_ACTION_DROP_PKT; + if (prStaRec->fgIsInPS) { + if (nicTxGetResource(prAdapter, TC4_INDEX) >= QM_MGMT_QUUEUD_THRESHOLD) + return FRAME_ACTION_TX_PKT; + else + return FRAME_ACTION_QUEUE_PKT; + } + + } /* FRAME_TYPE_802_1X */ + else if ((!IS_BSS_ACTIVE(prBssInfo)) + || (!prStaRec) + || (!prStaRec->fgIsInUse)) { + return FRAME_ACTION_DROP_PKT; + } + } while (0); + + if (prBssInfo->fgIsNetAbsent) { + DBGLOG(QM, LOUD, "Queue packets (Absent %u).\n", prBssInfo->ucNetTypeIndex); + return FRAME_ACTION_QUEUE_PKT; + } + + if (prStaRec && prStaRec->fgIsInPS) { + DBGLOG(QM, LOUD, "Queue packets (PS %u).\n", prStaRec->fgIsInPS); + return FRAME_ACTION_QUEUE_PKT; + } + switch (eFrameType) { + case FRAME_TYPE_802_1X: + if (!prStaRec->fgIsValid) + return FRAME_ACTION_QUEUE_PKT; + break; + + case FRAME_TYPE_MMPDU: + break; + + default: + ASSERT(0); + } + + return FRAME_ACTION_TX_PKT; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle BSS change operation Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) +{ + P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus; + P_BSS_INFO_T prBssInfo; + BOOLEAN fgIsNetAbsentOld; + + prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T) prEvent; + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[prEventBssStatus->ucNetTypeIdx]); + fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent; + prBssInfo->fgIsNetAbsent = prEventBssStatus->fgIsAbsent; + prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota; + + /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, fgIsAbsent=%d, FreeQuota=%d)\n", */ + /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota)); */ + + DBGLOG(QM, INFO, "NAF=%d,%d,%d\n", + prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, prBssInfo->ucBssFreeQuota); + + if (!prBssInfo->fgIsNetAbsent) { + /* QM_DBG_CNT_27 */ + QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27); + } else { + /* QM_DBG_CNT_28 */ + QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28); + } + /* From Absent to Present */ + if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) + kalSetEvent(prAdapter->prGlueInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Handle STA change PS mode Event from the FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) +{ + P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode; + P_STA_RECORD_T prStaRec; + BOOLEAN fgIsInPSOld; + + /* DbgPrint("QM:Event -RxBa\n"); */ + + prEventStaChangePsMode = (P_EVENT_STA_CHANGE_PS_MODE_T) prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaChangePsMode->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec) { + + fgIsInPSOld = prStaRec->fgIsInPS; + prStaRec->fgIsInPS = prEventStaChangePsMode->fgIsInPs; + + qmUpdateFreeQuota(prAdapter, + prStaRec, + prEventStaChangePsMode->ucUpdateMode, prEventStaChangePsMode->ucFreeQuota, 0); + + /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode (ucStaRecIdx=%d, fgIsInPs=%d)\n", */ + /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */ + + DBGLOG(QM, TRACE, "PS=%d,%d\n", prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS); + + /* From PS to Awake */ + if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) + kalSetEvent(prAdapter->prGlueInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update STA free quota Event from FW +* +* \param[in] prAdapter Adapter pointer +* \param[in] prEvent The event packet from the FW +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) +{ + P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota; + P_STA_RECORD_T prStaRec; + + prEventStaUpdateFreeQuota = (P_EVENT_STA_UPDATE_FREE_QUOTA_T) prEvent; + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec) { + if (prStaRec->fgIsInPS) { + qmUpdateFreeQuota(prAdapter, + prStaRec, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota, + prEventStaUpdateFreeQuota->aucReserved[0]); + + kalSetEvent(prAdapter->prGlueInfo); + } +#if 0 + DBGLOG(QM, TRACE, + "qmHandleEventStaUpdateFreeQuota (ucStaRecIdx=%d, ucUpdateMode=%d, ucFreeQuota=%d)\n", + prEventStaUpdateFreeQuota->ucStaRecIdx, prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota); +#endif + + DBGLOG(QM, TRACE, "UFQ=%d,%d,%d\n", + prEventStaUpdateFreeQuota->ucStaRecIdx, + prEventStaUpdateFreeQuota->ucUpdateMode, prEventStaUpdateFreeQuota->ucFreeQuota); + + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Update STA free quota +* +* \param[in] prStaRec the STA +* \param[in] ucUpdateMode the method to update free quota +* \param[in] ucFreeQuota the value for update +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN UINT_8 ucUpdateMode, IN UINT_8 ucFreeQuota, IN UINT_8 ucNumOfTxDone) +{ + + UINT_8 ucFreeQuotaForNonDelivery; + UINT_8 ucFreeQuotaForDelivery; + BOOLEAN flgIsUpdateForcedToDelivery; + + ASSERT(prStaRec); + DBGLOG(QM, LOUD, "qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n", + prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota); + + if (!prStaRec->fgIsInPS) + return; + + flgIsUpdateForcedToDelivery = FALSE; + + if (ucNumOfTxDone > 0) { + /* + update free quota by + num of tx done + resident free quota (delivery + non-delivery) + */ + UINT_8 ucAvailQuota; + + ucAvailQuota = ucNumOfTxDone + prStaRec->ucFreeQuotaForDelivery + prStaRec->ucFreeQuotaForNonDelivery; + if (ucAvailQuota > ucFreeQuota) /* sanity check */ + ucAvailQuota = ucFreeQuota; + + /* update current free quota */ + ucFreeQuota = ucAvailQuota; + + /* check if the update is from last packet */ + if (ucFreeQuota == (prStaRec->ucFreeQuota + 1)) { + /* just add the extra quota to delivery queue */ + + /* + EX: + 1. TDLS peer enters power save + 2. When the last 2 VI packets are tx done, we will receive 2 update events + 3. 1st update event: ucFreeQuota = 9 + 4. We will correct new quota for delivey and non-delivery to 7:2 + 5. 2rd update event: ucFreeQuota = 10 + 6. We will re-correct new quota for delivery and non-delivery to 5:5 + + But non-delivery queue is not busy. + So in the case, we will have wrong decision, i.e. higher queue always quota 5 + + Solution: skip the 2rd update event and just add the extra quota to delivery. + */ + + flgIsUpdateForcedToDelivery = TRUE; + } + } + + switch (ucUpdateMode) { + case FREE_QUOTA_UPDATE_MODE_INIT: + case FREE_QUOTA_UPDATE_MODE_OVERWRITE: + prStaRec->ucFreeQuota = ucFreeQuota; + break; + case FREE_QUOTA_UPDATE_MODE_INCREASE: + prStaRec->ucFreeQuota += ucFreeQuota; + break; + case FREE_QUOTA_UPDATE_MODE_DECREASE: + prStaRec->ucFreeQuota -= ucFreeQuota; + break; + default: + ASSERT(0); + } + + DBGLOG(QM, LOUD, "qmUpdateFreeQuota new ucFreeQuota=%d)\n", prStaRec->ucFreeQuota); + + ucFreeQuota = prStaRec->ucFreeQuota; + + ucFreeQuotaForNonDelivery = 0; + ucFreeQuotaForDelivery = 0; + + if (ucFreeQuota > 0) { + if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS + && prAdapter->rWifiVar.fgSupportUAPSD */) { + /* XXX We should assign quota to aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */ + + if (flgIsUpdateForcedToDelivery == FALSE) { + if (prStaRec->ucFreeQuotaForNonDelivery > 0 && prStaRec->ucFreeQuotaForDelivery > 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } else if (prStaRec->ucFreeQuotaForNonDelivery == 0 + && prStaRec->ucFreeQuotaForDelivery == 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) { + /* NonDelivery is not busy */ + if (ucFreeQuota >= 3) { + ucFreeQuotaForNonDelivery = 2; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } else { + ucFreeQuotaForDelivery = ucFreeQuota; + ucFreeQuotaForNonDelivery = 0; + } + } else if (prStaRec->ucFreeQuotaForDelivery > 0) { + /* Delivery is not busy */ + if (ucFreeQuota >= 3) { + ucFreeQuotaForDelivery = 2; + ucFreeQuotaForNonDelivery = ucFreeQuota - ucFreeQuotaForDelivery; + } else { + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } + } else { + ucFreeQuotaForNonDelivery = 2; + ucFreeQuotaForDelivery = ucFreeQuota - ucFreeQuotaForNonDelivery; + } + } else { + /* no use ? */ + /* !prStaRec->fgIsUapsdSupported */ + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } + /* ucFreeQuota > 0 */ + prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery; + prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery; + +#if (CFG_SUPPORT_TDLS_DBG == 1) + if (IS_TDLS_STA(prStaRec)) + DBGLOG(QM, LOUD, " quota %d %d %d\n", + ucFreeQuota, ucFreeQuotaForDelivery, ucFreeQuotaForNonDelivery); +#endif + + DBGLOG(QM, LOUD, "new QuotaForDelivery = %d QuotaForNonDelivery = %d\n", + prStaRec->ucFreeQuotaForDelivery, prStaRec->ucFreeQuotaForNonDelivery); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Return the reorder queued RX packets +* +* \param[in] (none) +* +* \return The number of queued RX packets +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter) +{ + UINT_32 i, u4Total; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + u4Total = 0; + /* XXX The summation may impact the performance */ + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem; +#if DBG && 0 + if (QUEUE_IS_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) + ASSERT(prQM->arRxBaTable[i].rReOrderQue == 0); +#endif + } + ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2)); + return u4Total; +} + +#if ARP_MONITER_ENABLE +VOID qmDetectArpNoResponse(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + struct sk_buff *prSkb = NULL; + PUINT_8 pucData = NULL; + UINT_16 u2EtherType = 0; + int arpOpCode = 0; + + prSkb = (struct sk_buff *)prMsduInfo->prPacket; + + if (!prSkb || (prSkb->len <= ETHER_HEADER_LEN)) + return; + + pucData = prSkb->data; + if (!pucData) + return; + u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); + + if (u2EtherType != ETH_P_ARP || (apIp[0] | apIp[1] | apIp[2] | apIp[3]) == 0) + return; + + if (strncmp(apIp, &pucData[ETH_TYPE_LEN_OFFSET + 26], sizeof(apIp))) /* dest ip address */ + return; + + arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); + if (arpOpCode == ARP_PRO_REQ) { + arpMoniter++; + if (arpMoniter > 20) { + DBGLOG(INIT, WARN, "IOT Critical issue, arp no resp, check AP!\n"); + aisBssBeaconTimeout(prAdapter); + arpMoniter = 0; + kalMemZero(apIp, sizeof(apIp)); + } + } +} + +VOID qmHandleRxArpPackets(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + PUINT_8 pucData = NULL; + UINT_16 u2EtherType = 0; + int arpOpCode = 0; + P_BSS_INFO_T prBssInfo = NULL; + + if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN) + return; + + pucData = (PUINT_8)prSwRfb->pvHeader; + if (!pucData) + return; + u2EtherType = (pucData[ETH_TYPE_LEN_OFFSET] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 1]); + + if (u2EtherType != ETH_P_ARP) + return; + + arpOpCode = (pucData[ETH_TYPE_LEN_OFFSET + 8] << 8) | (pucData[ETH_TYPE_LEN_OFFSET + 8 + 1]); + prBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX]); + if (arpOpCode == ARP_PRO_RSP) { + arpMoniter = 0; + if (prBssInfo && prBssInfo->prStaRecOfAP && prBssInfo->prStaRecOfAP->aucMacAddr) { + if (EQUAL_MAC_ADDR(&(pucData[ETH_TYPE_LEN_OFFSET + 10]), /* source hardware address */ + prBssInfo->prStaRecOfAP->aucMacAddr)) { + strncpy(apIp, &(pucData[ETH_TYPE_LEN_OFFSET + 16]), sizeof(apIp)); /* src ip address */ + DBGLOG(INIT, TRACE, "get arp response from AP %d.%d.%d.%d\n", + apIp[0], apIp[1], apIp[2], apIp[3]); + } + } + } +} + +VOID qmResetArpDetect(VOID) +{ + arpMoniter = 0; + kalMemZero(apIp, sizeof(apIp)); +} +#endif + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c new file mode 100644 index 0000000000000..6f5c0bcdd90bb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_bow.c @@ -0,0 +1,1177 @@ +/* +** Id: @(#) gl_bow.c@@ +*/ + +/*! \file gl_bow.c + \brief Main routines of Linux driver interface for 802.11 PAL (BT 3.0 + HS) + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_bow.c + * + * 02 16 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * [ALPS00235223] [Rose][ICS][Cross Feature][AEE-IPANIC]The device reboot automatically and then the "KE" pops up + * after you turn on the "Airplane mode".(once) + * + * [Root Cause] + * PAL operates BOW char dev poll after BOW char dev is registered. + * + * [Solution] + * Rejects PAL char device operation after BOW is unregistered or when wlan GLUE_FLAG_HALT is set. + * + * This is a workaround for BOW driver robustness, happens only in ICS. + * + * Root cause should be fixed by CR [ALPS00231570] + * + * 02 03 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * [ALPS00118114] [Rose][ICS][Free Test][Bluetooth]The "KE" pops up after you turn on the airplane mode.(5/5) + * + * [Root Cause] + * PAL operates BOW char dev poll after BOW char dev is registered. + * + * [Solution] + * Rejects PAL char device operation after BOW is unregistered. + * + * Happens only in ICS. + * + * Notified PAL owener to reivew MTKBT/PAL closing BOW char dev procedure. + * + * [Side Effect] + * None. + * + * 01 16 2012 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support BOW for 5GHz band. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 25 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Modify ampc0 char device for major number 151 for all MT6575 projects. + * + * 07 28 2011 cp.wu + * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl + * unlocked_ioctl returns as long instead of int. + * + * 07 28 2011 cp.wu + * [WCXRP00000884] [MT6620 Wi-Fi][Driver] Deprecate ioctl interface by unlocked ioctl + * migrate to unlocked ioctl interface + * + * 04 12 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add WMM IE for BOW initiator data. + * + * 04 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link disconnection event procedure for hotspot and change skb length check to 1514 bytes. + * + * 04 09 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Change Link connection event procedure and change skb length check to 1512 bytes. + * + * 03 27 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Support multiple physical link. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * replace alloc_netdev to alloc_netdev_mq for BoW + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 02 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Update net register and BOW for concurrent features. + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 cp.wu + * [WCXRP00000430] [MT6620 Wi-Fi][Firmware][Driver] Create V1.2 branch for MT6620E1 and MT6620E3 + * create V1.2 driver branch based on label MT6620_WIFI_DRIVER_V1_2_110209_1031 + * with BOW and P2P enabled as default + * + * 02 08 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Replace kfifo_get and kfifo_put with kfifo_out and kfifo_in. + * Update BOW get MAC status, remove returning event for AIS network type. + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation + * needs such information + * fill mac header length information for 802.1x frames. + * + * 11 11 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix BoW timer assert issue. + * + * 09 14 2010 chinghwa.yu + * NULL + * Add bowRunEventAAAComplete. + * + * 09 14 2010 cp.wu + * NULL + * correct typo: POLLOUT instead of POLL_OUT + * + * 09 13 2010 cp.wu + * NULL + * add waitq for poll() and read(). + * + * 08 24 2010 chinghwa.yu + * NULL + * Update BOW for the 1st time. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change variable names for multiple physical link to match with coding convention + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * multiple BoW interfaces need to compare with peer address + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * fix kalIndicateBOWEvent. + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler capability + * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include +#include "bss.h" + +#if CFG_ENABLE_BT_OVER_WIFI + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* @FIXME if there is command/event with payload length > 28 */ +#define MAX_BUFFER_SIZE (64) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#if CFG_BOW_TEST +UINT_32 g_u4PrevSysTime = 0; +UINT_32 g_u4CurrentSysTime = 0; +UINT_32 g_arBowRevPalPacketTime[11]; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* forward declarations */ +static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos); + +static ssize_t +mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos); + +static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg); + +static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait); + +static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp); + +static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp); + +/* character file operations */ +static const struct file_operations mt6620_ampc_fops = { + /* .owner = THIS_MODULE, */ + .read = mt6620_ampc_read, + .write = mt6620_ampc_write, + .unlocked_ioctl = mt6620_ampc_ioctl, + .poll = mt6620_ampc_poll, + .open = mt6620_ampc_open, + .release = mt6620_ampc_release, +}; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register for character device to communicate with 802.11 PAL +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glRegisterAmpc(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + if (prGlueInfo->rBowInfo.fgIsRegistered == TRUE) + return FALSE; + +#if 0 + /* 1. allocate major number dynamically */ + + if (alloc_chrdev_region(&(prGlueInfo->rBowInfo.u4DeviceNumber), 0, /* first minor number */ + 1, /* number */ + GLUE_BOW_DEVICE_NAME) != 0) + + return FALSE; +#endif + +#if 1 + +#if defined(CONFIG_AMPC_CDEV_NUM) + prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(CONFIG_AMPC_CDEV_NUM, 0); +#else + prGlueInfo->rBowInfo.u4DeviceNumber = MKDEV(226, 0); +#endif + + if (register_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1, /* number */ + GLUE_BOW_DEVICE_NAME) != 0) + + return FALSE; +#endif + + /* 2. spin-lock initialization */ + /* spin_lock_init(&(prGlueInfo->rBowInfo.rSpinLock)); */ + + /* 3. initialize kfifo */ +/* prGlueInfo->rBowInfo.prKfifo = kfifo_alloc(GLUE_BOW_KFIFO_DEPTH, + GFP_KERNEL, + &(prGlueInfo->rBowInfo.rSpinLock));*/ + if ((kfifo_alloc((struct kfifo *)&(prGlueInfo->rBowInfo.rKfifo), GLUE_BOW_KFIFO_DEPTH, GFP_KERNEL))) + goto fail_kfifo_alloc; + +/* if(prGlueInfo->rBowInfo.prKfifo == NULL) */ + if (&(prGlueInfo->rBowInfo.rKfifo) == NULL) + goto fail_kfifo_alloc; + + /* 4. initialize cdev */ + cdev_init(&(prGlueInfo->rBowInfo.cdev), &mt6620_ampc_fops); + /* prGlueInfo->rBowInfo.cdev.owner = THIS_MODULE; */ + prGlueInfo->rBowInfo.cdev.ops = &mt6620_ampc_fops; + + /* 5. add character device */ + if (cdev_add(&(prGlueInfo->rBowInfo.cdev), prGlueInfo->rBowInfo.u4DeviceNumber, 1)) + goto fail_cdev_add; + + /* 6. in queue initialization */ + init_waitqueue_head(&(prGlueInfo->rBowInfo.outq)); + + /* 7. finish */ + prGlueInfo->rBowInfo.fgIsRegistered = TRUE; + return TRUE; + +fail_cdev_add: + kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); +/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ +fail_kfifo_alloc: + unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); + return FALSE; +} /* end of glRegisterAmpc */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister character device for communicating with 802.11 PAL +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glUnregisterAmpc(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + if (prGlueInfo->rBowInfo.fgIsRegistered == FALSE) + return FALSE; + + prGlueInfo->rBowInfo.fgIsRegistered = FALSE; + + /* 1. free netdev if necessary */ +#if CFG_BOW_SEPARATE_DATA_PATH + kalUninitBowDevice(prGlueInfo); +#endif + + /* 2. removal of character device */ + cdev_del(&(prGlueInfo->rBowInfo.cdev)); + + /* 3. free kfifo */ +/* kfifo_free(prGlueInfo->rBowInfo.prKfifo); */ + kfifo_free(&(prGlueInfo->rBowInfo.rKfifo)); +/* prGlueInfo->rBowInfo.prKfifo = NULL; */ +/* prGlueInfo->rBowInfo.rKfifo = NULL; */ + + /* 4. free device number */ + unregister_chrdev_region(prGlueInfo->rBowInfo.u4DeviceNumber, 1); + + return TRUE; +} /* end of glUnregisterAmpc */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief read handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t mt6620_ampc_read(IN struct file *filp, IN char __user *buf, IN size_t size, IN OUT loff_t *ppos) +{ + UINT_8 aucBuffer[MAX_BUFFER_SIZE]; + ssize_t retval; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) + return -EFAULT; + /* size check */ +/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) >= size) */ + if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) >= size) + retval = size; + else + retval = kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); +/* retval = kfifo_len(prGlueInfo->rBowInfo.prKfifo); */ + +/* kfifo_get(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ +/* kfifo_out(prGlueInfo->rBowInfo.prKfifo, aucBuffer, retval); */ + if (!(kfifo_out(&(prGlueInfo->rBowInfo.rKfifo), aucBuffer, retval))) { + retval = -EIO; + return retval; + } + + if (copy_to_user(buf, aucBuffer, retval)) + retval = -EIO; + + return retval; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief write handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t +mt6620_ampc_write(IN struct file *filp, OUT const char __user *buf, IN size_t size, IN OUT loff_t *ppos) +{ +#if CFG_BOW_TEST + UINT_8 i; +#endif + + UINT_8 aucBuffer[MAX_BUFFER_SIZE]; + P_AMPC_COMMAND prCmd; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) + return -EFAULT; + + if (size > MAX_BUFFER_SIZE) + return -EINVAL; + else if (copy_from_user(aucBuffer, buf, size)) + return -EIO; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "AMP driver CMD buffer size : %d.\n", size); + + for (i = 0; i < MAX_BUFFER_SIZE; i++) + DBGLOG(BOW, EVENT, "AMP write content : 0x%x.\n", aucBuffer[i]); + + DBGLOG(BOW, EVENT, "BoW CMD write.\n"); +#endif + + prCmd = (P_AMPC_COMMAND) aucBuffer; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "AMP write content payload length : %d.\n", prCmd->rHeader.u2PayloadLength); + + DBGLOG(BOW, EVENT, "AMP write content header length : %d.\n", sizeof(AMPC_COMMAND_HEADER_T)); +#endif + + /* size check */ + if (prCmd->rHeader.u2PayloadLength + sizeof(AMPC_COMMAND_HEADER_T) != size) { +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "Wrong CMD total length.\n"); +#endif + + return -EINVAL; + } + + if (wlanbowHandleCommand(prGlueInfo->prAdapter, prCmd) == WLAN_STATUS_SUCCESS) + return size; + else + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static long mt6620_ampc_ioctl(IN struct file *filp, IN unsigned int cmd, IN OUT unsigned long arg) +{ + int err = 0; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) + return -EFAULT; + /* permission check */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + /* no ioctl is implemented yet */ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static unsigned int mt6620_ampc_poll(IN struct file *filp, IN poll_table *wait) +{ + unsigned int retval; + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); + + ASSERT(prGlueInfo); + + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) + return -EFAULT; + + poll_wait(filp, &prGlueInfo->rBowInfo.outq, wait); + + retval = (POLLOUT | POLLWRNORM); /* always accepts incoming command packets */ + +/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLOUT | POLLWRNORM, %x\n", retval)); */ + +/* if(kfifo_len(prGlueInfo->rBowInfo.prKfifo) > 0) */ + if (kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)) > 0) { + retval |= (POLLIN | POLLRDNORM); + +/* DBGLOG(BOW, EVENT, ("mt6620_ampc_pol, POLLIN | POLLRDNORM, %x\n", retval)); */ + + } + + return retval; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief open handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static int mt6620_ampc_open(IN struct inode *inodep, IN struct file *filp) +{ + P_GLUE_INFO_T prGlueInfo; + P_GL_BOW_INFO prBowInfo; + + prBowInfo = container_of(inodep->i_cdev, GL_BOW_INFO, cdev); + ASSERT(prBowInfo); + + prGlueInfo = container_of(prBowInfo, GLUE_INFO_T, rBowInfo); + ASSERT(prGlueInfo); + + /* set-up private data */ + filp->private_data = prGlueInfo; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief close handler for character device to communicate with 802.11 PAL +* +* \param[in] +* \return +* Follows Linux Character Device Interface +* +*/ +/*----------------------------------------------------------------------------*/ +static int mt6620_ampc_release(IN struct inode *inodep, IN struct file *filp) +{ + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = (P_GLUE_INFO_T) (filp->private_data); + + ASSERT(prGlueInfo); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to indicate event for Bluetooth over Wi-Fi +* +* \param[in] +* prGlueInfo +* prEvent +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent) +{ + size_t u4AvailSize, u4EventSize; + + ASSERT(prGlueInfo); + ASSERT(prEvent); + + /* check device */ + if ((prGlueInfo->rBowInfo.fgIsRegistered == FALSE) || (prGlueInfo->ulFlag & GLUE_FLAG_HALT)) + return; + +/* u4AvailSize = + GLUE_BOW_KFIFO_DEPTH - kfifo_len(prGlueInfo->rBowInfo.prKfifo);*/ + + u4AvailSize = GLUE_BOW_KFIFO_DEPTH - kfifo_len(&(prGlueInfo->rBowInfo.rKfifo)); + + u4EventSize = prEvent->rHeader.u2PayloadLength + sizeof(AMPC_EVENT_HEADER_T); + + /* check kfifo availability */ + if (u4AvailSize < u4EventSize) { + DBGLOG(BOW, EVENT, "[bow] no space for event: %zu/%zu\n", u4EventSize, u4AvailSize); + return; + } + /* queue into kfifo */ +/* kfifo_put(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ +/* kfifo_in(prGlueInfo->rBowInfo.prKfifo, (PUINT_8)prEvent, u4EventSize); */ + kfifo_in(&(prGlueInfo->rBowInfo.rKfifo), (PUINT_8) prEvent, u4EventSize); + wake_up_interruptible(&(prGlueInfo->rBowInfo.outq)); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ +ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 aucPeerAddress[6]) +{ + UINT_8 i; + + ASSERT(prGlueInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalGetBowState.\n"); +#endif + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalGetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "kalGetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, + prGlueInfo->rBowInfo.aeState[i]); + +#endif + + return prGlueInfo->rBowInfo.aeState[i]; + } + } + + return BOW_DEVICE_STATE_DISCONNECTED; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Bluetooth-over-Wi-Fi state in glue layer +* +* \param[in] +* prGlueInfo +* eBowState +* rPeerAddr +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, IN UINT_8 aucPeerAddress[6]) +{ + UINT_8 i; + + ASSERT(prGlueInfo); + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalSetBowState.\n"); + + DBGLOG(BOW, EVENT, "kalSetBowState, prGlueInfo->rBowInfo.arPeerAddr, %x:%x:%x:%x:%x:%x.\n", + prGlueInfo->rBowInfo.arPeerAddr[0], + prGlueInfo->rBowInfo.arPeerAddr[1], + prGlueInfo->rBowInfo.arPeerAddr[2], + prGlueInfo->rBowInfo.arPeerAddr[3], + prGlueInfo->rBowInfo.arPeerAddr[4], prGlueInfo->rBowInfo.arPeerAddr[5])); + + DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress, %x:%x:%x:%x:%x:%x.\n", + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5]); +#endif + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr, aucPeerAddress) == 0) { + prGlueInfo->rBowInfo.aeState[i] = eBowState; + +#if CFG_BOW_TEST + DBGLOG(BOW, EVENT, "kalSetBowState, aucPeerAddress %x, %x:%x:%x:%x:%x:%x.\n", i, + aucPeerAddress[0], + aucPeerAddress[1], + aucPeerAddress[2], + aucPeerAddress[3], aucPeerAddress[4], aucPeerAddress[5])); + + DBGLOG(BOW, EVENT, + "kalSetBowState, prGlueInfo->rBowInfo.aeState %x, %x.\n", i, + prGlueInfo->rBowInfo.aeState[i]); +#endif + + return TRUE; + } + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi global state +* +* \param[in] +* prGlueInfo +* +* \return +* BOW_DEVICE_STATE_DISCONNECTED +* in case there is no BoW connection or +* BoW connection under initialization +* +* BOW_DEVICE_STATE_STARTING +* in case there is no BoW connection but +* some BoW connection under initialization +* +* BOW_DEVICE_STATE_CONNECTED +* in case there is any BoW connection available +*/ +/*----------------------------------------------------------------------------*/ +ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + +/* Henry, can reduce this logic to indentify state change */ + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_CONNECTED) + return BOW_DEVICE_STATE_CONNECTED; + } + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_STARTING) + return BOW_DEVICE_STATE_STARTING; + } + + return BOW_DEVICE_STATE_DISCONNECTED; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi operating frequency +* +* \param[in] +* prGlueInfo +* +* \return +* in unit of KHz +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rBowInfo.u4FreqInKHz; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* +* \return +* 0: Responder +* 1: Initiator +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) + return prGlueInfo->rBowInfo.aucRole[i]; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* ucRole +* 0: Responder +* 1: Initiator +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr) +{ + UINT_32 i; + + ASSERT(prGlueInfo); + ASSERT(ucRole <= 1); + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (EQUAL_MAC_ADDR(prGlueInfo->rBowInfo.arPeerAddr[i], rPeerAddr) == 0) + prGlueInfo->rBowInfo.aucRole[i] = ucRole; /* Henry, 0 : Responder, 1 : Initiator */ + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get available Bluetooth-over-Wi-Fi physical link number +* +* \param[in] +* prGlueInfo +* \return +* UINT_32 +* how many physical links are aviailable +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo) +{ + UINT_8 i; + UINT_8 ucLinkCount = 0; + + ASSERT(prGlueInfo); + + for (i = 0; i < CFG_BOW_PHYSICAL_LINK_NUM; i++) { + if (prGlueInfo->rBowInfo.aeState[i] == BOW_DEVICE_STATE_DISCONNECTED) + ucLinkCount++; + } + +#if 0 /* CFG_BOW_TEST */ + DBGLOG(BOW, EVENT, "kalGetBowAvailablePhysicalLinkCount, ucLinkCount, %c.\n", ucLinkCount); +#endif + + return ucLinkCount; +} + +#if CFG_BOW_SEPARATE_DATA_PATH + +/* Net Device Hooks */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device open (ifup) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int bowOpen(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 2. carrier on & start TX queue */ + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); + + return 0; /* success */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device stop (ifdown) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int bowStop(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prDev); + + /* 2. turn of carrier */ + if (netif_carrier_ok(prDev)) + netif_carrier_off(prDev); + + return 0; +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is TX entry point of NET DEVICE. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prDev Pointer to struct net_device + * + * \retval NETDEV_TX_OK - on success. + * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. + */ +/*----------------------------------------------------------------------------*/ +static int bowHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + UINT_16 u2QueueIdx = 0; + UINT_8 ucDSAP, ucSSAP, ucControl; + UINT_8 aucOUI[3]; + PUINT_8 aucLookAheadBuf = NULL; + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + ASSERT(prGlueInfo); + + aucLookAheadBuf = prSkb->data; + + ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; + ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; + ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; + aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; + aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; + aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; + prGlueInfo->u8SkbToDriver++; + + if (!(ucDSAP == ETH_LLC_DSAP_SNAP && + ucSSAP == ETH_LLC_SSAP_SNAP && + ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && + aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && + aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) || (prSkb->len > 1514)) { + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, "Invalid BOW packet, skip tx\n"); +#endif + + dev_kfree_skb(prSkb); + prGlueInfo->u8SkbFreed++; + return NETDEV_TX_OK; + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(BOW, TRACE, "GLUE_FLAG_HALT skip tx\n"); + dev_kfree_skb(prSkb); + prGlueInfo->u8SkbFreed++; + return NETDEV_TX_OK; + } + + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, "Tx sk_buff->len: %d\n", prSkb->len); + DBGLOG(BOW, TRACE, "Tx sk_buff->data_len: %d\n", prSkb->data_len); + DBGLOG(BOW, TRACE, "Tx sk_buff->data:\n"); + + for (i = 0; i < prSkb->len; i++) { + DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); + + if ((i + 1) % 16 == 0) + DBGLOG(BOW, TRACE, "\n"); + } + + DBGLOG(BOW, TRACE, "\n"; +#endif +#if CFG_BOW_TEST +/* g_u4CurrentSysTime = (OS_SYSTIME)kalGetTimeTick(; */ + g_u4CurrentSysTime = (OS_SYSTIME) jiffies_to_usecs(jiffies); + i = g_u4CurrentSysTime - g_u4PrevSysTime; + if ((i >> 10) > 0) + i = 10; + else + i = i >> 7; + g_arBowRevPalPacketTime[i]++; + g_u4PrevSysTime = g_u4CurrentSysTime; +#endif + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx] >= + CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) + DBGLOG(TX, INFO, "netif_stop_subqueue for BOW, Queue len: %d\n", + prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_BOW_INDEX][u2QueueIdx]); + + netif_stop_subqueue(prDev, u2QueueIdx); + } else { + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + kalSetEvent(prGlueInfo); + /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ + return NETDEV_TX_OK; +} + +/* callbacks for netdevice */ +static const struct net_device_ops bow_netdev_ops = { + .ndo_open = bowOpen, .ndo_stop = bowStop, .ndo_start_xmit = bowHardStartXmit,}; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief initialize net device for Bluetooth-over-Wi-Fi +* +* \param[in] +* prGlueInfo +* prDevName +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName) +{ + P_ADAPTER_T prAdapter; + P_GL_HIF_INFO_T prHif; + PARAM_MAC_ADDRESS rMacAddr; + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + if (prGlueInfo->rBowInfo.fgIsNetRegistered == FALSE) { + prGlueInfo->rBowInfo.prDevHandler = + alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); + if (!prGlueInfo->rBowInfo.prDevHandler) + return FALSE; + + /* 1. setup netdev */ + /* 1.1 Point to shared glue structure */ + *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->rBowInfo.prDevHandler)) = prGlueInfo; + /* 1.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] |= 0x2; + /* change to local administrated address */ + ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->dev_addr, rMacAddr); + ether_addr_copy(prGlueInfo->rBowInfo.prDevHandler->perm_addr, + prGlueInfo->rBowInfo.prDevHandler->dev_addr); + /* 1.3 register callback functions */ + prGlueInfo->rBowInfo.prDevHandler->netdev_ops = &bow_netdev_ops; +#if (MTK_WCN_HIF_SDIO == 0) + SET_NETDEV_DEV(prGlueInfo->rBowInfo.prDevHandler, prHif->Dev); +#endif + register_netdev(prGlueInfo->rBowInfo.prDevHandler); + /* 2. net device initialize */ + netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); + /* 3. finish */ + prGlueInfo->rBowInfo.fgIsNetRegistered = TRUE; + } + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief uninitialize net device for Bluetooth-over-Wi-Fi +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + /* ASSERT(prGlueInfo->rBowInfo.fgIsRegistered == TRUE); */ + if (prGlueInfo->rBowInfo.fgIsNetRegistered == TRUE) { + prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; + if (netif_carrier_ok(prGlueInfo->rBowInfo.prDevHandler)) + netif_carrier_off(prGlueInfo->rBowInfo.prDevHandler); + + netif_tx_stop_all_queues(prGlueInfo->rBowInfo.prDevHandler); + /* netdevice unregistration & free */ + unregister_netdev(prGlueInfo->rBowInfo.prDevHandler); + free_netdev(prGlueInfo->rBowInfo.prDevHandler); + prGlueInfo->rBowInfo.prDevHandler = NULL; + return TRUE; + } else { + return FALSE; + } +} +#endif /* CFG_BOW_SEPARATE_DATA_PATH */ +#endif /* CFG_ENABLE_BT_OVER_WIFI */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c new file mode 100644 index 0000000000000..1fed65ebc60e6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_cfg80211.c @@ -0,0 +1,3110 @@ +/* +** Id: @(#) gl_cfg80211.c@@ +*/ + +/*! \file gl_cfg80211.c + \brief Main routines for supporintg MT6620 cfg80211 control interface + + This file contains the support routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_cfg80211.c +** +** 09 05 2013 cp.wu +** correct length to pass to wlanoidSetBssid() +** +** 09 04 2013 cp.wu +** fix typo +** +** 09 03 2013 cp.wu +** add path for reassociation +** +** 11 23 2012 yuche.tsai +** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely +** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 30 2012 chinglan.wang +** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only +** . + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include +#include +#include +#include "gl_cfg80211.h" +#include "gl_vendor.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* workaround for some ANR CRs. if suppliant is blocked longer than 10s, wifi hal will tell wifiMonitor +to teminate. for the case which can block supplicant 10s is to del key more than 5 times. the root cause +is that there is no resource in TC4, so del key command was not able to set, and then oid +timeout was happed. if we found the root cause why fw couldn't release TC resouce, we will remove this +workaround */ +static UINT_8 gucKeyIndex = 255; + +P_SW_RFB_T g_arGscnResultsTempBuffer[MAX_BUFFERED_GSCN_RESULTS]; +UINT_8 g_GscanResultsTempBufferIndex = 0; +UINT_8 g_arGscanResultsIndicateNumber[MAX_BUFFERED_GSCN_RESULTS] = { 0, 0, 0, 0, 0 }; + +UINT_8 g_GetResultsBufferedCnt = 0; +UINT_8 g_GetResultsCmdCnt = 0; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for change STA type between + * 1. Infrastructure Client (Non-AP STA) + * 2. Ad-Hoc IBSS + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int +mtk_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, enum nl80211_iftype type, /*u32 *flags,*/ struct vif_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_OP_MODE_T eOpMode; + UINT_32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + if (type == NL80211_IFTYPE_STATION) + eOpMode = NET_TYPE_INFRA; + else if (type == NL80211_IFTYPE_ADHOC) + eOpMode = NET_TYPE_IBSS; + else + return -EINVAL; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInfrastructureMode, + &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, WARN, "set infrastructure mode error:%x\n", rStatus); + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for adding key + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int +mtk_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) +{ + PARAM_KEY_T rKey; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + INT_32 i4Rslt = -EINVAL; + UINT_32 u4BufLen = 0; + UINT_8 tmp1[8]; + UINT_8 tmp2[8]; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(&rKey, sizeof(PARAM_KEY_T)); + + rKey.u4KeyIndex = key_index; + + if (mac_addr) { + COPY_MAC_ADDR(rKey.arBSSID, mac_addr); + if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && + (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + } + if (rKey.arBSSID[0] != 0xFF) { + rKey.u4KeyIndex |= BIT(31); + if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || + (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) + rKey.u4KeyIndex |= BIT(30); + } + } else { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + /* rKey.u4KeyIndex |= BIT(31);//Enable BIT 31 will make tx use bc key id,should use pairwise key id 0 */ + } + + if (params->key) { + /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ + kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); + if (params->key_len == 32) { + kalMemCopy(tmp1, ¶ms->key[16], 8); + kalMemCopy(tmp2, ¶ms->key[24], 8); + kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8); + kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8); + } + } + + rKey.u4KeyLength = params->key_len; + rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) + i4Rslt = 0; + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for getting key for specified STA + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int +mtk_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *)) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + /* not implemented */ + + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for removing key for specified STA + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PARAM_REMOVE_KEY_T rRemoveKey; + UINT_32 u4BufLen = 0; + INT_32 i4Rslt = -EINVAL; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + if (mac_addr) + COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); + else if (key_index <= gucKeyIndex) { /* new operation, reset gucKeyIndex */ + gucKeyIndex = 255; + } else { /* bypass the next remove key operation */ + gucKeyIndex = key_index; + return -EBUSY; + } + rRemoveKey.u4KeyIndex = key_index; + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveKey, &rRemoveKey, rRemoveKey.u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "remove key error:%x\n", rStatus); + if (WLAN_STATUS_FAILURE == rStatus && mac_addr) { + i4Rslt = -EBUSY; + gucKeyIndex = key_index; + } + } else { + gucKeyIndex = 255; + i4Rslt = 0; + } + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for setting default key on an interface + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int +mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + /* not implemented */ + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for setting set_default_mgmt_ke on an interface + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for getting station information such as RSSI + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) +{ +#define LINKSPEED_MAX_RANGE_11BGN 3000 + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + PARAM_MAC_ADDRESS arBssid; + UINT_32 u4BufLen; + UINT_32 u4Rate = 0; + UINT_32 u8diffTxBad, u8diffRetry; + INT_32 i4Rssi = 0; + PARAM_802_11_STATISTICS_STRUCT_T rStatistics; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); + + /* 1. check BSSID */ + if (UNEQUAL_MAC_ADDR(arBssid, mac)) { + /* wrong MAC address */ + DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", + mac, arBssid); + return -ENOENT; + } + + /* 2. fill TX rate */ + if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + } else { + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + + if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) { + /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n")); */ + DBGLOG(REQ, WARN, "last link speed\n"); + sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; + } else { + /* sinfo->filled |= STATION_INFO_TX_BITRATE; */ + sinfo->txrate.legacy = u4Rate / 1000; /* convert from 100bps to 100kbps */ + prGlueInfo->u4LinkSpeedCache = u4Rate / 1000; + } + } + + /* 3. fill RSSI */ + if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + } else { + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + if (rStatus != WLAN_STATUS_SUCCESS || (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) + || (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { + /* DBGLOG(REQ, WARN, "unable to retrieve link speed\n"); */ + DBGLOG(REQ, WARN, "last rssi\n"); + sinfo->signal = prGlueInfo->i4RssiCache; + } else { + /* in the cfg80211 layer, the signal is a signed char variable. */ + sinfo->signal = i4Rssi; /* dBm */ + prGlueInfo->i4RssiCache = i4Rssi; + } + sinfo->rx_packets = prGlueInfo->rNetDevStats.rx_packets; + + /* 4. Fill Tx OK and Tx Bad */ + + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + { + WLAN_STATUS rStatus; + + kalMemZero(&rStatistics, sizeof(rStatistics)); + /* Get Tx OK/Fail cnt from AIS statistic counter */ + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStatisticsPL, + &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "unable to retrieive statistic\n"); + } else { + INT_32 i4RssiThreshold = -85; /* set rssi threshold -85dBm */ + UINT_32 u4LinkspeedThreshold = 55; /* set link speed threshold 5.5Mbps */ + BOOLEAN fgWeighted = 0; + + /* calculate difference */ + u8diffTxBad = rStatistics.rFailedCount.QuadPart - prGlueInfo->u8Statistic[0]; + u8diffRetry = rStatistics.rRetryCount.QuadPart - prGlueInfo->u8Statistic[1]; + /* restore counters */ + prGlueInfo->u8Statistic[0] = rStatistics.rFailedCount.QuadPart; + prGlueInfo->u8Statistic[1] = rStatistics.rRetryCount.QuadPart; + + /* check threshold is valid */ + if (prGlueInfo->fgPoorlinkValid) { + if (prGlueInfo->i4RssiThreshold) + i4RssiThreshold = prGlueInfo->i4RssiThreshold; + if (prGlueInfo->u4LinkspeedThreshold) + u4LinkspeedThreshold = prGlueInfo->u4LinkspeedThreshold; + } + /* add weighted to fail counter */ + if (sinfo->txrate.legacy < u4LinkspeedThreshold || sinfo->signal < i4RssiThreshold) { + prGlueInfo->u8TotalFailCnt += (u8diffTxBad * 16 + u8diffRetry); + fgWeighted = 1; + } else { + prGlueInfo->u8TotalFailCnt += u8diffTxBad; + } + /* report counters */ + prGlueInfo->rNetDevStats.tx_packets = rStatistics.rTransmittedFragmentCount.QuadPart; + prGlueInfo->rNetDevStats.tx_errors = prGlueInfo->u8TotalFailCnt; + + sinfo->tx_packets = prGlueInfo->rNetDevStats.tx_packets; + sinfo->tx_failed = prGlueInfo->rNetDevStats.tx_errors; + /* Good Fail Bad Difference retry difference Linkspeed Rate Weighted */ + DBGLOG(REQ, TRACE, + "Poorlink State TxOK(%d) TxFail(%d) Bad(%d) Retry(%d)", + sinfo->tx_packets, + sinfo->tx_failed, + (int)u8diffTxBad, + (int)u8diffRetry); + DBGLOG(REQ, TRACE, + "Rate(%d) Signal(%d) Weight(%d) QuadPart(%d)\n", + sinfo->txrate.legacy, + sinfo->signal, + (int)fgWeighted, + (int)rStatistics.rMultipleRetryCount.QuadPart); + } + } + + } + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for adding a station information + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ +#if (CFG_SUPPORT_TDLS == 1) + /* + EX: In supplicant, + (Supplicant) wpa_tdls_process_tpk_m3() -> + (Supplicant) wpa_tdls_enable_link() -> + (Supplicant) wpa_sm_tdls_peer_addset() -> + (Supplicant) ..tdls_peer_addset() -> + (Supplicant) wpa_supplicant_tdls_peer_addset() -> + (Supplicant) wpa_drv_sta_add() -> + (Supplicant) ..sta_add() -> + (Supplicant) wpa_driver_nl80211_sta_add() -> + (NL80211) nl80211_set_station() -> + (Driver) mtk_cfg80211_change_station() + + if nl80211_set_station fails, supplicant will tear down the link. + */ + P_GLUE_INFO_T prGlueInfo; + TDLS_CMD_PEER_UPDATE_T rCmdUpdate; + WLAN_STATUS rStatus; + UINT_32 u4BufLen, u4Temp; + + /* sanity check */ + if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) + return -EINVAL; + + DBGLOG(TDLS, INFO, "%s: 0x%p 0x%x\n", __func__, params->supported_rates, params->sta_flags_set); + + if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) + return -EOPNOTSUPP; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + if (prGlueInfo == NULL) + return -EINVAL; + + /* TODO: check if we are station mode, not AP mode */ + + /* init */ + kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); + kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); + + if (params->supported_rates != NULL) { + u4Temp = params->supported_rates_len; + if (u4Temp > TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX) { + u4Temp = TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX; + DBGLOG(TDLS, ERROR, "%s sup rate too long: %d\n", __func__, params->supported_rates_len); + } + kalMemCopy(rCmdUpdate.aucSupRate, params->supported_rates, u4Temp); + rCmdUpdate.u2SupRateLen = u4Temp; + } + + /* + In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM + So force to support UAPSD here. + */ + rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */ + rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */ + + DBGLOG(TDLS, INFO, "%s: UapsdBitmap=0x%x UapsdMaxSp=%d\n", + __func__, rCmdUpdate.UapsdBitmap, rCmdUpdate.UapsdMaxSp); + + rCmdUpdate.u2Capability = params->capability; + + if (params->ext_capab != NULL) { + u4Temp = params->ext_capab_len; + if (u4Temp > TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN) { + u4Temp = TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN; + DBGLOG(TDLS, ERROR, "%s ext_capab too long: %d\n", __func__, params->ext_capab_len); + } + kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp); + rCmdUpdate.u2ExtCapLen = u4Temp; + } + + if (params->ht_capa != NULL) { + DBGLOG(TDLS, INFO, "%s: peer is 11n device\n", __func__); + + rCmdUpdate.rHtCap.u2CapInfo = params->ht_capa->cap_info; + rCmdUpdate.rHtCap.ucAmpduParamsInfo = params->ht_capa->ampdu_params_info; + rCmdUpdate.rHtCap.u2ExtHtCapInfo = params->ht_capa->extended_ht_cap_info; + rCmdUpdate.rHtCap.u4TxBfCapInfo = params->ht_capa->tx_BF_cap_info; + rCmdUpdate.rHtCap.ucAntennaSelInfo = params->ht_capa->antenna_selection_info; + kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask, + params->ht_capa->mcs.rx_mask, sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask)); + rCmdUpdate.rHtCap.rMCS.u2RxHighest = params->ht_capa->mcs.rx_highest; + rCmdUpdate.rHtCap.rMCS.ucTxParams = params->ht_capa->mcs.tx_params; + rCmdUpdate.fgIsSupHt = TRUE; + } + + /* update a TDLS peer record */ + rStatus = kalIoctl(prGlueInfo, + TdlsexPeerUpdate, + &rCmdUpdate, sizeof(TDLS_CMD_PEER_UPDATE_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s update error:%x\n", __func__, rStatus); + return -EINVAL; + } +#endif /* CFG_SUPPORT_TDLS */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for adding a station information + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ +#if (CFG_SUPPORT_TDLS == 1) + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + P_GLUE_INFO_T prGlueInfo; + TDLS_CMD_PEER_ADD_T rCmdCreate; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + + if ((wiphy == NULL) || (mac == NULL) || (params == NULL)) + return -EINVAL; + + /* + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, + NULL, 0); + + wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, + u16 aid, u16 capability, const u8 *supp_rates, + size_t supp_rates_len, + const struct ieee80211_ht_capabilities *ht_capab, + const struct ieee80211_vht_capabilities *vht_capab, + u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) + + Only MAC address of the peer is valid. + */ + + DBGLOG(TDLS, INFO, "%s: 0x%p %d\n", __func__, params->supported_rates, params->supported_rates_len); + + /* sanity check */ + if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) + return -EOPNOTSUPP; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + if (prGlueInfo == NULL) + return -EINVAL; + + /* TODO: check if we are station mode, not AP mode */ + + /* init */ + kalMemZero(&rCmdCreate, sizeof(rCmdCreate)); + kalMemCopy(rCmdCreate.aucPeerMac, mac, 6); + +#if 0 + rCmdCreate.eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + + rCmdCreate.u2CapInfo = params->capability; + + DBGLOG(TDLS, INFO, " %s: capability = 0x%x\n", __func__, rCmdCreate.u2CapInfo); + + if ((params->supported_rates != NULL) && (params->supported_rates_len != 0)) { + UINT32 u4Idx; + + DBGLOG(TDLS, INFO, " %s: sup rate = 0x", __func__); + + rIeSup.ucId = ELEM_ID_SUP_RATES; + rIeSup.ucLength = params->supported_rates_len; + for (u4Idx = 0; u4Idx < rIeSup.ucLength; u4Idx++) { + rIeSup.aucSupportedRates[u4Idx] = params->supported_rates[u4Idx]; + DBGLOG(TDLS, INFO, "%x ", rIeSup.aucSupportedRates[u4Idx]); + } + DBGLOG(TDLS, INFO, "\n"); + + rateGetRateSetFromIEs(&rIeSup, + NULL, + &rCmdCreate.u2OperationalRateSet, + &rCmdCreate.u2BSSBasicRateSet, &rCmdCreate.fgIsUnknownBssBasicRate); + } + + /* phy type */ +#endif + + /* create a TDLS peer record */ + rStatus = kalIoctl(prGlueInfo, + TdlsexPeerAdd, + &rCmdCreate, sizeof(TDLS_CMD_PEER_ADD_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(TDLS, ERROR, "%s create error:%x\n", __func__, rStatus); + return -EINVAL; + } +#endif /* CFG_SUPPORT_TDLS */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for deleting a station information + * + * @param + * + * @retval 0: successful + * others: failure + * + * @other + * must implement if you have add_station(). + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params) +//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to do a scan + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +static PARAM_SCAN_REQUEST_EXT_T rScanRequest; +int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; +/* PARAM_SCAN_REQUEST_EXT_T rScanRequest; */ + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "mtk_cfg80211_scan\n"); + kalMemZero(&rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T)); + + /* check if there is any pending scan not yet finished */ + if (prGlueInfo->prScanRequest != NULL) { + DBGLOG(REQ, ERROR, "prGlueInfo->prScanRequest != NULL\n"); + return -EBUSY; + } + + if (request->n_ssids == 0) { + rScanRequest.rSsid.u4SsidLen = 0; + } else if (request->n_ssids == 1) { + COPY_SSID(rScanRequest.rSsid.aucSsid, rScanRequest.rSsid.u4SsidLen, request->ssids[0].ssid, + request->ssids[0].ssid_len); + } else { + DBGLOG(REQ, ERROR, "request->n_ssids:%d\n", request->n_ssids); + return -EINVAL; + } + + if (request->ie_len > 0) { + rScanRequest.u4IELength = request->ie_len; + rScanRequest.pucIE = (PUINT_8) (request->ie); + } else { + rScanRequest.u4IELength = 0; + } +#if 0 + prGlueInfo->prScanRequest = request; + rStatus = kalIoctl(prGlueInfo, + wlanoidSetBssidListScanExt, + &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); + prGlueInfo->prScanRequest = NULL; + return -EINVAL; + } + + /*prGlueInfo->prScanRequest = request;*/ +#endif + + prGlueInfo->prScanRequest = request; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetBssidListScanExt, + &rScanRequest, sizeof(PARAM_SCAN_REQUEST_EXT_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + prGlueInfo->prScanRequest = NULL; + DBGLOG(REQ, ERROR, "scan error:%x\n", rStatus); + return -EINVAL; + } + + return 0; +} + +static UINT_8 wepBuf[48]; + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to connect to + * the ESS with the specified parameters + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + UINT_32 cipher; + PARAM_CONNECT_T rNewSsid; + BOOLEAN fgCarryWPSIE = FALSE; + ENUM_PARAM_OP_MODE_T eOpMode; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "[wlan] mtk_cfg80211_connect %p %zu\n", sme->ie, sme->ie_len); + + if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode > NET_TYPE_AUTO_SWITCH) + eOpMode = NET_TYPE_AUTO_SWITCH; + else + eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInfrastructureMode, + &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetInfrastructureMode fail 0x%x\n", rStatus); + return -EFAULT; + } + + /* after set operation mode, key table are cleared */ + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2; + else + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY; + break; + default: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY; + break; + } + + if (sme->crypto.n_ciphers_pairwise) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] = + sme->crypto.ciphers_pairwise[0]; + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + default: + DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + } + + if (sme->crypto.cipher_group) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite = sme->crypto.cipher_group; + switch (sme->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + default: + DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); + return -EINVAL; + } + } + + if (sme->crypto.n_akm_suites) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] = + sme->crypto.akm_suites[0]; + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA; + break; + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA_PSK; + break; + default: + DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); + return -EINVAL; + } + } else if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA2; + break; + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA2_PSK; + break; + default: + DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", sme->crypto.cipher_group); + return -EINVAL; + } + } + } + + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; + } + + prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy; + + prGlueInfo->fgWpsActive = FALSE; +#if CFG_SUPPORT_HOTSPOT_2_0 + prGlueInfo->fgConnectHS20AP = FALSE; +#endif + + if (sme->ie && sme->ie_len > 0) { + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + PUINT_8 prDesiredIE = NULL; + PUINT_8 pucIEStart = (PUINT_8)sme->ie; + +#if CFG_SUPPORT_WAPI + if (wextSrchDesiredWAPIIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiAssocInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(SEC, WARN, "[wapi] set wapi assoc info error:%x\n", rStatus); + } +#endif + + DBGLOG(REQ, TRACE, "[wlan] wlanoidSetWapiAssocInfo: .fgWapiMode = %d\n", + prGlueInfo->prAdapter->rWifiVar.rConnSettings.fgWapiMode); + +#if CFG_SUPPORT_WPS2 + if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD, (PUINT_8 *) &prDesiredIE)) { + prGlueInfo->fgWpsActive = TRUE; + fgCarryWPSIE = TRUE; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWSCAssocInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(SEC, WARN, "WSC] set WSC assoc info error:%x\n", rStatus); + } +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 + if (wextSrchDesiredHS20IE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetHS20Info, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ + } + } + if (wextSrchDesiredInterworkingIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInterworkingInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ + } + } + if (wextSrchDesiredRoamingConsortiumIE(pucIEStart, sme->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRoamingConsortiumIEInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ + } + } +#endif + } + + /* clear WSC Assoc IE buffer in case WPS IE is not detected */ + if (fgCarryWPSIE == FALSE) { + kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); + prGlueInfo->u2WSCAssocInfoIELen = 0; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus); + + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; + + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { + if (cipher & IW_AUTH_CIPHER_CCMP) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_TKIP) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_NONE) { + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + else + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, WARN, "set encryption mode error:%x\n", rStatus); + + if (sme->key_len != 0 && prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; + + prWepKey->u4Length = 12 + sme->key_len; + prWepKey->u4KeyLength = (UINT_32) sme->key_len; + prWepKey->u4KeyIndex = (UINT_32) sme->key_idx; + prWepKey->u4KeyIndex |= BIT(31); + if (prWepKey->u4KeyLength > 32) { + DBGLOG(REQ, ERROR, "Too long key length (%u)\n", prWepKey->u4KeyLength); + return -EINVAL; + } + kalMemCopy(prWepKey->aucKeyMaterial, sme->key, prWepKey->u4KeyLength); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddWep, + prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); + return -EFAULT; + } + } + + if (sme->channel) + rNewSsid.u4CenterFreq = sme->channel->center_freq; + else + rNewSsid.u4CenterFreq = 0; + rNewSsid.pucBssid = (UINT_8 *)sme->bssid; + rNewSsid.pucSsid = (UINT_8 *)sme->ssid; + rNewSsid.u4SsidLen = sme->ssid_len; + rStatus = kalIoctl(prGlueInfo, + wlanoidSetConnect, + (PVOID)(&rNewSsid), sizeof(PARAM_CONNECT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "set SSID:%x\n", rStatus); + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to disconnect from + * currently connected ESS + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to join an IBSS group + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params) +{ + PARAM_SSID_T rNewSsid; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4ChnlFreq; /* Store channel or frequency information */ + UINT_32 u4BufLen = 0; + WLAN_STATUS rStatus; + struct ieee80211_channel *channel = NULL; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* set channel */ + if (params->chandef.chan) + channel = params->chandef.chan; + if (channel) { + u4ChnlFreq = nicChannelNum2Freq(channel->hw_value); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetFrequency, + &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + } + + /* set SSID */ + kalMemCopy(rNewSsid.aucSsid, params->ssid, params->ssid_len); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetSsid, + (PVOID)(&rNewSsid), sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus); + return -EFAULT; + } + + return 0; + + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to leave from IBSS group + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to configure + * WLAN power managemenet + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + PARAM_POWER_MODE ePowerMode; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + if (enabled) { + if (timeout == -1) + ePowerMode = Param_PowerModeFast_PSP; + else + ePowerMode = Param_PowerModeMAX_PSP; + } else { + ePowerMode = Param_PowerModeCAM; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSet802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set_power_mgmt error:%x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cache + * a PMKID for a BSSID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); + return -ENOMEM; + } + + prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); + prPmkid->u4BSSIDInfoCount = 1; + kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, pmksa->bssid, 6); + kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, pmksa->pmkid, IW_PMKID_LEN); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, WARN, "add pmkid error:%x\n", rStatus); + kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to remove + * a cached PMKID for a BSSID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa) +{ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to flush + * all cached PMKID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_FLUSH\n"); + return -ENOMEM; + } + + prPmkid->u4Length = 8; + prPmkid->u4BSSIDInfoCount = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, prPmkid, sizeof(PARAM_PMKID_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, WARN, "flush pmkid error:%x\n", rStatus); + kalMemFree(prPmkid, VIR_MEM_TYPE, 8); + + return 0; +} + +void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + IN struct wireless_dev *wdev, + IN u16 frame_type, IN bool reg) +{ +#if 0 + P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; +#endif + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + do { + + DBGLOG(REQ, LOUD, "mtk_cfg80211_mgmt_frame_register\n"); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + switch (frame_type) { + case MAC_FRAME_PROBE_REQ: + if (reg) { + prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(REQ, LOUD, "Open packet filer probe request\n"); + } else { + prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(REQ, LOUD, "Close packet filer probe request\n"); + } + break; + case MAC_FRAME_ACTION: + if (reg) { + prGlueInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(REQ, LOUD, "Open packet filer action frame.\n"); + } else { + prGlueInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(REQ, LOUD, "Close packet filer action frame.\n"); + } + break; + default: + DBGLOG(REQ, TRACE, "Ask frog to add code for mgmt:%x\n", frame_type); + break; + } + + if (prGlueInfo->prAdapter != NULL) { + /* prGlueInfo->ulFlag |= GLUE_FLAG_FRAME_FILTER_AIS; */ + set_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + + if (in_interrupt()) + DBGLOG(REQ, TRACE, "It is in interrupt level\n"); + } +#if 0 + + prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + sizeof + (MSG_P2P_MGMT_FRAME_REGISTER_T)); + + if (prMgmtFrameRegister == NULL) { + ASSERT(FALSE); + break; + } + + prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; + + prMgmtFrameRegister->u2FrameType = frame_type; + prMgmtFrameRegister->fgIsRegister = reg; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); + +#endif + + } while (FALSE); + +} /* mtk_cfg80211_mgmt_frame_register */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to stay on a + * specified channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_REMAIN_ON_CHANNEL_T prMsgChnlReq = (P_MSG_REMAIN_ON_CHANNEL_T) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) + break; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + +#if 1 + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); +#endif + + *cookie = prGlueInfo->u8Cookie++; + + prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_REMAIN_ON_CHANNEL_T)); + + if (prMsgChnlReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + kalMemZero(prMsgChnlReq, sizeof(MSG_REMAIN_ON_CHANNEL_T)); + + prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_AIS_REMAIN_ON_CHANNEL; + prMsgChnlReq->u8Cookie = *cookie; + prMsgChnlReq->u4DurationMs = duration; + + prMsgChnlReq->ucChannelNum = nicFreq2ChannelNum(chan->center_freq * 1000); + + switch (chan->band) { + case NL80211_BAND_2GHZ: + prMsgChnlReq->eBand = BAND_2G4; + break; + case NL80211_BAND_5GHZ: + prMsgChnlReq->eBand = BAND_5G; + break; + default: + prMsgChnlReq->eBand = BAND_2G4; + break; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cancel staying + * on a specified channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prMsgChnlAbort = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL)) + break; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + +#if 1 + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); +#endif + + prMsgChnlAbort = + cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_CANCEL_REMAIN_ON_CHANNEL_T)); + + if (prMsgChnlAbort == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL; + prMsgChnlAbort->u8Cookie = cookie; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to send a management frame + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int +mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T) NULL; + P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; + PUINT_8 pucFrameBuf = (PUINT_8) NULL; + + do { +#if 1 + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); +#endif + + if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) + break; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + *cookie = prGlueInfo->u8Cookie++; + + /* Channel & Channel Type & Wait time are ignored. */ + prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_MGMT_TX_REQUEST_T)); + + if (prMsgTxReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->fgNoneCckRate = FALSE; + prMsgTxReq->fgIsWaitRsp = TRUE; + + prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); + prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; + if (prMsgTxReq->prMgmtMsduInfo == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->u8Cookie = *cookie; + prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX; + + pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucFrameBuf, params->buf, params->len); + + prMgmtFrame->u2FrameLength = params->len; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { + if (prMsgTxReq->prMgmtMsduInfo != NULL) + cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); + + cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); + } + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cancel the wait time + * from transmitting a management frame on another channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + /* not implemented */ + + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for handling sched_scan start/stop request + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ + +int +mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 i, u4BufLen; + P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + ASSERT(prGlueInfo); + + /* check if there is any pending scan/sched_scan not yet finished */ + if (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL) { + DBGLOG(SCN, ERROR, "(prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)\n"); + return -EBUSY; + } else if (request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM) { + DBGLOG(SCN, ERROR, "(request == NULL || request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM)\n"); + /* invalid scheduled scan request */ + return -EINVAL; + } else if (/* !request->n_ssids || */!request->n_match_sets) { + /* invalid scheduled scan request */ + return -EINVAL; + } + + prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST) kalMemAlloc(sizeof(PARAM_SCHED_SCAN_REQUEST), VIR_MEM_TYPE); + if (prSchedScanRequest == NULL) { + DBGLOG(SCN, ERROR, "(prSchedScanRequest == NULL) kalMemAlloc fail\n"); + return -ENOMEM; + } + + kalMemZero(prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST)); + + prSchedScanRequest->u4SsidNum = request->n_match_sets; + for (i = 0; i < request->n_match_sets; i++) { + if (request->match_sets == NULL || &(request->match_sets[i]) == NULL) { + prSchedScanRequest->arSsid[i].u4SsidLen = 0; + } else { + COPY_SSID(prSchedScanRequest->arSsid[i].aucSsid, + prSchedScanRequest->arSsid[i].u4SsidLen, + request->match_sets[i].ssid.ssid, request->match_sets[i].ssid.ssid_len); + } + } + + prSchedScanRequest->u4IELength = request->ie_len; + if (request->ie_len > 0) + prSchedScanRequest->pucIE = (PUINT_8) (request->ie); + + prSchedScanRequest->u2ScanInterval = (UINT_16) (request->scan_plans[0].interval); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetStartSchedScan, + prSchedScanRequest, sizeof(PARAM_SCHED_SCAN_REQUEST), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + kalMemFree(prSchedScanRequest, VIR_MEM_TYPE, sizeof(PARAM_SCHED_SCAN_REQUEST)); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(SCN, ERROR, "scheduled scan error:%x\n", rStatus); + return -EINVAL; + } + + prGlueInfo->prSchedScanRequest = request; + + return 0; +} + +int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev, u64 reqid) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* check if there is any pending scan/sched_scan not yet finished */ + if (prGlueInfo->prSchedScanRequest == NULL) { + DBGLOG(SCN, ERROR, "prGlueInfo->prSchedScanRequest == NULL\n"); + return -EBUSY; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(SCN, ERROR, "scheduled scan error, rStatus: %d\n", rStatus); + return -EINVAL; + } + + /* 1. reset first for newly incoming request */ + /* GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ + if (prGlueInfo->prSchedScanRequest != NULL) + prGlueInfo->prSchedScanRequest = NULL; + /* GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); */ + + DBGLOG(SCN, TRACE, "start work queue to send event\n"); + schedule_delayed_work(&sched_workq, 0); + DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for handling association request + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MAC_ADDRESS arBssid; +#if CFG_SUPPORT_HOTSPOT_2_0 + PUINT_8 prDesiredIE = NULL; +#endif + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &u4BufLen); + + /* 1. check BSSID */ + if (UNEQUAL_MAC_ADDR(arBssid, req->bss->bssid)) { + /* wrong MAC address */ + DBGLOG(REQ, WARN, "incorrect BSSID: [ %pM ] currently connected BSSID[ %pM ]\n", + req->bss->bssid, arBssid); + return -ENOENT; + } + + if (req->ie && req->ie_len > 0) { +#if CFG_SUPPORT_HOTSPOT_2_0 + if (wextSrchDesiredHS20IE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetHS20Info, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set HS20 assoc info error:%lx\n", rStatus); */ + } + } + + if (wextSrchDesiredInterworkingIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInterworkingInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set Interworking assoc info error:%lx\n", rStatus); */ + } + } + + if (wextSrchDesiredRoamingConsortiumIE((PUINT_8) req->ie, req->ie_len, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRoamingConsortiumIEInfo, + prDesiredIE, IE_SIZE(prDesiredIE), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[HS20] set RoamingConsortium assoc info error:%lx\n", rStatus); */ + } + } +#endif + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetBssid, + (PVOID) req->bss->bssid, MAC_ADDR_LEN, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus); + return -EINVAL; + } + + return 0; +} + +#if CONFIG_NL80211_TESTMODE +/* +#define NLA_PUT(skb, attrtype, attrlen, data) \ +do { \ + if (unlikely(nla_put(skb, attrtype, attrlen, data) < 0)) \ + goto nla_put_failure; \ +} while (0) + +#define NLA_PUT_TYPE(skb, type, attrtype, value) \ +do { \ + type __tmp = value; \ + NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \ +} while (0) + +#define NLA_PUT_U8(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u8, attrtype, value) + +#define NLA_PUT_U16(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u16, attrtype, value) + +#define NLA_PUT_U32(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u32, attrtype, value) + +#define NLA_PUT_U64(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u64, attrtype, value) +*/ +#if CFG_SUPPORT_WAPI +int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_SET_KEY_EXTS prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) NULL; + struct iw_encode_exts *prIWEncExt = (struct iw_encode_exts *)NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + UINT_32 u4BufLen = 0; + + P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; + + memset(keyStructBuf, 0, sizeof(keyStructBuf)); + + ASSERT(wiphy); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + if (data && len) { + prParams = (P_NL80211_DRIVER_SET_KEY_EXTS) data; + } else { + DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_key_ext, data is NULL\n"); + return -EINVAL; + } + + if (prParams) + prIWEncExt = (struct iw_encode_exts *)&prParams->ext; + + if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { + /* KeyID */ + prWpiKey->ucKeyID = prParams->key_index; + prWpiKey->ucKeyID--; + if (prWpiKey->ucKeyID > 1) { + /* key id is out of range */ + /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ + return -EINVAL; + } + + if (prIWEncExt->key_len != 32) { + /* key length not valid */ + /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ + return -EINVAL; + } + /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ + + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; + prWpiKey->eDirection = ENUM_WPI_RX; + } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; + prWpiKey->eDirection = ENUM_WPI_RX_TX; + } +/* #if CFG_SUPPORT_WAPI */ + /* handle_sec_msg_final(prIWEncExt->key, 32, prIWEncExt->key, NULL); */ +/* #endif */ + /* PN */ + memcpy(prWpiKey->aucPN, prIWEncExt->tx_seq, IW_ENCODE_SEQ_MAX_SIZE); + memcpy(prWpiKey->aucPN + IW_ENCODE_SEQ_MAX_SIZE, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); + + + /* BSSID */ + memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr, 6); + + memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); + prWpiKey->u4LenWPIEK = 16; + + memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); + prWpiKey->u4LenWPICK = 16; + + rstatus = kalIoctl(prGlueInfo, + wlanoidSetWapiKey, + prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rstatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ + fgIsValid = -EFAULT; + } + + } + return fgIsValid; +} +#endif + +int +mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + INT_32 i4Status = -EINVAL; + UINT_32 u4BufLen; + UINT_32 u4LinkScore; + UINT_32 u4TotalError; + UINT_32 u4TxExceedThresholdCount; + UINT_32 u4TxTotalCount; + + P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; + PARAM_GET_STA_STA_STATISTICS rQueryStaStatistics; + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + if (data && len) { + prParams = (P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS) data; + } else { + DBGLOG(QM, ERROR, "mtk_cfg80211_testmode_get_sta_statistics, data is NULL\n"); + return -EINVAL; + } +/* + if (!prParams->aucMacAddr) { + DBGLOG(QM, INFO, "%s MAC Address is NULL\n", __func__); + return -EINVAL; + } +*/ + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); + + if (!skb) { + DBGLOG(QM, ERROR, "%s allocate skb failed:%x\n", __func__, rStatus); + return -ENOMEM; + } + + DBGLOG(QM, TRACE, "Get [ %pM ] STA statistics\n", prParams->aucMacAddr); + + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, prParams->aucMacAddr); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStaStatistics, + &rQueryStaStatistics, sizeof(rQueryStaStatistics), TRUE, FALSE, TRUE, TRUE, &u4BufLen); + + /* Calcute Link Score */ + u4TxExceedThresholdCount = rQueryStaStatistics.u4TxExceedThresholdCount; + u4TxTotalCount = rQueryStaStatistics.u4TxTotalCount; + u4TotalError = rQueryStaStatistics.u4TxFailCount + rQueryStaStatistics.u4TxLifeTimeoutCount; + + /* u4LinkScore 10~100 , ExceedThreshold ratio 0~90 only */ + /* u4LinkScore 0~9 , Drop packet ratio 0~9 and all packets exceed threshold */ + if (u4TxTotalCount) { + if (u4TxExceedThresholdCount <= u4TxTotalCount) + u4LinkScore = (90 - ((u4TxExceedThresholdCount * 90) / u4TxTotalCount)); + else + u4LinkScore = 0; + } else { + u4LinkScore = 90; + } + + u4LinkScore += 10; + + if (u4LinkScore == 10) { + + if (u4TotalError <= u4TxTotalCount) + u4LinkScore = (10 - ((u4TotalError * 10) / u4TxTotalCount)); + else + u4LinkScore = 0; + + } + + if (u4LinkScore > 100) + u4LinkScore = 100; + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ + { + unsigned char __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, NL80211_DRIVER_TESTMODE_VERSION);*/ + { + unsigned char __tmp = NL80211_DRIVER_TESTMODE_VERSION; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /* NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, u4LinkScore); */ + { + unsigned int __tmp = u4LinkScore; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, prParams->aucMacAddr);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, &prParams->aucMacAddr) < 0)) + goto nla_put_failure; + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, rQueryStaStatistics.u4Flag);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4Flag; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + + /* FW part STA link status */ + /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_PER, rQueryStaStatistics.ucPer);*/ + { + unsigned char __tmp = rQueryStaStatistics.ucPer; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PER, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, rQueryStaStatistics.ucRcpi);*/ + { + unsigned char __tmp = rQueryStaStatistics.ucRcpi; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, rQueryStaStatistics.u4PhyMode);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4PhyMode; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U16(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, rQueryStaStatistics.u2LinkSpeed);*/ + { + unsigned short __tmp = rQueryStaStatistics.u2LinkSpeed; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, + sizeof(unsigned short), &__tmp) < 0)) + goto nla_put_failure; + } + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, rQueryStaStatistics.u4TxFailCount);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxFailCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, rQueryStaStatistics.u4TxLifeTimeoutCount);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxLifeTimeoutCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, rQueryStaStatistics.u4TxAverageAirTime);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxAverageAirTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /* Driver part link status */ + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, rQueryStaStatistics.u4TxTotalCount);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxTotalCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, + rQueryStaStatistics.u4TxExceedThresholdCount);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxExceedThresholdCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /*NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, + rQueryStaStatistics.u4TxAverageProcessTime);*/ + { + unsigned int __tmp = rQueryStaStatistics.u4TxAverageProcessTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + { + unsigned int __tmp = rQueryStaStatistics.u4TxMaxTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + + { + unsigned int __tmp = rQueryStaStatistics.u4TxAverageHifTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + { + unsigned int __tmp = rQueryStaStatistics.u4TxMaxHifTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, rQueryStaStatistics.u4EnqueueCounter); + */ + { + unsigned int __tmp = rQueryStaStatistics.u4EnqueueCounter; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, rQueryStaStatistics.u4DequeueCounter); + */ + { + unsigned int __tmp = rQueryStaStatistics.u4DequeueCounter; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, rQueryStaStatistics.u4EnqueueStaCounter); + */ + { + unsigned int __tmp = rQueryStaStatistics.u4EnqueueStaCounter; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, rQueryStaStatistics.u4DequeueStaCounter); + */ + { + unsigned int __tmp = rQueryStaStatistics.u4DequeueStaCounter; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, rQueryStaStatistics.IsrCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, rQueryStaStatistics.IsrPassCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrPassCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, rQueryStaStatistics.TaskIsrCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.TaskIsrCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, rQueryStaStatistics.IsrAbnormalCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrAbnormalCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, rQueryStaStatistics.IsrSoftWareCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrSoftWareCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + * NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, rQueryStaStatistics.IsrTxCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrTxCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* + *NLA_PUT_U32(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, rQueryStaStatistics.IsrRxCnt); + */ + { + unsigned int __tmp = rQueryStaStatistics.IsrRxCnt; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + /* Network counter */ + /*NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), rQueryStaStatistics.au4TcResourceEmptyCount);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), &rQueryStaStatistics.au4TcResourceEmptyCount) < 0)) + goto nla_put_failure; + /* + NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, + sizeof(rQueryStaStatistics.au4DequeueNoTcResource), rQueryStaStatistics.au4DequeueNoTcResource); + */ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, + sizeof(rQueryStaStatistics.au4DequeueNoTcResource), &rQueryStaStatistics.au4DequeueNoTcResource) < 0)) + goto nla_put_failure; + /* + NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceBackCount), rQueryStaStatistics.au4TcResourceBackCount); + */ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceBackCount), &rQueryStaStatistics.au4TcResourceBackCount) < 0)) + goto nla_put_failure; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceUsedCount), &rQueryStaStatistics.au4TcResourceUsedCount) < 0)) + goto nla_put_failure; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceWantedCount), + &rQueryStaStatistics.au4TcResourceWantedCount) < 0)) + goto nla_put_failure; + + /* Sta queue length */ + /*NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcQueLen), rQueryStaStatistics.au4TcQueLen);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcQueLen), &rQueryStaStatistics.au4TcQueLen) < 0)) + goto nla_put_failure; + + + /* Global QM counter */ + /*NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcAverageQueLen), rQueryStaStatistics.au4TcAverageQueLen);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcAverageQueLen), &rQueryStaStatistics.au4TcAverageQueLen) < 0)) + goto nla_put_failure; + + /*NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcCurrentQueLen), rQueryStaStatistics.au4TcCurrentQueLen);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcCurrentQueLen), &rQueryStaStatistics.au4TcCurrentQueLen) < 0)) + goto nla_put_failure; + + + /* Reserved field */ + /*NLA_PUT(skb, + NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, + sizeof(rQueryStaStatistics.au4Reserved), rQueryStaStatistics.au4Reserved);*/ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, + sizeof(rQueryStaStatistics.au4Reserved), &rQueryStaStatistics.au4Reserved) < 0)) + goto nla_put_failure; + + i4Status = cfg80211_testmode_reply(skb); + skb = NULL; + +nla_put_failure: + if (skb != NULL) + kfree_skb(skb); + return i4Status; +} + +int +mtk_cfg80211_testmode_get_link_detection(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) +{ + + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + INT_32 i4Status = -EINVAL; + UINT_32 u4BufLen; + + PARAM_802_11_STATISTICS_STRUCT_T rStatistics; + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(PARAM_GET_STA_STA_STATISTICS) + 1); + + if (!skb) { + DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); + return -ENOMEM; + } + + kalMemZero(&rStatistics, sizeof(rStatistics)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStatistics, + &rStatistics, sizeof(rStatistics), TRUE, TRUE, TRUE, FALSE, &u4BufLen); + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0);*/ + { + unsigned char __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, rStatistics.rFailedCount.QuadPart);*/ + { + u64 __tmp = rStatistics.rFailedCount.QuadPart; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_FAIL_CNT, + sizeof(u64), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, rStatistics.rRetryCount.QuadPart);*/ + { + u64 __tmp = rStatistics.rFailedCount.QuadPart; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_RETRY_CNT, + sizeof(u64), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, rStatistics.rMultipleRetryCount.QuadPart);*/ + { + u64 __tmp = rStatistics.rMultipleRetryCount.QuadPart; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, + sizeof(u64), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, rStatistics.rACKFailureCount.QuadPart);*/ + { + u64 __tmp = rStatistics.rACKFailureCount.QuadPart; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_ACK_FAIL_CNT, + sizeof(u64), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U64(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, rStatistics.rFCSErrorCount.QuadPart);*/ + { + u64 __tmp = rStatistics.rFCSErrorCount.QuadPart; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_LINK_FCS_ERR_CNT, + sizeof(u64), &__tmp) < 0)) + goto nla_put_failure; + } + + + i4Status = cfg80211_testmode_reply(skb); + skb = NULL; + +nla_put_failure: + if (skb != NULL) + kfree_skb(skb); + return i4Status; +} + +int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + UINT_32 u4SetInfoLen = 0; + + ASSERT(wiphy); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + if (data && len) + prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; + + if (prParams) { + if (prParams->set == 1) { + rstatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, + &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + } + } + + if (WLAN_STATUS_SUCCESS != rstatus) + fgIsValid = -EFAULT; + + return fgIsValid; +} + +#if CFG_SUPPORT_HOTSPOT_2_0 +int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct wpa_driver_hs20_data_s *prParams = NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + UINT_32 u4SetInfoLen = 0; + + ASSERT(wiphy); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + DBGLOG(REQ, TRACE, "--> %s()\n", __func__); + + if (data && len) { + prParams = (struct wpa_driver_hs20_data_s *)data; + + DBGLOG(REQ, TRACE, "[%s] Cmd Type (%d)\n", __func__, prParams->CmdType); + } + + if (prParams) { + int i; + + switch (prParams->CmdType) { + case HS20_CMD_ID_SET_BSSID_POOL: + DBGLOG(REQ, TRACE, "fgBssidPoolIsEnable=%d, ucNumBssidPool=%d\n", + prParams->hs20_set_bssid_pool.fgBssidPoolIsEnable, + prParams->hs20_set_bssid_pool.ucNumBssidPool); + for (i = 0; i < prParams->hs20_set_bssid_pool.ucNumBssidPool; i++) { + DBGLOG(REQ, TRACE, "[%d][ %pM ]\n", i, + (prParams->hs20_set_bssid_pool.arBssidPool[i])); + } + rstatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC) wlanoidSetHS20BssidPool, + &prParams->hs20_set_bssid_pool, + sizeof(struct param_hs20_set_bssid_pool), + FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + break; + default: + DBGLOG(REQ, TRACE, "[%s] Unknown Cmd Type (%d)\n", __func__, prParams->CmdType); + rstatus = WLAN_STATUS_FAILURE; + + } + + } + + if (WLAN_STATUS_SUCCESS != rstatus) + fgIsValid = -EFAULT; + + return fgIsValid; +} + +#endif +int +mtk_cfg80211_testmode_set_poorlink_param(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) +{ + int fgIsValid = 0; + P_NL80211_DRIVER_POORLINK_PARAMS prParams = NULL; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + if (data && len) { + prParams = (P_NL80211_DRIVER_POORLINK_PARAMS) data; + } else { + DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_set_poorlink_param, data is NULL\n"); + return -EINVAL; + } + if (prParams->ucLinkSpeed) + prGlueInfo->u4LinkspeedThreshold = prParams->ucLinkSpeed * 10; + if (prParams->cRssi) + prGlueInfo->i4RssiThreshold = prParams->cRssi; + if (!prGlueInfo->fgPoorlinkValid) + prGlueInfo->fgPoorlinkValid = 1; +#if 0 + DBGLOG(REQ, TRACE, "poorlink set param valid(%d)rssi(%d)linkspeed(%d)\n", + prGlueInfo->fgPoorlinkValid, prGlueInfo->i4RssiThreshold, prGlueInfo->u4LinkspeedThreshold); +#endif + + return fgIsValid; + +} + +int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) NULL; + INT_32 i4Status = -EINVAL; +#if CFG_SUPPORT_HOTSPOT_2_0 + BOOLEAN fgIsValid = 0; +#endif + + ASSERT(wiphy); + ASSERT(wdev); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + if (data && len) { + prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS) data; + } else { + DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd, data is NULL\n"); + return i4Status; + } + + /* Clear the version byte */ + prParams->index = prParams->index & ~BITS(24, 31); + + if (prParams) { + switch (prParams->index) { + case TESTMODE_CMD_ID_SW_CMD: /* SW cmd */ + i4Status = mtk_cfg80211_testmode_sw_cmd(wiphy, data, len); + break; + case TESTMODE_CMD_ID_WAPI: /* WAPI */ +#if CFG_SUPPORT_WAPI + i4Status = mtk_cfg80211_testmode_set_key_ext(wiphy, data, len); +#endif + break; + case TESTMODE_CMD_ID_SUSPEND: + { + P_NL80211_DRIVER_SUSPEND_PARAMS prParams = (P_NL80211_DRIVER_SUSPEND_PARAMS) data; + + if (prParams->suspend == 1) { + wlanHandleSystemSuspend(); + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + p2pHandleSystemSuspend(); + i4Status = 0; + } else if (prParams->suspend == 0) { + wlanHandleSystemResume(); + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + p2pHandleSystemResume(); + i4Status = 0; + } + break; + } + case TESTMODE_CMD_ID_STATISTICS: + i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); + break; + case TESTMODE_CMD_ID_LINK_DETECT: + i4Status = mtk_cfg80211_testmode_get_link_detection(wiphy, data, len, prGlueInfo); + break; + case TESTMODE_CMD_ID_POORLINK: + i4Status = mtk_cfg80211_testmode_set_poorlink_param(wiphy, data, len, prGlueInfo); + break; + +#if CFG_SUPPORT_HOTSPOT_2_0 + case TESTMODE_CMD_ID_HS20: + if (mtk_cfg80211_testmode_hs20_cmd(wiphy, data, len)) + fgIsValid = TRUE; + break; +#endif + default: + i4Status = -EINVAL; + break; + } + } + + return i4Status; +} + +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) +{ +#define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0 +#define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1 + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + INT_32 i4Status = -EINVAL, READY_TO_BEAM = 0; + +/* P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; */ + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(UINT_32)); + READY_TO_BEAM = + (UINT_32) (prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo. + fgIsGOInitialDone) & + (!prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); + DBGLOG(QM, TRACE, + "NFC:GOInitialDone[%d] and P2PScanning[%d]\n", + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone, + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); + + if (!skb) { + DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); + return -ENOMEM; + } + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, 0);*/ + { + unsigned char __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + /*NLA_PUT_U32(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, READY_TO_BEAM);*/ + { + unsigned int __tmp = READY_TO_BEAM; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + + i4Status = cfg80211_testmode_reply(skb); + skb = NULL; + +nla_put_failure: + if (skb != NULL) + kfree_skb(skb); + return i4Status; +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +int +mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo) +{ +#define MAXMUN_2_4G_CHA_NUM 14 +#define CHN_DIRTY_WEIGHT_UPPERBOUND 4 + + BOOLEAN fgIsReady = FALSE, fgIsFistRecord = TRUE; + BOOLEAN fgIsPureAP, fgIsLteSafeChn = FALSE; + + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_8 ucIdx = 0, ucMax_24G_Chn_List = 11, ucDefaultIdx = 0, ucArrayIdx = 0; + UINT_16 u2APNumScore = 0, u2UpThreshold = 0, u2LowThreshold = 0, ucInnerIdx = 0; + INT_32 i4Status = -EINVAL; + UINT_32 u4BufLen, u4LteSafeChnBitMask_2_4G = 0; + UINT32 AcsChnReport[4]; + /*RF_CHANNEL_INFO_T aucChannelList[MAXMUN_2_4G_CHA_NUM];*/ + + struct sk_buff *skb; + + /*PARAM_GET_CHN_LOAD rQueryLTEChn;*/ + P_PARAM_GET_CHN_LOAD prQueryLTEChn; + PARAM_PREFER_CHN_INFO rPreferChannels[2], ar2_4G_ChannelLoadingWeightScore[MAXMUN_2_4G_CHA_NUM]; + P_PARAM_CHN_LOAD_INFO prChnLoad; + P_PARAM_GET_CHN_LOAD prGetChnLoad; + + P_DOMAIN_INFO_ENTRY prDomainInfo; + +/* + P_PARAM_GET_CHN_LOAD prParams = NULL; +*/ + ASSERT(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(rPreferChannels, sizeof(rPreferChannels)); + fgIsPureAP = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode; +#if 0 + if (data && len) + prParams = (P_NL80211_DRIVER_GET_LTE_PARAMS) data; +#endif + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(AcsChnReport) + sizeof(UINT8) + 1); + if (!skb) { + DBGLOG(QM, TRACE, "%s allocate skb failed:%x\n", __func__, rStatus); + return -ENOMEM; + } + + DBGLOG(P2P, INFO, "[Auto Channel]Get LTE Channels\n"); + prQueryLTEChn = kalMemAlloc(sizeof(PARAM_GET_CHN_LOAD), VIR_MEM_TYPE); + if (prQueryLTEChn == NULL) { + DBGLOG(QM, TRACE, "alloc QueryLTEChn fail\n"); + kalMemFree(skb, VIR_MEM_TYPE, sizeof(struct sk_buff)); + return -ENOMEM; + } + kalMemZero(prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD)); + + /* Query LTE Safe Channels */ + prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] + = 0xFFFFFFFF; + + prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] + = 0xFFFFFFFF; + + prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] + = 0xFFFFFFFF; + + prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = + 0xFFFFFFFF; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryACSChannelList, prQueryLTEChn, sizeof(PARAM_GET_CHN_LOAD), + TRUE, FALSE, TRUE, TRUE, &u4BufLen); +#if 0 + if (fgIsPureAP) { + + AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = 0x20; /* Channel 6 */ + } else +#endif + { + fgIsReady = prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit; + rPreferChannels[0].u2APNum = 0xFFFF; + rPreferChannels[1].u2APNum = 0xFFFF; + + /* 4 In LTE Mode, Hotspot pick up channels from ch4. */ + ucDefaultIdx = 0; + /* + if (fgIsPureAP) { + ucDefaultIdx=3; //SKIP LTE Channels 1~3 + } + */ + + /* 4 Get the Maximun channel List in 2.4G Bands */ + + prDomainInfo = rlmDomainGetDomainInfo(prGlueInfo->prAdapter); + ASSERT(prDomainInfo); + + /* 4 ToDo: Enable Step 2 only if we could get Country Code from framework */ + /* 4 2. Get current domain channel list */ + +#if 0 + rlmDomainGetChnlList(prGlueInfo->prAdapter, + BAND_2G4, MAXMUN_2_4G_CHA_NUM, &ucMax_24G_Chn_List, aucChannelList); +#endif + + prGetChnLoad = (P_PARAM_GET_CHN_LOAD) &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); + for (ucIdx = 0; ucIdx < ucMax_24G_Chn_List; ucIdx++) { + DBGLOG(P2P, INFO, + "[Auto Channel] ch[%d]=%d\n", ucIdx, + prGetChnLoad->rEachChnLoad[ucIdx + ucInnerIdx].u2APNum); + } + + /*Calculate Each Channel Direty Score */ + for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { + +#if 1 + u2APNumScore = prGetChnLoad->rEachChnLoad[ucIdx].u2APNum * CHN_DIRTY_WEIGHT_UPPERBOUND; + u2UpThreshold = u2LowThreshold = 3; + + if (ucIdx < 3) { + u2UpThreshold = ucIdx; + u2LowThreshold = 3; + } else if (ucIdx >= (ucMax_24G_Chn_List - 3)) { + u2UpThreshold = 3; + u2LowThreshold = ucMax_24G_Chn_List - (ucIdx + 1); + + } + + /*Calculate Lower Channel Dirty Score */ + for (ucInnerIdx = 0; ucInnerIdx < u2LowThreshold; ucInnerIdx++) { + ucArrayIdx = ucIdx + ucInnerIdx + 1; + if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { + u2APNumScore += + (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * + (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); + } + } + + /*Calculate Upper Channel Dirty Score */ + for (ucInnerIdx = 0; ucInnerIdx < u2UpThreshold; ucInnerIdx++) { + ucArrayIdx = ucIdx - ucInnerIdx - 1; + if (ucArrayIdx < MAX_AUTO_CHAL_NUM) { + u2APNumScore += + (prGetChnLoad->rEachChnLoad[ucArrayIdx].u2APNum * + (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); + } + } + + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; + + DBGLOG(P2P, INFO, "[Auto Channel]chn=%d score=%d\n", ucIdx, u2APNumScore); +#else + if (ucIdx == 0) { + /* ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = + (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + + prGetChnLoad->rEachChnLoad[ucIdx+1].u2APNum*0.75); */ + u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) + ((3 * + (prGetChnLoad-> + rEachChnLoad[ucIdx + + 1]. + u2APNum + + prGetChnLoad-> + rEachChnLoad[ucIdx + + 2]. + u2APNum)) / 4))); + + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; + DBGLOG(P2P, INFO, + "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum)); + } + if ((ucIdx > 0) && (ucIdx < (MAXMUN_2_4G_CHA_NUM - 1))) { + u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + ((UINT_16) + ((3 * + (prGetChnLoad-> + rEachChnLoad[ucIdx + + 1]. + u2APNum + + prGetChnLoad-> + rEachChnLoad[ucIdx - + 1]. + u2APNum)) / 4))); + + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; + DBGLOG(P2P, INFO, + "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d+0.75*%d\n", ucIdx, + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx + 1].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); + } + + if (ucIdx == (MAXMUN_2_4G_CHA_NUM - 1)) { + u2APNumScore = (prGetChnLoad->rEachChnLoad[ucIdx].u2APNum + + ((UINT_16) ((3 * prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum) / 4))); + + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum = u2APNumScore; + DBGLOG(P2P, INFO, + "[Auto Channel]ucIdx=%d score=%d=%d+0.75*%d\n", ucIdx, + ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, + prGetChnLoad->rEachChnLoad[ucIdx - 1].u2APNum)); + } +#endif + + } + + u4LteSafeChnBitMask_2_4G = + prQueryLTEChn->rLteSafeChnList.au4SafeChannelBitmask[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; + + /*Find out the best channel */ + for (ucIdx = ucDefaultIdx; ucIdx < ucMax_24G_Chn_List; ucIdx++) { + /* 4 Skip LTE Unsafe Channel */ + fgIsLteSafeChn = ((u4LteSafeChnBitMask_2_4G & BIT(ucIdx + 1)) >> ucIdx); + if (!fgIsLteSafeChn) + continue; + + prChnLoad = + (P_PARAM_CHN_LOAD_INFO) &(prGlueInfo->prAdapter->rWifiVar. + rChnLoadInfo.rEachChnLoad[ucIdx]); + if (rPreferChannels[0].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum) { + rPreferChannels[1].ucChannel = rPreferChannels[0].ucChannel; + rPreferChannels[1].u2APNum = rPreferChannels[0].u2APNum; + + rPreferChannels[0].ucChannel = ucIdx; + rPreferChannels[0].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; + } else { + if (rPreferChannels[1].u2APNum >= ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum + || fgIsFistRecord == 1) { + fgIsFistRecord = FALSE; + rPreferChannels[1].ucChannel = ucIdx; + rPreferChannels[1].u2APNum = ar2_4G_ChannelLoadingWeightScore[ucIdx].u2APNum; + } + } + } + /* AcsChnRepot[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1-1] = + BITS((rQueryLTEChn.rLteSafeChnList.ucChannelLow-1),(rQueryLTEChn.rLteSafeChnList.ucChannelHigh-1)); */ + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] = fgIsReady ? BIT(31) : 0; + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1] |= BIT(rPreferChannels[0].ucChannel); + } + + /* ToDo: Support 5G Channel Selection */ + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1] = 0x11223344; + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1] = 0x55667788; + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1] = 0x99AABBCC; + + /*NLA_PUT_U8(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, 0);*/ + { + unsigned char __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_INVALID, sizeof(unsigned char), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]);*/ + { + unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1 - 1]; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]);*/ + { + unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34 - 1]; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]);*/ + { + unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149 - 1]; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + + /*NLA_PUT_U32(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, + AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]);*/ + { + unsigned int __tmp = AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184 - 1]; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + DBGLOG(P2P, INFO, + "[Auto Channel]Relpy AcsChanInfo[%x:%x:%x:%x]\n", AcsChnReport[0], AcsChnReport[1], AcsChnReport[2], + AcsChnReport[3]); + + i4Status = cfg80211_testmode_reply(skb); + /*need confirm cfg80211_testmode_reply will free skb*/ + skb = NULL; + /*kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD));*/ + +nla_put_failure: + kalMemFree(prQueryLTEChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_LOAD)); + if (skb != NULL) + kfree_skb(skb); + return i4Status; + +} +#endif +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief cfg80211 suspend callback, will be invoked in wiphy_suspend + * + * @param wiphy: pointer to wiphy + * wow: pointer to cfg80211_wowlan + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + if (kalHaltTryLock()) + return 0; + + if (kalIsHalted() || !wiphy) + goto end; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + set_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prGlueInfo->prAdapter->ulSuspendFlag); + set_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prGlueInfo->prAdapter->ulSuspendFlag); +end: + kalHaltUnlock(); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief cfg80211 resume callback, will be invoked in wiphy_resume. + * + * @param wiphy: pointer to wiphy + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_resume(struct wiphy *wiphy) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_BSS_DESC_T *pprBssDesc = NULL; + P_ADAPTER_T prAdapter = NULL; + UINT_8 i = 0; + + if (kalHaltTryLock()) + return 0; + + if (kalIsHalted() || !wiphy) + goto end; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + prAdapter = prGlueInfo->prAdapter; + clear_bit(SUSPEND_FLAG_CLEAR_WHEN_RESUME, &prAdapter->ulSuspendFlag); + pprBssDesc = &prAdapter->rWifiVar.rScanInfo.rNloParam.aprPendingBssDescToInd[0]; + for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { + if (pprBssDesc[i] == NULL) + break; + if (pprBssDesc[i]->u2RawLength == 0) + continue; + kalIndicateBssInfo(prGlueInfo, + (PUINT_8) pprBssDesc[i]->aucRawBuf, + pprBssDesc[i]->u2RawLength, + pprBssDesc[i]->ucChannelNum, + RCPI_TO_dBm(pprBssDesc[i]->ucRCPI)); + } + DBGLOG(SCN, INFO, "pending %d sched scan results\n", i); + if (i > 0) + kalMemZero(&pprBssDesc[0], i * sizeof(P_BSS_DESC_T)); +end: + kalHaltUnlock(); + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c new file mode 100644 index 0000000000000..abe366585d059 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_init.c @@ -0,0 +1,3501 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_init.c#7 +*/ + +/*! \file gl_init.c + \brief Main routines of Linux driver + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_init.c +** +** 09 03 2013 cp.wu +** add path for reassociation + * + * 07 17 2012 yuche.tsai + * NULL + * Fix compile error. + * + * 07 17 2012 yuche.tsai + * NULL + * Fix compile error for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 05 25 2012 yuche.tsai + * NULL + * Fix reset KE issue. + * + * 05 11 2012 cp.wu + * [WCXRP00001237] [MT6620 Wi-Fi][Driver] Show MAC address and MAC address source for ACS's convenience + * show MAC address & source while initiliazation + * + * 03 02 2012 terry.wu + * NULL + * EXPORT_SYMBOL(rsnParseCheckForWFAInfoElem);. + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 03 02 2012 terry.wu + * NULL + * Sync CFG80211 modification from branch 2,2. + * + * 03 02 2012 terry.wu + * NULL + * Enable CFG80211 Support. + * + * 12 22 2011 george.huang + * [WCXRP00000905] [MT6628 Wi-Fi][FW] Code refinement for ROM/ RAM module dependency + * using global variable instead of stack for setting wlanoidSetNetworkAddress(), due to buffer may be released before + * TX thread handling + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 14 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Fix large network type index assert in FW issue. + * + * 11 14 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 06 2011 eddie.chen + * [WCXRP00001027] [MT6628 Wi-Fi][Firmware/Driver] Tx fragmentation + * Add rlmDomainGetChnlList symbol. + * + * 09 22 2011 cm.chang + * NULL + * Safer writng stype to avoid unitialized regitry structure + * + * 09 21 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Avoid possible structure alignment problem + * + * 09 20 2011 chinglan.wang + * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. + * . + * + * 09 08 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * Use new fields ucChannelListMap and ucChannelListIndex in NVRAM + * + * 08 31 2011 cm.chang + * [WCXRP00000969] [MT6620 Wi-Fi][Driver][FW] Channel list for 5G band based on country code + * . + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * expose scnQuerySparseChannel() for P2P-FSM. + * + * 08 11 2011 cp.wu + * [WCXRP00000830] [MT6620 Wi-Fi][Firmware] Use MDRDY counter to detect empty channel for shortening scan time + * sparse channel detection: + * driver: collect sparse channel information with scan-done event + * + * 08 02 2011 yuche.tsai + * [WCXRP00000896] [Volunteer Patch][WiFi Direct][Driver] GO with multiple client, TX deauth to a disconnecting + * device issue. + * Fix GO send deauth frame issue. + * + * 07 07 2011 wh.su + * [WCXRP00000839] [MT6620 Wi-Fi][Driver] Add the dumpMemory8 and dumpMemory32 EXPORT_SYMBOL + * Add the dumpMemory8 symbol export for debug mode. + * + * 07 06 2011 terry.wu + * [WCXRP00000735] [MT6620 Wi-Fi][BoW][FW/Driver] Protect BoW connection establishment + * Improve BoW connection establishment speed. + * + * 07 05 2011 yuche.tsai + * [WCXRP00000821] [Volunteer Patch][WiFi Direct][Driver] WiFi Direct Connection Speed Issue + * Export one symbol for enhancement. + * + * 06 13 2011 eddie.chen + * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni + * Add tx rx statistics and netif_rx_ni. + * + * 05 27 2011 cp.wu + * [WCXRP00000749] [MT6620 Wi-Fi][Driver] Add band edge tx power control to Wi-Fi NVRAM + * invoke CMD_ID_SET_EDGE_TXPWR_LIMIT when there is valid data exist in NVRAM content. + * + * 05 18 2011 cp.wu + * [WCXRP00000734] [MT6620 Wi-Fi][Driver] Pass PHY_PARAM in NVRAM to firmware domain + * pass PHY_PARAM in NVRAM from driver to firmware. + * + * 05 09 2011 jeffrey.chang + * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change + * support ARP filter through kernel notifier + * + * 05 03 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Use kalMemAlloc to allocate event buffer for kalIndicateBOWEvent. + * + * 04 27 2011 george.huang + * [WCXRP00000684] [MT6620 Wi-Fi][Driver] Support P2P setting ARP filter + * Support P2P ARP filter setting on early suspend/ late resume + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Modify some driver connection flow or behavior to pass Sigma test more easier.. + * + * 04 12 2011 cm.chang + * [WCXRP00000634] [MT6620 Wi-Fi][Driver][FW] 2nd BSS will not support 40MHz bandwidth for concurrency + * . + * + * 04 11 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * export wlan functions to p2p + * + * 04 08 2011 pat.lu + * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver + * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver + * + * 04 08 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * glBusFreeIrq() should use the same pvCookie as glBusSetIrq() or request_irq()/free_irq() won't work as a pair. + * + * 04 08 2011 eddie.chen + * [WCXRP00000617] [MT6620 Wi-Fi][DRV/FW] Fix for sigma + * Fix for sigma + * + * 04 06 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * 1. do not check for pvData inside wlanNetCreate() due to it is NULL for eHPI port + * 2. update perm_addr as well for MAC address + * 3. not calling check_mem_region() anymore for eHPI + * 4. correct MSC_CS macro for 0-based notation + * + * 03 29 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * fix typo. + * + * 03 29 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism + * + * 03 23 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * apply multi-queue operation only for linux kernel > 2.6.26 + * + * 03 22 2011 pat.lu + * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build + * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability for compatible with linux 2.6.12. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * improve portability for awareness of early version of linux kernel and wireless extension. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 03 18 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * remove early suspend functions + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * reverse order to prevent probing racing. + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similar APIs to hide the difference. + * + * 03 15 2011 jeffrey.chang + * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM + * refine the queue_select function + * + * 03 10 2011 cp.wu + * [WCXRP00000532] [MT6620 Wi-Fi][Driver] Migrate NVRAM configuration procedures from MT6620 E2 to MT6620 E3 + * deprecate configuration used by MT6620 E2 + * + * 03 10 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Remove unnecessary assert and message. + * + * 03 08 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Export nicQmUpdateWmmParms. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 02 24 2011 george.huang + * [WCXRP00000495] [MT6620 Wi-Fi][FW] Support pattern filter for unwanted ARP frames + * Support ARP filter during suspended + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 02 17 2011 terry.wu + * [WCXRP00000459] [MT6620 Wi-Fi][Driver] Fix deference null pointer problem in wlanRemove + * Fix deference a null pointer problem in wlanRemove. + * + * 02 16 2011 jeffrey.chang + * NULL + * fix compilig error + * + * 02 16 2011 jeffrey.chang + * NULL + * Add query ipv4 and ipv6 address during early suspend and late resume + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 02 11 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add one more export symbol. + * + * 02 10 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add RX deauthentication & disassociation process under Hot-Spot mode. + * + * 02 09 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Halt p2p module init and exit until TxThread finished p2p register and unregister. + * + * 02 08 2011 george.huang + * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler + * Support querying power mode OID. + * + * 02 08 2011 yuche.tsai + * [WCXRP00000421] [Volunteer Patch][MT6620][Driver] Fix incorrect SSID length Issue + * Export Deactivation Network. + * + * 02 01 2011 jeffrey.chang + * [WCXRP00000414] KAL Timer is not unregistered when driver not loaded + * Unregister the KAL timer during driver unloading + * + * 01 26 2011 cm.chang + * [WCXRP00000395] [MT6620 Wi-Fi][Driver][FW] Search STA_REC with additional net type index argument + * Allocate system RAM if fixed message or mgmt buffer is not available + * + * 01 19 2011 cp.wu + * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 + * add compile option to check linux version 2.6.35 for different usage of system API to improve portability + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues + * due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 15 2010 cp.wu + * [WCXRP00000265] [MT6620 Wi-Fi][Driver] Remove set_mac_address routine from legacy Wi-Fi Android driver + * remove set MAC address. MAC address is always loaded from NVRAM instead. + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] + * Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 21 2010 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * . + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK + * HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000106] [MT6620 Wi-Fi][Driver] Enable setting multicast callback in Android + * . + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 27 2010 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000065] Update BoW design and settings + * Update BCM/BoW design and settings. + * + * 09 23 2010 cp.wu + * [WCXRP00000051] [MT6620 Wi-Fi][Driver] WHQL test fail in MAC address changed item + * use firmware reported mac address right after wlanAdapterStart() as permanent address + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 16 2010 yarco.yang + * NULL + * Support Linux x86 + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 jeffrey.chang + * NULL + * fix memory leak for module unloading + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 23 2010 jeffrey.chang + * + * bug fix: allocate regInfo when disabling firmware download + * + * 07 23 2010 jeffrey.chang + * + * use glue layer api to decrease or increase counter atomically + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power management macro + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Query statistics from firmware + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * modify tcp/ip checksum offload flags + * + * 04 16 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix tcp/ip checksum offload bug + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler + * * * * * * * * * * * * * * * * * capability + * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set MAC address from firmware + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * are done in adapter layer. + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)improve none-glue code portability + * * (2) disable set Multicast address during atomic context + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding debug module + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix f/w download start and load address by using config.h + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download support + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\52 2009-10-27 22:49:59 GMT mtk01090 +** Fix compile error for Linux EHPI driver +** \main\maintrunk.MT5921\51 2009-10-20 17:38:22 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, +** and then stop hw. +** \main\maintrunk.MT5921\50 2009-10-08 10:33:11 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input +** parameters and pointers. +** \main\maintrunk.MT5921\49 2009-09-28 20:19:05 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\48 2009-09-03 13:58:46 GMT mtk01088 +** remove non-used code +** \main\maintrunk.MT5921\47 2009-09-03 11:40:25 GMT mtk01088 +** adding the module parameter for wapi +** \main\maintrunk.MT5921\46 2009-08-18 22:56:41 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\45 2009-07-06 20:53:00 GMT mtk01088 +** adding the code to check the wapi 1x frame +** \main\maintrunk.MT5921\44 2009-06-23 23:18:55 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\43 2009-02-16 23:46:51 GMT mtk01461 +** Revise the order of increasing u4TxPendingFrameNum because of CFG_TX_RET_TX_CTRL_EARLY +** \main\maintrunk.MT5921\42 2009-01-22 13:11:59 GMT mtk01088 +** set the tid and 1x value at same packet reserved field +** \main\maintrunk.MT5921\41 2008-10-20 22:43:53 GMT mtk01104 +** Fix wrong variable name "prDev" in wlanStop() +** \main\maintrunk.MT5921\40 2008-10-16 15:37:10 GMT mtk01461 +** add handle WLAN_STATUS_SUCCESS in wlanHardStartXmit() for CFG_TX_RET_TX_CTRL_EARLY +** \main\maintrunk.MT5921\39 2008-09-25 15:56:21 GMT mtk01461 +** Update driver for Code review +** \main\maintrunk.MT5921\38 2008-09-05 17:25:07 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\37 2008-09-02 10:57:06 GMT mtk01461 +** Update driver for code review +** \main\maintrunk.MT5921\36 2008-08-05 01:53:28 GMT mtk01461 +** Add support for linux statistics +** \main\maintrunk.MT5921\35 2008-08-04 16:52:58 GMT mtk01461 +** Fix ASSERT if removing module in BG_SSID_SCAN state +** \main\maintrunk.MT5921\34 2008-06-13 22:52:24 GMT mtk01461 +** Revise status code handling in wlanHardStartXmit() for WLAN_STATUS_SUCCESS +** \main\maintrunk.MT5921\33 2008-05-30 18:56:53 GMT mtk01461 +** Not use wlanoidSetCurrentAddrForLinux() +** \main\maintrunk.MT5921\32 2008-05-30 14:39:40 GMT mtk01461 +** Remove WMM Assoc Flag +** \main\maintrunk.MT5921\31 2008-05-23 10:26:40 GMT mtk01084 +** modify wlanISR interface +** \main\maintrunk.MT5921\30 2008-05-03 18:52:36 GMT mtk01461 +** Fix Unset Broadcast filter when setMulticast +** \main\maintrunk.MT5921\29 2008-05-03 15:17:26 GMT mtk01461 +** Move Query Media Status to GLUE +** \main\maintrunk.MT5921\28 2008-04-24 22:48:21 GMT mtk01461 +** Revise set multicast function by using windows oid style for LP own back +** \main\maintrunk.MT5921\27 2008-04-24 12:00:08 GMT mtk01461 +** Fix multicast setting in Linux and add comment +** \main\maintrunk.MT5921\26 2008-03-28 10:40:22 GMT mtk01461 +** Fix set mac address func in Linux +** \main\maintrunk.MT5921\25 2008-03-26 15:37:26 GMT mtk01461 +** Add set MAC Address +** \main\maintrunk.MT5921\24 2008-03-26 14:24:53 GMT mtk01461 +** For Linux, set net_device has feature with checksum offload by default +** \main\maintrunk.MT5921\23 2008-03-11 14:50:52 GMT mtk01461 +** Fix typo +** \main\maintrunk.MT5921\22 2008-02-29 15:35:20 GMT mtk01088 +** add 1x decide code for sw port control +** \main\maintrunk.MT5921\21 2008-02-21 15:01:54 GMT mtk01461 +** Rearrange the set off place of GLUE spin lock in HardStartXmit +** \main\maintrunk.MT5921\20 2008-02-12 23:26:50 GMT mtk01461 +** Add debug option - Packet Order for Linux and add debug level - Event +** \main\maintrunk.MT5921\19 2007-12-11 00:11:12 GMT mtk01461 +** Fix SPIN_LOCK protection +** \main\maintrunk.MT5921\18 2007-11-30 17:02:25 GMT mtk01425 +** 1. Set Rx multicast packets mode before setting the address list +** \main\maintrunk.MT5921\17 2007-11-26 19:44:24 GMT mtk01461 +** Add OS_TIMESTAMP to packet +** \main\maintrunk.MT5921\16 2007-11-21 15:47:20 GMT mtk01088 +** fixed the unload module issue +** \main\maintrunk.MT5921\15 2007-11-07 18:37:38 GMT mtk01461 +** Fix compile warnning +** \main\maintrunk.MT5921\14 2007-11-02 01:03:19 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\13 2007-10-30 10:42:33 GMT mtk01425 +** 1. Refine for multicast list +** \main\maintrunk.MT5921\12 2007-10-25 18:08:13 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +** Revision 1.4 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:50 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_os.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "gl_cfg80211.h" +#include "precomp.h" +#if CFG_SUPPORT_AGPS_ASSIST +#include "gl_kal.h" +#endif +#if defined(CONFIG_MTK_TC1_FEATURE) +#include +#endif +#include "gl_vendor.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* #define MAX_IOREQ_NUM 10 */ + +BOOLEAN fgIsUnderSuspend = false; + + +#if CFG_ENABLE_WIFI_DIRECT +spinlock_t g_p2p_lock; +int g_u4P2PEnding = 0; +int g_u4P2POnOffing = 0; +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Tasklet mechanism is like buttom-half in Linux. We just want to + * send a signal to OS for interrupt defer processing. All resources + * are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty. + */ +typedef struct _WLANDEV_INFO_T { + struct net_device *prDev; +} WLANDEV_INFO_T, *P_WLANDEV_INFO_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#define CHAN2G(_channel, _freq, _flags) \ +{ \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_channel mtk_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +#define CHAN5G(_channel, _flags) \ +{ \ + .band = NL80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_channel mtk_5ghz_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(169, 0), CHAN5G(173, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +#define RATETAB_ENT(_rate, _rateid, _flags) \ +{ \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ +} + +/* for cfg80211 - rate table */ +static struct ieee80211_rate mtk_rates[] = { + RATETAB_ENT(10, 0x1000, 0), + RATETAB_ENT(20, 0x1001, 0), + RATETAB_ENT(55, 0x1002, 0), + RATETAB_ENT(110, 0x1003, 0), /* 802.11b */ + RATETAB_ENT(60, 0x2000, 0), + RATETAB_ENT(90, 0x2001, 0), + RATETAB_ENT(120, 0x2002, 0), + RATETAB_ENT(180, 0x2003, 0), + RATETAB_ENT(240, 0x2004, 0), + RATETAB_ENT(360, 0x2005, 0), + RATETAB_ENT(480, 0x2006, 0), + RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */ +}; + +#define mtk_a_rates (mtk_rates + 4) +#define mtk_a_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 4) +#define mtk_g_rates (mtk_rates + 0) +#define mtk_g_rates_size (sizeof(mtk_rates) / sizeof(mtk_rates[0]) - 0) + +#define WLAN_MCS_INFO \ +{ \ + .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},\ + .rx_highest = 0, \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ +} + +#define WLAN_HT_CAP \ +{ \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \ + | IEEE80211_HT_CAP_SM_PS \ + | IEEE80211_HT_CAP_GRN_FLD \ + | IEEE80211_HT_CAP_SGI_20 \ + | IEEE80211_HT_CAP_SGI_40, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \ + .mcs = WLAN_MCS_INFO, \ +} + +/********************************************************** +* Public for both legacy Wi-Fi and P2P to access +**********************************************************/ +struct ieee80211_supported_band mtk_band_2ghz = { + .band = NL80211_BAND_2GHZ, + .channels = mtk_2ghz_channels, + .n_channels = ARRAY_SIZE(mtk_2ghz_channels), + .bitrates = mtk_g_rates, + .n_bitrates = mtk_g_rates_size, + .ht_cap = WLAN_HT_CAP, +}; + +struct ieee80211_supported_band mtk_band_5ghz = { + .band = NL80211_BAND_5GHZ, + .channels = mtk_5ghz_channels, + .n_channels = ARRAY_SIZE(mtk_5ghz_channels), + .bitrates = mtk_a_rates, + .n_bitrates = mtk_a_rates_size, + .ht_cap = WLAN_HT_CAP, +}; + +const UINT_32 mtk_cipher_suites[5] = { + /* keep WEP first, it may be removed below */ + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + + /* keep last -- depends on hw flags! */ + WLAN_CIPHER_SUITE_AES_CMAC +}; + +/*********************************************************/ + +#define NIC_INF_NAME "wlan%d" /* interface name */ +#if CFG_TC1_FEATURE +#define NIC_INF_NAME_IN_AP_MODE "legacy%d" +#endif + +/* support to change debug module info dynamically */ +UINT_8 aucDebugModule[DBG_MODULE_NUM]; +UINT_32 u4DebugModule = 0; + +/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan device to 1 */ +static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { {0} }; + +static UINT_32 u4WlanDevNum; /* How many NICs coexist now */ + +/**20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan dead loack**/ +struct delayed_work sched_workq; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if CFG_ENABLE_WIFI_DIRECT +static SUB_MODULE_HANDLER rSubModHandler[SUB_MODULE_NUM] = { {NULL} }; +#endif + +static struct cfg80211_ops mtk_wlan_ops = { + .suspend = mtk_cfg80211_suspend, + .resume = mtk_cfg80211_resume, + .change_virtual_intf = mtk_cfg80211_change_iface, + .add_key = mtk_cfg80211_add_key, + .get_key = mtk_cfg80211_get_key, + .del_key = mtk_cfg80211_del_key, + .set_default_key = mtk_cfg80211_set_default_key, + .set_default_mgmt_key = mtk_cfg80211_set_default_mgmt_key, + .get_station = mtk_cfg80211_get_station, + .change_station = mtk_cfg80211_change_station, + .add_station = mtk_cfg80211_add_station, + .del_station = mtk_cfg80211_del_station, + .scan = mtk_cfg80211_scan, + .connect = mtk_cfg80211_connect, + .disconnect = mtk_cfg80211_disconnect, + .join_ibss = mtk_cfg80211_join_ibss, + .leave_ibss = mtk_cfg80211_leave_ibss, + .set_power_mgmt = mtk_cfg80211_set_power_mgmt, + .set_pmksa = mtk_cfg80211_set_pmksa, + .del_pmksa = mtk_cfg80211_del_pmksa, + .flush_pmksa = mtk_cfg80211_flush_pmksa, + .assoc = mtk_cfg80211_assoc, + /* Action Frame TX/RX */ + .remain_on_channel = mtk_cfg80211_remain_on_channel, + .cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel, + .mgmt_tx = mtk_cfg80211_mgmt_tx, +/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */ + .mgmt_frame_register = mtk_cfg80211_mgmt_frame_register, +#ifdef CONFIG_NL80211_TESTMODE + .testmode_cmd = mtk_cfg80211_testmode_cmd, +#endif +#if (CFG_SUPPORT_TDLS == 1) + .tdls_mgmt = TdlsexCfg80211TdlsMgmt, + .tdls_oper = TdlsexCfg80211TdlsOper, +#endif /* CFG_SUPPORT_TDLS */ +#if 1 /* Remove schedule_scan because we need more verification for NLO */ + .sched_scan_start = mtk_cfg80211_sched_scan_start, + .sched_scan_stop = mtk_cfg80211_sched_scan_stop, +#endif +}; + +static const struct wiphy_vendor_command mtk_wlan_vendor_ops[] = { + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_get_channel_list + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_set_country_code + }, + /* GSCAN */ + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_get_gscan_capabilities + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_SET_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_set_config + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = mtk_cfg80211_vendor_set_scan_config + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_enable_scan + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_enable_full_scan_results + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_get_scan_results + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_set_significant_change + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_SUBCMD_SET_HOTLIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_set_hotlist + }, + /* RTT */ + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = RTT_SUBCMD_GETCAPABILITY + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_get_rtt_capabilities + }, + /* Link Layer Statistics */ + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = LSTATS_SUBCMD_GET_INFO + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_llstats_get_info + }, + +}; + +static const struct nl80211_vendor_cmd_info mtk_wlan_vendor_events[] = { + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_FOUND + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_SCAN_RESULTS_AVAILABLE + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_FULL_SCAN_RESULTS + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = RTT_EVENT_COMPLETE + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_COMPLETE_SCAN + }, + { + .vendor_id = GOOGLE_OUI, + .subcmd = GSCAN_EVENT_HOTLIST_RESULTS_LOST + }, +}; + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes + mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + } +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, +}; +#endif + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Override the implementation of select queue +* +* \param[in] dev Pointer to struct net_device +* \param[in] skb Pointer to struct skb_buff +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +unsigned int _cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp = 0; + + /* skb->priority values from 256->263 are magic values + * directly indicate a specific 802.1d priority. This is + * to allow 802.1d priority to be passed directly in from + * tags + */ + + if (skb->priority >= 256 && skb->priority <= 263) + return skb->priority - 256; + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + } + return dscp >> 5; +} + +static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static UINT_16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + skb->priority = _cfg80211_classify8021d(skb); + + return au16Wlan1dToQueueIdx[skb->priority]; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Load NVRAM data and translate it into REG_INFO_T +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* \param[out] prRegInfo Pointer to struct REG_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void glLoadNvram(IN P_GLUE_INFO_T prGlueInfo, OUT P_REG_INFO_T prRegInfo) +{ + UINT_32 i, j; + UINT_8 aucTmp[2]; + PUINT_8 pucDest; + + ASSERT(prGlueInfo); + ASSERT(prRegInfo); + + if ((!prGlueInfo) || (!prRegInfo)) + return; + + if (kalCfgDataRead16(prGlueInfo, sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(UINT_16), (PUINT_16) aucTmp) == TRUE) { + prGlueInfo->fgNvramAvailable = TRUE; + + /* load MAC Address */ +#if !defined(CONFIG_MTK_TC1_FEATURE) + for (i = 0; i < PARAM_MAC_ADDR_LEN; i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, + (PUINT_16) (((PUINT_8) prRegInfo->aucMacAddr) + i)); + } +#else + TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prRegInfo->aucMacAddr); +#endif + + /* load country code */ + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), (PUINT_16) aucTmp); + + /* cast to wide characters */ + prRegInfo->au2CountryCode[0] = (UINT_16) aucTmp[0]; + prRegInfo->au2CountryCode[1] = (UINT_16) aucTmp[1]; + + /* load default normal TX power */ + for (i = 0; i < sizeof(TX_PWR_PARAM_T); i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i, + (PUINT_16) (((PUINT_8) &(prRegInfo->rTxPwr)) + i)); + } + + /* load feature flags */ + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), (PUINT_16) aucTmp); + prRegInfo->ucTxPwrValid = aucTmp[0]; + prRegInfo->ucSupport5GBand = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), (PUINT_16) aucTmp); + prRegInfo->uc2G4BwFixed20M = aucTmp[0]; + prRegInfo->uc5GBwFixed20M = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), (PUINT_16) aucTmp); + prRegInfo->ucEnable5GBand = aucTmp[0]; + + /* load EFUSE overriding part */ + for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i, + (PUINT_16) (((PUINT_8) &(prRegInfo->aucEFUSE)) + i)); + } + + /* load band edge tx power control */ + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), (PUINT_16) aucTmp); + prRegInfo->fg2G4BandEdgePwrUsed = (BOOLEAN) aucTmp[0]; + if (aucTmp[0]) { + prRegInfo->cBandEdgeMaxPwrCCK = (INT_8) aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, cBandEdgeMaxPwrOFDM20), (PUINT_16) aucTmp); + prRegInfo->cBandEdgeMaxPwrOFDM20 = (INT_8) aucTmp[0]; + prRegInfo->cBandEdgeMaxPwrOFDM40 = (INT_8) aucTmp[1]; + } + + /* load regulation subbands */ + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), (PUINT_16) aucTmp); + prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T) aucTmp[0]; + prRegInfo->ucRegChannelListIndex = aucTmp[1]; + + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + pucDest = (PUINT_8) &prRegInfo->rDomainInfo.rSubBand[i]; + for (j = 0; j < 6; j += sizeof(UINT_16)) { + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) + + (i * 6 + j), (PUINT_16) aucTmp); + + *pucDest++ = aucTmp[0]; + *pucDest++ = aucTmp[1]; + } + } + } + /* load RSSI compensation */ + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2GRssiCompensation), (PUINT_16) aucTmp); + prRegInfo->uc2GRssiCompensation = aucTmp[0]; + prRegInfo->uc5GRssiCompensation = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fgRssiCompensationValidbit), (PUINT_16) aucTmp); + prRegInfo->fgRssiCompensationValidbit = aucTmp[0]; + prRegInfo->ucRxAntennanumber = aucTmp[1]; + } else { + prGlueInfo->fgNvramAvailable = FALSE; + } + +} + +#if CFG_ENABLE_WIFI_DIRECT +/*----------------------------------------------------------------------------*/ +/*! +* \brief called by txthread, run sub module init function +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo) +{ + /*now, we only have p2p module */ + if (rSubModHandler[P2P_MODULE].fgIsInited == FALSE) { + rSubModHandler[P2P_MODULE].subModInit(prGlueInfo); + rSubModHandler[P2P_MODULE].fgIsInited = TRUE; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief called by txthread, run sub module exit function +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo) +{ + /*now, we only have p2p module */ + if (rSubModHandler[P2P_MODULE].fgIsInited == TRUE) { + rSubModHandler[P2P_MODULE].subModExit(prGlueInfo); + rSubModHandler[P2P_MODULE].fgIsInited = FALSE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set sub module init flag, force TxThread to run sub modle init +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo) +{ + /* 4 Mark HALT, notify main thread to finish current job */ + prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_INIT; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread finish sub module INIT */ + wait_for_completion_interruptible(&prGlueInfo->rSubModComp); + +#if 0 + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + p2pNetRegister(prGlueInfo); +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set sub module exit flag, force TxThread to run sub modle exit +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo) +{ +#if 0 + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + p2pNetUnregister(prGlueInfo); +#endif + + /* 4 Mark HALT, notify main thread to finish current job */ + prGlueInfo->ulFlag |= GLUE_FLAG_SUB_MOD_EXIT; + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread finish sub module EXIT */ + wait_for_completion_interruptible(&prGlueInfo->rSubModComp); + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set by sub module, indicate sub module is already inserted +* +* \param[in] rSubModInit, function pointer point to sub module init function +* \param[in] rSubModExit, function pointer point to sub module exit function +* \param[in] eSubModIdx, sub module index +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx) +{ + rSubModHandler[eSubModIdx].subModInit = rSubModInit; + rSubModHandler[eSubModIdx].subModExit = rSubModExit; + rSubModHandler[eSubModIdx].fgIsInited = FALSE; +} + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief check wlan is launched or not +* +* \param[in] (none) +* +* \return TRUE, wlan is already started +* FALSE, wlan is not started yet +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wlanIsLaunched(VOID) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + /* 4 <0> Sanity check */ + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (0 == u4WlanDevNum) + return FALSE; + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + + ASSERT(prDev); + if (NULL == prDev) + return FALSE; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (NULL == prGlueInfo) + return FALSE; + + return prGlueInfo->prAdapter->fgIsWlanLaunched; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Export wlan GLUE_INFO_T pointer to p2p module +* +* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T +* +* \return TRUE: get GlueInfo pointer successfully +* FALSE: wlan is not started yet +*/ +/*---------------------------------------------------------------------------*/ +BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (0 == u4WlanDevNum) + return FALSE; + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + if (NULL == prDev) + return FALSE; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + if (NULL == prGlueInfo) + return FALSE; + + if (FALSE == prGlueInfo->prAdapter->fgIsWlanLaunched) + return FALSE; + + *prGlueInfoExpAddr = prGlueInfo; + return TRUE; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release prDev from wlandev_array and free tasklet object related to it. +* +* \param[in] prDev Pointer to struct net_device +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void wlanClearDevIdx(struct net_device *prDev) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == prDev) { + arWlanDevInfo[i].prDev = NULL; + u4WlanDevNum--; + } + } + +} /* end of wlanClearDevIdx() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate an unique interface index, net_device::ifindex member for this +* wlan device. Store the net_device in wlandev_array, and initialize +* tasklet object related to it. +* +* \param[in] prDev Pointer to struct net_device +* +* \retval >= 0 The device number. +* \retval -1 Fail to get index. +*/ +/*----------------------------------------------------------------------------*/ +static int wlanGetDevIdx(struct net_device *prDev) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) { + /* Reserve 2 bytes space to store one digit of + * device number and NULL terminator. + */ + arWlanDevInfo[i].prDev = prDev; + u4WlanDevNum++; + return i; + } + } + + return -1; +} /* end of wlanGetDevIdx() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, a primary SOCKET interface to configure +* the interface lively. Handle an ioctl call on one of our devices. +* Everything Linux ioctl specific is done here. Then we pass the contents +* of the ifr->data to the request message handler. +* +* \param[in] prDev Linux kernel netdevice +* +* \param[in] prIfReq Our private ioctl request structure, typed for the generic +* struct ifreq so we can use ptr to function +* +* \param[in] cmd Command ID +* +* \retval 0 The IOCTL command is executed successfully. +* \retval <0 The execution of IOCTL command is failed. +*/ +/*----------------------------------------------------------------------------*/ +int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + + /* Verify input parameters for the following functions */ + ASSERT(prDev && prIfReq); + if (!prDev || !prIfReq) { + DBGLOG(INIT, ERROR, "Invalid input data\n"); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + if (!prGlueInfo) { + DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); + return -EFAULT; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + DBGLOG(INIT, ERROR, "Adapter is not ready\n"); + return -EINVAL; + } + + if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) { + /* 0x8B00 ~ 0x8BDF, wireless extension region */ + ret = wext_support_ioctl(prDev, prIfReq, i4Cmd); + } else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) { + /* 0x8BE0 ~ 0x8BFF, private ioctl region */ + ret = priv_support_ioctl(prDev, prIfReq, i4Cmd); + } else if (i4Cmd == SIOCDEVPRIVATE + 1) { + ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); + } else { + DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd); + ret = -EOPNOTSUPP; + } + + return ret; +} /* end of wlanDoIOCTL() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is to set multicast list and set rx mode. +* +* \param[in] prDev Pointer to struct net_device +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +static struct delayed_work workq; +static struct net_device *gPrDev; +static BOOLEAN fgIsWorkMcStart = FALSE; +static BOOLEAN fgIsWorkMcEverInit = FALSE; +static struct wireless_dev *gprWdev; + +static void createWirelessDevice(void) +{ + struct wiphy *prWiphy = NULL; + struct wireless_dev *prWdev = NULL; +#if CFG_SUPPORT_PERSIST_NETDEV + struct net_device *prNetDev = NULL; +#endif + + /* <1.1> Create wireless_dev */ + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); + return; + } + + + /* <1.2> Create wiphy */ + prWiphy = wiphy_new(&mtk_wlan_ops, sizeof(GLUE_INFO_T)); + if (!prWiphy) { + DBGLOG(INIT, ERROR, "Allocating memory to wiphy device failed\n"); + goto free_wdev; + } + + /* <1.3> configure wireless_dev & wiphy */ + prWdev->iftype = NL80211_IFTYPE_STATION; + prWiphy->max_scan_ssids = 1; /* FIXME: for combo scan */ + prWiphy->max_scan_ie_len = 512; + + prWiphy->max_sched_scan_ssids = CFG_SCAN_SSID_MAX_NUM; + prWiphy->max_match_sets = CFG_SCAN_SSID_MATCH_MAX_NUM; + prWiphy->max_sched_scan_ie_len = CFG_CFG80211_IE_BUF_LEN; + + prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; + /* always assign 5Ghz bands here, if the chip is not support 5Ghz, + bands[IEEE80211_BAND_5GHZ] will be assign to NULL */ + prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; + prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + prWiphy->cipher_suites = mtk_cipher_suites; + prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); + prWiphy->flags = WIPHY_FLAG_SUPPORTS_FW_ROAM + | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL + | WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; +#if CFG_SUPPORT_TDLS + TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags); +#endif /* CFG_SUPPORT_TDLS */ + prWiphy->max_remain_on_channel_duration = 5000; + prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes; + prWiphy->vendor_commands = mtk_wlan_vendor_ops; + prWiphy->n_vendor_commands = sizeof(mtk_wlan_vendor_ops) / sizeof(struct wiphy_vendor_command); + prWiphy->vendor_events = mtk_wlan_vendor_events; + prWiphy->n_vendor_events = ARRAY_SIZE(mtk_wlan_vendor_events); + + /* <1.4> wowlan support */ +#ifdef CONFIG_PM + prWiphy->wowlan = &mtk_wlan_wowlan_support; +#endif +#ifdef CONFIG_CFG80211_WEXT + /* <1.5> Use wireless extension to replace IOCTL */ + prWiphy->wext = &wext_handler_def; +#endif + + if (wiphy_register(prWiphy) < 0) { + DBGLOG(INIT, ERROR, "wiphy_register error\n"); + goto free_wiphy; + } + prWdev->wiphy = prWiphy; + +#if CFG_SUPPORT_PERSIST_NETDEV + /* <2> allocate and register net_device */ +#if CFG_TC1_FEATURE + if (wlan_if_changed) + prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); + else +#else + prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); +#endif + if (!prNetDev) { + DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); + goto unregister_wiphy; + } + + *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = (P_GLUE_INFO_T) wiphy_priv(prWiphy); + + prNetDev->netdev_ops = &wlan_netdev_ops; +#ifdef CONFIG_WIRELESS_EXT + prNetDev->wireless_handlers = &wext_handler_def; +#endif + netif_carrier_off(prNetDev); + netif_tx_stop_all_queues(prNetDev); + + /* <2.1> co-relate with wireless_dev bi-directionally */ + prNetDev->ieee80211_ptr = prWdev; + prWdev->netdev = prNetDev; +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prNetDev->features = NETIF_F_HW_CSUM; +#endif + + /* <2.2> co-relate net device & device tree */ + SET_NETDEV_DEV(prNetDev, wiphy_dev(prWiphy)); + + /* <2.3> register net_device */ + if (register_netdev(prWdev->netdev) < 0) { + DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); + goto unregister_wiphy; + } +#endif /* CFG_SUPPORT_PERSIST_NETDEV */ + gprWdev = prWdev; + DBGLOG(INIT, INFO, "create wireless device success\n"); + return; + +#if CFG_SUPPORT_PERSIST_NETDEV +unregister_wiphy: + wiphy_unregister(prWiphy); +#endif +free_wiphy: + wiphy_free(prWiphy); +free_wdev: + kfree(prWdev); +} + +static void destroyWirelessDevice(void) +{ +#if CFG_SUPPORT_PERSIST_NETDEV + unregister_netdev(gprWdev->netdev); + free_netdev(gprWdev->netdev); +#endif + wiphy_unregister(gprWdev->wiphy); + wiphy_free(gprWdev->wiphy); + kfree(gprWdev); + gprWdev = NULL; +} + +static void wlanSetMulticastList(struct net_device *prDev) +{ + gPrDev = prDev; + schedule_delayed_work(&workq, 0); +} + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * tx_thread, so we can't let tx_thread to do this */ + +static void wlanSetMulticastListWorkQueue(struct work_struct *work) +{ + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4PacketFilter = 0; + UINT_32 u4SetInfoLen; + struct net_device *prDev = gPrDev; + + fgIsWorkMcStart = TRUE; + + if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) + return; + if (kalIsHalted()) { + fgIsWorkMcStart = FALSE; + kalHaltUnlock(); + return; + } + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(INIT, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); + fgIsWorkMcStart = FALSE; + kalHaltUnlock(); + return; + } + + if (prDev->flags & IFF_PROMISC) + u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; + + if (prDev->flags & IFF_BROADCAST) + u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || + (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { + + u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } else { + u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; + } + } + + kalHaltUnlock(); + + if (kalIoctl(prGlueInfo, + wlanoidSetCurrentPacketFilter, + &u4PacketFilter, + sizeof(u4PacketFilter), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen) != WLAN_STATUS_SUCCESS) { + fgIsWorkMcStart = FALSE; + DBGLOG(INIT, ERROR, "wlanSetMulticastListWorkQueue kalIoctl u4PacketFilter=%d\n", u4PacketFilter); + return; + } + + if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ + struct netdev_hw_addr *ha; + PUINT_8 prMCAddrList = NULL; + UINT_32 i = 0; + + if (kalHaltLock(KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE)) + return; + if (kalIsHalted()) { + fgIsWorkMcStart = FALSE; + kalHaltUnlock(); + /*DBGLOG(INIT, WARN, "wlanSetMulticastListWorkQueue g_u4HaltFlag=%d\n", g_u4HaltFlag);*/ + return; + } + + prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE); + + netdev_for_each_mc_addr(ha, prDev) { + if (i < MAX_NUM_GROUP_ADDR) { + memcpy((prMCAddrList + i * ETH_ALEN), ha->addr, ETH_ALEN); + i++; + } + } + + kalHaltUnlock(); + + kalIoctl(prGlueInfo, + wlanoidSetMulticastList, + prMCAddrList, (i * ETH_ALEN), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + + kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN); + } + + fgIsWorkMcStart = FALSE; + +} /* end of wlanSetMulticastList() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate scheduled scan has been stopped +* +* \param[in] +* prGlueInfo +* +* \return +* None +*/ +/*----------------------------------------------------------------------------*/ +VOID wlanSchedScanStoppedWorkQueue(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct net_device *prDev = gPrDev; + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + if (!prGlueInfo) { + DBGLOG(SCN, ERROR, "prGlueInfo == NULL unexpected\n"); + return; + } + + /* 2. indication to cfg80211 */ + /* 20150205 change cfg80211_sched_scan_stopped to work queue due to sched_scan_mtx dead lock issue */ + cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo),0); + DBGLOG(SCN, INFO, + "cfg80211_sched_scan_stopped event send done\n"); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is TX entry point of NET DEVICE. +* +* \param[in] prSkb Pointer of the sk_buff to be sent +* \param[in] prDev Pointer to struct net_device +* +* \retval NETDEV_TX_OK - on success. +* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. +*/ +/*----------------------------------------------------------------------------*/ +int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + UINT_16 u2QueueIdx = 0; +#if (CFG_SUPPORT_TDLS_DBG == 1) + UINT16 u2Identifier = 0; +#endif + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + ASSERT(prGlueInfo); + prGlueInfo->u8SkbToDriver++; + +#if (CFG_SUPPORT_TDLS_DBG == 1) + { + UINT8 *pkt = prSkb->data; + + if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { + /* ip */ + u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); + /* u2TdlsTxSeq[u4TdlsTxSeqId ++] = u2Identifier; */ + DBGLOG(INIT, INFO, " %d\n", u2Identifier); + } + } +#endif + /* check if WiFi is halt */ + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "GLUE_FLAG_HALT skip tx\n"); + dev_kfree_skb(prSkb); + prGlueInfo->u8SkbFreed++; + return NETDEV_TX_OK; + } +#if CFG_SUPPORT_HOTSPOT_2_0 + if (prGlueInfo->fgIsDad) { + /* kalPrint("[Passpoint R2] Due to ipv4_dad...TX is forbidden\n"); */ + dev_kfree_skb(prSkb); + prGlueInfo->u8SkbFreed++; + return NETDEV_TX_OK; + } + if (prGlueInfo->fgIs6Dad) { + /* kalPrint("[Passpoint R2] Due to ipv6_dad...TX is forbidden\n"); */ + dev_kfree_skb(prSkb); + prGlueInfo->u8SkbFreed++; + return NETDEV_TX_OK; + } +#endif + + STATS_TX_TIME_ARRIVE(prSkb); + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, "sk_buff->len: %d\n", prSkb->len); + DBGLOG(BOW, TRACE, "sk_buff->data_len: %d\n", prSkb->data_len); + DBGLOG(BOW, TRACE, "sk_buff->data:\n"); + + for (i = 0; i < prSkb->len; i++) { + DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); + + if ((i + 1) % 16 == 0) + DBGLOG(BOW, TRACE, "\n"); + } + + DBGLOG(BOW, TRACE, "\n"); +#endif + + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + + /* non-1x packets */ + +#if CFG_DBG_GPIO_PINS + { + /* TX request from OS */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_LOW); + kalUdelay(1); + mtk_wcn_stp_debug_gpio_assert(IDX_TX_REQ, DBG_TIE_HIGH); + } +#endif + + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); +#endif + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + if (u2QueueIdx < CFG_MAX_TXQ_NUM) + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); +/* GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); */ +/* GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); */ + + if (u2QueueIdx < CFG_MAX_TXQ_NUM) { + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx] >= + CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { + DBGLOG(TX, INFO, "netif_stop_subqueue for wlan0, Queue len: %d\n", + prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_AIS_INDEX][u2QueueIdx]); + + netif_stop_subqueue(prDev, u2QueueIdx); + +#if (CONF_HIF_LOOPBACK_AUTO == 1) + prGlueInfo->rHifInfo.HifLoopbkFlg |= 0x01; +#endif /* CONF_HIF_LOOPBACK_AUTO */ + } + } + } else { + /* printk("is security frame\n"); */ + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + DBGLOG(TX, EVENT, "\n+++++ pending frame %d len = %d +++++\n", prGlueInfo->i4TxPendingFrameNum, prSkb->len); + prGlueInfo->rNetDevStats.tx_bytes += prSkb->len; + prGlueInfo->rNetDevStats.tx_packets++; + kalPerMonStart(prGlueInfo); + + /* set GLUE_FLAG_TXREQ_BIT */ + + /* pr->u4Flag |= GLUE_FLAG_TXREQ; */ + /* wake_up_interruptible(&prGlueInfo->waitq); */ + kalSetEvent(prGlueInfo); + + /* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */ + return NETDEV_TX_OK; +} /* end of wlanHardStartXmit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, to get the network interface statistical +* information. +* +* Whenever an application needs to get statistics for the interface, this method +* is called. This happens, for example, when ifconfig or netstat -i is run. +* +* \param[in] prDev Pointer to struct net_device. +* +* \return net_device_stats buffer pointer. +*/ +/*----------------------------------------------------------------------------*/ +struct net_device_stats *wlanGetStats(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + +#if 0 + WLAN_STATUS rStatus; + UINT_32 u4XmitError = 0; + UINT_32 u4XmitOk = 0; + UINT_32 u4RecvError = 0; + UINT_32 u4RecvOk = 0; + UINT_32 u4BufLen; + + ASSERT(prDev); + + /* @FIX ME: need a more clear way to do this */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryXmitError, &u4XmitError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryXmitOk, &u4XmitOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRcvOk, &u4RecvOk, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRcvError, &u4RecvError, sizeof(UINT_32), TRUE, TRUE, TRUE, &u4BufLen); + prGlueInfo->rNetDevStats.rx_packets = u4RecvOk; + prGlueInfo->rNetDevStats.tx_packets = u4XmitOk; + prGlueInfo->rNetDevStats.tx_errors = u4XmitError; + prGlueInfo->rNetDevStats.rx_errors = u4RecvError; + /* prGlueInfo->rNetDevStats.rx_bytes = rCustomNetDevStats.u4RxBytes; */ + /* prGlueInfo->rNetDevStats.tx_bytes = rCustomNetDevStats.u4TxBytes; */ + /* prGlueInfo->rNetDevStats.rx_errors = rCustomNetDevStats.u4RxErrors; */ + /* prGlueInfo->rNetDevStats.multicast = rCustomNetDevStats.u4Multicast; */ +#endif + /* prGlueInfo->rNetDevStats.rx_packets = 0; */ + /* prGlueInfo->rNetDevStats.tx_packets = 0; */ + prGlueInfo->rNetDevStats.tx_errors = 0; + prGlueInfo->rNetDevStats.rx_errors = 0; + /* prGlueInfo->rNetDevStats.rx_bytes = 0; */ + /* prGlueInfo->rNetDevStats.tx_bytes = 0; */ + prGlueInfo->rNetDevStats.rx_errors = 0; + prGlueInfo->rNetDevStats.multicast = 0; + + return &prGlueInfo->rNetDevStats; + +} /* end of wlanGetStats() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->init +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanInit succeeds. +* \retval -ENXIO No such device. +*/ +/*----------------------------------------------------------------------------*/ +static int wlanInit(struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + if (fgIsWorkMcEverInit == FALSE) { + if (!prDev) + return -ENXIO; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue); + + /* 20150205 work queue for sched_scan */ + INIT_DELAYED_WORK(&sched_workq, wlanSchedScanStoppedWorkQueue); + + fgIsWorkMcEverInit = TRUE; + } + + return 0; /* success */ +} /* end of wlanInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->uninit +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void wlanUninit(struct net_device *prDev) +{ + +} /* end of wlanUninit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->open +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanOpen succeeds. +* \retval < 0 The execution of wlanOpen failed. +*/ +/*----------------------------------------------------------------------------*/ +static int wlanOpen(struct net_device *prDev) +{ + ASSERT(prDev); + + netif_tx_start_all_queues(prDev); + + return 0; /* success */ +} /* end of wlanOpen() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->stop +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanStop succeeds. +* \retval < 0 The execution of wlanStop failed. +*/ +/*----------------------------------------------------------------------------*/ +static int wlanStop(struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct cfg80211_scan_request *prScanRequest = NULL; + + struct cfg80211_scan_info info = { + .aborted = true, + }; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + /* CFG80211 down */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prScanRequest != NULL) { + prScanRequest = prGlueInfo->prScanRequest; + prGlueInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (prScanRequest) + cfg80211_scan_done(prScanRequest, &info); + netif_tx_stop_all_queues(prDev); + + return 0; /* success */ +} /* end of wlanStop() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update channel table for cfg80211 based on current country domain + * + * \param[in] prGlueInfo Pointer to glue info + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo) +{ + UINT_8 i, j; + UINT_8 ucNumOfChannel; + RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels)]; + + /* 1. Disable all channels */ + for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) { + mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; + mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; + } + + for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) { + mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; + mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; + } + + /* 2. Get current domain channel list */ + rlmDomainGetChnlList(prGlueInfo->prAdapter, + BAND_NULL, FALSE, + ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels), + &ucNumOfChannel, aucChannelList); + + /* 3. Enable specific channel based on domain channel list */ + for (i = 0; i < ucNumOfChannel; i++) { + switch (aucChannelList[i].eBand) { + case BAND_2G4: + for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) { + if (mtk_2ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { + mtk_2ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; + mtk_2ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; + break; + } + } + break; + + case BAND_5G: + for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) { + if (mtk_5ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) { + mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; + mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; + break; + } + } + break; + + default: + DBGLOG(INIT, WARN, "Unknown band %d\n", aucChannelList[i].eBand); + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register the device to the kernel and return the index. +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanNetRegister succeeds. +* \retval < 0 The execution of wlanNetRegister failed. +*/ +/*----------------------------------------------------------------------------*/ +static INT_32 wlanNetRegister(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo; + INT_32 i4DevIdx = -1; + + ASSERT(prWdev); + + do { + if (!prWdev) + break; + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); + i4DevIdx = wlanGetDevIdx(prWdev->netdev); + if (i4DevIdx < 0) { + DBGLOG(INIT, ERROR, "wlanNetRegister: net_device number exceeds.\n"); + break; + } + +#if !CFG_SUPPORT_PERSIST_NETDEV + if (register_netdev(prWdev->netdev) < 0) { + DBGLOG(INIT, ERROR, "wlanNetRegister: net_device context is not registered.\n"); + + wiphy_unregister(prWdev->wiphy); + wlanClearDevIdx(prWdev->netdev); + i4DevIdx = -1; + } +#endif + if (i4DevIdx != -1) + prGlueInfo->fgIsRegistered = TRUE; + + } while (FALSE); + + return i4DevIdx; /* success */ +} /* end of wlanNetRegister() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister the device from the kernel +* +* \param[in] prWdev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID wlanNetUnregister(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo; + + if (!prWdev) { + DBGLOG(INIT, ERROR, "wlanNetUnregister: The device context is NULL\n"); + return; + } + DBGLOG(INIT, TRACE, "unregister net_dev(0x%p)\n", prWdev->netdev); + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); + wlanClearDevIdx(prWdev->netdev); +#if !CFG_SUPPORT_PERSIST_NETDEV + unregister_netdev(prWdev->netdev); +#endif + prGlueInfo->fgIsRegistered = FALSE; + + DBGLOG(INIT, INFO, "unregister wireless_dev(0x%p), ifindex=%d\n", prWdev, prWdev->netdev->ifindex); + +} /* end of wlanNetUnregister() */ + +static const struct net_device_ops wlan_netdev_ops = { + .ndo_open = wlanOpen, + .ndo_stop = wlanStop, + .ndo_set_rx_mode = wlanSetMulticastList, + .ndo_get_stats = wlanGetStats, + .ndo_do_ioctl = wlanDoIOCTL, + .ndo_start_xmit = wlanHardStartXmit, + .ndo_init = wlanInit, + .ndo_uninit = wlanUninit, + .ndo_select_queue = wlanSelectQueue, +}; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method for creating Linux NET4 struct net_device object and the +* private data(prGlueInfo and prAdapter). Setup the IO address to the HIF. +* Assign the function pointer to the net_device object +* +* \param[in] pvData Memory address for the device +* +* \retval Not null The wireless_dev object. +* \retval NULL Fail to create wireless_dev object +*/ +/*----------------------------------------------------------------------------*/ +static struct lock_class_key rSpinKey[SPIN_LOCK_NUM]; +static struct wireless_dev *wlanNetCreate(PVOID pvData) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct wireless_dev *prWdev = gprWdev; + UINT_32 i; + struct device *prDev; + + if (!prWdev) { + DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n"); + return NULL; + } + /* 4 <1> co-relate wiphy & prDev */ +#if MTK_WCN_HIF_SDIO + mtk_wcn_hif_sdio_get_dev(*((MTK_WCN_HIF_SDIO_CLTCTX *) pvData), &prDev); +#else +/* prDev = &((struct sdio_func *) pvData)->dev; //samp */ + prDev = pvData; /* samp */ +#endif + if (!prDev) + DBGLOG(INIT, WARN, "unable to get struct dev for wlan\n"); + /* don't set prDev as parent of wiphy->dev, because we have done device_add + in driver init. if we set parent here, parent will be not able to know this child, + and may occurs a KE in device_shutdown, to free wiphy->dev, because his parent + has been freed. */ + /*set_wiphy_dev(prWdev->wiphy, prDev);*/ + +#if !CFG_SUPPORT_PERSIST_NETDEV + /* 4 <3> Initial Glue structure */ + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); + kalMemZero(prGlueInfo, sizeof(GLUE_INFO_T)); + /* 4 <3.1> Create net device */ +#if CFG_TC1_FEATURE + if (wlan_if_changed) { + prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME_IN_AP_MODE, + NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); + } else { + prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); + } +#else + prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), NIC_INF_NAME, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); +#endif + if (!prGlueInfo->prDevHandler) { + DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); + return NULL; + } + DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated ifindex=%d\n", + prGlueInfo->prDevHandler, prGlueInfo->prDevHandler->ifindex); + + /* 4 <3.1.1> initialize net device varaiables */ + *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prDevHandler)) = prGlueInfo; + + prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops; +#ifdef CONFIG_WIRELESS_EXT + prGlueInfo->prDevHandler->wireless_handlers = &wext_handler_def; +#endif + netif_carrier_off(prGlueInfo->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prDevHandler); + + /* 4 <3.1.2> co-relate with wiphy bi-directionally */ + prGlueInfo->prDevHandler->ieee80211_ptr = prWdev; +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prGlueInfo->prDevHandler->features = NETIF_F_HW_CSUM; +#endif + prWdev->netdev = prGlueInfo->prDevHandler; + + /* 4 <3.1.3> co-relate net device & prDev */ + /*SET_NETDEV_DEV(prGlueInfo->prDevHandler, wiphy_dev(prWdev->wiphy));*/ + SET_NETDEV_DEV(prGlueInfo->prDevHandler, prDev); +#else /* CFG_SUPPORT_PERSIST_NETDEV */ + prGlueInfo->prDevHandler = gprWdev->netdev; +#endif /* CFG_SUPPORT_PERSIST_NETDEV */ + + /* 4 <3.2> initiali glue variables */ + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prGlueInfo->ePowerState = ParamDeviceStateD0; + prGlueInfo->fgIsMacAddrOverride = FALSE; + prGlueInfo->fgIsRegistered = FALSE; + prGlueInfo->prScanRequest = NULL; + +#if CFG_SUPPORT_HOTSPOT_2_0 + /* Init DAD */ + prGlueInfo->fgIsDad = FALSE; + prGlueInfo->fgIs6Dad = FALSE; + kalMemZero(prGlueInfo->aucDADipv4, 4); + kalMemZero(prGlueInfo->aucDADipv6, 16); +#endif + + init_completion(&prGlueInfo->rScanComp); + init_completion(&prGlueInfo->rHaltComp); + init_completion(&prGlueInfo->rPendComp); +#if CFG_ENABLE_WIFI_DIRECT + init_completion(&prGlueInfo->rSubModComp); +#endif + + /* initialize timer for OID timeout checker */ + kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler); + + for (i = 0; i < SPIN_LOCK_NUM; i++) { + spin_lock_init(&prGlueInfo->rSpinLock[i]); + lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]); + } + + /* initialize semaphore for ioctl */ + sema_init(&prGlueInfo->ioctl_sem, 1); + + glSetHifInfo(prGlueInfo, (ULONG) pvData); + + /* 4 <8> Init Queues */ + init_waitqueue_head(&prGlueInfo->waitq); + QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue); + QUEUE_INITIALIZE(&prGlueInfo->rTxQueue); + + /* 4 <4> Create Adapter structure */ + prGlueInfo->prAdapter = (P_ADAPTER_T) wlanAdapterCreate(prGlueInfo); + + if (!prGlueInfo->prAdapter) { + DBGLOG(INIT, ERROR, "Allocating memory to adapter failed\n"); + return NULL; + } + KAL_WAKE_LOCK_INIT(prAdapter, &prGlueInfo->rAhbIsrWakeLock, "WLAN AHB ISR"); +#if CFG_SUPPORT_PERSIST_NETDEV + dev_open(prGlueInfo->prDevHandler); + netif_carrier_off(prGlueInfo->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prDevHandler); +#endif + + return prWdev; +} /* end of wlanNetCreate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Destroying the struct net_device object and the private data. +* +* \param[in] prWdev Pointer to struct wireless_dev. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID wlanNetDestroy(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prWdev); + + if (!prWdev) { + DBGLOG(INIT, ERROR, "wlanNetDestroy: The device context is NULL\n"); + return; + } + + /* prGlueInfo is allocated with net_device */ + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); + ASSERT(prGlueInfo); + + /* destroy kal OS timer */ + kalCancelTimer(prGlueInfo); + + glClearHifInfo(prGlueInfo); + + wlanAdapterDestroy(prGlueInfo->prAdapter); + prGlueInfo->prAdapter = NULL; + +#if CFG_SUPPORT_PERSIST_NETDEV + /* take the net_device to down state */ + dev_close(prGlueInfo->prDevHandler); +#else + /* Free net_device and private data prGlueInfo, which are allocated by alloc_netdev(). */ + free_netdev(prWdev->netdev); +#endif + +} /* end of wlanNetDestroy() */ + +#ifndef CONFIG_X86 +UINT_8 g_aucBufIpAddr[32] = { 0 }; +static void wlanNotifyFwSuspend(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgSuspend) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen; + + rStatus = kalIoctl(prGlueInfo, + wlanoidNotifyFwSuspend, + (PVOID)&fgSuspend, + sizeof(fgSuspend), + FALSE, + FALSE, + TRUE, + FALSE, + &u4SetInfoLen); + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(INIT, INFO, "wlanNotifyFwSuspend fail\n"); +} + +void wlanHandleSystemSuspend(void) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ + UINT_32 u4NumIPv6 = 0; +#endif + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + + /* <1> Sanity check and acquire the net_device */ + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (u4WlanDevNum == 0) { + DBGLOG(INIT, ERROR, "wlanEarlySuspend u4WlanDevNum==0 invalid!!\n"); + return; + } + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + + fgIsUnderSuspend = true; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + kalPerMonDisable(prGlueInfo); + + if (!prDev || !(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { + goto notify_suspend; + } + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + + /* todo: traverse between list to find whole sets of IPv4 addresses */ + if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) + u4NumIPv4++; +#ifdef CONFIG_IPV6 + if (!prDev || !(prDev->ip6_ptr) || + !((struct in_device *)(prDev->ip6_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { + goto notify_suspend; + } + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0], ip6[1], ip6[2], ip6[3], + ip6[4], ip6[5], ip6[6], ip6[7], + ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] + ); + + /* todo: traverse between list to find whole sets of IPv6 addresses */ + if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) { + /* Do nothing */ + /* u4NumIPv6++; */ + } +#endif + + /* <7> set up the ARP filter */ + { + UINT_32 u4SetInfoLen = 0; + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = u4NumIPv4; +#ifdef CONFIG_IPV6 + prParamNetAddrList->u4AddressCount += u4NumIPv6; +#endif + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + prParamNetAddr = + (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); + } +#ifdef CONFIG_IPV6 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + sizeof(ip6)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(g_aucBufIpAddr)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + } + +notify_suspend: + DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) + wlanNotifyFwSuspend(prGlueInfo, TRUE); +} + +void wlanHandleSystemResume(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_8 ip[4] = { 0 }; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ +#endif + EVENT_AIS_BSS_INFO_T rParam; + UINT_32 u4BufLen = 0; + + /* <1> Sanity check and acquire the net_device */ + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (u4WlanDevNum == 0) { + DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n"); + return; + } + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + /* ASSERT(prDev); */ + + fgIsUnderSuspend = false; + + if (!prDev) { + DBGLOG(INIT, INFO, "prDev == NULL!!!\n"); + return; + } + /* <3> acquire the prGlueInfo */ + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + kalPerMonEnable(prGlueInfo); + + /* + We will receive the event in rx, we will check if the status is the same in driver + and FW, if not the same, trigger disconnetion procedure. + */ + + kalMemZero(&rParam, sizeof(EVENT_AIS_BSS_INFO_T)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBSSInfo, + &rParam, sizeof(EVENT_AIS_BSS_INFO_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Query BSSinfo fail 0x%x!!\n", rStatus); + } + + /* <2> get the IPv4 address */ + if (!(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { + goto notify_resume; + } + /* <4> copy the IPv4 address */ + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + +#ifdef CONFIG_IPV6 + /* <5> get the IPv6 address */ + if (!prDev || !(prDev->ip6_ptr) || + !((struct in_device *)(prDev->ip6_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { + goto notify_resume; + } + /* <6> copy the IPv6 address */ + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(INIT, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0], ip6[1], ip6[2], ip6[3], + ip6[4], ip6[5], ip6[6], ip6[7], + ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15] + ); +#endif + /* <7> clear the ARP filter */ + { + UINT_32 u4SetInfoLen = 0; +/* UINT_8 aucBuf[32] = {0}; */ + UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; + /* aucBuf; */ + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = 0; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + + ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + } + +notify_resume: + DBGLOG(INIT, INFO, "Query BSS result: %d %d %d, IP: %d.%d.%d.%d, rStatus: %u\n", + rParam.eConnectionState, rParam.eCurrentOPMode, rParam.fgIsNetActive, + ip[0], ip[1], ip[2], ip[3], rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + wlanNotifyFwSuspend(prGlueInfo, FALSE); + } +} +#endif /* ! CONFIG_X86 */ + +int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode) +{ +#if 0 + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + rSetP2P.u4Enable = p2pmode.u4Enable; + rSetP2P.u4Mode = p2pmode.u4Mode; + + if (!rSetP2P.u4Enable) + p2pNetUnregister(prGlueInfo, TRUE); + + rWlanStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pMode, + (PVOID) &rSetP2P, + sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + DBGLOG(INIT, INFO, "ret = %d\n", rWlanStatus); + if (rSetP2P.u4Enable) + p2pNetRegister(prGlueInfo, TRUE); + + return 0; + +#else + + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev)); + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + BOOLEAN fgIsP2PEnding; + UINT_32 u4BufLen = 0; + + GLUE_SPIN_LOCK_DECLARATION(); + + DBGLOG(INIT, INFO, "%u %u\n", (UINT_32) p2pmode.u4Enable, (UINT_32) p2pmode.u4Mode); + + /* avoid remove & p2p off command simultaneously */ + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + fgIsP2PEnding = g_u4P2PEnding; + g_u4P2POnOffing = 1; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + + if (fgIsP2PEnding == 1) { + /* skip the command if we are removing */ + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2POnOffing = 0; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + return 0; + } + + rSetP2P.u4Enable = p2pmode.u4Enable; + rSetP2P.u4Mode = p2pmode.u4Mode; + +#if !CFG_SUPPORT_PERSIST_NETDEV + if ((!rSetP2P.u4Enable) && (fgIsResetting == FALSE)) + p2pNetUnregister(prGlueInfo, TRUE); +#endif + /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ + /* + Scenario: + 1. System enters suspend/resume but not yet enter wlanearlysuspend() + or wlanlateresume(); + + 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() + and get g_halt_sem then do glRegisterEarlySuspend() or + glUnregisterEarlySuspend(); + + But system suspend/resume procedure is not yet finished so we + suspend; + + 3. System switches back to do suspend/resume procedure and execute + kalIoctl(). But driver does not yet release g_halt_sem so system + suspend in wlanearlysuspend() or wlanlateresume(); + + ==> deadlock occurs. + */ + + rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, (PVOID) &rSetP2P,/* pu4IntBuf[0]is used as input SubCmd */ + sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); +#if !CFG_SUPPORT_PERSIST_NETDEV + /* Need to check fgIsP2PRegistered, in case of whole chip reset. + * in this case, kalIOCTL return success always, + * and prGlueInfo->prP2pInfo may be NULL */ + if ((rSetP2P.u4Enable) && (prGlueInfo->prAdapter->fgIsP2PRegistered) && (fgIsResetting == FALSE)) + p2pNetRegister(prGlueInfo, TRUE); +#endif + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2POnOffing = 0; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + return 0; +#endif +} + +static void set_dbg_level_handler(unsigned char dbg_lvl[DBG_MODULE_NUM]) +{ + kalMemCopy(aucDebugModule, dbg_lvl, sizeof(aucDebugModule)); + kalPrint("[wlan] change debug level"); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Wlan probe function. This function probes and initializes the device. +* +* \param[in] pvData data passed by bus driver init function +* _HIF_EHPI: NULL +* _HIF_SDIO: sdio bus driver handle +* +* \retval 0 Success +* \retval negative value Failed +*/ +/*----------------------------------------------------------------------------*/ +static INT_32 wlanProbe(PVOID pvData) +{ + struct wireless_dev *prWdev = NULL; + enum probe_fail_reason { + BUS_INIT_FAIL, + NET_CREATE_FAIL, + BUS_SET_IRQ_FAIL, + ADAPTER_START_FAIL, + NET_REGISTER_FAIL, + PROC_INIT_FAIL, + FAIL_REASON_NUM + } eFailReason; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + INT_32 i4DevIdx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + INT_32 i4Status = 0; + BOOLEAN bRet = FALSE; + + eFailReason = FAIL_REASON_NUM; + do { + /* 4 <1> Initialize the IO port of the interface */ + /* GeorgeKuo: pData has different meaning for _HIF_XXX: + * _HIF_EHPI: pointer to memory base variable, which will be + * initialized by glBusInit(). + * _HIF_SDIO: bus driver handle + */ + + bRet = glBusInit(pvData); + wlanDebugInit(); + /* Cannot get IO address from interface */ + if (FALSE == bRet) { + DBGLOG(INIT, ERROR, KERN_ALERT "wlanProbe: glBusInit() fail\n"); + i4Status = -EIO; + eFailReason = BUS_INIT_FAIL; + break; + } + /* 4 <2> Create network device, Adapter, KalInfo, prDevHandler(netdev) */ + prWdev = wlanNetCreate(pvData); + if (prWdev == NULL) { + DBGLOG(INIT, ERROR, "wlanProbe: No memory for dev and its private\n"); + i4Status = -ENOMEM; + eFailReason = NET_CREATE_FAIL; + break; + } + /* 4 <2.5> Set the ioaddr to HIF Info */ + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy); + gPrDev = prGlueInfo->prDevHandler; + + /* 4 <4> Setup IRQ */ + prWlandevInfo = &arWlanDevInfo[i4DevIdx]; + + i4Status = glBusSetIrq(prWdev->netdev, NULL, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); + + if (i4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n"); + eFailReason = BUS_SET_IRQ_FAIL; + break; + } + + prGlueInfo->i4DevIdx = i4DevIdx; + + prAdapter = prGlueInfo->prAdapter; + + prGlueInfo->u4ReadyFlag = 0; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prAdapter->u4CSUMFlags = (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP); +#endif +#if CFG_SUPPORT_CFG_FILE + { + PUINT_8 pucConfigBuf; + UINT_32 u4ConfigReadLen; + + wlanCfgInit(prAdapter, NULL, 0, 0); + pucConfigBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE); + u4ConfigReadLen = 0; + DBGLOG(INIT, LOUD, "CFG_FILE: Read File...\n"); + if (pucConfigBuf) { + kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE); + if (kalReadToFile("/data/misc/wifi.cfg", + pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { + DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi.cfg\n"); + + } else if (kalReadToFile("/data/misc/wifi/wifi.cfg", + pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { + DBGLOG(INIT, LOUD, "CFG_FILE: Read /data/misc/wifi/wifi.cfg\n"); + } else if (kalReadToFile("/etc/firmware/wifi.cfg", + pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) { + DBGLOG(INIT, LOUD, "CFG_FILE: Read /etc/firmware/wifi.cfg\n"); + } + + if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0) + wlanCfgInit(prAdapter, pucConfigBuf, u4ConfigReadLen, 0); + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE); + } /* pucConfigBuf */ + } +#endif + /* 4 <5> Start Device */ + /* */ +#if CFG_ENABLE_FW_DOWNLOAD + DBGLOG(INIT, TRACE, "start to download firmware...\n"); + + /* before start adapter, we need to open and load firmware */ + { + UINT_32 u4FwSize = 0; + PVOID prFwBuffer = NULL; + P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; + + /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ + kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T)); + prRegInfo->u4StartAddress = CFG_FW_START_ADDRESS; + prRegInfo->u4LoadAddress = CFG_FW_LOAD_ADDRESS; + + /* Load NVRAM content to REG_INFO_T */ + glLoadNvram(prGlueInfo, prRegInfo); +#if CFG_SUPPORT_CFG_FILE + wlanCfgApply(prAdapter); +#endif + + /* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); */ + + prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; + prRegInfo->fgEnArpFilter = TRUE; + + if (kalFirmwareImageMapping(prGlueInfo, &prFwBuffer, &u4FwSize) == NULL) { + i4Status = -EIO; + DBGLOG(INIT, ERROR, "kalFirmwareImageMapping fail!\n"); + goto bailout; + } else { + + if (wlanAdapterStart(prAdapter, prRegInfo, prFwBuffer, + u4FwSize) != WLAN_STATUS_SUCCESS) { + i4Status = -EIO; + } + } + + kalFirmwareImageUnmapping(prGlueInfo, NULL, prFwBuffer); + +bailout: + /* kfree(prRegInfo); */ + + DBGLOG(INIT, TRACE, "download firmware status = %d\n", i4Status); + + if (i4Status < 0) { + GL_HIF_INFO_T *HifInfo; + UINT_32 u4FwCnt; + + DBGLOG(INIT, WARN, "CONNSYS FW CPUINFO:\n"); + HifInfo = &prAdapter->prGlueInfo->rHifInfo; + for (u4FwCnt = 0; u4FwCnt < 16; u4FwCnt++) + DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(HifInfo, CONN_MCU_CPUPCR)); + /* CONSYS_REG_READ(CONSYS_CPUPCR_REG) */ + + /* dump HIF/DMA registers, if fgIsBusAccessFailed is FALSE, otherwise, */ + /* dump HIF register may be hung */ + if (!fgIsBusAccessFailed) + HifRegDump(prGlueInfo->prAdapter); +/* if (prGlueInfo->rHifInfo.DmaOps->DmaRegDump != NULL) */ +/* prGlueInfo->rHifInfo.DmaOps->DmaRegDump(&prGlueInfo->rHifInfo); */ + eFailReason = ADAPTER_START_FAIL; + break; + } + } +#else + /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ + kalMemSet(&prGlueInfo->rRegInfo, 0, sizeof(REG_INFO_T)); + P_REG_INFO_T prRegInfo = &prGlueInfo->rRegInfo; + + /* Load NVRAM content to REG_INFO_T */ + glLoadNvram(prGlueInfo, prRegInfo); + + prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; + + if (wlanAdapterStart(prAdapter, prRegInfo, NULL, 0) != WLAN_STATUS_SUCCESS) { + i4Status = -EIO; + eFailReason = ADAPTER_START_FAIL; + break; + } +#endif + if (FALSE == prAdapter->fgEnable5GBand) + prWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + + prGlueInfo->main_thread = kthread_run(tx_thread, prGlueInfo->prDevHandler, "tx_thread"); + kalSetHalted(FALSE); +#if CFG_SUPPORT_ROAMING_ENC + /* adjust roaming threshold */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + CMD_ROAMING_INFO_T rRoamingInfo; + UINT_32 u4SetInfoLen = 0; + + prAdapter->fgIsRoamingEncEnabled = TRUE; + + /* suggestion from Tsaiyuan.Hsu */ + kalMemZero(&rRoamingInfo, sizeof(CMD_ROAMING_INFO_T)); + rRoamingInfo.fgIsFastRoamingApplied = TRUE; + + DBGLOG(INIT, TRACE, "Enable roaming enhance function\n"); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRoamingInfo, + &rRoamingInfo, sizeof(rRoamingInfo), TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(INIT, ERROR, "set roaming advance info fail 0x%x\n", rStatus); + } +#endif /* CFG_SUPPORT_ROAMING_ENC */ + +#if (CFG_SUPPORT_TXR_ENC == 1) + /* adjust tx rate switch threshold */ + rlmTxRateEnhanceConfig(prGlueInfo->prAdapter); +#endif /* CFG_SUPPORT_TXR_ENC */ + + /* set MAC address */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + struct sockaddr MacAddr; + UINT_32 u4SetInfoLen = 0; + + kalMemZero(MacAddr.sa_data, sizeof(MacAddr.sa_data)); + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryCurrentAddr, + &MacAddr.sa_data, + PARAM_MAC_ADDR_LEN, TRUE, TRUE, TRUE, FALSE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, "set MAC addr fail 0x%x\n", rStatus); + prGlueInfo->u4ReadyFlag = 0; + } else { + ether_addr_copy(prGlueInfo->prDevHandler->dev_addr, (const u8 *)&(MacAddr.sa_data)); + ether_addr_copy(prGlueInfo->prDevHandler->perm_addr, + prGlueInfo->prDevHandler->dev_addr); + + /* card is ready */ + prGlueInfo->u4ReadyFlag = 1; +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "MAC address: %pM ", (&MacAddr.sa_data)); +#endif + } + } + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + UINT_32 u4SetInfoLen = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetCSUMOffload, + (PVOID) &u4CSUMFlags, + sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(INIT, WARN, "set HW checksum offload fail 0x%x\n", rStatus); + } +#endif + + /* 4 <3> Register the card */ + DBGLOG(INIT, TRACE, "wlanNetRegister...\n"); + i4DevIdx = wlanNetRegister(prWdev); + if (i4DevIdx < 0) { + i4Status = -ENXIO; + DBGLOG(INIT, ERROR, "wlanProbe: Cannot register the net_device context to the kernel\n"); + eFailReason = NET_REGISTER_FAIL; + break; + } + + wlanRegisterNotifier(); + /* 4 <6> Initialize /proc filesystem */ +#ifdef WLAN_INCLUDE_PROC + DBGLOG(INIT, TRACE, "init procfs...\n"); + i4Status = procCreateFsEntry(prGlueInfo); + if (i4Status < 0) { + DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n"); + eFailReason = PROC_INIT_FAIL; + break; + } +#endif /* WLAN_INCLUDE_PROC */ + +#if CFG_ENABLE_BT_OVER_WIFI + prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE; + prGlueInfo->rBowInfo.fgIsRegistered = FALSE; + glRegisterAmpc(prGlueInfo); +#endif + +#if CFG_ENABLE_WIFI_DIRECT + DBGLOG(INIT, TRACE, "wlanSubModInit...\n"); + + /* wlan is launched */ + prGlueInfo->prAdapter->fgIsWlanLaunched = TRUE; + /* if p2p module is inserted, notify tx_thread to init p2p network */ + if (rSubModHandler[P2P_MODULE].subModInit) + wlanSubModInit(prGlueInfo); + /* register set_p2p_mode handler to mtk_wmt_wifi */ + register_set_p2p_mode_handler(set_p2p_mode_handler); +#endif +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT + if (glIsChipNeedWakelock(prGlueInfo)) + KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock, "WLAN AP"); +#endif + } while (FALSE); + + if (i4Status != WLAN_STATUS_SUCCESS) { + switch (eFailReason) { + case PROC_INIT_FAIL: + wlanNetUnregister(prWdev); + set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread stops */ + wait_for_completion_interruptible(&prGlueInfo->rHaltComp); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); + wlanAdapterStop(prAdapter); + glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); + wlanNetDestroy(prWdev); + break; + case NET_REGISTER_FAIL: + set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread stops */ + wait_for_completion_interruptible(&prGlueInfo->rHaltComp); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prAdapter->rTxThreadWakeLock); + wlanAdapterStop(prAdapter); + glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); + wlanNetDestroy(prWdev); + break; + case ADAPTER_START_FAIL: + glBusFreeIrq(prWdev->netdev, *((P_GLUE_INFO_T *) netdev_priv(prWdev->netdev))); + KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); + wlanNetDestroy(prWdev); + break; + case BUS_SET_IRQ_FAIL: + KAL_WAKE_LOCK_DESTROY(prAdapter, &prGlueInfo->rAhbIsrWakeLock); + wlanNetDestroy(prWdev); + break; + case NET_CREATE_FAIL: + break; + case BUS_INIT_FAIL: + break; + default: + break; + } + } +#if CFG_ENABLE_WIFI_DIRECT + { + GLUE_SPIN_LOCK_DECLARATION(); + + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2PEnding = 0; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + } +#endif +#if CFG_SUPPORT_AGPS_ASSIST + if (i4Status == WLAN_STATUS_SUCCESS) + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL, 0); +#endif +#if (CFG_SUPPORT_MET_PROFILING == 1) + { + int iMetInitRet = WLAN_STATUS_FAILURE; + + if (i4Status == WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, TRACE, "init MET procfs...\n"); + iMetInitRet = kalMetInitProcfs(prGlueInfo); + if (iMetInitRet < 0) + DBGLOG(INIT, ERROR, "wlanProbe: init MET procfs failed\n"); + } + } +#endif + if (i4Status == WLAN_STATUS_SUCCESS) { + /*Init performance monitor structure */ + kalPerMonInit(prGlueInfo); + /* probe ok */ + DBGLOG(INIT, TRACE, "wlanProbe ok\n"); + } else { + /* we don't care the return value of mtk_wcn_set_connsys_power_off_flag, + * because even this function returns + * error, we can also call core dump but only core dump failed. */ + if (g_IsNeedDoChipReset) + mtk_wcn_set_connsys_power_off_flag(0); + /* probe failed */ + DBGLOG(INIT, ERROR, "wlanProbe failed\n"); + } + + return i4Status; +} /* end of wlanProbe() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method to stop driver operation and release all resources. Following +* this call, no frame should go up or down through this interface. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static VOID wlanRemove(VOID) +{ +#define KAL_WLAN_REMOVE_TIMEOUT_MSEC 3000 + struct net_device *prDev = NULL; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + DBGLOG(INIT, LOUD, "Remove wlan!\n"); + + /* 4 <0> Sanity check */ + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (0 == u4WlanDevNum) { + DBGLOG(INIT, ERROR, "0 == u4WlanDevNum\n"); + return; + } + /* unregister set_p2p_mode handler to mtk_wmt_wifi */ + register_set_p2p_mode_handler(NULL); + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1]; + + ASSERT(prDev); + if (NULL == prDev) { + DBGLOG(INIT, ERROR, "NULL == prDev\n"); + return; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (NULL == prGlueInfo) { + DBGLOG(INIT, ERROR, "NULL == prGlueInfo\n"); + free_netdev(prDev); + return; + } + + kalPerMonDestroy(prGlueInfo); +#if CFG_ENABLE_WIFI_DIRECT + /* avoid remove & p2p off command simultaneously */ + { + BOOLEAN fgIsP2POnOffing; + + GLUE_SPIN_LOCK_DECLARATION(); + + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2PEnding = 1; + fgIsP2POnOffing = g_u4P2POnOffing; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + + DBGLOG(INIT, TRACE, "waiting for fgIsP2POnOffing...\n"); + + /* History: cannot use down() here, sometimes we cannot come back here */ + /* waiting for p2p off command finishes, we cannot skip the remove */ + while (1) { + if (fgIsP2POnOffing == 0) + break; + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + fgIsP2POnOffing = g_u4P2POnOffing; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + } + } +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + if (prGlueInfo->rBowInfo.fgIsNetRegistered) { + bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter); + /* wait 300ms for BoW module to send deauth */ + kalMsleep(300); + } +#endif + + /* 4 <1> Stopping handling interrupt and free IRQ */ + DBGLOG(INIT, TRACE, "free IRQ...\n"); + glBusFreeIrq(prDev, *((P_GLUE_INFO_T *) netdev_priv(prDev))); + + kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + + kalSetHalted(TRUE); /* before flush_delayed_work() */ + if (fgIsWorkMcStart == TRUE) { + DBGLOG(INIT, TRACE, "flush_delayed_work...\n"); + flush_delayed_work(&workq); /* flush_delayed_work_sync is deprecated */ + } + + flush_delayed_work(&sched_workq); + + DBGLOG(INIT, INFO, "down g_halt_sem...\n"); + kalHaltLock(KAL_WLAN_REMOVE_TIMEOUT_MSEC); +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT + if (glIsChipNeedWakelock(prGlueInfo)) + KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); +#endif + +/* flush_delayed_work_sync(&workq); */ +/* flush_delayed_work(&workq); */ /* flush_delayed_work_sync is deprecated */ + + /* 4 <2> Mark HALT, notify main thread to stop, and clean up queued requests */ +/* prGlueInfo->u4Flag |= GLUE_FLAG_HALT; */ + set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); + DBGLOG(INIT, TRACE, "waiting for tx_thread stop...\n"); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + + DBGLOG(INIT, TRACE, "wait_for_completion_interruptible\n"); + + /* wait main thread stops */ + wait_for_completion_interruptible(&prGlueInfo->rHaltComp); + + DBGLOG(INIT, TRACE, "mtk_sdiod stopped\n"); + + KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rTxThreadWakeLock); + KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &prGlueInfo->rAhbIsrWakeLock); + + /* prGlueInfo->rHifInfo.main_thread = NULL; */ + prGlueInfo->main_thread = NULL; + +#if CFG_ENABLE_BT_OVER_WIFI + if (prGlueInfo->rBowInfo.fgIsRegistered) + glUnregisterAmpc(prGlueInfo); +#endif + + /* 4 <3> Remove /proc filesystem. */ +#ifdef WLAN_INCLUDE_PROC + procRemoveProcfs(); +#endif /* WLAN_INCLUDE_PROC */ + +#if (CFG_SUPPORT_MET_PROFILING == 1) + kalMetRemoveProcfs(); +#endif + + /* Force to do DMA reset */ + DBGLOG(INIT, TRACE, "glResetHif\n"); + glResetHif(prGlueInfo); + + /* 4 <4> wlanAdapterStop */ + prAdapter = prGlueInfo->prAdapter; +#if CFG_SUPPORT_AGPS_ASSIST + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL, 0); +#endif + + wlanAdapterStop(prAdapter); + DBGLOG(INIT, TRACE, "Number of Stalled Packets = %d\n", prGlueInfo->i4TxPendingFrameNum); + +#if CFG_ENABLE_WIFI_DIRECT + prGlueInfo->prAdapter->fgIsWlanLaunched = FALSE; + if (prGlueInfo->prAdapter->fgIsP2PRegistered) { + DBGLOG(INIT, TRACE, "p2pNetUnregister...\n"); +#if !CFG_SUPPORT_PERSIST_NETDEV + p2pNetUnregister(prGlueInfo, FALSE); +#endif + DBGLOG(INIT, INFO, "p2pRemove...\n"); + p2pRemove(prGlueInfo); + } +#endif + + /* 4 <5> Release the Bus */ + glBusRelease(prDev); + + kalHaltUnlock(); + wlanDebugUninit(); + /* 4 <6> Unregister the card */ + wlanNetUnregister(prDev->ieee80211_ptr); + + /* 4 <7> Destroy the device */ + wlanNetDestroy(prDev->ieee80211_ptr); + prDev = NULL; + + DBGLOG(INIT, LOUD, "wlanUnregisterNotifier...\n"); + wlanUnregisterNotifier(); + + DBGLOG(INIT, INFO, "wlanRemove ok\n"); +} /* end of wlanRemove() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver entry point when the driver is configured as a Linux Module, and +* is called once at module load time, by the user-level modutils +* application: insmod or modprobe. +* +* \retval 0 Success +*/ +/*----------------------------------------------------------------------------*/ +/* 1 Module Entry Point */ +static int initWlan(void) +{ + int ret = 0, i; +#if DBG + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = DBG_CLASS_MASK; /* enable all */ +#else + /* Initial debug level is D1 */ + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = DBG_CLASS_ERROR | DBG_CLASS_WARN | DBG_CLASS_INFO | DBG_CLASS_STATE; +#endif /* DBG */ + DBGLOG(INIT, INFO, "initWlan\n"); + + spin_lock_init(&g_p2p_lock); + + /* memory pre-allocation */ + kalInitIOBuffer(); + procInitFs(); + createWirelessDevice(); + if (gprWdev) + glP2pCreateWirelessDevice((P_GLUE_INFO_T) wiphy_priv(gprWdev->wiphy)); + + ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0 : -EIO); + + if (ret == -EIO) { + kalUninitIOBuffer(); + return ret; + } +#if (CFG_CHIP_RESET_SUPPORT) + glResetInit(); +#endif + + /* register set_dbg_level handler to mtk_wmt_wifi */ + register_set_dbg_level_handler(set_dbg_level_handler); + + /* Set the initial DEBUG CLASS of each module */ + return ret; +} /* end of initWlan() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver exit point when the driver as a Linux Module is removed. Called +* at module unload time, by the user level modutils application: rmmod. +* This is our last chance to clean up after ourselves. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +/* 1 Module Leave Point */ +static VOID exitWlan(void) +{ + DBGLOG(INIT, INFO, "exitWlan\n"); + + /* unregister set_dbg_level handler to mtk_wmt_wifi */ + register_set_dbg_level_handler(NULL); + +#if CFG_CHIP_RESET_SUPPORT + glResetUninit(); +#endif + destroyWirelessDevice(); + glP2pDestroyWirelessDevice(); + + glUnregisterBus(wlanRemove); + + /* free pre-allocated memory */ + kalUninitIOBuffer(); + + DBGLOG(INIT, INFO, "exitWlan\n"); + procUninitProcFs(); + +} /* end of exitWlan() */ + +#ifdef MTK_WCN_BUILT_IN_DRIVER + +int mtk_wcn_wlan_gen2_init(void) +{ + return initWlan(); +} +EXPORT_SYMBOL(mtk_wcn_wlan_gen2_init); + +void mtk_wcn_wlan_gen2_exit(void) +{ + return exitWlan(); +} +EXPORT_SYMBOL(mtk_wcn_wlan_gen2_exit); + +#else + +module_init(initWlan); +module_exit(exitWlan); + +#endif + +MODULE_AUTHOR(NIC_AUTHOR); +MODULE_DESCRIPTION(NIC_DESC); +MODULE_SUPPORTED_DEVICE(NIC_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c new file mode 100644 index 0000000000000..e8f4f76960a52 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_kal.c @@ -0,0 +1,4801 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_kal.c#3 +*/ + +/*! \file gl_kal.c + \brief GLUE Layer will export the required procedures here for internal driver stack. + + This file contains all routines which are exported from GLUE Layer to internal + driver stack. +*/ + +/* +** Log: gl_kal.c +** +** 08 20 2012 yuche.tsai +** NULL +** Fix possible KE issue. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 05 31 2012 terry.wu + * NULL + * . + * + * 03 26 2012 cp.wu + * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist + * invoke put_cred() after get_current_cred() calls. + * + * 03 07 2012 yuche.tsai + * NULL + * Fix compile error when WiFi Direct is off. + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 02 20 2012 cp.wu + * [WCXRP00001187] [MT6620 Wi-Fi][Driver][Android] Add error handling while firmware image doesn't exist + * do not need to invoke free() while firmware image file doesn't exist + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 21 2011 cp.wu + * [WCXRP00001118] [MT6620 Wi-Fi][Driver] Corner case protections to pass Monkey testing + * 1. wlanoidQueryBssIdList might be passed with a non-zero length but a NULL pointer of buffer + * add more checking for such cases + * + * 2. kalSendComplete() might be invoked with a packet belongs to P2P network right after P2P is unregistered. + * add some tweaking to protect such cases because that net device has become invalid. + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 16 2011 yuche.tsai + * NULL + * Avoid using work thread. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 23 2011 yuche.tsai + * [WCXRP00000998] [Volunteer Patch][WiFi Direct][FW] P2P Social Channel & country domain issue + * Regulation domain feature check in. + * + * 08 12 2011 cp.wu + * [WCXRP00000913] [MT6620 Wi-Fi] create repository of source code dedicated for MT6620 E6 ASIC + * load WIFI_RAM_CODE_E6 for MT6620 E6 ASIC. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 06 13 2011 eddie.chen + * [WCXRP00000779] [MT6620 Wi-Fi][DRV] Add tx rx statistics in linux and use netif_rx_ni + * Add tx rx statistics and netif_rx_ni. + * + * 04 15 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW short range mode. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated + * network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 04 08 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * correct i4TxPendingFrameNum decreasing. + * + * 03 23 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * apply multi-queue operation only for linux kernel > 2.6.26 + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability for compatible with linux 2.6.12. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * improve portability for awareness of early version of linux kernel and wireless extension. + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * refix ... + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * correct compiling warning/error. + * + * 03 18 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * add more robust fault tolerance design when pre-allocation failed. (rarely happen) + * + * 03 17 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * use pre-allocated buffer for storing enhanced interrupt response as well + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similar APIs to hide the difference. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 14 2011 jeffrey.chang + * [WCXRP00000546] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] fix kernel build warning message + * fix kernel build warning message + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after + * connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 01 24 2011 cp.wu + * [WCXRP00000382] [MT6620 Wi-Fi][Driver] Track forwarding packet number with notifying tx thread for serving + * 1. add an extra counter for tracking pending forward frames. + * 2. notify TX service thread as well when there is pending forward frame + * 3. correct build errors leaded by introduction of Wi-Fi direct separation module + * + * 01 19 2011 cp.wu + * [WCXRP00000371] [MT6620 Wi-Fi][Driver] make linux glue layer portable for Android 2.3.1 with Linux 2.6.35.7 + * add compile option to check linux version 2.6.35 for different usage of system API to improve portability + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues + * due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field + * checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used + * to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 11 02 2010 jeffrey.chang + * [WCXRP00000145] [MT6620 Wi-Fi][Driver] fix issue of byte endian in packet classifier which discards BoW packets + * . + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 26 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000137] [MT6620 Wi-Fi] [FW] + * Support NIC capability query command + * 1) update NVRAM content template to ver 1.02 + * 2) add compile option for querying NIC capability (default: off) + * 3) modify AIS 5GHz support to run-time option, which could be turned on by registry or NVRAM setting + * 4) correct auto-rate compiler error under linux (treat warning as error) + * 5) simplify usage of NVRAM and REG_INFO_T + * 6) add version checking between driver and firmware + * + * 10 25 2010 jeffrey.chang + * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform + * Remove redundant code which cause mismatch of power control release + * + * 10 25 2010 jeffrey.chang + * [WCXRP00000129] [MT6620] [Driver] Kernel panic when rmmod module on Andriod platform + * Remove redundant GLUE_HALT condfition to avoid unmatched release of power control + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue + * refine the scan ioctl to prevent hanging of Android UI + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 06 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * if there is NVRAM, then use MAC address on NVRAM as default MAC address. + * + * 10 06 2010 cp.wu + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * code reorganization to improve isolation between GLUE and CORE layers. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + * associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 30 2010 cp.wu + * NULL + * API added: nicTxPendingPackets(), for simplifying porting layer + * + * 08 20 2010 yuche.tsai + * NULL + * Support second interface indicate when enabling P2P. + * + * 08 18 2010 yarco.yang + * NULL + * 1. Fixed HW checksum offload function not work under Linux issue. + * 2. Add debug message. + * + * 08 16 2010 jeffrey.chang + * NULL + * remove redundant code which cause kernel panic + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 jeffrey.chang + * + * add new KAL api + * + * 07 23 2010 jeffrey.chang + * + * bug fix: allocate regInfo when disabling firmware download + * + * 07 23 2010 jeffrey.chang + * + * use glue layer api to decrease or increase counter atomically + * + * 07 22 2010 jeffrey.chang + * + * modify tx thread and remove some spinlock + * + * 07 22 2010 jeffrey.chang + * + * use different spin lock for security frame + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * add spinlock for pending security frame count + * + * 07 19 2010 jeffrey.chang + * + * adjust the timer unit to microsecond + * + * 07 19 2010 jeffrey.chang + * + * timer should return value greater than zero + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 19 2010 jeffrey.chang + * + * add new kal api + * + * 07 19 2010 jeffrey.chang + * + * for linux driver migration + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 yarco.yang + * [WPD00003837][MT6620]Data Path Refine + * Merge g_arStaRec[] into adapter->arStaRec[] + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * remove unused files. + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix private ioctl for rftest + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * workaround for fixing request_firmware() failure on android 2.1 + * + * 05 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix kernel panic when debug mode enabled + * + * 05 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) Modify set mac address code + * 2) remove power management macro + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Disable network interface after disassociation + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 15 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * change firmware name + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * flush pending TX packets while unloading driver + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set driver own before handling cmd queue + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used + * 2) fix ioctl + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler + * * * * * * * * * * * * * * * * * * capability + * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add spinlock for i4TxPendingFrameNum access + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * * 2) add KAPI for handling association info + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix spinlock usage + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding firmware download KAPI + * + * 04 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Set MAC address from firmware + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1. free cmdinfo after command is emiited. + * 2. for BoW frames, user priority is extracted from sk_buff directly. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)deliver the kalOidComplete status to upper layer + * (2) fix spin lock + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * * 2) add 2 kal API for later integration + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * raising the priority of processing interrupt + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Bug fix: the tx thread will cause starvation of MMC thread, and the interrupt will never come in + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding secondary command queue for improving non-glue code portability + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download kal api + * + * 03 25 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add Bluetooth-over-Wifi frame header check + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\50 2009-09-28 20:19:08 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\49 2009-08-18 22:56:44 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\48 2009-06-23 23:18:58 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\47 2008-11-19 11:55:43 GMT mtk01088 +** fixed some lint warning, and rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\46 2008-09-02 21:07:42 GMT mtk01461 +** Remove ASSERT(pvBuf) in kalIndicateStatusAndComplete(), this parameter can be NULL +** \main\maintrunk.MT5921\45 2008-08-29 16:03:21 GMT mtk01088 +** remove non-used code for code review, add assert check +** \main\maintrunk.MT5921\44 2008-08-21 00:32:49 GMT mtk01461 +** \main\maintrunk.MT5921\43 2008-05-30 20:27:02 GMT mtk01461 +** Rename KAL function +** \main\maintrunk.MT5921\42 2008-05-30 15:47:29 GMT mtk01461 +** \main\maintrunk.MT5921\41 2008-05-30 15:13:04 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\40 2008-05-29 14:15:14 GMT mtk01084 +** remove un-used KAL function +** \main\maintrunk.MT5921\39 2008-05-03 15:17:30 GMT mtk01461 +** Move Query Media Status to GLUE +** \main\maintrunk.MT5921\38 2008-04-24 11:59:44 GMT mtk01461 +** change awake queue threshold and remove code which mark #if 0 +** \main\maintrunk.MT5921\37 2008-04-17 23:06:35 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\36 2008-04-08 15:38:56 GMT mtk01084 +** add KAL function to setting pattern search function enable/ disable +** \main\maintrunk.MT5921\35 2008-04-01 23:53:13 GMT mtk01461 +** Add comment +** \main\maintrunk.MT5921\34 2008-03-26 15:36:48 GMT mtk01461 +** Add update MAC Address for Linux +** \main\maintrunk.MT5921\33 2008-03-18 11:49:34 GMT mtk01084 +** update function for initial value access +** \main\maintrunk.MT5921\32 2008-03-18 10:25:22 GMT mtk01088 +** use kal update associate request at linux +** \main\maintrunk.MT5921\31 2008-03-06 23:43:08 GMT mtk01385 +** 1. add Query Registry Mac address function. +** \main\maintrunk.MT5921\30 2008-02-26 09:47:57 GMT mtk01084 +** modify KAL set network address/ checksum offload part +** \main\maintrunk.MT5921\29 2008-02-12 23:26:53 GMT mtk01461 +** Add debug option - Packet Order for Linux +** \main\maintrunk.MT5921\28 2008-01-09 17:54:43 GMT mtk01084 +** modify the argument of kalQueryPacketInfo() +** \main\maintrunk.MT5921\27 2007-12-24 16:02:03 GMT mtk01425 +** 1. Revise csum offload +** \main\maintrunk.MT5921\26 2007-11-30 17:03:36 GMT mtk01425 +** 1. Fix bugs +** +** \main\maintrunk.MT5921\25 2007-11-29 01:57:17 GMT mtk01461 +** Fix Windows RX multiple packet retain problem +** \main\maintrunk.MT5921\24 2007-11-20 11:24:07 GMT mtk01088 +** CR90, not doing the netif_carrier_off to let supplicant 1x pkt can be rcv at hardstattXmit +** \main\maintrunk.MT5921\23 2007-11-09 16:36:44 GMT mtk01425 +** 1. Modify for CSUM offloading with Tx Fragment +** \main\maintrunk.MT5921\22 2007-11-07 18:37:39 GMT mtk01461 +** Add Tx Fragmentation Support +** \main\maintrunk.MT5921\21 2007-11-06 19:34:06 GMT mtk01088 +** add the WPS code, indicate the mgmt frame to upper layer +** \main\maintrunk.MT5921\20 2007-11-02 01:03:21 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\19 2007-10-30 11:59:38 GMT MTK01425 +** 1. Update wlanQueryInformation +** \main\maintrunk.MT5921\18 2007-10-30 10:44:57 GMT mtk01425 +** 1. Refine multicast list code +** 2. Refine TCP/IP csum offload code +** +** Revision 1.5 2007/07/17 13:01:18 MTK01088 +** add associate req and rsp function +** +** Revision 1.4 2007/07/13 05:19:19 MTK01084 +** provide timer set functions +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include "gl_os.h" +#include "gl_wext.h" +#include "precomp.h" +#if defined(CONFIG_MTK_TC1_FEATURE) +#include +#endif +#if CFG_SUPPORT_AGPS_ASSIST +#include +#endif +#if CFG_SUPPORT_WAKEUP_REASON_DEBUG +#include +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if DBG +int allocatedMemSize = 0; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +/* #define MTK_DMA_BUF_MEMCPY_SUP */ +static PVOID pvIoBuffer; + +#ifdef MTK_DMA_BUF_MEMCPY_SUP +static PVOID pvIoPhyBuf; +static PVOID pvDmaBuffer; +static PVOID pvDmaPhyBuf; +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + +static UINT_32 pvIoBufferSize; +static UINT_32 pvIoBufferUsage; +static struct KAL_HALT_CTRL_T rHaltCtrl = { + .lock = __SEMAPHORE_INITIALIZER(rHaltCtrl.lock, 1), + .owner = NULL, + .fgHalt = TRUE, + .fgHeldByKalIoctl = FALSE, + .u4HoldStart = 0, +}; +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT +typedef enum _ENUM_WMTHWVER_TYPE_T { + WMTHWVER_MT6620_E1 = 0x0, + WMTHWVER_MT6620_E2 = 0x1, + WMTHWVER_MT6620_E3 = 0x2, + WMTHWVER_MT6620_E4 = 0x3, + WMTHWVER_MT6620_E5 = 0x4, + WMTHWVER_MT6620_E6 = 0x5, + WMTHWVER_MT6620_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo) +{ + KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &(prGlueInfo->rAhbIsrWakeLock), (HZ / 10)); /* 100ms */ +} + +#if CFG_ENABLE_FW_DOWNLOAD + +static struct file *filp; +static uid_t orgfsuid; +static gid_t orgfsgid; +static mm_segment_t orgfs; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* open firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo) +{ + UINT_8 aucFilePath[50]; + + /* FIX ME: since we don't have hotplug script in the filesystem + * , so the request_firmware() KAPI can not work properly + */ + + /* save uid and gid used for filesystem access. + * set user and group to 0(root) */ + struct cred *cred = (struct cred *)get_current_cred(); + + orgfsuid = cred->fsuid.val; + orgfsgid = cred->fsgid.val; + cred->fsuid.val = cred->fsgid.val = 0; + + ASSERT(prGlueInfo); + + orgfs = get_fs(); + set_fs(get_ds()); + + /* open the fw file */ +#if defined(MT6620) & CFG_MULTI_ECOVER_SUPPORT + switch (mtk_wcn_wmt_hwver_get()) { + case WMTHWVER_MT6620_E1: + case WMTHWVER_MT6620_E2: + case WMTHWVER_MT6620_E3: + case WMTHWVER_MT6620_E4: + case WMTHWVER_MT6620_E5: + filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); + break; + + case WMTHWVER_MT6620_E6: + default: + filp = filp_open("/etc/firmware/" CFG_FW_FILENAME "_E6", O_RDONLY, 0); + break; + } +#elif defined(MT6628) +/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6628", O_RDONLY, 0); */ +/* filp = filp_open("/etc/firmware/"CFG_FW_FILENAME"_MT6582", O_RDONLY, 0); */ +#if 0 /* new wifi ram code mechanism, waiting firmware ready, then we can enable these code */ + kalMemZero(aucFilePath, sizeof(aucFilePath)); + kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_AD", sizeof("/etc/firmware/" CFG_FW_FILENAME "_AD")); + filp = filp_open(aucFilePath, O_RDONLY, 0); + if (!IS_ERR(filp)) + goto open_success; +#endif + kalMemZero(aucFilePath, sizeof(aucFilePath)); + kalMemCopy(aucFilePath, "/etc/firmware/" CFG_FW_FILENAME "_", strlen("/etc/firmware/" CFG_FW_FILENAME "_")); + glGetChipInfo(prGlueInfo, &aucFilePath[strlen("/etc/firmware/" CFG_FW_FILENAME "_")]); + + DBGLOG(INIT, INFO, "open file: %s\n", aucFilePath); + + filp = filp_open(aucFilePath, O_RDONLY, 0); +#else + filp = filp_open("/etc/firmware/" CFG_FW_FILENAME, O_RDONLY, 0); +#endif + if (IS_ERR(filp)) { + DBGLOG(INIT, ERROR, "Open FW image: %s failed\n", CFG_FW_FILENAME); + goto error_open; + } +#if 0 +open_success: +#endif + DBGLOG(INIT, TRACE, "Open FW image: %s done\n", CFG_FW_FILENAME); + return WLAN_STATUS_SUCCESS; + +error_open: + /* restore */ + set_fs(orgfs); + cred->fsuid.val = orgfsuid; + cred->fsgid.val = orgfsgid; + put_cred(cred); + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* release firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + if ((filp != NULL) && !IS_ERR(filp)) { + /* close firmware file */ + filp_close(filp, NULL); + + /* restore */ + set_fs(orgfs); + { + struct cred *cred = (struct cred *)get_current_cred(); + + cred->fsuid.val = orgfsuid; + cred->fsgid.val = orgfsgid; + put_cred(cred); + } + filp = NULL; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* load firmware image in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, OUT PVOID prBuf, IN UINT_32 u4Offset, OUT PUINT_32 pu4Size) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + ASSERT(prBuf); + + /* l = filp->f_path.dentry->d_inode->i_size; */ +#if 0 + /* the object must have a read method */ + if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) || (filp->f_op->read == NULL)) { + goto error_read; + } else { + filp->f_pos = u4Offset; + *pu4Size = filp->f_op->read(filp, prBuf, *pu4Size, &filp->f_pos); + } +#else + /* the object must have a read method */ + if ((filp == NULL) || IS_ERR(filp) || (filp->f_op == NULL) ) { + goto error_read; + } else { + filp->f_pos = u4Offset; + *pu4Size = vfs_read(filp, prBuf, *pu4Size, &filp->f_pos); + } +#endif + + return WLAN_STATUS_SUCCESS; + +error_read: + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to +* query firmware image size in kernel space +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_32 pu4Size) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + + //*pu4Size = filp->f_path.dentry->d_inode->i_size; + *pu4Size = filp->f_op->llseek(filp, 0, 2); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to load firmware image +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image +* \param pu4FileLength File length and memory mapped length as well + +* \retval Map File Handle, used for unammping +*/ +/*----------------------------------------------------------------------------*/ + +PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) +{ + UINT_32 u4FwSize = 0; + PVOID prFwBuffer = NULL; + + DEBUGFUNC("kalFirmwareImageMapping"); + + ASSERT(prGlueInfo); + ASSERT(ppvMapFileBuf); + ASSERT(pu4FileLength); + + do { + /* <1> Open firmware */ + if (kalFirmwareOpen(prGlueInfo) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, TRACE, "kalFirmwareOpen fail!\n"); + break; + } + + /* <2> Query firmare size */ + kalFirmwareSize(prGlueInfo, &u4FwSize); + printk(KERN_ERR "%s firmware size %d\n", __FUNCTION__, u4FwSize); + /* <3> Use vmalloc for allocating large memory trunk */ + prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); + /* <4> Load image binary into buffer */ + if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, &u4FwSize) != WLAN_STATUS_SUCCESS) { + vfree(prFwBuffer); + kalFirmwareClose(prGlueInfo); + DBGLOG(INIT, TRACE, "kalFirmwareLoad fail!\n"); + break; + } + /* <5> write back info */ + *pu4FileLength = u4FwSize; + *ppvMapFileBuf = prFwBuffer; + + return prFwBuffer; + + } while (FALSE); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to unload firmware image mapped memory +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param pvFwHandle Pointer to mapping handle +* \param pvMapFileBuf Pointer to memory-mapped firmware image +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ + +VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) +{ + DEBUGFUNC("kalFirmwareImageUnmapping"); + + ASSERT(prGlueInfo); + + /* pvMapFileBuf might be NULL when file doesn't exist */ + if (pvMapFileBuf) + vfree(pvMapFileBuf); + + kalFirmwareClose(prGlueInfo); +} + +#endif + +#if 0 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to load firmware image +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image +* \param pu4FileLength File length and memory mapped length as well + +* \retval Map File Handle, used for unammping +*/ +/*----------------------------------------------------------------------------*/ + +PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength) +{ + INT_32 i4Ret = 0; + + DEBUGFUNC("kalFirmwareImageMapping"); + + ASSERT(prGlueInfo); + ASSERT(ppvMapFileBuf); + ASSERT(pu4FileLength); + + do { + GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; + + prGlueInfo->prFw = NULL; + + /* <1> Open firmware */ + i4Ret = request_firmware(&prGlueInfo->prFw, CFG_FW_FILENAME, prHifInfo->Dev); + + if (i4Ret) { + DBGLOG(INIT, TRACE, "fw %s:request failed %d\n", CFG_FW_FILENAME, i4Ret); + break; + } + *pu4FileLength = prGlueInfo->prFw->size; + *ppvMapFileBuf = prGlueInfo->prFw->data; + return prGlueInfo->prFw->data; + + } while (FALSE); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to unload firmware image mapped memory +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* \param pvFwHandle Pointer to mapping handle +* \param pvMapFileBuf Pointer to memory-mapped firmware image +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ + +VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) +{ + DEBUGFUNC("kalFirmwareImageUnmapping"); + + ASSERT(prGlueInfo); + ASSERT(pvMapFileBuf); + + release_firmware(prGlueInfo->prFw); + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to acquire +* OS SPIN_LOCK. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[out] pu4Flags Pointer of a variable for saving IRQ flags +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags) +{ + unsigned long u4Flags = 0; + + ASSERT(prGlueInfo); + ASSERT(pu4Flags); + + if (rLockCategory < SPIN_LOCK_NUM) { + +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + + *pu4Flags = u4Flags; +/* DBGLOG(INIT, TRACE, ("A+%d\n", rLockCategory)); */ + } + +} /* end of kalAcquireSpinLock() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to release +* OS SPIN_LOCK. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[in] u4Flags Saved IRQ flags +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags) +{ + ASSERT(prGlueInfo); + + if (rLockCategory < SPIN_LOCK_NUM) { + /* DBGLOG(INIT, TRACE, ("A-%d %d %d\n", rLockCategory, u4MemAllocCnt, u4MemFreeCnt)); */ +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], u4Flags); +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + + } + +} /* end of kalReleaseSpinLock() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is provided by GLUE Layer for internal driver stack to update +* current MAC address. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pucMacAddr Pointer of current MAC address +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr) +{ + ASSERT(prGlueInfo); + ASSERT(pucMacAddr); + + if (UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) + memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, PARAM_MAC_ADDR_LEN); + +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! +* \brief To query the packet information for offload related parameters. +* +* \param[in] pvPacket Pointer to the packet descriptor. +* \param[in] pucFlag Points to the offload related parameter. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag) +{ + struct sk_buff *skb = (struct sk_buff *)pvPacket; + UINT_8 ucFlag = 0; + + ASSERT(pvPacket); + ASSERT(pucFlag); + + + if (skb->ip_summed == CHECKSUM_PARTIAL) { +#if DBG + /* Kevin: do double check, we can remove this part in Normal Driver. + * Because we register NIC feature with NETIF_F_IP_CSUM for MT5912B MAC, so + * we'll process IP packet only. + */ + if (skb->protocol != htons(ETH_P_IP)) { + /* printk("Wrong skb->protocol( = %08x) for TX Checksum Offload.\n", skb->protocol); */ + } else +#endif + ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); + } + + *pucFlag = ucFlag; + +} /* kalQueryChksumOffloadParam */ + +/* 4 2007/10/8, mikewu, this is rewritten by Mike */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief To update the checksum offload status to the packet to be indicated to OS. +* +* \param[in] pvPacket Pointer to the packet descriptor. +* \param[in] pucFlag Points to the offload related parameter. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T aeCSUM[]) +{ + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + ASSERT(pvPacket); + + if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS) && + ((aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) || (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb->ip_summed = CHECKSUM_NONE; +#if DBG + if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) + DBGLOG(RX, TRACE, "RX: \"non-IPv4/IPv6\" Packet\n"); + else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) + DBGLOG(RX, TRACE, "RX: \"bad IP Checksum\" Packet\n"); + else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) + DBGLOG(RX, TRACE, "RX: \"bad TCP Checksum\" Packet\n"); + else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) + DBGLOG(RX, TRACE, "RX: \"bad UDP Checksum\" Packet\n"); + else + /* Do nothing */ +#endif + } + +} /* kalUpdateRxCSUMOffloadParam */ +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called to free packet allocated from kalPacketAlloc. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of the packet descriptor +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) +{ + dev_kfree_skb((struct sk_buff *)pvPacket); + if (prGlueInfo) + prGlueInfo->u8SkbFreed++; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Only handles driver own creating packet (coalescing buffer). +* +* \param prGlueInfo Pointer of GLUE Data Structure +* \param u4Size Pointer of Packet Handle +* \param ppucData Status Code for OS upper layer +* +* \return NULL: Failed to allocate skb, Not NULL get skb +*/ +/*----------------------------------------------------------------------------*/ +PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData) +{ + struct sk_buff *prSkb = dev_alloc_skb(u4Size); + + if (prSkb) + *ppucData = (PUINT_8) (prSkb->data); +#if DBG + { + PUINT_32 pu4Head = (PUINT_32) &prSkb->cb[0]; + *pu4Head = (UINT_32) prSkb->head; + DBGLOG(RX, TRACE, "prSkb->head = %#x, prSkb->cb = %#x\n", (UINT_32) prSkb->head, *pu4Head); + } +#endif + return (PVOID) prSkb; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Process the received packet for indicating to OS. +* +* \param[in] prGlueInfo Pointer to the Adapter structure. +* \param[in] pvPacket Pointer of the packet descriptor +* \param[in] pucPacketStart The starting address of the buffer of Rx packet. +* \param[in] u4PacketLen The packet length. +* \param[in] pfgIsRetain Is the packet to be retained. +* \param[in] aerCSUM The result of TCP/ IP checksum offload. +* +* \retval WLAN_STATUS_SUCCESS. +* \retval WLAN_STATUS_FAILURE. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, + /* IN PBOOLEAN pfgIsRetain, */ + IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aerCSUM[]) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + skb->data = pucPacketStart; + skb_reset_tail_pointer(skb); /* reset tail pointer first, for 64bit kernel,we should call linux kernel API */ + skb_trim(skb, 0); /* only if skb->len > len, then skb_trim has effect */ + skb_put(skb, u4PacketLen); /* shift tail and skb->len to correct value */ + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + kalUpdateRxCSUMOffloadParam(skb, aerCSUM); +#endif + + return rStatus; +} + +#if (CONF_HIF_LOOPBACK_AUTO == 1) +/*----------------------------------------------------------------------------*/ +/*! +* \brief Do HIF loopback test. +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +unsigned int testmode = 0; +unsigned int testlen = 64; + +void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo) +{ +#define HIF_LOOPBK_AUTO_TEST_LEN 1600 +/* GL_HIF_INFO_T *HifInfo; */ + static unsigned int txcnt; + struct sk_buff *MsduInfo; + UINT_8 *Pkt; + UINT_32 RegVal; + UINT_32 PktLen = 16; + + /* Init */ + if (testmode != 0) { + PktLen = kalRandomNumber() % 1520; + if (PktLen < 64) + PktLen = 64; + } else { + PktLen = testlen++; + if (PktLen > 1520) { + testmode = 1; + PktLen = 64; + } + } + +/* PktLen = 100; */ + DBGLOG(INIT, INFO, "kalDevLoopbkAuto> Send a packet to HIF (len = %d) (total = %d)...\n", PktLen, ++txcnt); +/* HifInfo = &GlueInfo->rHifInfo; */ + + /* Allocate a MSDU_INFO_T */ + MsduInfo = kalPacketAlloc(GlueInfo, HIF_LOOPBK_AUTO_TEST_LEN, &Pkt); + if (MsduInfo == NULL) { + DBGLOG(INIT, WARN, "No PKT_INFO_T for sending loopback packet!\n"); + return; + } + + /* Init the packet */ + MsduInfo->dev = GlueInfo->prDevHandler; + if (MsduInfo->dev == NULL) { + DBGLOG(INIT, WARN, "MsduInfo->dev == NULL!!\n"); + kalPacketFree(GlueInfo, MsduInfo); + return; + } + + MsduInfo->len = PktLen; + kalMemSet(MsduInfo->data, 0xff, 6); + kalMemSet(MsduInfo->data + 6, 0x5a, PktLen - 6); + + /* Simulate OS to send the packet */ + wlanHardStartXmit(MsduInfo, MsduInfo->dev); + +#if 0 + PktLen += 4; + if (PktLen >= 1600) + PktLen = 16; +#endif + + /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ +/* HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(1000); */ +/* add_timer(&(HifInfo->HifTmrLoopbkFn)); */ +} + +int kalDevLoopbkThread(IN void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); + GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; + int ret; + static int test; + + while (TRUE) { + ret = wait_event_interruptible(HifInfo->HifWaitq, (HifInfo->HifLoopbkFlg != 0)); + + if (HifInfo->HifLoopbkFlg == 0xFFFFFFFF) + break; + + while (TRUE) { + /* if ((HifInfo->HifLoopbkFlg & 0x01) == 0) */ + if (GlueInfo->i4TxPendingFrameNum < 64) { + DBGLOG(INIT, INFO, "GlueInfo->i4TxPendingFrameNum = %d\n", + GlueInfo->i4TxPendingFrameNum); + kalDevLoopbkAuto(GlueInfo); + + if (testmode == 0) + kalMsleep(3000); + } else + kalMsleep(1); + } + } +} + +void kalDevLoopbkRxHandle(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + static unsigned int rxcnt; + UINT_32 i; + UINT_8 *Buf = prSwRfb->pucRecvBuff + sizeof(HIF_TX_HEADER_T); + P_HIF_RX_HEADER_T prHifRxHdr = prSwRfb->prHifRxHdr; + UINT_32 len = prHifRxHdr->u2PacketLen - sizeof(HIF_TX_HEADER_T); + + if (len > 1600) { + while (1) + DBGLOG(INIT, ERROR, "HIF> Loopback len > 1600!!! error!!!\n"); + } + + for (i = 0; i < 6; i++) { + if (Buf[i] != 0xff) { + while (1) { + DBGLOG(INIT, ERROR, "HIF> Loopbk dst addr error (len = %d)!\n", len); + dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); + } + } + } + + for (i = 6; i < len; i++) { + if (Buf[i] != 0x5a) { + while (1) { + DBGLOG(INIT, ERROR, "HIF> Loopbk error (len = %d)!\n", len); + dumpMemory8(prSwRfb->pucRecvBuff, prHifRxHdr->u2PacketLen); + } + } + } + + DBGLOG(INIT, INFO, "HIF> Loopbk OK (len = %d) (total = %d)!\n", len, ++rxcnt); +} +#endif /* CONF_HIF_LOOPBACK_AUTO */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate an array of received packets is available for higher +* level protocol uses. +* +* \param[in] prGlueInfo Pointer to the Adapter structure. +* \param[in] apvPkts The packet array to be indicated +* \param[in] ucPktNum The number of packets to be indicated +* +* \retval TRUE Success. +* +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum) +{ + UINT_8 ucIdx = 0; + struct net_device *prNetDev = prGlueInfo->prDevHandler; + struct sk_buff *prSkb = NULL; + + ASSERT(prGlueInfo); + ASSERT(apvPkts); + +#if CFG_BOW_TEST + UINT_32 i; +#endif + + for (ucIdx = 0; ucIdx < ucPktNum; ucIdx++) { + prSkb = apvPkts[ucIdx]; +#if DBG + do { + PUINT_8 pu4Head = (PUINT_8) &prSkb->cb[0]; + UINT_32 u4HeadValue = 0; + + kalMemCopy(&u4HeadValue, pu4Head, sizeof(u4HeadValue)); + DBGLOG(RX, TRACE, "prSkb->head = %p, prSkb->cb = 0x%x\n", pu4Head, u4HeadValue); + } while (0); +#endif + + if (GLUE_GET_PKT_IS_P2P(prSkb)) { + /* P2P */ +#if CFG_ENABLE_WIFI_DIRECT + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + prNetDev = kalP2PGetDevHdlr(prGlueInfo); + /* prNetDev->stats.rx_bytes += prSkb->len; */ + /* prNetDev->stats.rx_packets++; */ + prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes += prSkb->len; + prGlueInfo->prP2PInfo->rNetDevStats.rx_packets++; + +#else + prNetDev = prGlueInfo->prDevHandler; +#endif + } else if (GLUE_GET_PKT_IS_PAL(prSkb)) { + /* BOW */ +#if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_SEPARATE_DATA_PATH + if (prGlueInfo->rBowInfo.fgIsNetRegistered) + prNetDev = prGlueInfo->rBowInfo.prDevHandler; +#else + prNetDev = prGlueInfo->prDevHandler; +#endif + } else { + /* AIS */ + prNetDev = prGlueInfo->prDevHandler; + prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; + prGlueInfo->rNetDevStats.rx_packets++; + + } + + /* check if the "unicast" packet is from us */ + if (kalMemCmp(prSkb->data, prSkb->data + 6, 6) == 0) { + /* we will filter broadcast/multicast packet sent from us in hardware */ + /* source address = destination address ? */ + DBGLOG(RX, EVENT, + "kalRxIndicatePkts got from us!!! Drop it! ([ %pM ] len %d)\n", + prSkb->data, prSkb->len); + wlanReturnPacket(prGlueInfo->prAdapter, prSkb); + continue; + } +#if (CFG_SUPPORT_TDLS == 1) + if (TdlsexRxFrameDrop(prGlueInfo, prSkb->data) == TRUE) { + /* drop the received TDLS action frame */ + DBGLOG(TDLS, WARN, + " %s: drop a received packet from %pM %u\n", + __func__, prSkb->data, + (UINT32) ((P_ADAPTER_T) (prGlueInfo->prAdapter))->rRxCtrl.rFreeSwRfbList.u4NumElem); + wlanReturnPacket(prGlueInfo->prAdapter, prSkb); + continue; + } + + /* + get a TDLS request/response/confirm, we need to parse the HT IE + because older supplicant does not pass HT IE to us + */ + TdlsexRxFrameHandle(prGlueInfo, prSkb->data, prSkb->len); +#endif /* CFG_SUPPORT_TDLS */ + + STATS_RX_PKT_INFO_DISPLAY(prSkb->data); + + //prNetDev->last_rx = jiffies; + prSkb->protocol = eth_type_trans(prSkb, prNetDev); + prSkb->dev = prNetDev; + /* DBGLOG_MEM32(RX, TRACE, (PUINT_32)prSkb->data, prSkb->len); */ + DBGLOG(RX, TRACE, "kalRxIndicatePkts len = %d\n", prSkb->len); + +#if CFG_BOW_TEST + DBGLOG(BOW, TRACE, "Rx sk_buff->len: %d\n", prSkb->len); + DBGLOG(BOW, TRACE, "Rx sk_buff->data_len: %d\n", prSkb->data_len); + DBGLOG(BOW, TRACE, "Rx sk_buff->data:\n"); + + for (i = 0; i < prSkb->len; i++) { + DBGLOG(BOW, TRACE, "%4x", prSkb->data[i]); + + if ((i + 1) % 16 == 0) + DBGLOG(BOW, TRACE, "\n"); + } + + DBGLOG(BOW, TRACE, "\n"); +#endif + + if (!in_interrupt()) + netif_rx_ni(prSkb); /* only in non-interrupt context */ + else + netif_rx(prSkb); + + wlanReturnPacket(prGlueInfo->prAdapter, NULL); + } + + kalPerMonStart(prGlueInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Called by driver to indicate event to upper layer, for example, the wpa +* supplicant or wireless tools. +* +* \param[in] pvAdapter Pointer to the adapter descriptor. +* \param[in] eStatus Indicated status. +* \param[in] pvBuf Indicated message buffer. +* \param[in] u4BufLen Indicated message buffer size. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 ScanCnt = 0, ScanDoneFailCnt = 0; +VOID +kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen) +{ + UINT_32 bufLen; + P_PARAM_STATUS_INDICATION_T pStatus = (P_PARAM_STATUS_INDICATION_T) pvBuf; + P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T) pStatus; + P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = (P_PARAM_PMKID_CANDIDATE_LIST_T) (pStatus + 1); + PARAM_MAC_ADDRESS arBssid; + struct cfg80211_scan_request *prScanRequest = NULL; + PARAM_SSID_T ssid; + struct ieee80211_channel *prChannel = NULL; + struct cfg80211_bss *bss; + UINT_8 ucChannelNum; + P_BSS_DESC_T prBssDesc = NULL; + struct cfg80211_scan_info info = { + .aborted = false, + }; + + GLUE_SPIN_LOCK_DECLARATION(); + + kalMemZero(arBssid, MAC_ADDR_LEN); + + ASSERT(prGlueInfo); + + switch (eStatus) { + case WLAN_STATUS_ROAM_OUT_FIND_BEST: + case WLAN_STATUS_MEDIA_CONNECT: + + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; + + /* indicate assoc event */ + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &bufLen); + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); + + /* switch netif on */ + netif_carrier_on(prGlueInfo->prDevHandler); + + do { + /* print message on console */ + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQuerySsid, &ssid, sizeof(ssid), &bufLen); + + ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? + (PARAM_MAX_LEN_SSID - 1) : ssid.u4SsidLen] = '\0'; + DBGLOG(AIS, INFO, " %s netif_carrier_on [ssid:%s %pM ]\n", + prGlueInfo->prDevHandler->name, ssid.aucSsid, arBssid); + } while (0); + + if (prGlueInfo->fgIsRegistered == TRUE) { + struct cfg80211_bss *bss_others = NULL; + UINT_8 ucLoopCnt = 15; /* only loop 15 times to avoid dead loop */ + + /* retrieve channel */ + ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); + if (ucChannelNum <= 14) { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_2GHZ)); + } else { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_5GHZ)); + } + + /* ensure BSS exists */ + bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), prChannel, arBssid, + ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + + if (bss == NULL) { + /* create BSS on-the-fly */ + prBssDesc = + wlanGetTargetBssDescByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); + + if (prBssDesc != NULL) { + bss = cfg80211_inform_bss(priv_to_wiphy(prGlueInfo), prChannel, + CFG80211_BSS_FTYPE_PRESP, + arBssid, 0, /* TSF */ + WLAN_CAPABILITY_ESS, + prBssDesc->u2BeaconInterval, /* beacon interval */ + prBssDesc->aucIEBuf, /* IE */ + prBssDesc->u2IELength, /* IE Length */ + RCPI_TO_dBm(prBssDesc->ucRCPI) * 100, /* MBM */ + GFP_KERNEL); + } + } + /* remove all bsses that before and only channel different with the current connected one + if without this patch, UI will show channel A is connected even if AP has change channel + from A to B */ + while (ucLoopCnt--) { + bss_others = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), NULL, arBssid, + ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (bss && bss_others && bss_others != bss) { + DBGLOG(SCN, INFO, "remove BSSes that only channel different\n"); + cfg80211_unlink_bss(priv_to_wiphy(prGlueInfo), bss_others); + } else + break; + } + + /* CFG80211 Indication */ + if (eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { + /*cfg80211_roamed_bss(prGlueInfo->prDevHandler, + bss, + prGlueInfo->aucReqIe, + prGlueInfo->u4ReqIeLength, + prGlueInfo->aucRspIe, prGlueInfo->u4RspIeLength, GFP_KERNEL); + */ + struct cfg80211_roam_info roam_info = { + .bss = bss, + .req_ie = prGlueInfo->aucReqIe, + .req_ie_len = prGlueInfo->u4ReqIeLength, + .resp_ie = prGlueInfo->aucRspIe, + .resp_ie_len = prGlueInfo->u4RspIeLength + }; + cfg80211_roamed(prGlueInfo->prDevHandler, + &roam_info, + GFP_KERNEL); + } else { + /* to support user space roaming, cfg80211 will change the sme_state to connecting + before reassociate */ + cfg80211_connect_result(prGlueInfo->prDevHandler, + arBssid, + prGlueInfo->aucReqIe, + prGlueInfo->u4ReqIeLength, + prGlueInfo->aucRspIe, + prGlueInfo->u4RspIeLength, WLAN_STATUS_SUCCESS, GFP_KERNEL); + } + } + + break; + + case WLAN_STATUS_MEDIA_DISCONNECT: + case WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY: + /* indicate disassoc event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); + /* For CR 90 and CR99, While supplicant do reassociate, driver will do netif_carrier_off first, + after associated success, at joinComplete(), do netif_carier_on, + but for unknown reason, the supplicant 1x pkt will not called the driver + hardStartXmit, for template workaround these bugs, add this compiling flag + */ + /* switch netif off */ + + DBGLOG(AIS, INFO, "[wifi] %s netif_carrier_off\n", + prGlueInfo->prDevHandler->name); + + netif_carrier_off(prGlueInfo->prDevHandler); + + if (prGlueInfo->fgIsRegistered == TRUE) { + P_WIFI_VAR_T prWifiVar = &prGlueInfo->prAdapter->rWifiVar; + UINT_16 u2DeauthReason = prWifiVar->arBssInfo[NETWORK_TYPE_AIS_INDEX].u2DeauthReason; + /* CFG80211 Indication */ + DBGLOG(AIS, INFO, "[wifi] %s cfg80211_disconnected\n", prGlueInfo->prDevHandler->name); + cfg80211_disconnected(prGlueInfo->prDevHandler, u2DeauthReason, NULL, 0, false, GFP_KERNEL); + } + + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + + break; + + case WLAN_STATUS_SCAN_COMPLETE: + /* indicate scan complete event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); + + /* 1. reset first for newly incoming request */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prScanRequest != NULL) { + prScanRequest = prGlueInfo->prScanRequest; + prGlueInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + /* 2. then CFG80211 Indication */ + DBGLOG(SCN, TRACE, "[ais] scan complete %p %d %d\n", prScanRequest, ScanCnt, ScanDoneFailCnt); + + if (prScanRequest != NULL) + cfg80211_scan_done(prScanRequest, &info); + break; + case WLAN_STATUS_CONNECT_INDICATION: + /* indicate AIS Jion fail event + if (prGlueInfo->prDevHandler->ieee80211_ptr->sme_state == CFG80211_SME_CONNECTING) */ + cfg80211_connect_result(prGlueInfo->prDevHandler, + prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc->aucBSSID, + prGlueInfo->aucReqIe, + prGlueInfo->u4ReqIeLength, + prGlueInfo->aucRspIe, + prGlueInfo->u4RspIeLength, WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); + break; + +#if 0 + case WLAN_STATUS_MSDU_OK: + if (netif_running(prGlueInfo->prDevHandler)) + netif_wake_queue(prGlueInfo->prDevHandler); + break; +#endif + + case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: + if (pStatus) { + switch (pStatus->eStatusType) { + case ENUM_STATUS_TYPE_AUTHENTICATION: + /* + printk(KERN_NOTICE "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [ %pM ] F:%lx\n", + pAuth->Request[0].Length, + pAuth->Request[0].Bssid, + pAuth->Request[0].Flags); + */ + /* indicate (UC/GC) MIC ERROR event only */ + if ((pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || + (pAuth->arRequest[0].u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR)) { + cfg80211_michael_mic_failure(prGlueInfo->prDevHandler, NULL, + (pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_PAIRWISE_ERROR) ? + NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP, + 0, NULL, GFP_KERNEL); + wext_indicate_wext_event(prGlueInfo, IWEVMICHAELMICFAILURE, + (unsigned char *)&pAuth->arRequest[0], + pAuth->arRequest[0].u4Length); + } + break; + + case ENUM_STATUS_TYPE_CANDIDATE_LIST: + /* + printk(KERN_NOTICE "Param_StatusType_PMKID_CandidateList: Ver(%ld) Num(%ld)\n", + pPmkid->u2Version, + pPmkid->u4NumCandidates); + if (pPmkid->u4NumCandidates > 0) { + printk(KERN_NOTICE "candidate[ %pM ] preAuth Flag:%lx\n", + pPmkid->arCandidateList[0].rBSSID, + pPmkid->arCandidateList[0].fgFlags); + } + */ + { + UINT_32 i = 0; + /*struct net_device *prDev = prGlueInfo->prDevHandler; */ + P_PARAM_PMKID_CANDIDATE_T prCand = NULL; + /* indicate pmk candidate via cfg80211 to supplicant, + the second parameter is 1000 for + cfg80211_pmksa_candidate_notify, because wpa_supplicant defined it. */ + for (i = 0; i < pPmkid->u4NumCandidates; i++) { + prCand = &pPmkid->arCandidateList[i]; + cfg80211_pmksa_candidate_notify(prGlueInfo->prDevHandler, 1000, + prCand->arBSSID, prCand->u4Flags, + GFP_KERNEL); + + wext_indicate_wext_event(prGlueInfo, + IWEVPMKIDCAND, + (unsigned char *)prCand, + pPmkid->u4NumCandidates); + } + } + break; + + default: + /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ + /* + printk(KERN_NOTICE "unknown media specific indication type:%x\n", + pStatus->StatusType); + */ + break; + } + } else { + /* + printk(KERN_WARNING "media specific indication buffer NULL\n"); + */ + } + break; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + case WLAN_STATUS_BWCS_UPDATE: + { + wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, sizeof(PTA_IPC_T)); + } + + break; + +#endif + + default: + /* + printk(KERN_WARNING "unknown indication:%lx\n", eStatus); + */ + break; + } +} /* kalIndicateStatusAndComplete */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to update the (re)association request +* information to the structure used to query and set +* OID_802_11_ASSOCIATION_INFORMATION. +* +* \param[in] prGlueInfo Pointer to the Glue structure. +* \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association +* Request frame from the AP. +* \param[in] u4FrameBodyLen The length of the frame body of the last +* (Re)Association Request frame. +* \param[in] fgReassocRequest TRUE, if it is a Reassociation Request frame. +* +* \return (none) +* +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) +{ + PUINT_8 cp; + + ASSERT(prGlueInfo); + + /* reset */ + prGlueInfo->u4ReqIeLength = 0; + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } else { + if (u4FrameBodyLen < 9) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2 */ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } else { + /* Capability information field 2 */ + /* Listen interval field 2 */ + cp += 4; + u4FrameBodyLen -= 4; + } + + wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, u4FrameBodyLen); + + if (u4FrameBodyLen <= CFG_CFG80211_IE_BUF_LEN) { + prGlueInfo->u4ReqIeLength = u4FrameBodyLen; + kalMemCopy(prGlueInfo->aucReqIe, cp, u4FrameBodyLen); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This routine is called to update the (re)association +* response information to the structure used to reply with +* cfg80211_connect_result +* +* @param prGlueInfo Pointer to adapter descriptor +* @param pucFrameBody Pointer to the frame body of the last (Re)Association +* Response frame from the AP +* @param u4FrameBodyLen The length of the frame body of the last +* (Re)Association Response frame +* +* @return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen) +{ + UINT_32 u4IEOffset = 6; /* cap_info, status_code & assoc_id */ + UINT_32 u4IELength = u4FrameBodyLen - u4IEOffset; + + ASSERT(prGlueInfo); + + /* reset */ + prGlueInfo->u4RspIeLength = 0; + + if (u4IELength <= CFG_CFG80211_IE_BUF_LEN) { + prGlueInfo->u4RspIeLength = u4IELength; + kalMemCopy(prGlueInfo->aucRspIe, pucFrameBody + u4IEOffset, u4IELength); + } + +} /* kalUpdateReAssocRspInfo */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Notify OS with SendComplete event of the specific packet. Linux should +* free packets here. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] status Status Code for OS upper layer +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) +{ + + struct net_device *prDev = NULL; + struct sk_buff *prSkb = NULL; + UINT_16 u2QueueIdx = 0; + UINT_8 ucNetworkType = 0; + BOOLEAN fgIsValidDevice = TRUE; + + ASSERT(pvPacket); + ASSERT(prGlueInfo->i4TxPendingFrameNum); + + prSkb = (struct sk_buff *)pvPacket; + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + + if (GLUE_GET_PKT_IS_PAL(prSkb)) { + ucNetworkType = NETWORK_TYPE_BOW_INDEX; + } else if (GLUE_GET_PKT_IS_P2P(prSkb)) { + ucNetworkType = NETWORK_TYPE_P2P_INDEX; + +#if CFG_ENABLE_WIFI_DIRECT + /* in case packet was sent after P2P device is unregistered */ + if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) + fgIsValidDevice = FALSE; +#endif + } else { + ucNetworkType = NETWORK_TYPE_AIS_INDEX; + } + + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + if (u2QueueIdx < CFG_MAX_TXQ_NUM) + GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); + prDev = prSkb->dev; + + ASSERT(prDev); + + if ((fgIsValidDevice == TRUE) && (u2QueueIdx < CFG_MAX_TXQ_NUM)) { + if (netif_subqueue_stopped(prDev, prSkb) && + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx] <= + CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD) { + DBGLOG(TX, INFO, "netif_wake_subqueue for bss: %d. Queue len: %d\n", + ucNetworkType, + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucNetworkType][u2QueueIdx]); + netif_wake_subqueue(prDev, u2QueueIdx); + +#if (CONF_HIF_LOOPBACK_AUTO == 1) + prGlueInfo->rHifInfo.HifLoopbkFlg &= ~0x01; +#endif /* CONF_HIF_LOOPBACK_AUTO */ + } + } + + dev_kfree_skb((struct sk_buff *)pvPacket); + prGlueInfo->u8SkbFreed++; + + DBGLOG(TX, EVENT, "----- pending frame %d -----\n", prGlueInfo->i4TxPendingFrameNum); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Copy Mac Address setting from registry. It's All Zeros in Linux. +* +* \param[in] prAdapter Pointer to the Adapter structure +* +* \param[out] paucMacAddr Pointer to the Mac Address buffer +* +* \retval WLAN_STATUS_SUCCESS +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +VOID kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_8 paucMacAddr) +{ + UINT_8 aucZeroMac[MAC_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 } + + DEBUGFUNC("kalQueryRegistryMacAddr"); + + ASSERT(prGlueInfo); + ASSERT(paucMacAddr); + + kalMemCopy((PVOID) paucMacAddr, (PVOID) aucZeroMac, MAC_ADDR_LEN); + +} /* end of kalQueryRegistryMacAddr() */ + +#if CFG_SUPPORT_EXT_CONFIG +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read external configuration, ex. NVRAM or file +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + /* External data is given from user space by ioctl or /proc, not read by + driver. + */ + if (0 != prGlueInfo->u4ExtCfgLength) + DBGLOG(INIT, TRACE, "Read external configuration data -- OK\n"); + else + DBGLOG(INIT, TRACE, "Read external configuration data -- fail\n"); + + return prGlueInfo->u4ExtCfgLength; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This inline function is to extract some packet information, including +* user priority, packet length, destination address, 802.1x and BT over Wi-Fi +* or not. +* +* @param prGlueInfo Pointer to the glue structure +* @param prNdisPacket Packet descriptor +* @param pucPriorityParam User priority +* @param pu4PacketLen Packet length +* @param pucEthDestAddr Destination address +* @param pfgIs1X 802.1x packet or not +* @param pfgIsPAL BT over Wi-Fi packet or not +* @prGenUse General used param +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ + +BOOLEAN +kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT PUINT_8 pucPriorityParam, + OUT PUINT_32 pu4PacketLen, + OUT PUINT_8 pucEthDestAddr, + OUT PBOOLEAN pfgIs1X, + OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, + OUT PVOID prGenUse) +{ + + UINT_32 u4PacketLen; + + UINT_8 ucUserPriority = USER_PRIORITY_DEFAULT; /* Default */ + UINT_16 u2EtherTypeLen; + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + PUINT_8 aucLookAheadBuf = NULL; + + DEBUGFUNC("kalQoSFrameClassifierAndPacketInfo"); + + u4PacketLen = prSkb->len; + + if (u4PacketLen < ETH_HLEN) { + DBGLOG(TX, WARN, "Invalid Ether packet length: %u\n", (UINT_32) u4PacketLen); + return FALSE; + } + + aucLookAheadBuf = prSkb->data; + + *pfgIs1X = FALSE; + *pfgIsPAL = FALSE; + + /* 4 <3> Obtain the User Priority for WMM */ + u2EtherTypeLen = (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET] << 8) | (aucLookAheadBuf[ETH_TYPE_LEN_OFFSET + 1]); + + if ((u2EtherTypeLen == ETH_P_IP) && (u4PacketLen >= LOOK_AHEAD_LEN)) { + PUINT_8 pucIpHdr = &aucLookAheadBuf[ETH_HLEN]; + UINT_8 ucIpVersion; + + ucIpVersion = (pucIpHdr[0] & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + if (ucIpVersion == IPVERSION) { + UINT_8 ucIpTos; + /* Get the DSCP value from the header of IP packet. */ + ucIpTos = pucIpHdr[1]; + ucUserPriority = ((ucIpTos & IPTOS_PREC_MASK) >> IPTOS_PREC_OFFSET); + } + + /* TODO(Kevin): Add TSPEC classifier here */ + } else if (u2EtherTypeLen == ETH_P_1X || u2EtherTypeLen == ETH_P_PRE_1X) { /* For Port Control */ + PUINT_8 pucEapol = &aucLookAheadBuf[ETH_HLEN]; + UINT_8 ucEapolType = pucEapol[1]; + UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; + /* + * generate a seq number used to trace security frame TX + */ + if (prGenUse) + *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); + + switch (ucEapolType) { + case 0: /* eap packet */ + DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", + pucEapol[4], pucEapol[5], pucEapol[7], + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + case 1: /* eapol start */ + DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + case 3: /* key */ + DBGLOG(TX, INFO, + " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x... seqNo %d\n", + u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], + pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + } + *pfgIs1X = TRUE; + } +#if CFG_SUPPORT_WAPI + else if (u2EtherTypeLen == ETH_WPI_1X) { + PUINT_8 pucEthBody = &aucLookAheadBuf[ETH_HLEN]; + UINT_8 ucSubType = pucEthBody[3]; /* sub type filed*/ + UINT_16 u2Length = *(PUINT_16)&pucEthBody[6]; + UINT_16 u2Seq = *(PUINT_16)&pucEthBody[8]; + + DBGLOG(TX, INFO, " WAPI: subType %d, Len %d, Seq %d\n", + ucSubType, u2Length, u2Seq); + *pfgIs1X = TRUE; + } +#endif +#if (CFG_SUPPORT_TDLS == 1) + else if (u2EtherTypeLen == TDLS_FRM_PROT_TYPE) { + /* TDLS case */ + TDLSEX_UP_ASSIGN(ucUserPriority); + } +#endif /* CFG_SUPPORT_TDLS */ + else if (u2EtherTypeLen <= 1500) { /* 802.3 Frame */ + UINT_8 ucDSAP, ucSSAP, ucControl; + UINT_8 aucOUI[3]; + + ucDSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET]; + ucSSAP = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 1]; + ucControl = *(PUINT_8) &aucLookAheadBuf[ETH_LLC_OFFSET + 2]; + + aucOUI[0] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET]; + aucOUI[1] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 1]; + aucOUI[2] = *(PUINT_8) &aucLookAheadBuf[ETH_SNAP_OFFSET + 2]; + + if (ucDSAP == ETH_LLC_DSAP_SNAP && + ucSSAP == ETH_LLC_SSAP_SNAP && + ucControl == ETH_LLC_CONTROL_UNNUMBERED_INFORMATION && + aucOUI[0] == ETH_SNAP_BT_SIG_OUI_0 && + aucOUI[1] == ETH_SNAP_BT_SIG_OUI_1 && aucOUI[2] == ETH_SNAP_BT_SIG_OUI_2) { + + UINT_16 tmp = + ((aucLookAheadBuf[ETH_SNAP_OFFSET + 3] << 8) | aucLookAheadBuf[ETH_SNAP_OFFSET + 4]); + + *pfgIsPAL = TRUE; + ucUserPriority = (UINT_8) prSkb->priority; + + if (tmp == BOW_PROTOCOL_ID_SECURITY_FRAME) { + PUINT_8 pucEapol = &aucLookAheadBuf[ETH_SNAP_OFFSET + 5]; + UINT_8 ucEapolType = pucEapol[1]; + UINT_16 u2KeyInfo = pucEapol[5]<<8 | pucEapol[6]; + if (prGenUse) + *(UINT_8 *)prGenUse = nicIncreaseCmdSeqNum(prGlueInfo->prAdapter); + + switch (ucEapolType) { + case 0: /* eap packet */ + DBGLOG(TX, INFO, " EAP Packet: code %d, id %d, type %d, seqNo %d\n", + pucEapol[4], pucEapol[5], pucEapol[7], + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + case 1: /* eapol start */ + DBGLOG(TX, INFO, " EAPOL: start, seqNo %d\n", + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + case 3: /* key */ + DBGLOG(TX, INFO, + " EAPOL: key, KeyInfo 0x%04x, Nonce %02x%02x%02x%02x%02x%02x%02x%02x seqNo %d\n", + u2KeyInfo, pucEapol[17], pucEapol[18], pucEapol[19], pucEapol[20], + pucEapol[21], pucEapol[22], pucEapol[23], pucEapol[24], + prGenUse ? *(UINT_8 *)prGenUse : 0); + break; + } + *pfgIs1X = TRUE; + } + } + } + /* 4 <4> Return the value of Priority Parameter. */ + *pucPriorityParam = ucUserPriority; + + /* 4 <5> Retrieve Packet Information - DA */ + /* Packet Length/ Destination Address */ + *pu4PacketLen = u4PacketLen; + + kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); + + /* <6> Network type */ +#if CFG_ENABLE_BT_OVER_WIFI + if (*pfgIsPAL == TRUE) { + *pucNetworkType = NETWORK_TYPE_BOW_INDEX; + } else +#endif + { +#if CFG_ENABLE_WIFI_DIRECT + if (prGlueInfo->prAdapter->fgIsP2PRegistered && GLUE_GET_PKT_IS_P2P(prPacket)) { + *pucNetworkType = NETWORK_TYPE_P2P_INDEX; + } else +#endif + { + *pucNetworkType = NETWORK_TYPE_AIS_INDEX; + } + } + return TRUE; +} /* end of kalQoSFrameClassifier() */ + +VOID +kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus) +{ + + ASSERT(prGlueInfo); + /* remove timeout check timer */ + wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); + + /* if (prGlueInfo->u4TimeoutFlag != 1) { */ + prGlueInfo->rPendStatus = rOidStatus; + DBGLOG(OID, TEMP, "kalOidComplete, caller: %p\n", __builtin_return_address(0)); + complete(&prGlueInfo->rPendComp); + prGlueInfo->u4OidCompleteFlag = 1; + /* } */ + /* else let it timeout on kalIoctl entry */ +} + +VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo) +{ + /* if (prGlueInfo->u4TimeoutFlag != 1) { */ + /* clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->u4Flag); */ + if (prGlueInfo->u4OidCompleteFlag != 1) { + DBGLOG(OID, TEMP, "kalOidClearance, caller: %p\n", __builtin_return_address(0)); + complete(&prGlueInfo->rPendComp); + } + /* } */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is used to transfer linux ioctl to OID, and we +* need to specify the behavior of the OID by ourself +* +* @param prGlueInfo Pointer to the glue structure +* @param pvInfoBuf Data buffer +* @param u4InfoBufLen Data buffer length +* @param fgRead Is this a read OID +* @param fgWaitResp does this OID need to wait for values +* @param fgCmd does this OID compose command packet +* @param pu4QryInfoLen The data length of the return values +* +* @retval TRUE Success to extract information +* @retval FALSE Fail to extract correct information +*/ +/*----------------------------------------------------------------------------*/ + +/* todo: enqueue the i/o requests for multiple processes access */ +/* */ +/* currently, return -1 */ +/* */ + +/* static GL_IO_REQ_T OidEntry; */ + +WLAN_STATUS +kalIoctl(IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen) +{ + P_GL_IO_REQ_T prIoReq = NULL; + WLAN_STATUS ret = WLAN_STATUS_SUCCESS; + + if (fgIsResetting == TRUE) + return WLAN_STATUS_SUCCESS; + + /* GLUE_SPIN_LOCK_DECLARATION(); */ + ASSERT(prGlueInfo); + + /* <1> Check if driver is halt */ + /* if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { */ + /* return WLAN_STATUS_ADAPTER_NOT_READY; */ + /* } */ + + /* if wait longer than double OID timeout timer, then will show backtrace who held halt lock. + at this case, we will return kalIoctl failure because tx_thread may be hung */ + if (kalHaltLock(2 * WLAN_OID_TIMEOUT_THRESHOLD)) + return WLAN_STATUS_FAILURE; + + if (kalIsHalted()) { + kalHaltUnlock(); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (down_interruptible(&prGlueInfo->ioctl_sem)) { + kalHaltUnlock(); + return WLAN_STATUS_FAILURE; + } + + /* <2> TODO: thread-safe */ + + /* <3> point to the OidEntry of Glue layer */ + + prIoReq = &(prGlueInfo->OidEntry); + + ASSERT(prIoReq); + + /* <4> Compose the I/O request */ + prIoReq->prAdapter = prGlueInfo->prAdapter; + prIoReq->pfnOidHandler = pfnOidHandler; + prIoReq->pvInfoBuf = pvInfoBuf; + prIoReq->u4InfoBufLen = u4InfoBufLen; + prIoReq->pu4QryInfoLen = pu4QryInfoLen; + prIoReq->fgRead = fgRead; + prIoReq->fgWaitResp = fgWaitResp; + prIoReq->rStatus = WLAN_STATUS_FAILURE; +#if CFG_ENABLE_WIFI_DIRECT + prIoReq->fgIsP2pOid = fgIsP2pOid; +#endif + + /* <5> Reset the status of pending OID */ + prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; + /* prGlueInfo->u4TimeoutFlag = 0; */ + /* prGlueInfo->u4OidCompleteFlag = 0; */ + + /* <6> Check if we use the command queue */ + prIoReq->u4Flag = fgCmd; + + /* <7> schedule the OID bit */ + set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); + + /* <8> Wake up tx thread to handle kick start the I/O request */ + wake_up_interruptible(&prGlueInfo->waitq); + + /* <9> Block and wait for event or timeout, current the timeout is 5 secs */ + /* if (wait_for_completion_interruptible_timeout(&prGlueInfo->rPendComp, 5 * KAL_HZ)) { */ + /* if (!wait_for_completion_interruptible(&prGlueInfo->rPendComp)) { */ + DBGLOG(OID, TEMP, "kalIoctl: before wait, caller: %p\n", __builtin_return_address(0)); + wait_for_completion(&prGlueInfo->rPendComp); { + /* Case 1: No timeout. */ + /* if return WLAN_STATUS_PENDING, the status of cmd is stored in prGlueInfo */ + if (prIoReq->rStatus == WLAN_STATUS_PENDING) + ret = prGlueInfo->rPendStatus; + else + ret = prIoReq->rStatus; + } +#if 0 + else { + /* Case 2: timeout */ + /* clear pending OID's cmd in CMD queue */ + if (fgCmd) { + prGlueInfo->u4TimeoutFlag = 1; + wlanReleasePendingOid(prGlueInfo->prAdapter, 0); + } + ret = WLAN_STATUS_FAILURE; + } +#endif + DBGLOG(OID, TEMP, "kalIoctl: done\n"); + up(&prGlueInfo->ioctl_sem); + kalHaltUnlock(); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending security frames +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* Clear pending security frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear pending security frames +* belongs to dedicated network type +* +* \param prGlueInfo Pointer of GLUE Data Structure +* \param eNetworkTypeIdx Network Type Index +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* Clear pending security frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && prCmdInfo->eNetworkType == eNetworkTypeIdx) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending management frames +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* Clear pending management frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear all pending management frames +* belongs to dedicated network type +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* Clear pending management frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && + prCmdInfo->eNetworkType == eNetworkTypeIdx) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} /* kalClearMgmtFramesByNetType */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief This function is a kernel thread function for handling command packets +* Tx requests and interrupt events +* +* @param data data pointer to private data of tx_thread +* +* @retval If the function succeeds, the return value is 0. +* Otherwise, an error code is returned. +* +*/ +/*----------------------------------------------------------------------------*/ + +int tx_thread(void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); + + P_QUE_ENTRY_T prQueueEntry = NULL; + P_GL_IO_REQ_T prIoReq = NULL; + P_QUE_T prTxQueue = NULL; + P_QUE_T prCmdQue = NULL; + + int ret = 0; + + BOOLEAN fgNeedHwAccess = FALSE; + + struct sk_buff *prSkb = NULL; + + /* for spin lock acquire and release */ + GLUE_SPIN_LOCK_DECLARATION(); + + prTxQueue = &prGlueInfo->rTxQueue; + prCmdQue = &prGlueInfo->rCmdQueue; + + current->flags |= PF_NOFREEZE; + + DBGLOG(INIT, INFO, "tx_thread starts running...\n"); + + while (TRUE) { + +#if CFG_ENABLE_WIFI_DIRECT + /*run p2p multicast list work. */ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) + p2pSetMulticastListWorkQueueWrapper(prGlueInfo); +#endif + + if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { + P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; + /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ + prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); + prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); + DBGLOG(INIT, INFO, "tx_thread should stop now...\n"); + break; + } + + /* + * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT + * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT + * + */ + KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); + + ret = wait_event_interruptible(prGlueInfo->waitq, (prGlueInfo->ulFlag != 0)); + + KAL_WAKE_LOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); + +/* #if (CONF_HIF_LOOPBACK_AUTO == 1) */ +/* if (test_and_clear_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &prGlueInfo->u4Flag)) { */ +/* kalDevLoopbkAuto(prGlueInfo); */ +/* } */ +/* #endif */ /* CONF_HIF_LOOPBACK_AUTO */ + +#if CFG_DBG_GPIO_PINS + /* TX thread Wake up */ + mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_LOW); +#endif +#if CFG_ENABLE_WIFI_DIRECT + /*run p2p multicast list work. */ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) + p2pSetMulticastListWorkQueueWrapper(prGlueInfo); + + if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag)) { + p2pFuncUpdateMgmtFrameRegister(prGlueInfo->prAdapter, + prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter); + } +#endif + if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { + P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; + /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ + prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); + prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &(prGlueInfo->prAdapter)->rTxThreadWakeLock); + DBGLOG(INIT, INFO, "<1>tx_thread should stop now...\n"); + break; + } + + fgNeedHwAccess = FALSE; + + /* Handle Interrupt */ + if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->ulFlag)) { + if (fgNeedHwAccess == FALSE) { + fgNeedHwAccess = TRUE; + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + } + + /* the Wi-Fi interrupt is already disabled in mmc thread, + so we set the flag only to enable the interrupt later */ + prGlueInfo->prAdapter->fgIsIntEnable = FALSE; + /* wlanISR(prGlueInfo->prAdapter, TRUE); */ + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + /* Should stop now... skip pending interrupt */ + DBGLOG(INIT, INFO, "ignore pending interrupt\n"); + } else { + prGlueInfo->TaskIsrCnt++; + wlanIST(prGlueInfo->prAdapter); + } + } + + /* transfer ioctl to OID request */ +#if 0 + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "<2>tx_thread should stop now...\n"); + break; + } +#endif + + do { + if (test_and_clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag)) { + /* get current prIoReq */ + prGlueInfo->u4OidCompleteFlag = 0; + + prIoReq = &(prGlueInfo->OidEntry); +#if CFG_ENABLE_WIFI_DIRECT + if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE && prIoReq->fgIsP2pOid == TRUE) { + /* if this Oid belongs to p2p and p2p module is removed + * do nothing, + */ + } else +#endif + { + if (FALSE == prIoReq->fgRead) { + prIoReq->rStatus = wlanSetInformation(prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } else { + prIoReq->rStatus = wlanQueryInformation(prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } + + if (prIoReq->rStatus != WLAN_STATUS_PENDING) { + DBGLOG(OID, TEMP, "tx_thread, complete\n"); + complete(&prGlueInfo->rPendComp); + } else { + wlanoidTimeoutCheck(prGlueInfo->prAdapter, prIoReq->pfnOidHandler); + } + } + } + + } while (FALSE); + + /* + * + * if TX request, clear the TXREQ flag. TXREQ set by kalSetEvent/GlueSetEvent + * indicates the following requests occur + * + */ +#if 0 + if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "<3>tx_thread should stop now...\n"); + break; + } +#endif + + if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, &prGlueInfo->ulFlag)) { + /* Process Mailbox Messages */ + wlanProcessMboxMessage(prGlueInfo->prAdapter); + + /* Process CMD request */ + do { + if (prCmdQue->u4NumElem > 0) { + if (fgNeedHwAccess == FALSE) { + fgNeedHwAccess = TRUE; + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + } + wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); + } + } while (FALSE); + + /* Handle Packet Tx */ + { + while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_REMOVE_HEAD(prTxQueue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + ASSERT(prQueueEntry); + if (NULL == prQueueEntry) + break; + + prSkb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + ASSERT(prSkb); + if (NULL == prSkb) { + DBGLOG(INIT, ERROR, "prSkb == NULL!\n"); + continue; + } +#if (CFG_SUPPORT_TDLS_DBG == 1) + UINT8 *pkt = prSkb->data; + UINT16 u2Identifier; + + if ((*(pkt + 12) == 0x08) && (*(pkt + 13) == 0x00)) { + /* ip */ + u2Identifier = ((*(pkt + 18)) << 8) | (*(pkt + 19)); + DBGLOG(INIT, LOUD, " %d\n", u2Identifier); + } +#endif + if (wlanEnqueueTxPacket(prGlueInfo->prAdapter, + (P_NATIVE_PACKET) prSkb) == WLAN_STATUS_RESOURCES) { + /* no available entry in rFreeMsduInfoList */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_HEAD(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + break; + } + } + + if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) { + /* send packets to HIF here */ + wlanTxPendingPackets(prGlueInfo->prAdapter, &fgNeedHwAccess); + } + } + + } + + /* Process RX, In linux, we don't need to free sk_buff by ourself */ + + /* In linux, we don't need to free sk_buff by ourself */ + + /* In linux, we don't do reset */ + if (fgNeedHwAccess == TRUE) + wlanReleasePowerControl(prGlueInfo->prAdapter); + + /* handle cnmTimer time out */ + if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag)) + wlanTimerTimeoutCheck(prGlueInfo->prAdapter); +#if CFG_DBG_GPIO_PINS + /* TX thread go to sleep */ + if (!prGlueInfo->ulFlag) + mtk_wcn_stp_debug_gpio_assert(IDX_TX_THREAD, DBG_TIE_HIGH); +#endif + } + +#if 0 + if (fgNeedHwAccess == TRUE) + wlanReleasePowerControl(prGlueInfo->prAdapter); +#endif + + /* exit while loop, tx thread is closed so we flush all pending packets */ + /* flush the pending TX packets */ + if (prGlueInfo->i4TxPendingFrameNum > 0) + kalFlushPendingTxPackets(prGlueInfo); + + /* flush pending security frames */ + if (prGlueInfo->i4TxPendingSecurityFrameNum > 0) + kalClearSecurityFrames(prGlueInfo); + + /* remove pending oid */ + wlanReleasePendingOid(prGlueInfo->prAdapter, 0); + + /* In linux, we don't need to free sk_buff by ourself */ + + DBGLOG(INIT, INFO, "mtk_sdiod stops\n"); + complete(&prGlueInfo->rHaltComp); + + return 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to check if card is removed +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval TRUE: card is removed +* FALSE: card is still attached +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return FALSE; + /* Linux MMC doesn't have removal notification yet */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to send command to firmware for overriding netweork address + * + * \param pvGlueInfo Pointer of GLUE Data Structure + + * \retval TRUE + * FALSE + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr) +{ + ASSERT(prGlueInfo); + + if (prGlueInfo->fgIsMacAddrOverride == FALSE) { +#if !defined(CONFIG_X86) +#if !defined(CONFIG_MTK_TC1_FEATURE) + UINT_32 i; +#endif + BOOLEAN fgIsReadError = FALSE; + +#if !defined(CONFIG_MTK_TC1_FEATURE) + for (i = 0; i < MAC_ADDR_LEN; i += 2) { + if (kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, + (PUINT_16) (((PUINT_8) prMacAddr) + i)) == FALSE) { + fgIsReadError = TRUE; + break; + } + } +#else + TC1_FAC_NAME(FacReadWifiMacAddr) ((unsigned char *)prMacAddr); +#endif + + if (fgIsReadError == TRUE) + return FALSE; + else + return TRUE; +#else + /* x86 Linux doesn't need to override network address so far */ + return FALSE; +#endif + } else { + COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); + + return TRUE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to flush pending TX packets in glue layer +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prTxQue; + P_QUE_ENTRY_T prQueueEntry; + PVOID prPacket; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + prTxQue = &(prGlueInfo->rTxQueue); + + if (prGlueInfo->i4TxPendingFrameNum) { + while (TRUE) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + if (prQueueEntry == NULL) + break; + + prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + + kalSendComplete(prGlueInfo, prPacket, WLAN_STATUS_NOT_ACCEPTED); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is get indicated media state +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->eParamMediaStateIndicated; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to set indicated media state +* +* \param pvGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate) +{ + ASSERT(prGlueInfo); + + prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to clear pending OID staying in command queue +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + + if (((P_CMD_INFO_T) prQueueEntry)->fgIsOid) { + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + break; + } + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + if (prCmdInfo) { + if (prCmdInfo->pfCmdTimeoutHandler) + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); + else + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_NOT_ACCEPTED); + + prGlueInfo->u4OidCompleteFlag = 1; + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to insert command into prCmdQueue +* +* \param prGlueInfo Pointer of GLUE Data Structure +* prQueueEntry Pointer of queue entry to be inserted +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry) +{ + P_QUE_T prCmdQue; + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + ASSERT(prQueueEntry); + + prCmdQue = &prGlueInfo->rCmdQueue; + + prCmdInfo = (P_CMD_INFO_T) prQueueEntry; + if (prCmdInfo->prPacket && prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + prMsduInfo = (P_MSDU_INFO_T) (prCmdInfo->prPacket); + prMsduInfo->eCmdType = prCmdInfo->eCmdType; + prMsduInfo->ucCID = prCmdInfo->ucCID; + prMsduInfo->u4InqueTime = kalGetTimeTick(); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Handle EVENT_ID_ASSOC_INFO event packet by indicating to OS with +* proper information +* +* @param pvGlueInfo Pointer of GLUE Data Structure +* @param prAssocInfo Pointer of EVENT_ID_ASSOC_INFO Packet +* +* @return none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo) +{ + /* to do */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to get firmware load address from registry +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rRegInfo.u4LoadAddress; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to get firmware start address from registry +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rRegInfo.u4StartAddress; +} + +/*----------------------------------------------------------------------------*/ +/*! + * * @brief Notify OS with SendComplete event of the specific packet. Linux should + * * free packets here. + * * + * * @param pvGlueInfo Pointer of GLUE Data Structure + * * @param pvPacket Pointer of Packet Handle + * * @param status Status Code for OS upper layer + * * + * * @return none + * */ +/*----------------------------------------------------------------------------*/ + +/* / Todo */ +VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus) +{ + ASSERT(pvPacket); + + dev_kfree_skb((struct sk_buff *)pvPacket); + if (prGlueInfo) + prGlueInfo->u8SkbFreed++; + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); +} + +UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return (UINT_32) (prGlueInfo->i4TxPendingFrameNum); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to retrieve the number of pending commands +* (including MMPDU, 802.1X and command packets) +* +* \param prGlueInfo Pointer of GLUE Data Structure +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + + ASSERT(prGlueInfo); + prCmdQue = &prGlueInfo->rCmdQueue; + + return prCmdQue->u4NumElem; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Timer Initialization Procedure +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* \param[in] prTimerHandler Pointer to timer handling function, whose only +* argument is "prAdapter" +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ + +/* static struct timer_list tickfn; */ + +VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler) +{ + + ASSERT(prGlueInfo); + + init_timer(&(prGlueInfo->tickfn)); + prGlueInfo->tickfn.function = prTimerHandler; + prGlueInfo->tickfn.data = (ULONG) prGlueInfo; +} + +/* Todo */ +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the time to do the time out check. +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* \param[in] rInterval Time out interval from current time. +* +* \retval TRUE Success. +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval) +{ + ASSERT(prGlueInfo); + del_timer_sync(&(prGlueInfo->tickfn)); + + prGlueInfo->tickfn.expires = jiffies + u4Interval * HZ / MSEC_PER_SEC; + add_timer(&(prGlueInfo->tickfn)); + + return TRUE; /* success */ +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to cancel +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* +* \retval TRUE : Timer has been canceled +* FALAE : Timer doens't exist +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); + + if (del_timer_sync(&(prGlueInfo->tickfn)) >= 0) + return TRUE; + else + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is a callback function for scanning done +* +* \param[in] prGlueInfo Pointer to GLUE Data Structure +* +* \retval none +* +*/ +/*----------------------------------------------------------------------------*/ +VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prGlueInfo); + + prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); + /* report all queued beacon/probe response frames to upper layer */ + scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_INFRASTRUCTURE, NULL); + cnmTimerStopTimer(prGlueInfo->prAdapter, &prAisFsmInfo->rScanDoneTimer); + + /* check for system configuration for generating error message on scan list */ + wlanCheckSystemConfiguration(prGlueInfo->prAdapter); + + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is used to generate a random number +* +* \param none +* +* \retval UINT_32 +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalRandomNumber(VOID) +{ + UINT_32 number = 0; + + get_random_bytes(&number, 4); + + return number; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief command timeout call-back function + * + * \param[in] prGlueInfo Pointer to the GLUE data structure. + * + * \retval (none) + */ +/*----------------------------------------------------------------------------*/ +VOID kalTimeoutHandler(ULONG arg) +{ + + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) arg; + + ASSERT(prGlueInfo); + + /* Notify tx thread for timeout event */ + set_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); + wake_up_interruptible(&prGlueInfo->waitq); + +} + +VOID kalSetEvent(P_GLUE_INFO_T pr) +{ + set_bit(GLUE_FLAG_TXREQ_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if configuration file (NVRAM/Registry) exists +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo) +{ +#if !defined(CONFIG_X86) + ASSERT(prGlueInfo); + + return prGlueInfo->fgNvramAvailable; +#else + /* there is no configuration data for x86-linux */ + return FALSE; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Registry information +* +* \param[in] +* prGlueInfo +* +* \return +* Pointer of REG_INFO_T +*/ +/*----------------------------------------------------------------------------*/ +P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return &(prGlueInfo->rRegInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve version information of corresponding configuration file +* +* \param[in] +* prGlueInfo +* +* \param[out] +* pu2Part1CfgOwnVersion +* pu2Part1CfgPeerVersion +* pu2Part2CfgOwnVersion +* pu2Part2CfgPeerVersion +* +* \return +* NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_16 pu2Part1CfgOwnVersion, + OUT PUINT_16 pu2Part1CfgPeerVersion, + OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion) +{ + ASSERT(prGlueInfo); + + ASSERT(pu2Part1CfgOwnVersion); + ASSERT(pu2Part1CfgPeerVersion); + ASSERT(pu2Part2CfgOwnVersion); + ASSERT(pu2Part2CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion), pu2Part1CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1PeerVersion), pu2Part1CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion), pu2Part2CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2PeerVersion), pu2Part2CfgPeerVersion); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the WPS is active or not +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->fgWpsActive; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief update RSSI and LinkQuality to GLUE layer +* +* \param[in] +* prGlueInfo +* eNetTypeIdx +* cRssi +* cLinkQuality +* +* \return +* None +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality) +{ + struct iw_statistics *pStats = (struct iw_statistics *)NULL; + + ASSERT(prGlueInfo); + + switch (eNetTypeIdx) { + case KAL_NETWORK_TYPE_AIS_INDEX: + pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); + break; +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case KAL_NETWORK_TYPE_P2P_INDEX: + pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); + break; +#endif +#endif + default: + break; + + } + + if (pStats) { + pStats->qual.qual = cLinkQuality; + pStats->qual.noise = 0; + pStats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; + pStats->qual.level = 0x100 + cRssi; + pStats->qual.updated |= IW_QUAL_LEVEL_UPDATED; + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Pre-allocate I/O buffer +* +* \param[in] +* none +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalInitIOBuffer(VOID) +{ + UINT_32 u4Size; + + if (CFG_COALESCING_BUFFER_SIZE >= CFG_RX_COALESCING_BUFFER_SIZE) + u4Size = CFG_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); + else + u4Size = CFG_RX_COALESCING_BUFFER_SIZE + sizeof(ENHANCE_MODE_DATA_STRUCT_T); + +#ifdef MTK_DMA_BUF_MEMCPY_SUP + pvDmaBuffer = dma_alloc_coherent(NULL, CFG_RX_MAX_PKT_SIZE, &pvDmaPhyBuf, GFP_KERNEL); + if (pvDmaBuffer == NULL) + return FALSE; +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + + pvIoBuffer = kmalloc(u4Size, GFP_KERNEL); +/* pvIoBuffer = dma_alloc_coherent(NULL, u4Size, &pvIoPhyBuf, GFP_KERNEL); */ + if (pvIoBuffer) { + pvIoBufferSize = u4Size; + pvIoBufferUsage = 0; + + return TRUE; + } + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free pre-allocated I/O buffer +* +* \param[in] +* none +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalUninitIOBuffer(VOID) +{ + kfree(pvIoBuffer); +#ifdef MTK_DMA_BUF_MEMCPY_SUP + dma_free_coherent(NULL, CFG_RX_MAX_PKT_SIZE, pvDmaBuffer, pvDmaPhyBuf); +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + /* dma_free_coherent(NULL, pvIoBufferSize, pvIoBuffer, pvIoPhyBuf); */ + + pvIoBuffer = (PVOID) NULL; + pvIoBufferSize = 0; + pvIoBufferUsage = 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dispatch pre-allocated I/O buffer +* +* \param[in] +* u4AllocSize +* +* \return +* PVOID for pointer of pre-allocated I/O buffer +*/ +/*----------------------------------------------------------------------------*/ +PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize) +{ + PVOID ret = (PVOID) NULL; + + if (pvIoBuffer) { + if (u4AllocSize <= (pvIoBufferSize - pvIoBufferUsage)) { + ret = (PVOID) &(((PUINT_8) (pvIoBuffer))[pvIoBufferUsage]); + pvIoBufferUsage += u4AllocSize; + } + } else { + /* fault tolerance */ + ret = (PVOID) kalMemAlloc(u4AllocSize, PHY_MEM_TYPE); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Release all dispatched I/O buffer +* +* \param[in] +* none +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size) +{ + if (pvIoBuffer) { + pvIoBufferUsage -= u4Size; + } else { + /* fault tolerance */ + kalMemFree(pvAddr, PHY_MEM_TYPE, u4Size); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, + pucNumOfChannel, paucChannelList); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (IS_NET_ACTIVE(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX) && + p2pFuncIsAPMode(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo)) + return TRUE; +#endif + + return FALSE; +} + +#ifdef MTK_DMA_BUF_MEMCPY_SUP +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function gets the physical address for Pre-allocate I/O buffer. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[out] pu4Flags Pointer of a variable for saving IRQ flags +* +* \return physical addr +*/ +/*----------------------------------------------------------------------------*/ +ULONG kalIOPhyAddrGet(IN ULONG VirtAddr) +{ + ULONG PhyAddr; + + if ((VirtAddr >= (ULONG) pvIoBuffer) && (VirtAddr <= ((ULONG) (pvIoBuffer) + pvIoBufferSize))) { + PhyAddr = (ULONG) pvIoPhyBuf; + PhyAddr += (VirtAddr - (ULONG) (pvIoBuffer)); + return PhyAddr; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function gets the physical address for Pre-allocate I/O buffer. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] rLockCategory Specify which SPIN_LOCK +* \param[out] pu4Flags Pointer of a variable for saving IRQ flags +* +* \return physical addr +*/ +/*----------------------------------------------------------------------------*/ +VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr) +{ + *VirtAddr = pvDmaBuffer; + *PhyAddr = pvDmaPhyBuf; +} +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/*! +* \brief to check if the MFP is active or not +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rWpaInfo.u4Mfp; +} +#endif + +struct file *kalFileOpen(const char *path, int flags, int rights) +{ + struct file *filp = NULL; + mm_segment_t oldfs; + int err = 0; + + oldfs = get_fs(); + set_fs(get_ds()); + filp = filp_open(path, flags, rights); + set_fs(oldfs); + if (IS_ERR(filp)) { + err = PTR_ERR(filp); + return NULL; + } + return filp; +} + +VOID kalFileClose(struct file *file) +{ + filp_close(file, NULL); +} + +UINT_32 kalFileRead(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) +{ + mm_segment_t oldfs; + INT_32 ret; + + oldfs = get_fs(); + set_fs(get_ds()); + + ret = vfs_read(file, data, size, &offset); + + set_fs(oldfs); + return ret; +} + +UINT_32 kalFileWrite(struct file *file, UINT_64 offset, UINT_8 *data, UINT_32 size) +{ + mm_segment_t oldfs; + INT_32 ret; + + oldfs = get_fs(); + set_fs(get_ds()); + + ret = vfs_write(file, data, size, &offset); + + set_fs(oldfs); + return ret; +} + +UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size) +{ + struct file *file = NULL; + UINT_32 ret = -1; + UINT_32 u4Flags = 0; + + if (fgDoAppend) + u4Flags = O_APPEND; + + file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); + if (file) { + ret = kalFileWrite(file, 0, pucData, u4Size); + kalFileClose(file); + } + + return ret; +} + +INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize) +{ + struct file *file = NULL; + INT_32 ret = -1; + UINT_32 u4ReadSize = 0; + + DBGLOG(INIT, LOUD, "kalReadToFile() path %s\n", pucPath); + + file = kalFileOpen(pucPath, O_RDONLY, 0); + + if ((file != NULL) && !IS_ERR(file)) { + u4ReadSize = kalFileRead(file, 0, pucData, u4Size); + kalFileClose(file); + if (pu4ReadSize) + *pu4ReadSize = u4ReadSize; + ret = 0; + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate BSS-INFO to NL80211 as scanning result +* +* \param[in] +* prGlueInfo +* pucBeaconProbeResp +* u4FrameLen +* +* +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucBeaconProbeResp, + IN UINT_32 u4FrameLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength) +{ + struct wiphy *wiphy; + struct ieee80211_channel *prChannel = NULL; + + ASSERT(prGlueInfo); + wiphy = priv_to_wiphy(prGlueInfo); + + /* search through channel entries */ + if (ucChannelNum <= 14) { + prChannel = + ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = + ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); + } + + if (prChannel != NULL && (prGlueInfo->prScanRequest != NULL || prGlueInfo->prSchedScanRequest != NULL)) { + struct cfg80211_bss *bss; +#if CFG_SUPPORT_TSF_USING_BOOTTIME + struct ieee80211_mgmt *prMgmtFrame = (struct ieee80211_mgmt *)pucBeaconProbeResp; + + prMgmtFrame->u.beacon.timestamp = kalGetBootTime(); +#endif + ScanCnt++; + + /* indicate to NL80211 subsystem */ + bss = cfg80211_inform_bss_frame(wiphy, + prChannel, + (struct ieee80211_mgmt *)pucBeaconProbeResp, + u4FrameLen, i4SignalStrength * 100, GFP_KERNEL); + + if (!bss) { + ScanDoneFailCnt++; + DBGLOG(SCN, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", + ucChannelNum, i4SignalStrength); + } else { + cfg80211_put_bss(wiphy, bss); + DBGLOG(SCN, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", + ucChannelNum, i4SignalStrength); + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate channel ready +* +* \param[in] +* prGlueInfo +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, + IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs) +{ + struct ieee80211_channel *prChannel = NULL; + enum nl80211_channel_type rChannelType; + + /* ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); */ + + if (prGlueInfo->fgIsRegistered == TRUE) { + if (ucChannelNum <= 14) { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); + } + + switch (eSco) { + case CHNL_EXT_SCN: + rChannelType = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + rChannelType = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + rChannelType = NL80211_CHAN_HT40PLUS; + break; + + case CHNL_EXT_RES: + default: + rChannelType = NL80211_CHAN_HT20; + break; + } + + cfg80211_ready_on_channel(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, u4DurationMs, + GFP_KERNEL); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate channel expiration +* +* \param[in] +* prGlueInfo +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum) +{ + struct ieee80211_channel *prChannel = NULL; + enum nl80211_channel_type rChannelType; + + ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_AIS_INDEX); + + if (prGlueInfo->fgIsRegistered == TRUE) { + if (ucChannelNum <= 14) { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = + ieee80211_get_channel(priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, NL80211_BAND_5GHZ)); + } + + switch (eSco) { + case CHNL_EXT_SCN: + rChannelType = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + rChannelType = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + rChannelType = NL80211_CHAN_HT40PLUS; + break; + + case CHNL_EXT_RES: + default: + rChannelType = NL80211_CHAN_HT20; + break; + } + + cfg80211_remain_on_channel_expired(prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, prChannel, + GFP_KERNEL); + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate Mgmt tx status +* +* \param[in] +* prGlueInfo +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) +{ + + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { + DBGLOG(AIS, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", + prGlueInfo, pucFrameBuf, u4FrameLen); + ASSERT(FALSE); + break; + } + + cfg80211_mgmt_tx_status(prGlueInfo->prDevHandler->ieee80211_ptr, + u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); + } while (FALSE); + +} /* kalIndicateMgmtTxStatus */ + +VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) +{ +#define DBG_MGMT_FRAME_INDICATION 1 + INT_32 i4Freq = 0; + UINT_8 ucChnlNum = 0; +#if DBG_MGMT_FRAME_INDICATION + P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; +#endif + + do { + if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { + ASSERT(FALSE); + break; + } + + ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; + +#if DBG_MGMT_FRAME_INDICATION + prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; + + switch (prWlanHeader->u2FrameCtrl) { + case MAC_FRAME_PROBE_REQ: + DBGLOG(AIS, TRACE, "RX Probe Req at channel %d ", ucChnlNum); + break; + case MAC_FRAME_PROBE_RSP: + DBGLOG(AIS, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); + break; + case MAC_FRAME_ACTION: + DBGLOG(AIS, TRACE, "RX Action frame at channel %d ", ucChnlNum); + break; + default: + DBGLOG(AIS, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); + break; + } + +#endif + i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; + + cfg80211_rx_mgmt(prGlueInfo->prDevHandler->ieee80211_ptr, /* struct net_device * dev, */ + i4Freq, + RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), + prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_KERNEL); + } while (FALSE); + +} /* kalIndicateRxMgmtFrame */ + +#if CFG_SUPPORT_AGPS_ASSIST +BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + struct sk_buff *skb = cfg80211_testmode_alloc_event_skb(priv_to_wiphy(prGlueInfo), + dataLen, GFP_KERNEL); + if (!skb) { + DBGLOG(AIS, ERROR, "kalIndicateAgpsNotify: alloc skb failed\n"); + return FALSE; + } + + /* DBGLOG(CCX, INFO, ("WLAN_STATUS_AGPS_NOTIFY, cmd=%d\n", cmd)); */ + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_CMD, sizeof(cmd), &cmd) < 0)) + goto nla_put_failure; + if (dataLen > 0 && data && unlikely(nla_put(skb, MTK_ATTR_AGPS_DATA, dataLen, data) < 0)) + goto nla_put_failure; + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFINDEX, sizeof(UINT_32), &prGlueInfo->prDevHandler->ifindex) < 0)) + goto nla_put_failure; + /* currently, the ifname maybe wlan0, p2p0, so the maximum name length will be 5 bytes */ + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFNAME, 5, prGlueInfo->prDevHandler->name) < 0)) + goto nla_put_failure; + cfg80211_testmode_event(skb, GFP_KERNEL); + return TRUE; + +nla_put_failure: + kfree_skb(skb); + return FALSE; +} +#endif + +#if (CFG_SUPPORT_MET_PROFILING == 1) +#define PROC_MET_PROF_CTRL "met_ctrl" +#define PROC_MET_PROF_PORT "met_port" + +struct proc_dir_entry *pMetProcDir; +void *pMetGlobalData = NULL; +static unsigned long __read_mostly tracing_mark_write_addr; + +static inline void __mt_update_tracing_mark_write_addr(void) +{ + if (unlikely(0 == tracing_mark_write_addr)) + tracing_mark_write_addr = kallsyms_lookup_name("tracing_mark_write"); +} + +VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb) +{ + UINT_8 ucIpVersion; + UINT_16 u2UdpSrcPort; + UINT_16 u2RtpSn; + PUINT_8 pucEthHdr = prSkb->data; + PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; + + /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ + /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ + /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ + /* printk("MET_PROF: MET enable=%d(HardXmit)\n", prGlueInfo->u8MetProfEnable); */ + if (prGlueInfo->u8MetProfEnable == 1) { + u2UdpSrcPort = prGlueInfo->u16MetUdpPort; + if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { + /* IP */ + pucIpHdr = pucEthHdr + ETH_HLEN; + ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { + /* UDP */ + pucUdpHdr = pucIpHdr + IP_HEADER_LEN; + /* check UDP port number */ + if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { + /* RTP */ + pucRtpHdr = pucUdpHdr + 8; + u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; + /* trace_printk("S|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); + //frm_sequence); */ +#ifdef CONFIG_TRACING + __mt_update_tracing_mark_write_addr(); + if (tracing_mark_write_addr != 0) { + event_trace_printk(tracing_mark_write_addr, "S|%d|%s|%d\n", + current->tgid, "WIFI-CHIP", u2RtpSn); + } +#endif + } + } + } + } +} + +VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + UINT_8 ucIpVersion; + UINT_16 u2UdpSrcPort; + UINT_16 u2RtpSn; + struct sk_buff *prSkb = (struct sk_buff *)prMsduInfo->prPacket; + PUINT_8 pucEthHdr = prSkb->data; + PUINT_8 pucIpHdr, pucUdpHdr, pucRtpHdr; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + /* | Ethernet(14) | IP(20) | UDP(8)| RTP(12) | */ + /* UDP==> |SRC_PORT(2)|DST_PORT(2)|LEN(2)|CHKSUM(2)| */ + /* RTP==> |CTRL(2)|SEQ(2)|TimeStamp(4)|... */ + /* printk("MET_PROF: MET enable=%d(TxMsdu)\n", prGlueInfo->u8MetProfEnable); */ + if (prGlueInfo->u8MetProfEnable == 1) { + u2UdpSrcPort = prGlueInfo->u16MetUdpPort; + if ((*(pucEthHdr + 12) == 0x08) && (*(pucEthHdr + 13) == 0x00)) { + /* IP */ + pucIpHdr = pucEthHdr + ETH_HLEN; + ucIpVersion = (*pucIpHdr & IPVH_VERSION_MASK) >> IPVH_VERSION_OFFSET; + if ((ucIpVersion == IPVERSION) && (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP)) { + /* UDP */ + pucUdpHdr = pucIpHdr + IP_HEADER_LEN; + /* check UDP port number */ + if (((UINT_16) pucUdpHdr[0] << 8 | (UINT_16) pucUdpHdr[1]) == u2UdpSrcPort) { + /* RTP */ + pucRtpHdr = pucUdpHdr + 8; + u2RtpSn = (UINT_16) pucRtpHdr[2] << 8 | pucRtpHdr[3]; + /* trace_printk("F|%d|%s|%d\n", current->tgid, "WIFI-CHIP", u2RtpSn); + //frm_sequence); */ +#ifdef CONFIG_TRACING + __mt_update_tracing_mark_write_addr(); + if (tracing_mark_write_addr != 0) { + event_trace_printk(tracing_mark_write_addr, "F|%d|%s|%d\n", + current->tgid, "WIFI-CHIP", u2RtpSn); + } +#endif + } + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t kalMetCtrlWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) +{ + char acBuf[128 + 1]; /* + 1 for "\0" */ + UINT_32 u4CopySize; + int u8MetProfEnable; + + IN P_GLUE_INFO_T prGlueInfo; + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, u4CopySize)) + return -1; + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, " %d", &u8MetProfEnable) == 1) + DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC Enable=%d\n", u8MetProfEnable); + if (pMetGlobalData != NULL) { + prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; + prGlueInfo->u8MetProfEnable = (UINT_8) u8MetProfEnable; + } + return count; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for adjusting Debug Level to turn on/off debugging message. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static ssize_t kalMetPortWriteProcfs(struct file *file, const char __user *buffer, size_t count, loff_t *off) +{ + char acBuf[128 + 1]; /* + 1 for "\0" */ + UINT_32 u4CopySize; + int u16MetUdpPort; + + IN P_GLUE_INFO_T prGlueInfo; + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, u4CopySize)) + return -1; + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, " %d", &u16MetUdpPort) == 1) + DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC UDP_PORT=%d\n", u16MetUdpPort); + if (pMetGlobalData != NULL) { + prGlueInfo = (P_GLUE_INFO_T) pMetGlobalData; + prGlueInfo->u16MetUdpPort = (UINT_16) u16MetUdpPort; + } + return count; +} + +const struct file_operations rMetProcCtrlFops = { +.write = kalMetCtrlWriteProcfs +}; + +const struct file_operations rMetProcPortFops = { +.write = kalMetPortWriteProcfs +}; + +int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo) +{ + /* struct proc_dir_entry *pMetProcDir; */ + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, INFO, "init proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + /* + * Directory: Root (/proc/net/wlan0) + */ + pMetProcDir = proc_mkdir("wlan0", init_net.proc_net); + if (pMetProcDir == NULL) + return -ENOENT; + /* + /proc/net/wlan0 + |-- met_ctrl (PROC_MET_PROF_CTRL) + |-- met_port (PROC_MET_PROF_PORT) + */ + /* proc_create(PROC_MET_PROF_CTRL, 0x0644, pMetProcDir, &rMetProcFops); */ + proc_create(PROC_MET_PROF_CTRL, 0, pMetProcDir, &rMetProcCtrlFops); + proc_create(PROC_MET_PROF_PORT, 0, pMetProcDir, &rMetProcPortFops); + + pMetGlobalData = (void *)prGlueInfo; + + return 0; +} + +int kalMetRemoveProcfs(void) +{ + + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, WARN, "remove proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + remove_proc_entry(PROC_MET_PROF_CTRL, pMetProcDir); + remove_proc_entry(PROC_MET_PROF_PORT, pMetProcDir); + /* remove root directory (proc/net/wlan0) */ + remove_proc_entry("wlan0", init_net.proc_net); + /* clear MetGlobalData */ + pMetGlobalData = NULL; + + return 0; +} +#endif +UINT_64 kalGetBootTime(void) +{ + struct timespec ts; + UINT_64 bootTime = 0; + + get_monotonic_boottime(&ts); + /* we assign ts.tv_sec to bootTime first, then multiply USEC_PER_SEC + this will prevent multiply result turn to a negative value on 32bit system */ + bootTime = ts.tv_sec; + bootTime *= USEC_PER_SEC; + bootTime += ts.tv_nsec / NSEC_PER_USEC; + return bootTime; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate scheduled scan results are avilable +* +* \param[in] +* prGlueInfo +* +* \return +* None +*/ +/*----------------------------------------------------------------------------*/ +VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + cfg80211_sched_scan_results(priv_to_wiphy(prGlueInfo),0); + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To indicate scheduled scan has been stopped +* +* \param[in] +* prGlueInfo +* +* \return +* None +*/ +/*----------------------------------------------------------------------------*/ +VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo) +{ + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* 1. reset first for newly incoming request */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prSchedScanRequest != NULL) + prGlueInfo->prSchedScanRequest = NULL; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + DBGLOG(SCN, INFO, "cfg80211_sched_scan_stopped send event\n"); + + /* 2. indication to cfg80211 */ + /* 20150205 change cfg80211_sched_scan_stopped to work queue to use K thread to send event instead of Tx thread + due to sched_scan_mtx dead lock issue by Tx thread serves oid cmds and send event in the same time */ + DBGLOG(SCN, TRACE, "start work queue to send event\n"); + schedule_delayed_work(&sched_workq, 0); + DBGLOG(SCN, TRACE, "tx_thread return from kalSchedScanStoppped\n"); + +} + +#if CFG_SUPPORT_WAKEUP_REASON_DEBUG +/* if SPM is not implement this function, we will use this default one */ +wake_reason_t __weak slp_get_wake_reason(VOID) +{ + return WR_NONE; +} +/* if SPM is not implement this function, we will use this default one */ +UINT_32 __weak spm_get_last_wakeup_src(VOID) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To check if device if wake up by wlan +* +* \param[in] +* prAdapter +* +* \return +* TRUE: wake up by wlan; otherwise, FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter) +{ + /* SUSPEND_FLAG_FOR_WAKEUP_REASON is set means system has suspended, but may be failed + duo to some driver suspend failed. so we need help of function slp_get_wake_reason */ + if (test_and_clear_bit(SUSPEND_FLAG_FOR_WAKEUP_REASON, &prAdapter->ulSuspendFlag) == 0) + return FALSE; + /* if slp_get_wake_reason or spm_get_last_wakeup_src is NULL, it means SPM module didn't implement + it. then we should return FALSE always. otherwise, if slp_get_wake_reason returns WR_WAKE_SRC, + then it means the host is suspend successfully. */ + if (slp_get_wake_reason() != WR_WAKE_SRC) + return FALSE; + /* spm_get_last_wakeup_src will returns the last wakeup source, + WAKE_SRC_CONN2AP is connsys */ + return !!(spm_get_last_wakeup_src() & WAKE_SRC_CONN2AP); +} +#endif + +INT_32 kalHaltLock(UINT_32 waitMs) +{ + INT_32 i4Ret = 0; + + if (waitMs) { + i4Ret = down_timeout(&rHaltCtrl.lock, MSEC_TO_JIFFIES(waitMs)); + if (!i4Ret) + goto success; + if (i4Ret != -ETIME) + return i4Ret; + if (rHaltCtrl.fgHeldByKalIoctl) { + P_GLUE_INFO_T prGlueInfo = NULL; + + wlanExportGlueInfo(&prGlueInfo); + + DBGLOG(INIT, ERROR, + "kalIoctl was executed longer than %u ms, show backtrace of tx_thread!\n", + kalGetTimeTick() - rHaltCtrl.u4HoldStart); + if (prGlueInfo) + show_stack(prGlueInfo->main_thread, NULL); + } else { + DBGLOG(INIT, ERROR, "halt lock held by %s pid %d longer than %u ms!\n", + rHaltCtrl.owner->comm, rHaltCtrl.owner->pid, + kalGetTimeTick() - rHaltCtrl.u4HoldStart); + show_stack(rHaltCtrl.owner, NULL); + } + return i4Ret; + } + down(&rHaltCtrl.lock); +success: + rHaltCtrl.owner = current; + rHaltCtrl.u4HoldStart = kalGetTimeTick(); + return 0; +} + +INT_32 kalHaltTryLock(VOID) +{ + INT_32 i4Ret = 0; + + i4Ret = down_trylock(&rHaltCtrl.lock); + if (i4Ret) + return i4Ret; + rHaltCtrl.owner = current; + rHaltCtrl.u4HoldStart = kalGetTimeTick(); + return 0; +} + +VOID kalHaltUnlock(VOID) +{ + if (kalGetTimeTick() - rHaltCtrl.u4HoldStart > WLAN_OID_TIMEOUT_THRESHOLD * 2 && + rHaltCtrl.owner) + DBGLOG(INIT, ERROR, "process %s pid %d hold halt lock longer than 4s!\n", + rHaltCtrl.owner->comm, rHaltCtrl.owner->pid); + rHaltCtrl.owner = NULL; + up(&rHaltCtrl.lock); +} + +VOID kalSetHalted(BOOLEAN fgHalt) +{ + rHaltCtrl.fgHalt = fgHalt; +} + +BOOLEAN kalIsHalted(VOID) +{ + return rHaltCtrl.fgHalt; +} +VOID kalPerMonDump(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + DBGLOG(SW4, WARN, "ulPerfMonFlag:0x%lx\n", prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, WARN, "ulLastTxBytes:%ld\n", prPerMonitor->ulLastTxBytes); + DBGLOG(SW4, WARN, "ulLastRxBytes:%ld\n", prPerMonitor->ulLastRxBytes); + DBGLOG(SW4, WARN, "ulP2PLastTxBytes:%ld\n", prPerMonitor->ulP2PLastTxBytes); + DBGLOG(SW4, WARN, "ulP2PLastRxBytes:%ld\n", prPerMonitor->ulP2PLastRxBytes); + DBGLOG(SW4, WARN, "ulThroughput:%ld\n", prPerMonitor->ulThroughput); + DBGLOG(SW4, WARN, "u4UpdatePeriod:%d\n", prPerMonitor->u4UpdatePeriod); + DBGLOG(SW4, WARN, "u4TarPerfLevel:%d\n", prPerMonitor->u4TarPerfLevel); + DBGLOG(SW4, WARN, "u4CurrPerfLevel:%d\n", prPerMonitor->u4CurrPerfLevel); + DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.tx_bytes); + DBGLOG(SW4, WARN, "netStats tx_bytes:%ld\n", prGlueInfo->rNetDevStats.rx_bytes); + DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes); + DBGLOG(SW4, WARN, "p2p netStats tx_bytes:%ld\n", prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes); +} + +inline INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + DBGLOG(SW4, INFO, "enter %s\n", __func__); + if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) + DBGLOG(SW4, WARN, "abnormal, perf monitory already running\n"); + KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); + KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); + KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); + prPerMonitor->u4UpdatePeriod = 1000; + cnmTimerInitTimer(prGlueInfo->prAdapter, + &prPerMonitor->rPerfMonTimer, + (PFN_MGMT_TIMEOUT_FUNC) kalPerMonHandler, (ULONG) NULL); + DBGLOG(SW4, INFO, "exit %s\n", __func__); + return 0; +} + +inline INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + + DBGLOG(SW4, INFO, "enter %s\n", __func__); + if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + DBGLOG(SW4, TRACE, "need to stop before disable\n"); + kalPerMonStop(prGlueInfo); + } + KAL_SET_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, TRACE, "exit %s\n", __func__); + return 0; +} + +inline INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + + DBGLOG(SW4, INFO, "enter %s\n", __func__); + KAL_CLR_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, TRACE, "exit %s\n", __func__); + return 0; +} + +inline INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + DBGLOG(SW4, TRACE, "enter %s\n", __func__); + if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) + return 0; + if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + DBGLOG(SW4, TRACE, "perf monitor already running\n"); + return 0; + } + cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); + KAL_SET_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); + KAL_CLR_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, INFO, "perf monitor started\n"); + return 0; +} + +inline INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo) +{ + struct GL_PER_MON_T *prPerMonitor; + + prPerMonitor = &prGlueInfo->prAdapter->rPerMonitor; + DBGLOG(SW4, TRACE, "enter %s\n", __func__); + + if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + DBGLOG(SW4, TRACE, "perf monitory disabled\n"); + return 0; + } + + if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + DBGLOG(SW4, TRACE, "perf monitory already stopped\n"); + return 0; + } + + KAL_SET_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag); + if (KAL_TEST_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + cnmTimerStopTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer); + KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); + prPerMonitor->ulLastRxBytes = 0; + prPerMonitor->ulLastTxBytes = 0; + prPerMonitor->ulP2PLastRxBytes = 0; + prPerMonitor->ulP2PLastTxBytes = 0; + prPerMonitor->ulThroughput = 0; + prPerMonitor->u4CurrPerfLevel = 0; + prPerMonitor->u4TarPerfLevel = 0; + /*Cancel CPU performance mode request*/ + kalBoostCpu(0); + } + DBGLOG(SW4, TRACE, "exit %s\n", __func__); + return 0; +} + +inline INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo) +{ + kalPerMonDisable(prGlueInfo); + return 0; +} + +VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam) +{ + /*Calculate current throughput*/ + struct GL_PER_MON_T *prPerMonitor; + + LONG latestTxBytes, latestRxBytes, txDiffBytes, rxDiffBytes; + LONG p2pLatestTxBytes, p2pLatestRxBytes, p2pTxDiffBytes, p2pRxDiffBytes; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + if ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) || (!prAdapter->fgIsP2PRegistered)) + return; + + prPerMonitor = &prAdapter->rPerMonitor; + DBGLOG(SW4, TRACE, "enter kalPerMonHandler\n"); + if (KAL_TEST_BIT(PERF_MON_DISABLE_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, WARN, "perf monitory disabled, omit timeout event\n"); + return; + } + + if (KAL_TEST_BIT(PERF_MON_STOP_BIT_OFF, prPerMonitor->ulPerfMonFlag)) { + KAL_CLR_BIT(PERF_MON_RUNNING_BIT_OFF, prPerMonitor->ulPerfMonFlag); + DBGLOG(SW4, WARN, "perf monitory stopped, omit timeout event\n"); + return; + } + latestTxBytes = prGlueInfo->rNetDevStats.tx_bytes; + latestRxBytes = prGlueInfo->rNetDevStats.rx_bytes; + p2pLatestTxBytes = prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes; + p2pLatestRxBytes = prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes; + if (0 == prPerMonitor->ulLastRxBytes && + 0 == prPerMonitor->ulLastTxBytes && + 0 == prPerMonitor->ulP2PLastRxBytes && + 0 == prPerMonitor->ulP2PLastTxBytes) { + prPerMonitor->ulThroughput = 0; + } else { + txDiffBytes = latestTxBytes - prPerMonitor->ulLastTxBytes; + rxDiffBytes = latestRxBytes - prPerMonitor->ulLastRxBytes; + if (0 > txDiffBytes) + txDiffBytes = -(txDiffBytes); + if (0 > rxDiffBytes) + rxDiffBytes = -(rxDiffBytes); + + p2pTxDiffBytes = p2pLatestTxBytes - prPerMonitor->ulP2PLastTxBytes; + p2pRxDiffBytes = p2pLatestRxBytes - prPerMonitor->ulP2PLastRxBytes; + if (0 > p2pTxDiffBytes) + p2pTxDiffBytes = -(p2pTxDiffBytes); + if (0 > p2pRxDiffBytes) + p2pRxDiffBytes = -(p2pRxDiffBytes); + + prPerMonitor->ulThroughput = txDiffBytes + rxDiffBytes + p2pTxDiffBytes + p2pRxDiffBytes; + prPerMonitor->ulThroughput *= 1000; + prPerMonitor->ulThroughput /= prPerMonitor->u4UpdatePeriod; + prPerMonitor->ulThroughput <<= 3; + } + /*start the timer again to make sure we can cancel performance mode request in the end*/ + cnmTimerStartTimer(prGlueInfo->prAdapter, &prPerMonitor->rPerfMonTimer, prPerMonitor->u4UpdatePeriod); + + prPerMonitor->ulLastTxBytes = latestTxBytes; + prPerMonitor->ulLastRxBytes = latestRxBytes; + prPerMonitor->ulP2PLastTxBytes = p2pLatestTxBytes; + prPerMonitor->ulP2PLastRxBytes = p2pLatestRxBytes; + + if (prPerMonitor->ulThroughput < THROUGHPUT_L1_THRESHOLD) + prPerMonitor->u4TarPerfLevel = 0; + else if (prPerMonitor->ulThroughput < THROUGHPUT_L2_THRESHOLD) + prPerMonitor->u4TarPerfLevel = 1; + else if (prPerMonitor->ulThroughput < THROUGHPUT_L3_THRESHOLD) + prPerMonitor->u4TarPerfLevel = 2; + else + prPerMonitor->u4TarPerfLevel = 3; + if (prPerMonitor->u4TarPerfLevel != prPerMonitor->u4CurrPerfLevel) { + if (0 == prPerMonitor->u4TarPerfLevel) { + /*cancel CPU performance mode request*/ + kalPerMonStop(prGlueInfo); + } else{ + DBGLOG(SW4, TRACE, "throughput:%ld bps\n", prPerMonitor->ulThroughput); + /*adjust CPU core number to prPerMonitor->u4TarPerfLevel+1*/ + kalBoostCpu(prPerMonitor->u4TarPerfLevel+1); + /*start the timer again to make sure we can cancel performance mode request in the end*/ + cnmTimerStartTimer(prGlueInfo->prAdapter, + &prPerMonitor->rPerfMonTimer, + prPerMonitor->u4UpdatePeriod); + } + } + prPerMonitor->u4CurrPerfLevel = prPerMonitor->u4TarPerfLevel; + DBGLOG(SW4, TRACE, "exit kalPerMonHandler\n"); +} + +INT32 __weak kalBoostCpu(UINT_32 core_num) +{ + DBGLOG(SW4, WARN, "enter weak kalBoostCpu, core_num:%d\n", core_num); + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c new file mode 100644 index 0000000000000..2d96315389429 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p.c @@ -0,0 +1,4671 @@ +/* +** Id: @(#) gl_p2p.c@@ +*/ + +/*! \file gl_p2p.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_p2p.c +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 17 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 16 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 14 2012 yuche.tsai +** NULL +** FPB from ALPS.JB to phase 2 release. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Fix compile error for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 01 09 2012 terry.wu + * [WCXRP00001166] [Wi-Fi] [Driver] cfg80211 integration for p2p newtork + * cfg80211 integration for p2p network. + * + * 12 19 2011 terry.wu + * [WCXRP00001142] [Wi-Fi] [P2P Driver] XOR local admin bit to generate p2p net device MAC + * XOR local administrated bit to generate net device MAC of p2p network. + * + * 12 02 2011 yuche.tsai + * NULL + * Fix possible KE when unload p2p. + * + * 11 24 2011 yuche.tsai + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 16 2011 yuche.tsai + * [WCXRP00001107] [Volunteer Patch][Driver] Large Network Type index assert in FW issue. + * Avoid using work thread in set p2p multicast address callback. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix default device name issue. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service + * discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 11 07 2011 yuche.tsai + * NULL + * [ALPS 00087243] KE in worker thread. + * The multicast address list is scheduled in worker thread. + * Before the worker thread is excuted, if P2P is unloaded, a KE may occur. + * + * 10 26 2011 terry.wu + * [WCXRP00001066] [MT6620 Wi-Fi] [P2P Driver] Fix P2P Oid Issue + * Fix some P2P OID functions didn't raise its flag "fgIsP2pOid" issue. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * Support Channel Query. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 26 2011 yuche.tsai + * NULL + * Fix bug of parsing secondary device list type issue. + * + * 08 24 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Abort. + * + * 08 23 2011 yuche.tsai + * NULL + * Fix multicast address list issue of P2P. + * + * 08 22 2011 chinglan.wang + * NULL + * Fix invitation indication bug.. + * + * 08 16 2011 cp.wu + * [WCXRP00000934] [MT6620 Wi-Fi][Driver][P2P] Wi-Fi hot spot with auto sparse channel residence + * auto channel decision for 2.4GHz hot spot mode + * + * 08 16 2011 chinglan.wang + * NULL + * Add the group id information in the invitation indication. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 08 05 2011 yuche.tsai + * [WCXRP00000856] [Volunteer Patch][WiFi Direct][Driver] MT6620 WiFi Direct IOT Issue with BCM solution. + * Add Password ID check for quick connection. + * Also modify some connection policy. + * + * 07 18 2011 chinglan.wang + * NULL + * Add IOC_P2P_GO_WSC_IE (p2p capability). + * + * 06 14 2011 yuche.tsai + * NULL + * Add compile flag to disable persistent group support. + * + * 05 04 2011 chinglan.wang + * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver + * . + * + * 05 02 2011 yuche.tsai + * [WCXRP00000693] [Volunteer Patch][MT6620][Driver] Clear Formation Flag after TX lifetime timeout. + * Clear formation flag after formation timeout. + * + * 04 22 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * . + * + * 04 21 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * 1. Revise P2P power mode setting. + * 2. Revise fast-PS for concurrent + * + * 04 19 2011 wh.su + * NULL + * Adding length check before doing WPA RSN IE parsing for scan results indicate. + * + * 04 14 2011 yuche.tsai + * [WCXRP00000646] [Volunteer Patch][MT6620][FW/Driver] Sigma Test Modification for some test case. + * Connection flow refine for Sigma test. + * + * 04 08 2011 yuche.tsai + * [WCXRP00000624] [Volunteer Patch][MT6620][Driver] Add device discoverability support for GO. + * Add device discoverability support. + * + * 04 08 2011 george.huang + * [WCXRP00000621] [MT6620 Wi-Fi][Driver] Support P2P supplicant to set power mode + * separate settings of P2P and AIS + * + * 04 07 2011 terry.wu + * [WCXRP00000619] [MT6620 Wi-Fi][Driver] fix kernel panic may occur when removing wlan + * Fix kernel panic may occur when removing wlan driver. + * + * 03 31 2011 wh.su + * [WCXRP00000614] [MT6620 Wi-Fi][Driver] P2P: Update beacon content while setting WSC IE + * Update the wsc ie to beacon content. + * + * 03 25 2011 wh.su + * NULL + * add the sample code for set power mode and get power mode. + * + * 03 25 2011 yuche.tsai + * NULL + * Improve some error handleing. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 22 2011 yuche.tsai + * [WCXRP00000584] [Volunteer Patch][MT6620][Driver] Add beacon timeout support for WiFi Direct. + * Modify formation policy. + * + * 03 22 2011 yuche.tsai + * NULL + * Modify formation policy setting. + * + * 03 18 2011 yuche.tsai + * [WCXRP00000574] [Volunteer Patch][MT6620][Driver] Modify P2P FSM Connection Flow + * Modify connection flow after Group Formation Complete, or device connect to a GO. + * Instead of request channel & connect directly, we use scan to allocate channel bandwidth & connect after RX BCN. + * + * 03 15 2011 wh.su + * [WCXRP00000563] [MT6620 Wi-Fi] [P2P] Set local config method while set password Id ready + * set lccal config method method while set password Id ready. + * + * 03 15 2011 yuche.tsai + * [WCXRP00000560] [Volunteer Patch][MT6620][Driver] P2P Connection from UI using KEY/DISPLAY issue + * Fix some configure method issue. + * + * 03 15 2011 jeffrey.chang + * [WCXRP00000558] [MT6620 Wi-Fi][MT6620 Wi-Fi][Driver] refine the queue selection algorithm for WMM + * refine queue_select function + * + * 03 13 2011 wh.su + * [WCXRP00000530] [MT6620 Wi-Fi] [Driver] skip doing p2pRunEventAAAComplete after send assoc response Tx Done + * add code for avoid compiling warning. + * + * 03 10 2011 yuche.tsai + * NULL + * Add P2P API. + * + * 03 10 2011 terry.wu + * [WCXRP00000505] [MT6620 Wi-Fi][Driver/FW] WiFi Direct Integration + * Remove unnecessary assert and message. + * + * 03 08 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * support the power save related p2p setting. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify P2P's netdevice functions to support multiple H/W queues + * + * 03 03 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * for get request, the buffer length to be copied is header + payload. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add code to let the beacon and probe response for Auto GO WSC . + * + * 03 02 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * add a missed break. + * + * 03 01 2011 yuche.tsai + * [WCXRP00000501] [Volunteer Patch][MT6620][Driver] No common channel issue when doing GO formation + * Update channel issue when doing GO formation.. + * + * 02 25 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * add the Operation channel setting. + * + * 02 23 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * fixed the set int ioctl set index and value map to driver issue. + * + * 02 22 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int from supplicant, and can used to set the p2p parameters + * + * 02 21 2011 terry.wu + * [WCXRP00000476] [MT6620 Wi-Fi][Driver] Clean P2P scan list while removing P2P + * Clean P2P scan list while removing P2P. + * + * 02 18 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * fixed the ioctl setting that index not map to spec defined config method. + * + * 02 17 2011 wh.su + * [WCXRP00000471] [MT6620 Wi-Fi][Driver] Add P2P Provison discovery append Config Method attribute at WSC IE + * append the WSC IE config method attribute at provision discovery request. + * + * 02 17 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * modify the structure pointer for set WSC IE. + * + * 02 16 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * fixed the probe request send out without WSC IE issue (at P2P). + * + * 02 09 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * fix typo + * + * 02 09 2011 yuche.tsai + * [WCXRP00000431] [Volunteer Patch][MT6620][Driver] Add MLME support for deauthentication under AP(Hot-Spot) mode. + * Add Support for MLME deauthentication for Hot-Spot. + * + * 01 25 2011 terry.wu + * [WCXRP00000393] [MT6620 Wi-Fi][Driver] Add new module insert parameter + * Add a new module parameter to indicate current runnig mode, P2P or AP. + * + * 01 12 2011 yuche.tsai + * [WCXRP00000352] [Volunteer Patch][MT6620][Driver] P2P Statsion Record Client List Issue + * 1. Modify Channel Acquire Time of AP mode from 5s to 1s. + * 2. Call cnmP2pIsPermit() before active P2P network. + * 3. Add channel selection support for AP mode. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * ioctl implementations for P2P Service Discovery + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 12 15 2010 cp.wu + * NULL + * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() + * + * 12 08 2010 yuche.tsai + * [WCXRP00000245] [MT6620][Driver] Invitation & Provision Discovery Feature Check-in + * [WCXRP000000245][MT6620][Driver] Invitation Request Feature Add + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 17 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID[WCXRP00000179] [MT6620 Wi-Fi][FW] Set the Tx + * lowest rate at wlan table for normal operation + * fixed some ASSERT check. + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 10 2010 george.huang + * NULL + * update iwpriv LP related + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at win XP. + * + * 09 09 2010 cp.wu + * NULL + * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 08 25 2010 cp.wu + * NULL + * add netdev_ops(NDO) for linux kernel 2.6.31 or greater + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 20 2010 cp.wu + * NULL + * correct typo. + * + * 08 20 2010 yuche.tsai + * NULL + * Invert Connection request provision status parameter. + * + * 08 19 2010 cp.wu + * NULL + * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. + * + * 08 18 2010 cp.wu + * NULL + * modify pwp ioctls attribution by removing FIXED_SIZE. + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 17 2010 cp.wu + * NULL + * correct p2p net device registration with NULL pointer access issue. + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 16 2010 cp.wu + * NULL + * add subroutines for P2P to set multicast list. + * + * 08 16 2010 george.huang + * NULL + * add wext handlers to link P2P set PS profile/ network address function (TBD) + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 12 2010 cp.wu + * NULL + * follow-up with ioctl interface update for Wi-Fi Direct application + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * add basic support for ioctl of getting scan result. (only address and SSID are reporterd though) + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant + * + * 08 03 2010 cp.wu + * NULL + * surpress compilation warning. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 23 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * p2p interface revised to be sync. with HAL + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement private io controls for Wi-Fi Direct + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * 1) add timeout handler mechanism for pending command packets + * 2) add p2p add/removal key + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement wireless extension ioctls in iw_handler form. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include + +#include "gl_os.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "gl_p2p_os.h" +#include "gl_p2p_ioctl.h" +#include "gl_vendor.h" + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define ARGV_MAX_NUM (4) + +/*For CFG80211 - wiphy parameters*/ +#define MAX_SCAN_LIST_NUM (1) +#define MAX_SCAN_IE_LEN (512) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +static struct cfg80211_ops mtk_p2p_ops = { + .change_virtual_intf = mtk_p2p_cfg80211_change_iface, /* 1st */ + .change_bss = mtk_p2p_cfg80211_change_bss, + .scan = mtk_p2p_cfg80211_scan, + .remain_on_channel = mtk_p2p_cfg80211_remain_on_channel, + .cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel, + .mgmt_tx = mtk_p2p_cfg80211_mgmt_tx, + .connect = mtk_p2p_cfg80211_connect, + .disconnect = mtk_p2p_cfg80211_disconnect, + .deauth = mtk_p2p_cfg80211_deauth, + .disassoc = mtk_p2p_cfg80211_disassoc, + .start_ap = mtk_p2p_cfg80211_start_ap, + .change_beacon = mtk_p2p_cfg80211_change_beacon, + .stop_ap = mtk_p2p_cfg80211_stop_ap, + .set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params, + .del_station = mtk_p2p_cfg80211_del_station, + .set_monitor_channel = mtk_p2p_cfg80211_set_channel, + .set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask, + .mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register, + .get_station = mtk_p2p_cfg80211_get_station, + .add_key = mtk_p2p_cfg80211_add_key, + .get_key = mtk_p2p_cfg80211_get_key, + .del_key = mtk_p2p_cfg80211_del_key, + .set_default_key = mtk_p2p_cfg80211_set_default_key, + .join_ibss = mtk_p2p_cfg80211_join_ibss, + .leave_ibss = mtk_p2p_cfg80211_leave_ibss, + .set_tx_power = mtk_p2p_cfg80211_set_txpower, + .get_tx_power = mtk_p2p_cfg80211_get_txpower, + .set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt, +#ifdef CONFIG_NL80211_TESTMODE + .testmode_cmd = mtk_p2p_cfg80211_testmode_cmd, +#endif +}; + +static const struct wiphy_vendor_command mtk_p2p_vendor_ops[] = { + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_get_channel_list + }, + { + { + .vendor_id = GOOGLE_OUI, + .subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = mtk_cfg80211_vendor_set_country_code + }, +}; + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes + mtk_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) + } +}; + +#endif + +/* the legacy wireless extension stuff */ +static const iw_handler rP2PIwStandardHandler[] = { + [SIOCGIWPRIV - SIOCIWFIRST] = mtk_p2p_wext_get_priv, + [SIOCGIWSCAN - SIOCIWFIRST] = mtk_p2p_wext_discovery_results, + [SIOCSIWESSID - SIOCIWFIRST] = mtk_p2p_wext_reconnect, + [SIOCSIWAUTH - SIOCIWFIRST] = mtk_p2p_wext_set_auth, + [SIOCSIWENCODEEXT - SIOCIWFIRST] = mtk_p2p_wext_set_key, + [SIOCSIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_set_powermode, + [SIOCGIWPOWER - SIOCIWFIRST] = mtk_p2p_wext_get_powermode, + [SIOCSIWTXPOW - SIOCIWFIRST] = mtk_p2p_wext_set_txpow, +#if CFG_SUPPORT_P2P_RSSI_QUERY + [SIOCGIWSTATS - SIOCIWFIRST] = mtk_p2p_wext_get_rssi, +#endif + [SIOCSIWMLME - SIOCIWFIRST] = mtk_p2p_wext_mlme_handler, +}; + +static const iw_handler rP2PIwPrivHandler[] = { + [IOC_P2P_CFG_DEVICE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_local_dev_info, + [IOC_P2P_PROVISION_COMPLETE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_provision_complete, + [IOC_P2P_START_STOP_DISCOVERY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_start_stop_discovery, + [IOC_P2P_DISCOVERY_RESULTS - SIOCIWFIRSTPRIV] = mtk_p2p_wext_discovery_results, + [IOC_P2P_WSC_BEACON_PROBE_RSP_IE - SIOCIWFIRSTPRIV] = mtk_p2p_wext_wsc_ie, + [IOC_P2P_CONNECT_DISCONNECT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_connect_disconnect, + [IOC_P2P_PASSWORD_READY - SIOCIWFIRSTPRIV] = mtk_p2p_wext_password_ready, +/* [IOC_P2P_SET_PWR_MGMT_PARAM - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_pm_param, */ + [IOC_P2P_SET_INT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_int, + [IOC_P2P_GET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_get_struct, + [IOC_P2P_SET_STRUCT - SIOCIWFIRSTPRIV] = mtk_p2p_wext_set_struct, + [IOC_P2P_GET_REQ_DEVICE_INFO - SIOCIWFIRSTPRIV] = mtk_p2p_wext_request_dev_info, +}; + +static const struct iw_priv_args rP2PIwPrivTable[] = { + { + .cmd = IOC_P2P_CFG_DEVICE, + .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CFG_DEVICE_TYPE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_CFG_DEVICE"} + , + { + .cmd = IOC_P2P_START_STOP_DISCOVERY, + .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_REQ_DEVICE_TYPE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_DISCOVERY"} + , + { + .cmd = IOC_P2P_DISCOVERY_RESULTS, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_RESULT"} + , + { + .cmd = IOC_P2P_WSC_BEACON_PROBE_RSP_IE, + .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_HOSTAPD_PARAM), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_WSC_IE"} + , + { + .cmd = IOC_P2P_CONNECT_DISCONNECT, + .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CONNECT_DEVICE), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_CONNECT"} + , + { + .cmd = IOC_P2P_PASSWORD_READY, + .set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_PASSWORD_READY), + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_PASSWD_RDY"} + , + { + .cmd = IOC_P2P_GET_STRUCT, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = 256, + .name = "P2P_GET_STRUCT"} + , + { + .cmd = IOC_P2P_SET_STRUCT, + .set_args = 256, + .get_args = IW_PRIV_TYPE_NONE, + .name = "P2P_SET_STRUCT"} + , + { + .cmd = IOC_P2P_GET_REQ_DEVICE_INFO, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_DEVICE_REQ), + .name = "P2P_GET_REQDEV"} + , + { + /* SET STRUCT sub-ioctls commands */ + .cmd = PRIV_CMD_OID, + .set_args = 256, + .get_args = IW_PRIV_TYPE_NONE, + .name = "set_oid"} + , + { + /* GET STRUCT sub-ioctls commands */ + .cmd = PRIV_CMD_OID, + .set_args = IW_PRIV_TYPE_NONE, + .get_args = 256, + .name = "get_oid"} +}; + +const struct iw_handler_def mtk_p2p_wext_handler_def = { + .num_standard = (__u16) sizeof(rP2PIwStandardHandler) / sizeof(iw_handler), + .num_private = (__u16) sizeof(rP2PIwPrivHandler) / sizeof(iw_handler), + .num_private_args = (__u16) sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args), + .standard = rP2PIwStandardHandler, + .private = rP2PIwPrivHandler, + .private_args = rP2PIwPrivTable, +#if CFG_SUPPORT_P2P_RSSI_QUERY + .get_wireless_stats = mtk_p2p_wext_get_wireless_stats, +#else + .get_wireless_stats = NULL, +#endif +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support p2p_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, +}; +#endif + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* for IE Searching */ +extern BOOLEAN +wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); + +#if CFG_SUPPORT_WPS +extern BOOLEAN +wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); +#endif + +/* Net Device Hooks */ +static int p2pOpen(IN struct net_device *prDev); + +static int p2pStop(IN struct net_device *prDev); + +static struct net_device_stats *p2pGetStats(IN struct net_device *prDev); + +static void p2pSetMulticastList(IN struct net_device *prDev); + +static int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev); + +static int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd); + +static int p2pSetMACAddress(IN struct net_device *prDev, void *addr); + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Override the implementation of select queue +* +* \param[in] dev Pointer to struct net_device +* \param[in] skb Pointer to struct skb_buff +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ + +unsigned int _p2p_cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp = 0; + + /* skb->priority values from 256->263 are magic values + * directly indicate a specific 802.1d priority. This is + * to allow 802.1d priority to be passed directly in from + * tags + */ + + if (skb->priority >= 256 && skb->priority <= 263) + return skb->priority - 256; + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + } + return dscp >> 5; +} + +static const UINT_16 au16Wlan1dToQueueIdx[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static UINT_16 p2pSelectQueue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + skb->priority = _p2p_cfg80211_classify8021d(skb); + + return au16Wlan1dToQueueIdx[skb->priority]; +} + +static struct net_device *g_P2pPrDev; +static struct wireless_dev *gprP2pWdev; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->init +* +* \param[in] prDev Pointer to struct net_device. +* +* \retval 0 The execution of wlanInit succeeds. +* \retval -ENXIO No such device. +*/ +/*----------------------------------------------------------------------------*/ +static int p2pInit(struct net_device *prDev) +{ +/* P_GLUE_INFO_T prGlueInfo; */ + if (!prDev) + return -ENXIO; + + DBGLOG(P2P, INFO, "dev name=%s\n", prDev->name); + return 0; /* success */ +} /* end of p2pInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A function for prDev->uninit +* +* \param[in] prDev Pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +static void p2pUninit(IN struct net_device *prDev) +{ + +} /* end of p2pUninit() */ + +static const struct net_device_ops p2p_netdev_ops = { + .ndo_open = p2pOpen, + .ndo_stop = p2pStop, + .ndo_set_mac_address = p2pSetMACAddress, + .ndo_set_rx_mode = p2pSetMulticastList, + .ndo_get_stats = p2pGetStats, + .ndo_do_ioctl = p2pDoIOCTL, + .ndo_start_xmit = p2pHardStartXmit, + .ndo_select_queue = p2pSelectQueue, + .ndo_init = p2pInit, + .ndo_uninit = p2pUninit, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS +* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdapter = NULL; + P_WIFI_VAR_T prWifiVar = NULL; + + if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { + ASSERT(FALSE); + return FALSE; + } + + prAdapter = prGlueInfo->prAdapter; + prWifiVar = &(prAdapter->rWifiVar); + + if (!prWifiVar) { + ASSERT(FALSE); + return FALSE; + } + + do { + if (prGlueInfo->prP2PInfo == NULL) { + /*alloc memory for p2p info */ + prGlueInfo->prP2PInfo = kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); + prAdapter->prP2pInfo = kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); + prWifiVar->prP2PConnSettings = kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T), VIR_MEM_TYPE); + prWifiVar->prP2pFsmInfo = kalMemAlloc(sizeof(P2P_FSM_INFO_T), VIR_MEM_TYPE); + prWifiVar->prP2pSpecificBssInfo = kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T), VIR_MEM_TYPE); + } else { + ASSERT(prAdapter->prP2pInfo != NULL); + ASSERT(prWifiVar->prP2PConnSettings != NULL); + ASSERT(prWifiVar->prP2pFsmInfo != NULL); + ASSERT(prWifiVar->prP2pSpecificBssInfo != NULL); + } + /*MUST set memory to 0 */ + if (prGlueInfo->prP2PInfo) + kalMemZero(prGlueInfo->prP2PInfo, sizeof(GL_P2P_INFO_T)); + if (prAdapter->prP2pInfo) + kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); + if (prWifiVar->prP2PConnSettings) + kalMemZero(prWifiVar->prP2PConnSettings, sizeof(P2P_CONNECTION_SETTINGS_T)); + if (prWifiVar->prP2pFsmInfo) + kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); + if (prWifiVar->prP2pSpecificBssInfo) + kalMemZero(prWifiVar->prP2pSpecificBssInfo, sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + } while (FALSE); + + /* chk if alloc successful or not */ + if (prGlueInfo->prP2PInfo && + prAdapter->prP2pInfo && + prWifiVar->prP2PConnSettings && prWifiVar->prP2pFsmInfo && prWifiVar->prP2pSpecificBssInfo) { + return TRUE; + } + + if (prWifiVar->prP2pSpecificBssInfo) { + kalMemFree(prWifiVar->prP2pSpecificBssInfo, VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + prWifiVar->prP2pSpecificBssInfo = NULL; + } + if (prWifiVar->prP2pFsmInfo) { + kalMemFree(prWifiVar->prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); + + prWifiVar->prP2pFsmInfo = NULL; + } + if (prWifiVar->prP2PConnSettings) { + kalMemFree(prWifiVar->prP2PConnSettings, VIR_MEM_TYPE, sizeof(P2P_CONNECTION_SETTINGS_T)); + + prWifiVar->prP2PConnSettings = NULL; + } + if (prGlueInfo->prP2PInfo) { + kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); + + prGlueInfo->prP2PInfo = NULL; + } + if (prAdapter->prP2pInfo) { + kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); + + prAdapter->prP2pInfo = NULL; + } + return FALSE; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS +* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo) +{ + + if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { + ASSERT(FALSE); + return FALSE; + } + + /* free memory after p2p module is ALREADY unregistered */ + if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { + + kalMemFree(prGlueInfo->prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); + kalMemFree(prGlueInfo->prP2PInfo, VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings, VIR_MEM_TYPE, + sizeof(P2P_CONNECTION_SETTINGS_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); + kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo, VIR_MEM_TYPE, + sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + /*Reomve p2p bss scan list */ + scanRemoveAllP2pBssDesc(prGlueInfo->prAdapter); + + /*reset all pointer to NULL */ + prGlueInfo->prP2PInfo = NULL; + prGlueInfo->prAdapter->prP2pInfo = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo = NULL; + prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo = NULL; + + return TRUE; + } else { + return FALSE; + } + +} + +#if !CFG_SUPPORT_PERSIST_NETDEV +BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) +{ + BOOLEAN fgDoRegister = FALSE; +/* BOOLEAN fgRollbackRtnlLock = FALSE; */ + BOOLEAN ret; + + GLUE_SPIN_LOCK_DECLARATION(); + + if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { + ASSERT(FALSE); + return FALSE; + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_UNREGISTERED) { + prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERING; + fgDoRegister = TRUE; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!fgDoRegister) + return TRUE; + + /* net device initialize */ + netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + + /* register for net device */ + if (register_netdev(prGlueInfo->prP2PInfo->prDevHandler) < 0) { + DBGLOG(P2P, WARN, "unable to register netdevice for p2p\n"); + + free_netdev(prGlueInfo->prP2PInfo->prDevHandler); + + ret = FALSE; + } else { + prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED; + ret = TRUE; + } + return ret; +} + +BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired) +{ + BOOLEAN fgDoUnregister = FALSE; +/* BOOLEAN fgRollbackRtnlLock = FALSE; */ + GLUE_SPIN_LOCK_DECLARATION(); + + if ((!prGlueInfo) || (!prGlueInfo->prAdapter)) { + ASSERT(FALSE); + return FALSE; + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED) { + prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERING; + fgDoUnregister = TRUE; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!fgDoUnregister) + return TRUE; + + /* prepare for removal */ + if (netif_carrier_ok(prGlueInfo->prP2PInfo->prDevHandler)) + netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler); + + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + DBGLOG(P2P, INFO, "P2P unregister_netdev 0x%p\n", prGlueInfo->prP2PInfo->prDevHandler); + unregister_netdev(prGlueInfo->prP2PInfo->prDevHandler); + + prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; + + return TRUE; +} +#endif + +BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo) +{ + struct wiphy *prWiphy = NULL; + struct wireless_dev *prWdev = NULL; +#if CFG_SUPPORT_PERSIST_NETDEV + struct net_device *prNetDev = NULL; +#endif +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(P2P, ERROR, "allocate p2p wireless device fail, no memory\n"); + return FALSE; + } + /* 1. allocate WIPHY */ + prWiphy = wiphy_new(&mtk_p2p_ops, sizeof(P_GLUE_INFO_T)); + if (!prWiphy) { + DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n"); + goto free_wdev; + } + + prWiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION); + + prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; + prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; + + prWiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes; + prWiphy->max_remain_on_channel_duration = 5000; + prWiphy->cipher_suites = mtk_cipher_suites; + prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); + prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME; + prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; + prWiphy->ap_sme_capa = 1; + + prWiphy->max_scan_ssids = MAX_SCAN_LIST_NUM; + prWiphy->max_scan_ie_len = MAX_SCAN_IE_LEN; + prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + prWiphy->vendor_commands = mtk_p2p_vendor_ops; + prWiphy->n_vendor_commands = sizeof(mtk_p2p_vendor_ops) / sizeof(struct wiphy_vendor_command); + +#ifdef CONFIG_PM + prWiphy->wowlan = &p2p_wowlan_support; +#endif + + /* 2.1 set priv as pointer to glue structure */ + *((P_GLUE_INFO_T *) wiphy_priv(prWiphy)) = prGlueInfo; + if (wiphy_register(prWiphy) < 0) { + DBGLOG(P2P, ERROR, "fail to register wiphy for p2p\n"); + goto free_wiphy; + } + prWdev->wiphy = prWiphy; +#if CFG_SUPPORT_PERSIST_NETDEV + /* 3. allocate netdev */ + prNetDev = alloc_netdev_mq(sizeof(P_GLUE_INFO_T), P2P_MODE_INF_NAME, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); + if (!prNetDev) { + DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); + goto unregister_wiphy; + } + + /* 4. setup netdev */ + /* 4.1 Point to shared glue structure */ + *((P_GLUE_INFO_T *) netdev_priv(prNetDev)) = prGlueInfo; + + /* 4.2 fill hardware address */ + /* COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] ^= 0x2; // change to local administrated address + memcpy(prGlueInfo->prP2PInfo->prDevHandler->dev_addr, rMacAddr, ETH_ALEN); + memcpy(prGlueInfo->prP2PInfo->prDevHandler->perm_addr, + prGlueInfo->prP2PInfo->prDevHandler->dev_addr, ETH_ALEN);*/ + + /* 4.3 register callback functions */ + prNetDev->netdev_ops = &p2p_netdev_ops; + /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def;*/ + + prNetDev->ieee80211_ptr = prWdev; + prWdev->netdev = prNetDev; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prNetDev->features = NETIF_F_IP_CSUM; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + /* net device initialize */ + netif_carrier_off(prNetDev); + netif_tx_stop_all_queues(prNetDev); + + /* register for net device */ + if (register_netdev(prNetDev) < 0) { + DBGLOG(P2P, ERROR, "unable to register netdevice for p2p\n"); + free_netdev(prNetDev); + goto unregister_wiphy; + } +#endif + gprP2pWdev = prWdev; + return TRUE; + +#if CFG_SUPPORT_PERSIST_NETDEV +unregister_wiphy: + wiphy_unregister(prWiphy); +#endif +free_wiphy: + wiphy_free(prWiphy); +free_wdev: + kfree(prWdev); +#endif + return FALSE; +} + +void glP2pDestroyWirelessDevice(VOID) +{ +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#if CFG_SUPPORT_PERSIST_NETDEV + unregister_netdev(gprP2pWdev->netdev); + free_netdev(gprP2pWdev->netdev); +#endif + wiphy_unregister(gprP2pWdev->wiphy); + wiphy_free(gprP2pWdev->wiphy); + kfree(gprP2pWdev); + gprP2pWdev = NULL; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Register for cfg80211 for Wi-Fi Direct +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode) +{ + P_ADAPTER_T prAdapter = NULL; + P_GL_HIF_INFO_T prHif = NULL; + PARAM_MAC_ADDRESS rMacAddr; + struct net_device *prDevHandler = NULL; +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + struct device *prDev; +#endif + + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + + DBGLOG(P2P, TRACE, "glRegisterP2P\n"); +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + if (!gprP2pWdev) { + DBGLOG(P2P, ERROR, "gl_p2p, wireless device is not exist\n"); + return FALSE; + } +#endif + /*0. allocate p2pinfo */ + if (!p2PAllocInfo(prGlueInfo)) { + DBGLOG(P2P, ERROR, "Allocate memory for p2p FAILED\n"); + ASSERT(0); + return FALSE; + } +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prGlueInfo->prP2PInfo->prWdev = gprP2pWdev; + /* 1. fill wiphy parameters */ +#if MTK_WCN_HIF_SDIO + mtk_wcn_hif_sdio_get_dev(prHif->cltCtx, &prDev); + if (!prDev) + DBGLOG(P2P, WARN, "unable to get struct dev for p2p\n"); +#else + prDev = prHif->Dev; +#endif + /*set_wiphy_dev(gprP2pWdev->wiphy, prDev);*/ + if (!prGlueInfo->prAdapter->fgEnable5GBand) + gprP2pWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + + /* 2 set priv as pointer to glue structure */ + *(P_GLUE_INFO_T *) wiphy_priv(gprP2pWdev->wiphy) = prGlueInfo; + + if (fgIsApMode) { + gprP2pWdev->iftype = NL80211_IFTYPE_AP; +#if CFG_SUPPORT_PERSIST_NETDEV + if (kalStrnCmp(gprP2pWdev->netdev->name, AP_MODE_INF_NAME, 2)) { + rtnl_lock(); + dev_change_name(gprP2pWdev->netdev->name, AP_MODE_INF_NAME); + rtnl_unlock(); + } +#endif + } else { +#if CFG_SUPPORT_PERSIST_NETDEV + if (kalStrnCmp(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME, 3)) { + rtnl_lock(); + dev_change_name(gprP2pWdev->netdev->name, P2P_MODE_INF_NAME); + rtnl_unlock(); + } +#endif + gprP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + } +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + +#if CFG_SUPPORT_PERSIST_NETDEV + prP2PInfo->prDevHandler = gprP2pWdev->netdev; +#else /* CFG_SUPPORT_PERSIST_NETDEV */ + /* 3. allocate netdev */ + prDevHandler = + alloc_netdev_mq(sizeof(P_GLUE_INFO_T), prDevName, NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); + if (!prDevHandler) { + DBGLOG(P2P, ERROR, "unable to allocate netdevice for p2p\n"); + return FALSE; + } + prGlueInfo->prP2PInfo->prDevHandler = prDevHandler; + /* 4. setup netdev */ + /* 4.1 Point to shared glue structure */ + *((P_GLUE_INFO_T *) netdev_priv(prDevHandler)) = prGlueInfo; + + /* 4.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] ^= 0x2; /* change to local administrated address */ + ether_addr_copy(prDevHandler->dev_addr, rMacAddr); + ether_addr_copy(prDevHandler->perm_addr, prDevHandler->dev_addr); + + /* 4.3 register callback functions */ + prDevHandler->netdev_ops = &p2p_netdev_ops; + /* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; */ + +#if (MTK_WCN_HIF_SDIO == 0) + SET_NETDEV_DEV(prDevHandler, prHif->Dev); +#endif + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prDevHandler->ieee80211_ptr = gprP2pWdev; + gprP2pWdev->netdev = prDevHandler; +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prDevHandler->features = NETIF_F_IP_CSUM; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ +#endif /* CFG_SUPPORT_PERSIST_NETDEV */ + + /* 5. set p2p net device register state */ + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; + + /* 6. setup running mode */ + prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = fgIsApMode; + + /* 7. finish */ + p2pFsmInit(prAdapter); + + p2pFuncInitConnectionSettings(prAdapter, prAdapter->rWifiVar.prP2PConnSettings); + + /* Active network too early would cause HW not able to sleep. + * Defer the network active time. + */ +/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + return TRUE; +} /* end of glRegisterP2P() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Unregister Net Device for Wi-Fi Direct +* +* \param[in] prGlueInfo Pointer to glue info +* +* \return TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + /* normal flow: this func will called first before wlanRemove, and it can do fsmUninit/deactivateNetwork + gracefully. */ + /* when reset: because tx_thread with fw has stopped, so it can't do these job and the recovery will be + dependent on chip system reset. */ + /* if so, just skip it by flag GLUE_FLAG_HALT(warning: when tx_thread was stop, this flag was not cleared, + and NEED TO KEEP IT NOT CLEARED!). */ + if (!(prGlueInfo->ulFlag & GLUE_FLAG_HALT)) { + p2pFsmUninit(prGlueInfo->prAdapter); + nicDeactivateNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX); + } +#if CFG_SUPPORT_PERSIST_NETDEV + dev_close(prGlueInfo->prP2PInfo->prDevHandler); +#else + free_netdev(prGlueInfo->prP2PInfo->prDevHandler); + prGlueInfo->prP2PInfo->prDevHandler = NULL; +#endif + /* Free p2p memory */ + if (!p2PFreeInfo(prGlueInfo)) { + DBGLOG(P2P, ERROR, "Free memory for p2p FAILED\n"); + ASSERT(0); + return FALSE; + } + return TRUE; +} /* end of glUnregisterP2P() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for stop p2p fsm immediate + * + * \param[in] prGlueInfo Pointer to struct P_GLUE_INFO_T. + * + * \retval TRUE The execution succeeds. + * \retval FALSE The execution failed. + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo) +{ +/* P_ADAPTER_T prAdapter = NULL; */ +/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ + + ASSERT(prGlueInfo); + +/* prAdapter = prGlueInfo->prAdapter; */ +/* ASSERT(prAdapter); */ + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler); + +#if 0 + /* 2. switch P2P-FSM off */ + /* 2.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); /* Can't trigger P2P FSM */ + DBGLOG(P2P, ERROR, "Allocate for p2p mesasage FAILED\n"); + /* return -ENOMEM; */ + } + + /* 2.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = FALSE; + + /* 2.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_UNBUF); + +#endif + + /* 3. stop queue and turn off carrier */ + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; + + return TRUE; +} /* end of p2pStop() */ + +/* Net Device Hooks */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device open (ifup) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int p2pOpen(IN struct net_device *prDev) +{ +/* P_GLUE_INFO_T prGlueInfo = NULL; */ +/* P_ADAPTER_T prAdapter = NULL; */ +/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ + + ASSERT(prDev); + +#if 0 /* Move after device name set. (mtk_p2p_set_local_dev_info) */ + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* 1. switch P2P-FSM on */ + /* 1.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + /* 1.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = TRUE; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); +#endif + + /* 2. carrier on & start TX queue */ + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); + + return 0; /* success */ +} /* end of p2pOpen() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device stop (ifdown) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int p2pStop(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + /* P_ADAPTER_T prAdapter = NULL; */ +/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + + struct cfg80211_scan_info info = { + .aborted = true, + }; + + struct cfg80211_scan_request *prScanRequest = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + ASSERT(prGlueP2pInfo); + + /* CFG80211 down */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueP2pInfo->prScanRequest != NULL) { + prScanRequest = prGlueP2pInfo->prScanRequest; + prGlueP2pInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (prScanRequest) + cfg80211_scan_done(prScanRequest, &info); +#if 0 + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prDev); + + /* 2. switch P2P-FSM off */ + /* 2.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + /* 2.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = FALSE; + + /* 2.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); +#endif + /* 3. stop queue and turn off carrier */ + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_DISCONNECTED; + + netif_tx_stop_all_queues(prDev); + if (netif_carrier_ok(prDev)) + netif_carrier_off(prDev); + + return 0; +} /* end of p2pStop() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface statistical + * information. + * + * Whenever an application needs to get statistics for the interface, this method + * is called. This happens, for example, when ifconfig or netstat -i is run. + * + * \param[in] prDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + */ +/*----------------------------------------------------------------------------*/ +struct net_device_stats *p2pGetStats(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + +#if CFG_SUPPORT_PERSIST_NETDEV + /* @FIXME */ + /* prDev->stats.rx_packets = 0; */ + /* prDev->stats.tx_packets = 0; */ + prDev->stats.tx_errors = 0; + prDev->stats.rx_errors = 0; + /* prDev->stats.rx_bytes = 0; */ + /* prDev->stats.tx_bytes = 0; */ + prDev->stats.multicast = 0; + + return &prDev->stats; + +#else + /* prGlueInfo->prP2PInfo->rNetDevStats.rx_packets = 0; */ + /* prGlueInfo->prP2PInfo->rNetDevStats.tx_packets = 0; */ + prGlueInfo->prP2PInfo->rNetDevStats.tx_errors = 0; + prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; + /* prGlueInfo->prP2PInfo->rNetDevStats.rx_bytes = 0; */ + /* prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes = 0; */ + /* prGlueInfo->prP2PInfo->rNetDevStats.rx_errors = 0; */ + prGlueInfo->prP2PInfo->rNetDevStats.multicast = 0; + + return &prGlueInfo->prP2PInfo->rNetDevStats; +#endif +} /* end of p2pGetStats() */ + +static void p2pSetMulticastList(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); + return; + } + + g_P2pPrDev = prDev; + + /* 4 Mark HALT, notify main thread to finish current job */ +/* prGlueInfo->u4Flag |= GLUE_FLAG_SUB_MOD_MULTICAST; */ + set_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + +} /* p2pSetMulticastList */ + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * tx_thread, so we can't let tx_thread to do this */ + +void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo) +{ + if (!prGlueInfo) { + DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); + return; + } +#if CFG_ENABLE_WIFI_DIRECT + if (prGlueInfo->prAdapter->fgIsP2PRegistered) + mtk_p2p_wext_set_Multicastlist(prGlueInfo); +#endif +} /* end of p2pSetMulticastListWorkQueueWrapper() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to set multicast list and set rx mode. + * + * \param[in] prDev Pointer to struct net_device + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void mtk_p2p_wext_set_Multicastlist(P_GLUE_INFO_T prGlueInfo) +{ + UINT_32 u4SetInfoLen = 0; + struct net_device *prDev = g_P2pPrDev; + + prGlueInfo = (NULL != prDev) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL; + + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(P2P, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo); + return; + } + + if (prDev->flags & IFF_PROMISC) + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; + + if (prDev->flags & IFF_BROADCAST) + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || + (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } else { + prGlueInfo->prP2PInfo->u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; + } + } + + if (prGlueInfo->prP2PInfo->u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ + struct netdev_hw_addr *ha; + UINT_32 i = 0; + + netdev_for_each_mc_addr(ha, prDev) { + if (i < MAX_NUM_GROUP_ADDR) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucMCAddrList[i]), ha->addr); + i++; + } + } + + DBGLOG(P2P, TRACE, "SEt Multicast Address List\n"); + + if (i >= MAX_NUM_GROUP_ADDR) + return; + wlanoidSetP2PMulticastList(prGlueInfo->prAdapter, + &(prGlueInfo->prP2PInfo->aucMCAddrList[0]), (i * ETH_ALEN), &u4SetInfoLen); + + } + +} /* end of mtk_p2p_wext_set_Multicastlist */ + +/*----------------------------------------------------------------------------*/ +/*! + * * \brief This function is TX entry point of NET DEVICE. + * * + * * \param[in] prSkb Pointer of the sk_buff to be sent + * * \param[in] prDev Pointer to struct net_device + * * + * * \retval NETDEV_TX_OK - on success. + * * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. + * */ +/*----------------------------------------------------------------------------*/ +int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) +{ + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_16 u2QueueIdx = 0; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prSkb); + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + prGlueInfo->u8SkbToDriver++; + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(P2P, ERROR, "GLUE_FLAG_HALT skip tx\n"); + prGlueInfo->u8SkbFreed++; + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } +#if (CFG_SUPPORT_MET_PROFILING == 1) + kalMetProfilingStart(prGlueInfo, prSkb); +#endif + + /* mark as P2P packets */ + GLUE_SET_PKT_FLAG_P2P(prSkb); +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + GLUE_SET_PKT_ARRIVAL_TIME(prSkb, kalGetTimeTick()); +#endif + + STATS_TX_TIME_ARRIVE(prSkb); + prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb) == FALSE) { + + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + + if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { + DBGLOG(P2P, ERROR, "Incorrect queue index, skip this frame\n"); + prGlueInfo->u8SkbFreed++; + dev_kfree_skb(prSkb); + return NETDEV_TX_OK; + } + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); + + if (prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx] >= + CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD) { + DBGLOG(TX, INFO, "netif_stop_subqueue for p2p0, Queue len: %d\n", + prGlueInfo->ai4TxPendingFrameNumPerQueue[NETWORK_TYPE_P2P_INDEX][u2QueueIdx]); + netif_stop_subqueue(prDev, u2QueueIdx); + } + } else { + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + } + + kalSetEvent(prGlueInfo); + + /* Statistic usage. */ + prGlueInfo->prP2PInfo->rNetDevStats.tx_bytes += prSkb->len; + prGlueInfo->prP2PInfo->rNetDevStats.tx_packets++; + /* prDev->stats.tx_packets++; */ + kalPerMonStart(prGlueInfo); + return NETDEV_TX_OK; +} /* end of p2pHardStartXmit() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, a primary SOCKET interface to configure + * the interface lively. Handle an ioctl call on one of our devices. + * Everything Linux ioctl specific is done here. Then we pass the contents + * of the ifr->data to the request message handler. + * + * \param[in] prDev Linux kernel netdevice + * + * \param[in] prIfReq Our private ioctl request structure, typed for the generic + * struct ifreq so we can use ptr to function + * + * \param[in] cmd Command ID + * + * \retval 0 The IOCTL command is executed successfully. + * \retval <0 The execution of IOCTL command is failed. + */ +/*----------------------------------------------------------------------------*/ +int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + + ASSERT(prDev && prIfReq); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + if (!prGlueInfo) { + DBGLOG(P2P, ERROR, "prGlueInfo is NULL\n"); + return -EFAULT; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + DBGLOG(P2P, ERROR, "Adapter is not ready\n"); + return -EINVAL; + } + + rIwReqInfo.cmd = (__u16) i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case SIOCSIWENCODEEXT: + /* Set Encryption Material after 4-way handshaking is done */ + if (prIwReq->u.encoding.pointer) { + u4ExtraSize = prIwReq->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, prIwReq->u.encoding.pointer, prIwReq->u.encoding.length)) + ret = -EFAULT; + } else if (prIwReq->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) + ret = mtk_p2p_wext_set_key(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + break; + + case SIOCSIWMLME: + /* IW_MLME_DISASSOC used for disconnection */ + if (prIwReq->u.data.length != sizeof(struct iw_mlme)) { + DBGLOG(P2P, WARN, "MLME buffer strange:%d\n", prIwReq->u.data.length); + ret = -EINVAL; + break; + } + + if (!prIwReq->u.data.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, prIwReq->u.data.pointer, sizeof(struct iw_mlme))) + ret = -EFAULT; + else + ret = mtk_p2p_wext_mlme_handler(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf); + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); + prExtraBuf = NULL; + break; + + case SIOCGIWPRIV: + /* This ioctl is used to list all IW privilege ioctls */ + ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case SIOCGIWSCAN: + ret = mtk_p2p_wext_discovery_results(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case SIOCSIWAUTH: + ret = mtk_p2p_wext_set_auth(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; + + case IOC_P2P_CFG_DEVICE: + case IOC_P2P_PROVISION_COMPLETE: + case IOC_P2P_START_STOP_DISCOVERY: + case IOC_P2P_DISCOVERY_RESULTS: + case IOC_P2P_WSC_BEACON_PROBE_RSP_IE: + case IOC_P2P_CONNECT_DISCONNECT: + case IOC_P2P_PASSWORD_READY: + case IOC_P2P_GET_STRUCT: + case IOC_P2P_SET_STRUCT: + case IOC_P2P_GET_REQ_DEVICE_INFO: + ret = + rP2PIwPrivHandler[i4Cmd - SIOCIWFIRSTPRIV] (prDev, &rIwReqInfo, &(prIwReq->u), + (char *)&(prIwReq->u)); + break; +#if CFG_SUPPORT_P2P_RSSI_QUERY + case SIOCGIWSTATS: + ret = mtk_p2p_wext_get_rssi(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + break; +#endif + case IOC_GET_PRIVATE_IOCTL_CMD: + ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); + + break; + default: + ret = -ENOTTY; + } + + return ret; +} /* end of p2pDoIOCTL() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To report the iw private args table to user space. + * + * \param[in] prDev Net device requested. + * \param[in] info Pointer to iw_request_info. + * \param[inout] wrqu Pointer to iwreq_data. + * \param[inout] extra + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_priv(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + struct iw_point *prData = (struct iw_point *)&wrqu->data; + UINT_16 u2BufferSize = prData->length; + + /* Update our private args table size */ + prData->length = (__u16)sizeof(rP2PIwPrivTable); + if (u2BufferSize < prData->length) + return -E2BIG; + + if (prData->length) { + if (copy_to_user(prData->pointer, rP2PIwPrivTable, sizeof(rP2PIwPrivTable))) + return -EFAULT; + } + + return 0; +} /* end of mtk_p2p_wext_get_priv() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate P2P-FSM for re-associate to the connecting device + * + * \param[in] prDev Net device requested. + * \param[inout] wrqu Pointer to iwreq_data + * + * \retval 0 For success. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_reconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_HDR_T prMsgHdr; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); + if (!prMsgHdr) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + /* 1.2 fill message */ + + DBGLOG(P2P, TRACE, "mtk_p2p_wext_reconnect: P2P Reconnect\n"); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); +#endif + return 0; +} /* end of mtk_p2p_wext_reconnect() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief MLME command handler +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prP2pBssInfo = &(prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX]); + + DBGLOG(P2P, TRACE, "mtk_p2p_wext_mlme_handler:\n"); + + switch (mlme->cmd) { + case IW_MLME_DISASSOC: + prMsgP2PConnAbt = + (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + if (!prMsgP2PConnAbt) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, mlme->addr.sa_data); + + prMsgP2PConnAbt->u2ReasonCode = mlme->reason_code; + + if (EQUAL_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prP2pBssInfo->aucOwnMacAddr)) { + DBGLOG(P2P, TRACE, "P2P Connection Abort:\n"); + + /* 1.2 fill message */ + prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + } else { + DBGLOG(P2P, TRACE, "P2P Connection Pause:\n"); + + /* 1.2 fill message */ + } + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); + + break; + + default: + return -EOPNOTSUPP; + } +#endif + return 0; +} /* end of mtk_p2p_wext_mlme_handler() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_PROVISION_COMPLETE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData = (struct iw_point *)&wrqu->data; + P_MSG_HDR_T prMsgHdr; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + switch (prData->flags) { + case P2P_PROVISIONING_SUCCESS: + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); + if (!prMsgHdr) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + /* 1.2 fill message */ + + prGlueInfo->prP2PInfo->u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); + + break; + + case P2P_PROVISIONING_FAIL: + + break; + + default: + return -EOPNOTSUPP; + } +#endif + + return 0; +} /* end of mtk_p2p_wext_set_provision_complete() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_START_STOP_DISCOVERY) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ +#if 0 + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData = (struct iw_point *)&wrqu->data; + P_IW_P2P_REQ_DEVICE_TYPE prReqDeviceType = (P_IW_P2P_REQ_DEVICE_TYPE) extra; + UINT_8 au4IeBuf[MAX_IE_LENGTH]; + P_MSG_HDR_T prMsgHdr; + P_MSG_P2P_DEVICE_DISCOVER_T prDiscoverMsg; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + if (prData->flags == P2P_STOP_DISCOVERY) { + prMsgHdr = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_HDR_T)); + + if (!prMsgHdr) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgHdr, MSG_SEND_METHOD_BUF); + } else if (prData->flags == P2P_START_DISCOVERY) { + + /* retrieve IE for Probe Response */ + if (prReqDeviceType->probe_rsp_len > 0) { + if (prReqDeviceType->probe_rsp_len <= MAX_IE_LENGTH) { + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[2], prReqDeviceType->probe_rsp_ie, + prReqDeviceType->probe_rsp_len)) { + return -EFAULT; + } + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prReqDeviceType->probe_rsp_len; + } else { + return -E2BIG; + } + } + + /* retrieve IE for Probe Request */ + if (prReqDeviceType->probe_req_len > 0) { + if (prReqDeviceType->probe_req_len <= MAX_IE_LENGTH) { + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[1], prReqDeviceType->probe_req_ie, + prReqDeviceType->probe_req_len)) { + return -EFAULT; + } + prGlueInfo->prP2PInfo->u2WSCIELen[1] = prReqDeviceType->probe_req_len; + } else { + return -E2BIG; + } + } + /* update IE for Probe Request */ + + if (prReqDeviceType->scan_type == P2P_LISTEN) { + /* update listening parameter */ + + /* @TODO: update prConnSettings for Probe Response IE */ + } else { + /* indicate P2P-FSM with MID_MNY_P2P_DEVICE_DISCOVERY */ + prDiscoverMsg = (P_MSG_P2P_DEVICE_DISCOVER_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_DEVICE_DISCOVER_T)); + + if (!prDiscoverMsg) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + prDiscoverMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; + prDiscoverMsg->u4DevDiscoverTime = 0; /* unlimited */ + prDiscoverMsg->fgIsSpecificType = TRUE; + prDiscoverMsg->rTargetDeviceType.u2CategoryID = + *(PUINT_16) (&(prReqDeviceType->pri_device_type[0])); + prDiscoverMsg->rTargetDeviceType.u2SubCategoryID = + *(PUINT_16) (&(prReqDeviceType->pri_device_type[6])); + COPY_MAC_ADDR(prDiscoverMsg->aucTargetDeviceID, aucNullAddr); + + /* @FIXME: parameter to be refined, where to pass IE buffer ? */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDiscoverMsg, MSG_SEND_METHOD_BUF); + } + } else { + return -EINVAL; + } +#endif + + return 0; +} /* end of mtk_p2p_wext_start_stop_discovery() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_request(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int i4Status = 0; +#if 0 + P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + struct iw_point *prData = (struct iw_point *)&wrqu->data; + P_IW_P2P_IOCTL_INVITATION_STRUCT prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) NULL; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + prIoctlInvitation = (P_IW_P2P_IOCTL_INVITATION_STRUCT) extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + + if (prIoctlInvitation->ucReinvoke == 1) { + /* TODO: Set Group ID */ + p2pFuncSetGroupID(prAdapter, prIoctlInvitation->aucGroupID, prIoctlInvitation->aucSsid, + prIoctlInvitation->u4SsidLen); + } + + else { + P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationReq = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; + + /* TODO: Do Invitation. */ + prMsgP2PInvitationReq = + (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_INVITATION_REQUEST_T)); + if (!prMsgP2PInvitationReq) { + ASSERT(0); /* Can't trigger P2P FSM */ + i4Status = -ENOMEM; + break; + } + + /* 1.2 fill message */ + kalMemCopy(prMsgP2PInvitationReq->aucDeviceID, prIoctlInvitation->aucDeviceID, MAC_ADDR_LEN); + + DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationReq, MSG_SEND_METHOD_BUF); + + } + + } while (FALSE); +#endif + + return i4Status; + +} + +/* mtk_p2p_wext_invitation_request */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_abort(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int i4Status = 0; +#if 0 + P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + struct iw_point *prData = (struct iw_point *)&wrqu->data; + P_IW_P2P_IOCTL_ABORT_INVITATION prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) NULL; + + UINT_8 bssid[MAC_ADDR_LEN]; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + prIoctlInvitationAbort = (P_IW_P2P_IOCTL_ABORT_INVITATION) extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + P_MSG_P2P_INVITATION_REQUEST_T prMsgP2PInvitationAbort = (P_MSG_P2P_INVITATION_REQUEST_T) NULL; + + prMsgP2PInvitationAbort = + (P_MSG_P2P_INVITATION_REQUEST_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_INVITATION_REQUEST_T)); + + if (!prMsgP2PInvitationAbort) { + ASSERT(0); /* Can't trigger P2P FSM */ + i4Status = -ENOMEM; + break; + } + + /* 1.2 fill message */ + kalMemCopy(prMsgP2PInvitationAbort->aucDeviceID, prIoctlInvitationAbort->dev_addr, + MAC_ADDR_LEN); + + DBGLOG(P2P, TRACE, "mtk_p2p_wext_invitation_request: P2P Invitation Req\n"); + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PInvitationAbort, MSG_SEND_METHOD_BUF); + + + } while (FALSE); +#endif + + return i4Status; + +} + +/* mtk_p2p_wext_invitation_abort */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To override p2p interface address + * + * \param[in] prDev Net device requested. + * \param[in] addr Pointer to address + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int p2pSetMACAddress(IN struct net_device *prDev, void *addr) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* @FIXME */ + return eth_mac_addr(prDev, addr); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher suite +* +* \param[in] prDev Net device requested. +* \param[out] +* +* \retval 0 Success. +* \retval -EINVAL Invalid parameter +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_auth(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_param *prAuth = (struct iw_param *)wrqu; + + ASSERT(prDev); + ASSERT(prAuth); + if (FALSE == GLUE_CHK_PR2(prDev, prAuth)) + return -EINVAL; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + /* Save information to glue info and process later when ssid is set. */ + switch (prAuth->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + break; + case IW_AUTH_CIPHER_PAIRWISE: + prGlueInfo->prP2PInfo->u4CipherPairwise = prAuth->value; + break; + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_80211_AUTH_ALG: + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + default: + /* @TODO */ + break; + } + + return 0; +} /* end of mtk_p2p_wext_set_auth() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[out] prIfReq Pointer to ifreq structure, content is copied back to +* user space buffer in gl_iwpriv_table. +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_key(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int ret = 0; + struct iw_encode_ext *prIWEncExt; + struct iw_point *prEnc; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + UINT_8 keyStructBuf[100]; + P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; + P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + do { + if (wrqu->encoding.pointer) { + u4ExtraSize = wrqu->encoding.length; + /*need confirm u4ExtraSize > 0 but is not very large*/ + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + /* here should set prExtraBuf default value */ + memset(prExtraBuf, 0, u4ExtraSize); + if (copy_from_user(prExtraBuf, wrqu->encoding.pointer, wrqu->encoding.length)) { + ret = -EFAULT; + break; + } + } else if (wrqu->encoding.length != 0) { + ret = -EINVAL; + break; + } + + prEnc = &wrqu->encoding; + /* here, need confirm (struct iw_encode_ext) < u4ExtraSize */ + prIWEncExt = (struct iw_encode_ext *)prExtraBuf; + + if (GLUE_CHK_PR3(prDev, prEnc, prExtraBuf) != TRUE) { + ret = -EINVAL; + break; + } + + memset(keyStructBuf, 0, sizeof(keyStructBuf)); + + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { /* Key Removal */ + prRemoveKey->u4Length = sizeof(*prRemoveKey); + memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveP2PKey, + prRemoveKey, + prRemoveKey->u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + ret = -EFAULT; + } else { + if (prIWEncExt->alg == IW_ENCODE_ALG_CCMP) { + /* KeyID */ + prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + ((prEnc->flags & IW_ENCODE_INDEX) - 1) : 0; + if (prKey->u4KeyIndex <= 3) { + /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ + /* Tx Key Bit(31) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + prKey->u4KeyIndex |= 0x1UL << 31; + + /* Pairwise Key Bit(30) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* group key */ + } else { + /* pairwise key */ + prKey->u4KeyIndex |= 0x1UL << 30; + } + + /* Rx SC Bit(29) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + prKey->u4KeyIndex |= 0x1UL << 29; + memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, + IW_ENCODE_SEQ_MAX_SIZE); + } + + /* BSSID */ + memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + + prKey->u4KeyLength = prIWEncExt->key_len; + prKey->u4Length = + ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + + prKey->u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddP2PKey, + prKey, + prKey->u4Length, + FALSE, FALSE, TRUE, TRUE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + ret = -EFAULT; + } else { + ret = -EINVAL; + } + } else { + ret = -EINVAL; + } + } + + } while (FALSE); + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + + return ret; +} /* end of mtk_p2p_wext_set_key() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief set the p2p gc power mode +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_powermode(IN struct net_device *prNetDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + /* printk("set_powermode = %d, value = %d\n", wrqu->power.disabled, wrqu->power.value); */ + struct iw_param *prPower = (struct iw_param *)&wrqu->power; +#if 1 + PARAM_POWER_MODE ePowerMode; + INT_32 i4PowerValue; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ + /* prPower->value, prPower->disabled, prPower->flags); */ + + if (prPower->disabled) { + ePowerMode = Param_PowerModeCAM; + } else { + i4PowerValue = prPower->value; +#if WIRELESS_EXT < 21 + i4PowerValue /= 1000000; +#endif + if (i4PowerValue == 0) { + ePowerMode = Param_PowerModeCAM; + } else if (i4PowerValue == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (i4PowerValue == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } else { + DBGLOG(P2P, ERROR, "%s(): unsupported power management mode value = %d.\n", + __func__, prPower->value); + + return -EINVAL; + } + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, TRUE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ + return -EFAULT; + } +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief get the p2p gc power mode +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_powermode(IN struct net_device *prNetDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + /* printk("mtk_p2p_wext_get_powermode\n"); */ + /* wrqu->power.disabled = 0; */ + /* wrqu->power.value = 1; */ + + struct iw_param *prPower = (struct iw_param *)&wrqu->power; + PARAM_POWER_MODE ePowerMode = Param_PowerModeMax; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) + return -EINVAL; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + +#if 1 + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pPowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), TRUE, FALSE, FALSE, TRUE, &u4BufLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryP2pPowerSaveProfile, &ePowerMode, sizeof(ePowerMode), &u4BufLen); +#endif + + prPower->value = 0; + prPower->disabled = 1; + + if (Param_PowerModeCAM == ePowerMode) { + prPower->value = 0; + prPower->disabled = 1; + } else if (Param_PowerModeMAX_PSP == ePowerMode) { + prPower->value = 1; + prPower->disabled = 0; + } else if (Param_PowerModeFast_PSP == ePowerMode) { + prPower->value = 2; + prPower->disabled = 0; + } + + prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; +#if WIRELESS_EXT < 21 + prPower->value *= 1000000; +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_CFG_DEVICE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_CFG_DEVICE_TYPE prDeviceCfg = (P_IW_P2P_CFG_DEVICE_TYPE) extra; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + /* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T)NULL; */ + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo; + + /* update connection settings for P2P-FSM */ + /* 1. update SSID */ + if (prDeviceCfg->ssid_len > ELEM_MAX_LEN_SSID) + prConnSettings->ucSSIDLen = ELEM_MAX_LEN_SSID; + else + prConnSettings->ucSSIDLen = prDeviceCfg->ssid_len; + + if (copy_from_user(prConnSettings->aucSSID, prDeviceCfg->ssid, prConnSettings->ucSSIDLen)) + return -EFAULT; + /* 2. update device type (WPS IE) */ + kalMemCopy(&(prConnSettings->rPrimaryDevTypeBE), &(prDeviceCfg->pri_device_type), sizeof(DEVICE_TYPE_T)); +#if P2P_MAX_SUPPORTED_SEC_DEV_TYPE_COUNT + kalMemCopy(&(prConnSettings->arSecondaryDevTypeBE[0]), &(prDeviceCfg->snd_device_type), sizeof(DEVICE_TYPE_T)); +#endif + + /* 3. update device name */ + if (prDeviceCfg->device_name_len > WPS_ATTRI_MAX_LEN_DEVICE_NAME) + prConnSettings->ucDevNameLen = WPS_ATTRI_MAX_LEN_DEVICE_NAME; + else + prConnSettings->ucDevNameLen = prDeviceCfg->device_name_len; + if (copy_from_user(prConnSettings->aucDevName, prDeviceCfg->device_name, prConnSettings->ucDevNameLen)) + return -EFAULT; + /* 4. update GO intent */ + prConnSettings->ucGoIntent = prDeviceCfg->intend; + + /* Preferred channel bandwidth */ + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; + prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode = prDeviceCfg->ch_width ? CONFIG_BW_20_40M : CONFIG_BW_20M; + +#if 0 + /* 1. switch P2P-FSM on */ + /* 1.1 allocate for message */ + prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + + if (!prFuncSwitch) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + /* 1.2 fill message */ + prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prFuncSwitch->fgIsFuncOn = TRUE; + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF); +#endif + return 0; +} /* end of mtk_p2p_wext_set_local_dev_info() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief I/O Control handler for both + * IOC_P2P_START_STOP_DISCOVERY & SIOCGIWSCAN + * + * \param[in] prDev Net device requested. + * \param[inout] wrqu Pointer to iwreq_data + * + * \retval 0 Success. + * \retval -EFAULT Setting parameters to driver fail. + * \retval -EOPNOTSUPP Key size not supported. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_discovery_results(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + struct iw_event iwe; + char *current_ev = extra; + UINT_32 i; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_P2P_INFO_T prP2PInfo = (P_P2P_INFO_T) NULL; + P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = (P_EVENT_P2P_DEV_DISCOVER_RESULT_T) NULL; + P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prP2PInfo = prAdapter->prP2pInfo; + + for (i = 0; i < prP2PInfo->u4DeviceNum; i++) { + prTargetResult = &prP2PInfo->arP2pDiscoverResult[i]; + + /* SIOCGIWAP */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, prTargetResult->aucInterfaceAddr, 6); + + current_ev = iwe_stream_add_event(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + + /* SIOCGIWESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = prTargetResult->u2NameLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, &iwe, prTargetResult->aucName); + + /* IWEVGENIE for WPA IE */ + if (prTargetResult->u2IELength <= 600 && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0xDD, (PUINT_8 *) &prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); + } +#if CFG_SUPPORT_WPS + + /* IWEVGENIE for WPS IE */ + if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPSIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0xDD, (PUINT_8 *) &prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); + } +#endif + + /* IWEVGENIE for RSN IE */ + if ((prTargetResult->u2IELength <= 600) && wextSrchDesiredWPAIE(prTargetResult->pucIeBuf, + prTargetResult->u2IELength, + 0x30, (PUINT_8 *) &prDesiredIE)) { + + iwe.cmd = IWEVGENIE; + iwe.u.data.flags = 1; + iwe.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, &iwe, (char *)prDesiredIE); + } + + /* IOC_P2P_GO_WSC_IE */ +#if 1 + /* device capability */ + if (1) { + UINT_8 data[40]; + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 9 + sizeof("p2p_cap="); + if (iwe.u.data.length > 40) + iwe.u.data.length = 40; + + snprintf(data, iwe.u.data.length, "p2p_cap=%02x%02x%02x%02x%c", + prTargetResult->ucDeviceCapabilityBitmap, prTargetResult->ucGroupCapabilityBitmap, + (UINT_8) prTargetResult->u2ConfigMethod, + (UINT_8) (prTargetResult->u2ConfigMethod >> 8), '\0'); + current_ev = + iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); + + /* printk("%s\n", data); */ + kalMemZero(data, 40); + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 13 + sizeof("p2p_dev_type="); + if (iwe.u.data.length > 40) + iwe.u.data.length = 40; + + snprintf(data, iwe.u.data.length, "p2p_dev_type=%02x%02x%02x%02x%02x%02x%c", + (UINT_8) prTargetResult->rPriDevType.u2CategoryID, + (UINT_8) prTargetResult->rPriDevType.u2SubCategoryID, + (UINT_8) prTargetResult->arSecDevType[0].u2CategoryID, + (UINT_8) prTargetResult->arSecDevType[0].u2SubCategoryID, + (UINT_8) prTargetResult->arSecDevType[1].u2CategoryID, + (UINT_8) prTargetResult->arSecDevType[1].u2SubCategoryID, '\0'); + current_ev = + iwe_stream_add_point(info, current_ev, extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); + /* printk("%s\n", data); */ + + kalMemZero(data, 40); + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.flags = 0; + iwe.u.data.length = 17 + sizeof("p2p_grp_bssid="); + if (iwe.u.data.length > 40) + iwe.u.data.length = 40; + + snprintf(data, iwe.u.data.length, "p2p_grp_bssid= %pM %c", + prTargetResult->aucBSSID, '\0'); + current_ev = iwe_stream_add_point(info, current_ev, + extra + IW_SCAN_MAX_DATA, &iwe, (char *)data); + /* printk("%s\n", data); */ + + } +#endif + } + + /* Length of data */ + wrqu->data.length = (current_ev - extra); + wrqu->data.flags = 0; + + return 0; +} /* end of mtk_p2p_wext_discovery_results() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_WSC_BEACON_PROBE_RSP_IE) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_HOSTAPD_PARAM prHostapdParam = (P_IW_P2P_HOSTAPD_PARAM) extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + if (prHostapdParam->len > 0) { + if (prHostapdParam->len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[0], prHostapdParam->data, prHostapdParam->len)) { + return -EFAULT; + } + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[2], prHostapdParam->data, prHostapdParam->len)) { + return -EFAULT; + } + } else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[0] = prHostapdParam->len; + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prHostapdParam->len; + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + bssUpdateBeaconContent(prAdapter, NETWORK_TYPE_P2P_INDEX); + + /* @TODO: send message to P2P-FSM */ + + return 0; +} /* end of mtk_p2p_wext_wsc_ie() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_CONNECT_DISCONNECT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_point *prData = (struct iw_point *)&wrqu->data; +/* P_IW_P2P_CONNECT_DEVICE prConnectDevice = (P_IW_P2P_CONNECT_DEVICE)extra; */ +/* P_MSG_HDR_T prMsgHdr; */ +/* P_MSG_P2P_CONNECTION_REQUEST_T prMsgP2PConnReq; */ +/* P_MSG_P2P_CONNECTION_ABORT_T prMsgP2PConnAbt; */ +/* UINT_8 aucBCAddr[] = BC_MAC_ADDR; */ + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + if (prData->flags == P2P_CONNECT) { +#if 0 + /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_REQ */ + prMsgP2PConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + if (!prMsgP2PConnReq) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnReq, MSG_SEND_METHOD_BUF); +#endif + } else if (prData->flags == P2P_DISCONNECT) { +#if 0 + /* indicate P2P-FSM with MID_MNY_P2P_CONNECTION_ABORT */ + prMsgP2PConnAbt = (P_MSG_HDR_T) cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (!prMsgP2PConnAbt) { + ASSERT(0); /* Can't trigger P2P FSM */ + return -ENOMEM; + } + + COPY_MAC_ADDR(prMsgP2PConnAbt->aucTargetID, prConnectDevice->sta_addr); + + prMsgP2PConnAbt->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgP2PConnAbt, MSG_SEND_METHOD_BUF); +#endif + } else { + return -EINVAL; + } + + return 0; +} /* end of mtk_p2p_wext_connect_disconnect() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_PASSWORD_READY) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_password_ready(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_PASSWORD_READY prPasswordReady = (P_IW_P2P_PASSWORD_READY) extra; + P_P2P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + prConnSettings = prAdapter->rWifiVar.prP2PConnSettings; + + /* retrieve IE for Probe Request */ + if (prPasswordReady->probe_req_len > 0) { + if (prPasswordReady->probe_req_len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[1], prPasswordReady->probe_req_ie, + prPasswordReady->probe_req_len)) { + return -EFAULT; + } + } else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[1] = prPasswordReady->probe_req_len; + + /* retrieve IE for Probe Response */ + if (prPasswordReady->probe_rsp_len > 0) { + if (prPasswordReady->probe_rsp_len <= MAX_WSC_IE_LENGTH) { + if (copy_from_user + (prGlueInfo->prP2PInfo->aucWSCIE[2], prPasswordReady->probe_rsp_ie, + prPasswordReady->probe_rsp_len)) { + return -EFAULT; + } + } else { + return -E2BIG; + } + } + + prGlueInfo->prP2PInfo->u2WSCIELen[2] = prPasswordReady->probe_rsp_len; + + switch (prPasswordReady->active_config_method) { + case 1: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_PUSH_BUTTON; + break; + case 2: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_KEYPAD; + break; + case 3: + prConnSettings->u2LocalConfigMethod = WPS_ATTRI_CFG_METHOD_DISPLAY; + break; + default: + break; + } + + prConnSettings->fgIsPasswordIDRdy = TRUE; + return 0; +} /* end of mtk_p2p_wext_password_ready() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_REQ_DEVICE_INFO) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_DEVICE_REQ prDeviceReq = (P_IW_P2P_DEVICE_REQ) extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* specify data length */ + wrqu->data.length = sizeof(IW_P2P_DEVICE_REQ); + + /* copy to upper-layer supplied buffer */ + kalMemCopy(prDeviceReq->name, prGlueInfo->prP2PInfo->aucConnReqDevName, + prGlueInfo->prP2PInfo->u4ConnReqNameLength); + prDeviceReq->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; + prDeviceReq->name[prDeviceReq->name_len] = '\0'; + COPY_MAC_ADDR(prDeviceReq->device_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); + prDeviceReq->device_type = prGlueInfo->prP2PInfo->ucConnReqDevType; + prDeviceReq->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; + prDeviceReq->active_config_method = prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod; + + return 0; +} /* end of mtk_p2p_wext_request_dev_info() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_IOCTL_INVITATION_INDICATE prInvIndicate = (P_IW_P2P_IOCTL_INVITATION_INDICATE) extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* specify data length */ + wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_INDICATE); + + /* copy to upper-layer supplied buffer */ + kalMemCopy(prInvIndicate->dev_name, prGlueInfo->prP2PInfo->aucConnReqDevName, + prGlueInfo->prP2PInfo->u4ConnReqNameLength); + kalMemCopy(prInvIndicate->group_bssid, prGlueInfo->prP2PInfo->rConnReqGroupAddr, MAC_ADDR_LEN); + prInvIndicate->name_len = prGlueInfo->prP2PInfo->u4ConnReqNameLength; + prInvIndicate->dev_name[prInvIndicate->name_len] = '\0'; + COPY_MAC_ADDR(prInvIndicate->dev_addr, prGlueInfo->prP2PInfo->rConnReqPeerAddr); + prInvIndicate->config_method = prGlueInfo->prP2PInfo->i4ConnReqConfigMethod; + prInvIndicate->operating_channel = prGlueInfo->prP2PInfo->ucOperatingChnl; + prInvIndicate->invitation_type = prGlueInfo->prP2PInfo->ucInvitationType; + + return 0; +} /* end of mtk_p2p_wext_invitation_indicate() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_invitation_status(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_IOCTL_INVITATION_STATUS prInvStatus = (P_IW_P2P_IOCTL_INVITATION_STATUS) extra; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* specify data length */ + wrqu->data.length = sizeof(IW_P2P_IOCTL_INVITATION_STATUS); + + /* copy to upper-layer supplied buffer */ + prInvStatus->status_code = prGlueInfo->prP2PInfo->u4InvStatus; + + return 0; +} /* end of mtk_p2p_wext_invitation_status() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief indicate an event to supplicant for device found +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval TRUE Success. +* \retval FALSE Failure +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_FND"); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PDVCFND event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + + return FALSE; +} /* end of kalP2PIndicateFound() */ + +int +mtk_p2p_wext_set_network_address(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* @TODO: invoke wlan_p2p functions */ +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pNetworkAddress, + prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); +#endif + + return 0; + +} + +int +mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* @TODO: invoke wlan_p2p functions */ +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, + prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); +#endif + + return 0; + +} + +int +mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* @TODO: invoke wlan_p2p functions */ +#if 0 + rStatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetP2pPowerSaveProfile, + prKey, prKey->u4Length, FALSE, FALSE, TRUE, &u4BufLen); +#endif + + return 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_start_formation(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int i4Status = 0; + P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; +/* struct iw_point *prData = (struct iw_point*)&wrqu->data; */ + P_IW_P2P_IOCTL_START_FORMATION prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) NULL; + + do { + if ((prDev == NULL) || (extra == NULL)) { + ASSERT(FALSE); + i4Status = -EINVAL; + break; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + prIoctlStartFormation = (P_IW_P2P_IOCTL_START_FORMATION) extra; + + if (prGlueInfo == NULL) { + i4Status = -EINVAL; + break; + } + + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + i4Status = -EINVAL; + break; + } + + } while (FALSE); + + return i4Status; + +} + +/* mtk_p2p_wext_start_formation */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_INT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Setting parameters not support. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_int(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 index; + INT_32 value; + PUINT_32 pu4IntBuf; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T) NULL; + UINT_32 u4Leng; + + ASSERT(prDev); + ASSERT(wrqu); + + /* printk("mtk_p2p_wext_set_int\n"); */ + pu4IntBuf = (PUINT_32) extra; + + if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) + return -EINVAL; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + prP2pFsmInfo = prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo; + + u4SubCmd = (UINT_32) wrqu->mode; + index = pu4IntBuf[1]; + value = pu4IntBuf[2]; + + DBGLOG(P2P, INFO, "set parameter, u4SubCmd=%d idx=%d value=%d\n", (INT_16) u4SubCmd, (INT_16) index, value); + + switch (u4SubCmd) { + case PRIV_CMD_INT_P2P_SET: + switch (index) { + case 0: /* Listen CH */ + { + UINT_8 ucSuggestChnl = 0; + + prP2pConnSettings->ucListenChnl = value; + + /* 20110920 - frog: User configurations are placed in ConnSettings. */ + if (rlmFuncFindAvailableChannel + (prGlueInfo->prAdapter, value, &ucSuggestChnl, TRUE, TRUE)) { + prP2pSpecificBssInfo->ucListenChannel = value; + } else { + prP2pSpecificBssInfo->ucListenChannel = ucSuggestChnl; + } + + break; + } + case 1: /* P2p mode */ + break; + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, + (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, + (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + status = + mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); + break; + case 100: /* Oper CH */ + /* 20110920 - frog: User configurations are placed in ConnSettings. */ + prP2pConnSettings->ucOperatingChnl = value; + break; + case 101: /* Local config Method, for P2P SDK */ + /* prP2pConnSettings->u2LocalConfigMethod; */ + break; + case 102: /* Sigma P2p reset */ + kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); + /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ + break; + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + case 104: /* P2p send persence, duration */ + break; + case 105: /* P2p send persence, interval */ + break; + case 106: /* P2P set sleep */ + value = 1; + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + break; + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + status = + mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rOppPsParam); + break; + case 108: /* p2p_set_power_save */ + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, + &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + + break; + + default: + break; + } + break; + default: + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_SET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; + + ASSERT(prDev); + ASSERT(wrqu); + + if (FALSE == GLUE_CHK_PR2(prDev, wrqu)) + return -EINVAL; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + u4SubCmd = (UINT_32) wrqu->data.flags; + + kalMemZero(&prGlueInfo->prP2PInfo->aucOidBuf[0], sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) + DBGLOG(P2P, INFO, "extra buffer is valid\n"); + else + DBGLOG(P2P, INFO, "extra 0x%p\n", extra); + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEND_SD_RESPONSE: + status = mtk_p2p_wext_send_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_SEND_SD_REQUEST: + status = mtk_p2p_wext_send_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_TERMINATE_SD_PHASE: + status = mtk_p2p_wext_terminate_service_discovery_phase(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_INVITATION: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_INVITATION_STRUCT)) { + /* Do nothing */ + /* status = mtk_p2p_wext_invitation_request(prDev, info, wrqu, + (char *)(prP2PReq->aucBuffer)); */ + } + break; + + case P2P_CMD_ID_INVITATION_ABORT: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_ABORT_INVITATION)) { + /* Do nothing */ + /* status = mtk_p2p_wext_invitation_abort(prDev, info, wrqu, + (char *)(prP2PReq->aucBuffer)); */ + } + break; + + case P2P_CMD_ID_START_FORMATION: + if (prP2PReq->inBufferLength == sizeof(IW_P2P_IOCTL_START_FORMATION)) + status = mtk_p2p_wext_start_formation(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + break; + default: + status = -EOPNOTSUPP; + } + + break; +#if CFG_SUPPORT_ANTI_PIRACY + case PRIV_SEC_CHECK_OID: + if (wrqu->data.length > 256) { + status = -EOPNOTSUPP; + break; + } + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), wrqu->data.pointer, wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), extra, wrqu->data.length)) + DBGLOG(P2P, INFO, "extra buffer is valid\n"); + else + DBGLOG(P2P, INFO, "extra 0x%p\n", extra); + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); + + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEC_CHECK: + status = mtk_p2p_wext_set_sec_check_request(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + } + break; +#endif + case PRIV_CMD_P2P_VERSION: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), wrqu->data.pointer, wrqu->data.length)) { + status = -EFAULT; + break; + } + + if (!kalMemCmp(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), extra, wrqu->data.length)) + DBGLOG(P2P, INFO, "extra buffer is valid\n"); + else + DBGLOG(P2P, INFO, "extra 0x%p\n", extra); + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_P2P_VERSION: + status = mtk_p2p_wext_set_p2p_version(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + break; + } + break; + default: + status = -EOPNOTSUPP; + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler (IOC_P2P_GET_STRUCT) +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + int status = 0; + UINT_32 u4SubCmd = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = NULL; + + ASSERT(prDev); + ASSERT(wrqu); + + if (!prDev || !wrqu) { + DBGLOG(P2P, WARN, "%s(): invalid param(0x%p, 0x%p)\n", __func__, prDev, wrqu); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + u4SubCmd = (UINT_32) wrqu->data.flags; + + kalMemZero(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), sizeof(prGlueInfo->prP2PInfo->aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { + DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_GET_SD_REQUEST: + status = mtk_p2p_wext_get_service_discovery_request(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_GET_SD_RESPONSE: + status = mtk_p2p_wext_get_service_discovery_response(prDev, info, wrqu, (char *)prP2PReq); + break; + + case P2P_CMD_ID_INVITATION_INDICATE: + { + status = + mtk_p2p_wext_invitation_indicate(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + prP2PReq->outBufferLength = wrqu->data.length; + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } else { + return 0; + } + break; + } + case P2P_CMD_ID_INVITATION_STATUS: + { + status = + mtk_p2p_wext_invitation_status(prDev, info, wrqu, (char *)(prP2PReq->aucBuffer)); + prP2PReq->outBufferLength = wrqu->data.length; + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.length + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } else { + return 0; + } + break; + } + case P2P_CMD_ID_GET_CH_LIST: + { + UINT_16 i; + UINT_8 NumOfChannel = 50; + RF_CHANNEL_INFO_T aucChannelList[50]; + UINT_8 ucMaxChannelNum = 50; + PUINT_8 pucChnlList = (PUINT_8) prP2PReq->aucBuffer; + + kalGetChnlList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, aucChannelList); + if (NumOfChannel > 50) + NumOfChannel = 50; + prP2PReq->outBufferLength = NumOfChannel; + /*here must confirm NumOfChannel < 16, for prP2PReq->aucBuffer 16 byte*/ + if (NumOfChannel >= 15) { + /*DBGLOG(P2P, ERROR, "channel num > 15\n", __func__);*/ + ASSERT(FALSE); + } + + for (i = 0; i < NumOfChannel; i++) { +#if 0 + /* 20120208 frog: modify to avoid clockwork warning. */ + prP2PReq->aucBuffer[i] = aucChannelList[i].ucChannelNum; +#else + *pucChnlList = aucChannelList[i].ucChannelNum; + pucChnlList++; +#endif + } + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + NumOfChannel + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } else { + return 0; + } + break; + } + + case P2P_CMD_ID_GET_OP_CH: + { + prP2PReq->inBufferLength = 4; + + status = wlanoidQueryP2pOpChannel(prGlueInfo->prAdapter, + prP2PReq->aucBuffer, + prP2PReq->inBufferLength, &prP2PReq->outBufferLength); + + if (status == 0) { /* WLAN_STATUS_SUCCESS */ + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, + aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } else { + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + break; + } + + default: + status = -EOPNOTSUPP; + } + + break; +#if CFG_SUPPORT_ANTI_PIRACY + case PRIV_SEC_CHECK_OID: + if (wrqu->data.length > 256) { + status = -EOPNOTSUPP; + break; + } + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucSecCheck[0]), + wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { + DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucSecCheck[0])); + + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_SEC_CHECK: + status = mtk_p2p_wext_get_sec_check_response(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + } + break; +#endif + case PRIV_CMD_P2P_VERSION: + if (copy_from_user(&(prGlueInfo->prP2PInfo->aucOidBuf[0]), + wrqu->data.pointer, sizeof(IW_P2P_TRANSPORT_STRUCT))) { + DBGLOG(P2P, ERROR, "%s() copy_from_user oidBuf fail\n", __func__); + return -EFAULT; + } + + prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) (&(prGlueInfo->prP2PInfo->aucOidBuf[0])); + + switch (prP2PReq->u4CmdId) { + case P2P_CMD_ID_P2P_VERSION: + status = mtk_p2p_wext_get_p2p_version(prDev, info, wrqu, (char *)prP2PReq); + break; + default: + status = -EOPNOTSUPP; + break; + } + + /* Copy queried data to user. */ + if (status == 0) { /* WLAN_STATUS_SUCCESS */ + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + prP2PReq->outBufferLength + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + + else { + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + } + + break; + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* getting service discovery request frame from driver +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen = 0; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidGetP2PSDRequest, + prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + + prP2PReq->outBufferLength = u4QueryInfoLen; + + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } else { + return 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* getting service discovery response frame from driver +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen = 0; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidGetP2PSDResponse, + prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + + prP2PReq->outBufferLength = u4QueryInfoLen; + + if (copy_to_user(wrqu->data.pointer, + &(prGlueInfo->prP2PInfo->aucOidBuf[0]), + u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + return 0; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* sending service discovery request frame +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSendP2PSDRequest, + prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* sending service discovery response frame +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSendP2PSDResponse, + prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetSecCheckRequest, + prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen = 0; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_wext_get_sec_check_response\n"); + rStatus = kalIoctl(prGlueInfo, + wlanoidGetSecCheckResponse, + prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + + prP2PReq->outBufferLength = u4QueryInfoLen; + + if (copy_to_user(wrqu->data.pointer, + prP2PReq->aucBuffer, u4QueryInfoLen + OFFSET_OF(IW_P2P_TRANSPORT_STRUCT, aucBuffer))) { + DBGLOG(P2P, ERROR, "%s() copy_to_user() fail\n", __func__); + return -EIO; + } + return 0; + +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* terminating service discovery phase +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2PTerminateSDPhase, + prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; + /* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ + P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_wext_set_noa_param\n"); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetNoaParam, prNoaParam, /* prP2PReq->aucBuffer, */ + sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ + FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief P2P Private I/O Control handler for +* +* \param[in] prDev Net device requested. +* \param[inout] wrqu Pointer to iwreq_data +* +* \retval 0 Success. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int +mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4SetInfoLen; +/* P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT)extra; */ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_wext_set_oppps_param\n"); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetOppPsParam, prOppPsParam, /* prP2PReq->aucBuffer, */ + sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T), /* prP2PReq->inBufferLength, */ + FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return 0; +} + +int +mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + UINT_32 u4SetInfoLen; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSupplicantVersion, + prP2PReq->aucBuffer, prP2PReq->inBufferLength, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return rStatus; + +} + +/* mtk_p2p_wext_set_p2p_version */ + +int +mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + P_IW_P2P_TRANSPORT_STRUCT prP2PReq = (P_IW_P2P_TRANSPORT_STRUCT) extra; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pVersion, + prP2PReq->aucBuffer, prP2PReq->outBufferLength, TRUE, FALSE, TRUE, TRUE, &u4QueryInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return rStatus; + +} /* mtk_p2p_wext_get_p2p_version */ + +#if CFG_SUPPORT_P2P_RSSI_QUERY + +int +mtk_p2p_wext_get_rssi(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen; + struct iw_point *prData = (struct iw_point *)&wrqu->data; + UINT_16 u2BufferSize = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rssi; + struct iw_statistics *pStats = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + rStatus = WLAN_STATUS_FAILURE; + goto stat_out; + } + + pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &u4QueryInfoLen); + + u2BufferSize = prData->length; + + if (u2BufferSize < sizeof(struct iw_statistics)) + return -E2BIG; + + if (copy_to_user(prData->pointer, pStats, sizeof(struct iw_statistics))) + rStatus = WLAN_STATUS_FAILURE; + +stat_out: + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + else + return rStatus; + +} /* mtk_p2p_wext_get_rssi */ + +struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_statistics *pStats = NULL; + INT_32 i4Rssi; + UINT_32 bufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) + goto stat_out; + + pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); + + if (!prDev || !netif_carrier_ok(prDev)) { + /* network not connected */ + goto stat_out; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryP2pRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, TRUE, &bufLen); + +stat_out: + return pStats; +} /* mtk_p2p_wext_get_wireless_stats */ + +#endif /* CFG_SUPPORT_P2P_RSSI_QUERY */ + +int +mtk_p2p_wext_set_txpow(IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_ADAPTER_T prAdapter = (P_ADAPTER_T) NULL; +#if 0 + P_MSG_P2P_FUNCTION_SWITCH_T prMsgFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) NULL; +#endif + int i4Ret = 0; + + ASSERT(prDev); + ASSERT(prTxPow); + + do { + if ((!prDev) || (!prTxPow)) { + i4Ret = -EINVAL; + break; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + if (!prGlueInfo) { + i4Ret = -EINVAL; + break; + } + + prAdapter = prGlueInfo->prAdapter; +#if 0 + prMsgFuncSwitch = + (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_FUNCTION_SWITCH_T)); + if (!prMsgFuncSwitch) { + ASSERT(0); + return -ENOMEM; + } + + prMsgFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + + if (prTxPow->disabled) { + /* Dissolve. */ + prMsgFuncSwitch->fgIsFuncOn = FALSE; + } else { + + /* Re-enable function. */ + prMsgFuncSwitch->fgIsFuncOn = TRUE; + } + + /* 1.3 send message */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgFuncSwitch, MSG_SEND_METHOD_BUF); +#endif + + } while (FALSE); + + return i4Ret; +} /* mtk_p2p_wext_set_txpow */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c new file mode 100644 index 0000000000000..4d71e0c59b05d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_cfg80211.c @@ -0,0 +1,1935 @@ +/* +** Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_cfg80211.c + \brief Main routines of Linux driver interface for Wi-Fi Direct + using cfg80211 interface + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_p2p_cfg80211.c +** +** 01 30 2013 yuche.tsai +** [ALPS00455459] [GN_WIFI]??wifi direct??????????? +** Fix possible race condition under GO mode. +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 09 05 2012 wh.su +** [ALPS00351547] [6577JB][WiFi direct]The 3rd device fail to establish p2p connection with GO sometimes +** sync with the ICS code. +** +** 08 31 2012 yuche.tsai +** [ALPS00349585] [6577JB][WiFi direct][KE]Establish p2p connection while both device have connected to AP previously, +** one device reboots automatically with KE +** Fix possible KE when concurrent & disconnect. +** +** 08 21 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 20 2012 yuche.tsai +** NULL +** Fix possible KE issue. +** +** 08 17 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 16 2012 yuche.tsai +** NULL +** Fix compile warning. +** +** 08 14 2012 yuche.tsai +** NULL +** Fix p2p bug find on ALPS.JB trunk. +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Fix compile error for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#include +#include +#include +#include +#include +#include + +#include "precomp.h" +#include "gl_cfg80211.h" +#include "gl_p2p_ioctl.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wformat" +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +BOOLEAN +mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, + IN enum nl80211_channel_type channel_type, + IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + P2P_PARAM_KEY_T rKey; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + kalMemZero(&rKey, sizeof(P2P_PARAM_KEY_T)); + + rKey.u4KeyIndex = key_index; + if (mac_addr) { + ether_addr_copy(rKey.arBSSID, mac_addr); + if ((rKey.arBSSID[0] == 0x00) && (rKey.arBSSID[1] == 0x00) && (rKey.arBSSID[2] == 0x00) && + (rKey.arBSSID[3] == 0x00) && (rKey.arBSSID[4] == 0x00) && (rKey.arBSSID[5] == 0x00)) { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + } + if (rKey.arBSSID[0] != 0xFF) { + rKey.u4KeyIndex |= BIT(31); + if ((rKey.arBSSID[0] != 0x00) || (rKey.arBSSID[1] != 0x00) || (rKey.arBSSID[2] != 0x00) || + (rKey.arBSSID[3] != 0x00) || (rKey.arBSSID[4] != 0x00) || (rKey.arBSSID[5] != 0x00)) + rKey.u4KeyIndex |= BIT(30); + } else { + rKey.u4KeyIndex |= BIT(31); + } + } else { + rKey.arBSSID[0] = 0xff; + rKey.arBSSID[1] = 0xff; + rKey.arBSSID[2] = 0xff; + rKey.arBSSID[3] = 0xff; + rKey.arBSSID[4] = 0xff; + rKey.arBSSID[5] = 0xff; + rKey.u4KeyIndex |= BIT(31); /* ???? */ + } + if (params->key) { + /* rKey.aucKeyMaterial[0] = kalMemAlloc(params->key_len, VIR_MEM_TYPE); */ + kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); + } + rKey.u4KeyLength = params->key_len; + rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddP2PKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) + i4Rslt = 0; + + return i4Rslt; +} + +int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) +) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_REMOVE_KEY_T prRemoveKey; + INT_32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + i4Rslt = 0; + return i4Rslt; + } + + kalMemZero(&prRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + if (mac_addr) + memcpy(prRemoveKey.arBSSID, mac_addr, PARAM_MAC_ADDR_LEN); + prRemoveKey.u4KeyIndex = key_index; + prRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveP2PKey, + &prRemoveKey, prRemoveKey.u4Length, FALSE, FALSE, TRUE, TRUE, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) + i4Rslt = 0; + + return i4Rslt; +} + +int +mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, u8 key_index, bool unicast, bool multicast) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return WLAN_STATUS_SUCCESS; +} + +int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + INT_32 i4RetRslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; + P2P_STATION_INFO_T rP2pStaInfo; + + ASSERT(wiphy); + + do { + if ((wiphy == NULL) || (ndev == NULL) || (sinfo == NULL) || (mac == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_get_station\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + sinfo->filled = 0; + + /* Get station information. */ + /* 1. Inactive time? */ + p2pFuncGetStationInfo(prGlueInfo->prAdapter, (PUINT_8)mac, &rP2pStaInfo); + + /* Inactive time. */ + sinfo->filled |= NL80211_STA_INFO_INACTIVE_TIME; + sinfo->inactive_time = rP2pStaInfo.u4InactiveTime; + sinfo->generation = prP2pGlueInfo->i4Generation; + + i4RetRslt = 0; + } while (FALSE); + + return i4RetRslt; +} + +int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; + P_MSG_P2P_SCAN_REQUEST_T prMsgScanRequest = (P_MSG_P2P_SCAN_REQUEST_T) NULL; + UINT_32 u4MsgSize = 0, u4Idx = 0; + INT_32 i4RetRslt = -EINVAL; + P_RF_CHANNEL_INFO_T prRfChannelInfo = (P_RF_CHANNEL_INFO_T) NULL; + P_P2P_SSID_STRUCT_T prSsidStruct = (P_P2P_SSID_STRUCT_T) NULL; + struct ieee80211_channel *prChannel = NULL; + struct cfg80211_ssid *prSsid = NULL; + + /* [---------Channel---------] [---------SSID---------][---------IE---------] */ + DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan\n"); + + do { + if ((wiphy == NULL) || (request == NULL)) + break; + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + if (prP2pGlueInfo == NULL) { + ASSERT(FALSE); + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_scan.\n"); + + if (prP2pGlueInfo->prScanRequest != NULL) { + /* There have been a scan request on-going processing. */ + DBGLOG(P2P, TRACE, "There have been a scan request on-going processing.\n"); + break; + } + + prP2pGlueInfo->prScanRequest = request; + + /* Should find out why the n_channels so many? */ + if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { + request->n_channels = MAXIMUM_OPERATION_CHANNEL_LIST; + DBGLOG(P2P, TRACE, "Channel list exceed the maximun support.\n"); + } + + u4MsgSize = sizeof(MSG_P2P_SCAN_REQUEST_T) + + (request->n_channels * sizeof(RF_CHANNEL_INFO_T)) + + (request->n_ssids * sizeof(PARAM_SSID_T)) + request->ie_len; + + prMsgScanRequest = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, u4MsgSize); + + if (prMsgScanRequest == NULL) { + ASSERT(FALSE); + i4RetRslt = -ENOMEM; + prP2pGlueInfo->prScanRequest = NULL; + DBGLOG(INIT, TRACE, "mtk_p2p_cfg80211_scan Allocate Mem failed\n"); + break; + } + + DBGLOG(P2P, TRACE, "Generating scan request message.\n"); + + prMsgScanRequest->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; + + DBGLOG(P2P, INFO, "Requesting channel number:%d.\n", request->n_channels); + + for (u4Idx = 0; u4Idx < request->n_channels; u4Idx++) { + /* Translate Freq from MHz to channel number. */ + prRfChannelInfo = &(prMsgScanRequest->arChannelListInfo[u4Idx]); + prChannel = request->channels[u4Idx]; + + prRfChannelInfo->ucChannelNum = nicFreq2ChannelNum(prChannel->center_freq * 1000); + DBGLOG(P2P, TRACE, "Scanning Channel:%d, freq: %d\n", + prRfChannelInfo->ucChannelNum, prChannel->center_freq); + switch (prChannel->band) { + case NL80211_BAND_2GHZ: + prRfChannelInfo->eBand = BAND_2G4; + break; + case NL80211_BAND_5GHZ: + prRfChannelInfo->eBand = BAND_5G; + break; + default: + DBGLOG(P2P, TRACE, "UNKNOWN Band info from supplicant\n"); + prRfChannelInfo->eBand = BAND_NULL; + break; + } + + /* Iteration. */ + prRfChannelInfo++; + } + prMsgScanRequest->u4NumChannel = request->n_channels; + + DBGLOG(P2P, TRACE, "Finish channel list.\n"); + + /* SSID */ + prSsid = request->ssids; + prSsidStruct = (P_P2P_SSID_STRUCT_T) prRfChannelInfo; + if (prSsidStruct) { + if (request->n_ssids) { + ASSERT((ULONG) prSsidStruct == (ULONG)&(prMsgScanRequest->arChannelListInfo[u4Idx])); + prMsgScanRequest->prSSID = prSsidStruct; + } + + for (u4Idx = 0; u4Idx < request->n_ssids; u4Idx++) { + COPY_SSID(prSsidStruct->aucSsid, + prSsidStruct->ucSsidLen, request->ssids->ssid, request->ssids->ssid_len); + + prSsidStruct++; + prSsid++; + } + + prMsgScanRequest->i4SsidNum = request->n_ssids; + + DBGLOG(P2P, TRACE, "Finish SSID list:%d.\n", request->n_ssids); + + /* IE BUFFERS */ + prMsgScanRequest->pucIEBuf = (PUINT_8) prSsidStruct; + if (request->ie_len) { + kalMemCopy(prMsgScanRequest->pucIEBuf, request->ie, request->ie_len); + prMsgScanRequest->u4IELen = request->ie_len; + } + } + + DBGLOG(P2P, TRACE, "Finish IE Buffer.\n"); +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = FALSE; +#endif + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgScanRequest, MSG_SEND_METHOD_BUF); + + i4RetRslt = 0; + } while (FALSE); + + return i4RetRslt; +} /* mtk_p2p_cfg80211_scan */ + +int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + + do { + if (wiphy == NULL) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_wiphy_params\n"); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY short param is changed.\n"); + } + + if (changed & WIPHY_PARAM_RETRY_LONG) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY long param is changed.\n"); + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY fragmentation threshold is changed.\n"); + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY RTS threshold is changed.\n"); + } + + if (changed & WIPHY_PARAM_COVERAGE_CLASS) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The coverage class is changed???\n"); + } + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_set_wiphy_params */ + +int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 value; + UINT_32 u4Leng; + + ASSERT(wiphy); + + if (enabled) + value = 2; + else + value = 0; + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_power_mgmt ps=%d.\n", enabled); + + /* p2p_set_power_save */ + kalIoctl(prGlueInfo, wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + return 0; +} + +/* &&&&&&&&&&&&&&&&&&&&&&&&&& Add for ICS Wi-Fi Direct Support. &&&&&&&&&&&&&&&&&&&&&&& */ +int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; + P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) NULL; + PUINT_8 pucBuffer = (PUINT_8) NULL; + /* P_IE_SSID_T prSsidIE = (P_IE_SSID_T)NULL; */ + + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_chan_def *chandef = &wdev->preset_chandef; + + do { + if ((wiphy == NULL) || (settings == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_ap.\n"); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + +#if 1 + mtk_p2p_cfg80211_set_channel(wiphy, chandef); +#else + prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->ucOperatingChnl = + (chandef->chan->center_freq - 2407) / 5; + prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings->eBand = BAND_2G4; +#endif + + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + (sizeof(MSG_P2P_BEACON_UPDATE_T) + + settings->beacon.head_len + + settings->beacon.tail_len)); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + + if (settings->beacon.head_len != 0) { + kalMemCopy(pucBuffer, settings->beacon.head, settings->beacon.head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = settings->beacon.head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) settings->beacon.head_len); + } else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (settings->beacon.tail_len != 0) { + UINT_32 ucLen = settings->beacon.tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + + /*Add TIM IE */ + /* IEEE 802.11 2007 - 7.3.2.6 */ + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; + /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ + TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ + TIM_IE(pucBuffer)->ucDTIMPeriod = 1; + TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; + /* will be overwrite by FW */ + ucLen += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + kalMemCopy(pucBuffer, settings->beacon.tail, settings->beacon.tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + } else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); + + prP2pStartAPMsg = (P_MSG_P2P_START_AP_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, sizeof(MSG_P2P_START_AP_T)); + + if (prP2pStartAPMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prP2pStartAPMsg->rMsgHdr.eMsgId = MID_MNY_P2P_START_AP; + + prP2pStartAPMsg->fgIsPrivacy = settings->privacy; + + prP2pStartAPMsg->u4BcnInterval = settings->beacon_interval; + + prP2pStartAPMsg->u4DtimPeriod = settings->dtim_period; + + /* Copy NO SSID. */ + prP2pStartAPMsg->ucHiddenSsidType = settings->hidden_ssid; + + COPY_SSID(prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen, settings->ssid, settings->ssid_len); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pStartAPMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT + if (glIsChipNeedWakelock(prGlueInfo)) + KAL_WAKE_LOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); +#endif + + } while (FALSE); + + return i4Rslt; + +/* /////////////////////// */ + /** + * struct cfg80211_ap_settings - AP configuration + * + * Used to configure an AP interface. + * + * @beacon: beacon data + * @beacon_interval: beacon interval + * @dtim_period: DTIM period + * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from + * user space) + * @ssid_len: length of @ssid + * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames + * @crypto: crypto settings + * @privacy: the BSS uses privacy + * @auth_type: Authentication type (algorithm) + * @inactivity_timeout: time in seconds to determine station's inactivity. + */ +/* struct cfg80211_ap_settings { */ +/* struct cfg80211_beacon_data beacon; */ +/* */ +/* int beacon_interval, dtim_period; */ +/* const u8 *ssid; */ +/* size_t ssid_len; */ +/* enum nl80211_hidden_ssid hidden_ssid; */ +/* struct cfg80211_crypto_settings crypto; */ +/* bool privacy; */ +/* enum nl80211_auth_type auth_type; */ +/* int inactivity_timeout; */ +/* }; */ +/* ////////////////// */ + + return i4Rslt; +} /* mtk_p2p_cfg80211_start_ap */ + +int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL; + PUINT_8 pucBuffer = (PUINT_8) NULL; + + do { + if ((wiphy == NULL) || (info == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_beacon.\n"); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + (sizeof(MSG_P2P_BEACON_UPDATE_T) + + info->head_len + info->tail_len)); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + + if (info->head_len != 0) { + kalMemCopy(pucBuffer, info->head, info->head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = info->head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (UINT_32) info->head_len); + } else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (info->tail_len != 0) { + UINT_32 ucLen = info->tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + + /*Add TIM IE */ + /* IEEE 802.11 2007 - 7.3.2.6 */ + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + TIM_IE(pucBuffer)->ucLength = (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + 4) */; + /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 only) */ + TIM_IE(pucBuffer)->ucDTIMCount = 0 /*prBssInfo->ucDTIMCount */; /* will be overwrite by FW */ + TIM_IE(pucBuffer)->ucDTIMPeriod = 1; + TIM_IE(pucBuffer)->ucBitmapControl = 0 /*ucBitmapControl | (UINT_8)u4N1 */; + /* will be overwrite by FW */ + ucLen += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + kalMemCopy(pucBuffer, info->tail, info->tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + } else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); + +/* ////////////////////////// */ +/** + * struct cfg80211_beacon_data - beacon data + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed + * @tail: tail portion of beacon (after TIM IE) + * or %NULL if not changed + * @head_len: length of @head + * @tail_len: length of @tail + * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL + * @beacon_ies_len: length of beacon_ies in octets + * @proberesp_ies: extra information element(s) to add into Probe Response + * frames or %NULL + * @proberesp_ies_len: length of proberesp_ies in octets + * @assocresp_ies: extra information element(s) to add into (Re)Association + * Response frames or %NULL + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template (@probe_resp) + * @probe_resp: probe response template (AP mode only) + */ +/* struct cfg80211_beacon_data { */ +/* const u8 *head, *tail; */ +/* const u8 *beacon_ies; */ +/* const u8 *proberesp_ies; */ +/* const u8 *assocresp_ies; */ +/* const u8 *probe_resp; */ + +/* size_t head_len, tail_len; */ +/* size_t beacon_ies_len; */ +/* size_t proberesp_ies_len; */ +/* size_t assocresp_ies_len; */ +/* size_t probe_resp_len; */ +/* }; */ + +/* ////////////////////////// */ + + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_change_beacon */ + +int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; + + do { + if (wiphy == NULL) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_stop_ap.\n"); + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* Switch OP MOde. */ + prP2pSwitchMode = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prP2pSwitchMode == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prP2pSwitchMode->rMsgHdr.eMsgId = MID_MNY_P2P_STOP_AP; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pSwitchMode, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT + if (glIsChipNeedWakelock(prGlueInfo)) + KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &prGlueInfo->prAdapter->rApWakeLock); +#endif + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_stop_ap */ + +/* TODO: */ +int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* not implemented yet */ + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_deauth.\n"); + + return -EINVAL; +} /* mtk_p2p_cfg80211_deauth */ + +/* TODO: */ +int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_disassoc.\n"); + + /* not implemented yet */ + + return -EINVAL; +} /* mtk_p2p_cfg80211_disassoc */ + +int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + P_MSG_P2P_CHNL_REQUEST_T prMsgChnlReq = (P_MSG_P2P_CHNL_REQUEST_T) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || (cookie == NULL)) + break; + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + *cookie = prGlueP2pInfo->u8Cookie++; + + prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_REQUEST_T)); + + if (prMsgChnlReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_remain_on_channel\n"); + + prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; + prMsgChnlReq->u8Cookie = *cookie; + prMsgChnlReq->u4Duration = duration; + + mtk_p2p_cfg80211func_channel_format_switch(chan, NL80211_CHAN_HT20, /* 4 KH Need Check */ + &prMsgChnlReq->rChannelInfo, &prMsgChnlReq->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlReq, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} + +/* mtk_p2p_cfg80211_remain_on_channel */ +int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_MSG_P2P_CHNL_ABORT_T prMsgChnlAbort = (P_MSG_P2P_CHNL_ABORT_T) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL)) + break; + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CHNL_ABORT_T)); + + if (prMsgChnlAbort == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_cancel_remain_on_channel\n"); + + prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_ABORT; + prMsgChnlAbort->u8Cookie = cookie; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgChnlAbort, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_cancel_remain_on_channel */ + +int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T *prMsgExtListenReq = NULL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_P2P_MGMT_TX_REQUEST_T) NULL; + P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T) NULL; + PUINT_8 pucFrameBuf = (PUINT_8) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || (cookie == NULL)) + break; + /* DBGLOG(P2P, TRACE, ("mtk_p2p_cfg80211_mgmt_tx\n")); */ + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + *cookie = prGlueP2pInfo->u8Cookie++; + + /* Channel & Channel Type & Wait time are ignored. */ + prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_MGMT_TX_REQUEST_T)); + + if (prMsgTxReq == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + /* Here need to extend the listen interval */ + prMsgExtListenReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(struct _MSG_P2P_EXTEND_LISTEN_INTERVAL_T)); + if (prMsgExtListenReq) { + prMsgExtListenReq->rMsgHdr.eMsgId = MID_MNY_P2P_EXTEND_LISTEN_INTERVAL; + prMsgExtListenReq->wait = params->wait; + DBGLOG(P2P, INFO, "ext listen, wait: %d\n", prMsgExtListenReq->wait); + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgExtListenReq, + MSG_SEND_METHOD_BUF); + } + + prMsgTxReq->fgNoneCckRate = FALSE; + prMsgTxReq->fgIsWaitRsp = TRUE; + + prMgmtFrame = cnmMgtPktAlloc(prGlueInfo->prAdapter, (UINT_32) (params->len + MAC_TX_RESERVED_FIELD)); + + prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; + if (prMsgTxReq->prMgmtMsduInfo == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->u8Cookie = *cookie; + prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_TX; + + pucFrameBuf = (PUINT_8) ((ULONG) prMgmtFrame->prPacket + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucFrameBuf, params->buf, params->len); + + prMgmtFrame->u2FrameLength = params->len; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgTxReq, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { + if (prMsgTxReq->prMgmtMsduInfo != NULL) + cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); + + cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); + } + + return i4Rslt; +} /* mtk_p2p_cfg80211_mgmt_tx */ + +int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + switch (params->use_cts_prot) { + case -1: + DBGLOG(P2P, TRACE, "CTS protection no change\n"); + break; + case 0: + DBGLOG(P2P, TRACE, "CTS protection disable.\n"); + break; + case 1: + DBGLOG(P2P, TRACE, "CTS protection enable\n"); + break; + default: + DBGLOG(P2P, TRACE, "CTS protection unknown\n"); + break; + } + + switch (params->use_short_preamble) { + case -1: + DBGLOG(P2P, TRACE, "Short prreamble no change\n"); + break; + case 0: + DBGLOG(P2P, TRACE, "Short prreamble disable.\n"); + break; + case 1: + DBGLOG(P2P, TRACE, "Short prreamble enable\n"); + break; + default: + DBGLOG(P2P, TRACE, "Short prreamble unknown\n"); + break; + } + +#if 0 + /* not implemented yet */ + p2pFuncChangeBssParam(prGlueInfo->prAdapter, + prBssInfo->fgIsProtection, + prBssInfo->fgIsShortPreambleAllowed, prBssInfo->fgUseShortSlotTime, + /* Basic rates */ + /* basic rates len */ + /* ap isolate */ + /* ht opmode. */ + ); +#else + i4Rslt = 0; +#endif + + return i4Rslt; +} /* mtk_p2p_cfg80211_change_bss */ + +int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params) +//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; + UINT_8 aucBcMac[] = BC_MAC_ADDR; + const UINT_8 *mac = NULL; + + do { + if ((wiphy == NULL) || (dev == NULL)) + break; + + if (params->mac == NULL) + mac = aucBcMac; + else + mac = params->mac; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_del_station.\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(MSG_P2P_CONNECTION_ABORT_T), + VIR_MEM_TYPE); */ + prDisconnectMsg = + (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnectMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prDisconnectMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + COPY_MAC_ADDR(prDisconnectMsg->aucTargetID, mac); + prDisconnectMsg->u2ReasonCode = REASON_CODE_UNSPECIFIED; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnectMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; + +} /* mtk_p2p_cfg80211_del_station */ + +int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; + + do { + if ((wiphy == NULL) || (dev == NULL) || (sme == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_connect.\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prConnReqMsg = + (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + (sizeof(MSG_P2P_CONNECTION_REQUEST_T) + sme->ie_len)); + + if (prConnReqMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prConnReqMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + COPY_SSID(prConnReqMsg->rSsid.aucSsid, prConnReqMsg->rSsid.ucSsidLen, sme->ssid, sme->ssid_len); + + COPY_MAC_ADDR(prConnReqMsg->aucBssid, sme->bssid); + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_connect to %pM, IE len: %d\n", + prConnReqMsg->aucBssid, sme->ie_len); + + DBGLOG(P2P, TRACE, "Assoc Req IE Buffer Length:%d\n", sme->ie_len); + kalMemCopy(prConnReqMsg->aucIEBuf, sme->ie, sme->ie_len); + prConnReqMsg->u4IELen = sme->ie_len; + + mtk_p2p_cfg80211func_channel_format_switch(sme->channel, + NL80211_CHAN_NO_HT, + &prConnReqMsg->rChannelInfo, &prConnReqMsg->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prConnReqMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_connect */ + +int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T) NULL; + UINT_8 aucBCAddr[] = BC_MAC_ADDR; + + do { + if ((wiphy == NULL) || (dev == NULL)) + break; + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + +/* prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(P_MSG_P2P_CONNECTION_ABORT_T), VIR_MEM_TYPE); */ + prDisconnMsg = + (P_MSG_P2P_CONNECTION_ABORT_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.Allocate Memory Failed.\n"); + break; + } + + prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + prDisconnMsg->u2ReasonCode = reason_code; + prDisconnMsg->fgSendDeauth = TRUE; + COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prDisconnMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_disconnect */ + +int +mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type,/* IN u32 *flags,*/ IN struct vif_params *params) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + INT_32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T) NULL; + + do { + if ((wiphy == NULL) || (ndev == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_iface.\n"); + + if (ndev->ieee80211_ptr) + ndev->ieee80211_ptr->iftype = type; + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* Switch OP MOde. */ + prSwitchModeMsg = + (P_MSG_P2P_SWITCH_OP_MODE_T) cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prSwitchModeMsg == NULL) { + ASSERT(FALSE); + i4Rslt = -ENOMEM; + break; + } + + prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_CLIENT.\n"); + case NL80211_IFTYPE_STATION: + if (type == NL80211_IFTYPE_STATION) + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_STATION.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + break; + case NL80211_IFTYPE_AP: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_AP.\n"); + case NL80211_IFTYPE_P2P_GO: + if (type == NL80211_IFTYPE_P2P_GO) + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_GO not AP.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + break; + default: + DBGLOG(P2P, TRACE, "Other type :%d .\n", type); + prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; + break; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prSwitchModeMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + + } while (FALSE); + + return i4Rslt; + +} /* mtk_p2p_cfg80211_change_iface */ + +int mtk_p2p_cfg80211_set_channel(IN struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + RF_CHANNEL_INFO_T rRfChnlInfo; + + do { + if (wiphy == NULL) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_channel.\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + mtk_p2p_cfg80211func_channel_format_switch(chandef->chan, chandef->width, &rRfChnlInfo, NULL); + p2pFuncSetChannel(prGlueInfo->prAdapter, &rRfChnlInfo); + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; + +} + +/* mtk_p2p_cfg80211_set_channel */ + +int +mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, + IN struct net_device *dev, + IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask) +{ + INT_32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + do { + if ((wiphy == NULL) || (dev == NULL) || (mask == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_bitrate_mask\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + /* TODO: Set bitrate mask of the peer? */ + + i4Rslt = 0; + } while (FALSE); + + return i4Rslt; +} /* mtk_p2p_cfg80211_set_bitrate_mask */ + +void mtk_p2p_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + struct wireless_dev *wdev, + IN u16 frame_type, IN bool reg) +{ +#if 0 + P_MSG_P2P_MGMT_FRAME_REGISTER_T prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) NULL; +#endif + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL)) + break; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_mgmt_frame_register\n"); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + switch (frame_type) { + case MAC_FRAME_PROBE_REQ: + if (reg) { + prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); + } else { + prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); + } + break; + case MAC_FRAME_ACTION: + if (reg) { + prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); + } else { + prGlueInfo->prP2PInfo->u4OsMgmtFrameFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); + } + break; + default: + DBGLOG(P2P, ERROR, "Ask frog to add code for mgmt:%x\n", frame_type); + break; + } + + if ((prGlueInfo->prAdapter != NULL) && (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE)) { + + /* prGlueInfo->u4Flag |= GLUE_FLAG_FRAME_FILTER; */ + set_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + + if (in_interrupt()) + DBGLOG(P2P, TRACE, "It is in interrupt level\n"); + } +#if 0 + + prMgmtFrameRegister = (P_MSG_P2P_MGMT_FRAME_REGISTER_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + sizeof + (MSG_P2P_MGMT_FRAME_REGISTER_T)); + + if (prMgmtFrameRegister == NULL) { + ASSERT(FALSE); + break; + } + + prMgmtFrameRegister->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_FRAME_REGISTER; + + prMgmtFrameRegister->u2FrameType = frame_type; + prMgmtFrameRegister->fgIsRegister = reg; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMgmtFrameRegister, MSG_SEND_METHOD_BUF); + +#endif + + } while (FALSE); + +} /* mtk_p2p_cfg80211_mgmt_frame_register */ + +BOOLEAN +mtk_p2p_cfg80211func_channel_format_switch(IN struct ieee80211_channel *channel, + IN enum nl80211_channel_type channel_type, + IN P_RF_CHANNEL_INFO_T prRfChnlInfo, IN P_ENUM_CHNL_EXT_T prChnlSco) +{ + BOOLEAN fgIsValid = FALSE; + + do { + if (channel == NULL) + break; + + if (prRfChnlInfo) { + prRfChnlInfo->ucChannelNum = nicFreq2ChannelNum(channel->center_freq * 1000); + + switch (channel->band) { + case NL80211_BAND_2GHZ: + prRfChnlInfo->eBand = BAND_2G4; + break; + case NL80211_BAND_5GHZ: + prRfChnlInfo->eBand = BAND_5G; + break; + default: + prRfChnlInfo->eBand = BAND_2G4; + break; + } + + } + + if (prChnlSco) { + + switch (channel_type) { + case NL80211_CHAN_NO_HT: + *prChnlSco = CHNL_EXT_SCN; + break; + case NL80211_CHAN_HT20: + *prChnlSco = CHNL_EXT_SCN; + break; + case NL80211_CHAN_HT40MINUS: + *prChnlSco = CHNL_EXT_SCA; + break; + case NL80211_CHAN_HT40PLUS: + *prChnlSco = CHNL_EXT_SCB; + break; + default: + ASSERT(FALSE); + *prChnlSco = CHNL_EXT_SCN; + break; + } + } + + fgIsValid = TRUE; + } while (FALSE); + + return fgIsValid; +} + +/* mtk_p2p_cfg80211func_channel_format_switch */ + +#if CONFIG_NL80211_TESTMODE +int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_TEST_PARAMS prParams = (P_NL80211_DRIVER_TEST_PARAMS) NULL; + INT_32 i4Status = -EINVAL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = NULL; + + ASSERT(wiphy); + ASSERT(wdev); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_cmd\n"); + + if (data && len) { + prParams = (P_NL80211_DRIVER_TEST_PARAMS) data; + } else { + DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_cmd, data is NULL\n"); + return i4Status; + } + + if (prParams->index >> 24 == 0x01) { + /* New version */ + } else { + /* Old version */ + mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(wiphy, data, len); + i4Status = 0; + return i4Status; + } + + /* Clear the version byte */ + prParams->index = prParams->index & ~BITS(24, 31); + + if (prParams) { + switch (prParams->index) { + case 1: /* P2P Simga */ +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + { + P_NL80211_DRIVER_SW_CMD_PARAMS prParamsCmd; + + prParamsCmd = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; + + if ((prParamsCmd->adr & 0xffff0000) == 0xffff0000) { + i4Status = mtk_p2p_cfg80211_testmode_sw_cmd(wiphy, data, len); + break; + } + } +#endif + i4Status = mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(wiphy, data, len); + break; +#if CFG_SUPPORT_WFD + case 2: /* WFD */ + i4Status = mtk_p2p_cfg80211_testmode_wfd_update_cmd(wiphy, data, len); + break; +#endif + case 3: /* Hotspot Client Management */ + i4Status = mtk_p2p_cfg80211_testmode_hotspot_block_cmd(wiphy, data, len); + break; + case 0x10: + i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, prGlueInfo); + break; +#if 1 + case 0x11: /*NFC Beam + Indication */ + prChnlReqInfo = &prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rChnlReqInfo; + if (data && len) { + P_NL80211_DRIVER_SET_NFC_PARAMS prParams = (P_NL80211_DRIVER_SET_NFC_PARAMS) data; + + prChnlReqInfo->NFC_BEAM = prParams->NFC_Enable; + DBGLOG(P2P, INFO, "NFC: BEAM[%d]\n", prChnlReqInfo->NFC_BEAM); + } + break; + case 0x12: /*NFC Beam + Indication */ + DBGLOG(P2P, INFO, "NFC: Polling\n"); + i4Status = mtk_cfg80211_testmode_get_scan_done(wiphy, data, len, prGlueInfo); + break; +#endif +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + case 0x30: + i4Status = mtk_cfg80211_testmode_get_lte_channel(wiphy, data, len, prGlueInfo); + break; +#endif + + default: + i4Status = -EINVAL; + break; + } + } + + return i4Status; +} + +int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + NL80211_DRIVER_TEST_PRE_PARAMS rParams; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + UINT_32 index_mode; + UINT_32 index; + INT_32 value; + int status = 0; + UINT_32 u4Leng; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + kalMemZero(&rParams, sizeof(NL80211_DRIVER_TEST_PRE_PARAMS)); + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd\n"); + + if (data && len) + memcpy(&rParams, data, len); + + DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA,idx_mode=%d idx=%d value=%u\n", + (INT_16) rParams.idx_mode, (INT_16) rParams.idx, rParams.value); + + index_mode = rParams.idx_mode; + index = rParams.idx; + value = rParams.value; + + switch (index) { + case 0: /* Listen CH */ + break; + case 1: /* P2p mode */ + break; + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 100: /* Oper CH */ + /* 20110920 - frog: User configurations are placed in ConnSettings. */ + /* prP2pConnSettings->ucOperatingChnl = value; */ + break; + case 101: /* Local config Method, for P2P SDK */ + prP2pConnSettings->u2LocalConfigMethod = value; + break; + case 102: /* Sigma P2p reset */ + /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ + /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ + p2pFsmUninit(prGlueInfo->prAdapter); + p2pFsmInit(prGlueInfo->prAdapter); + break; + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + case 104: /* P2p send persence, duration */ + break; + case 105: /* P2p send persence, interval */ + break; + case 106: /* P2P set sleep */ + value = 1; + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + break; + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ + break; + case 108: /* p2p_set_power_save */ + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + + break; + default: + break; + } + + return status; + +} + +int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_P2P_SIGMA_PARAMS prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + UINT_32 index; + INT_32 value; + int status = 0; + UINT_32 u4Leng; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd\n"); + + if (data && len) { + prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS) data; + } else { + DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd, data is NULL or len is 0\n"); + return -EINVAL; + } + + index = (INT_32) prParams->idx; + value = (INT_32) prParams->value; + + DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA, idx=%d value=%d\n", + (INT_32) prParams->idx, (INT_32) prParams->value); + + switch (index) { + case 0: /* Listen CH */ + break; + case 1: /* P2p mode */ + break; + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char *)&prP2pSpecificBssInfo->rNoaParam); */ + break; + case 100: /* Oper CH */ + /* 20110920 - frog: User configurations are placed in ConnSettings. */ + /* prP2pConnSettings->ucOperatingChnl = value; */ + break; + case 101: /* Local config Method, for P2P SDK */ + prP2pConnSettings->u2LocalConfigMethod = value; + break; + case 102: /* Sigma P2p reset */ + /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, MAC_ADDR_LEN); */ + /* prP2pConnSettings->eConnectionPolicy = ENUM_P2P_CONNECTION_POLICY_AUTO; */ + break; + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + case 104: /* P2p send persence, duration */ + break; + case 105: /* P2p send persence, interval */ + break; + case 106: /* P2P set sleep */ + value = 1; + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + break; + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + /* status = mtk_p2p_wext_set_oppps_param(prDev,info,wrqu,(char *)&prP2pSpecificBssInfo->rOppPsParam); */ + break; + case 108: /* p2p_set_power_save */ + kalIoctl(prGlueInfo, + wlanoidSetP2pPowerSaveProfile, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + + break; + case 109: /* Max Clients */ + kalP2PSetMaxClients(prGlueInfo, value); + break; + case 110: /* Hotspot WPS mode */ + kalIoctl(prGlueInfo, wlanoidSetP2pWPSmode, &value, sizeof(value), FALSE, FALSE, TRUE, TRUE, &u4Leng); + break; + default: + break; + } + + return status; + +} + +#if CFG_SUPPORT_WFD +int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_WFD_PARAMS prParams = (P_NL80211_DRIVER_WFD_PARAMS) NULL; + int status = 0; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; + static UINT_8 prevWfdEnable; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + prParams = (P_NL80211_DRIVER_WFD_PARAMS) data; + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_testmode_wfd_update_cmd\n"); + + /* to reduce log, print when state changed */ + if (prevWfdEnable != prParams->WfdEnable) { + prevWfdEnable = prParams->WfdEnable; + DBGLOG(P2P, INFO, "WFD Enable:%x\n", prParams->WfdEnable); + DBGLOG(P2P, INFO, "WFD Session Available:%x\n", prParams->WfdSessionAvailable); + DBGLOG(P2P, INFO, "WFD Couple Sink Status:%x\n", prParams->WfdCoupleSinkStatus); + /* aucReserved0[2] */ + DBGLOG(P2P, INFO, "WFD Device Info:%x\n", prParams->WfdDevInfo); + DBGLOG(P2P, INFO, "WFD Control Port:%x\n", prParams->WfdControlPort); + DBGLOG(P2P, INFO, "WFD Maximum Throughput:%x\n", prParams->WfdMaximumTp); + DBGLOG(P2P, INFO, "WFD Extend Capability:%x\n", prParams->WfdExtendCap); + DBGLOG(P2P, INFO, "WFD Couple Sink Addr %pM\n", prParams->WfdCoupleSinkAddress); + DBGLOG(P2P, INFO, "WFD Associated BSSID %pM\n", prParams->WfdAssociatedBssid); + /* UINT_8 aucVideolp[4]; */ + /* UINT_8 aucAudiolp[4]; */ + DBGLOG(P2P, INFO, "WFD Video Port:%x\n", prParams->WfdVideoPort); + DBGLOG(P2P, INFO, "WFD Audio Port:%x\n", prParams->WfdAudioPort); + DBGLOG(P2P, INFO, "WFD Flag:%x\n", prParams->WfdFlag); + DBGLOG(P2P, INFO, "WFD Policy:%x\n", prParams->WfdPolicy); + DBGLOG(P2P, INFO, "WFD State:%x\n", prParams->WfdState); + /* UINT_8 aucWfdSessionInformationIE[24*8]; */ + DBGLOG(P2P, INFO, "WFD Session Info Length:%x\n", prParams->WfdSessionInformationIELen); + /* UINT_8 aucReserved1[2]; */ + DBGLOG(P2P, INFO, "WFD Primary Sink Addr %pM\n", prParams->aucWfdPrimarySinkMac); + DBGLOG(P2P, INFO, "WFD Secondary Sink Addr %pM\n", prParams->aucWfdSecondarySinkMac); + DBGLOG(P2P, INFO, "WFD Advanced Flag:%x\n", prParams->WfdAdvanceFlag); + DBGLOG(P2P, INFO, "WFD Sigma mode:%x\n", prParams->WfdSigmaMode); + /* UINT_8 aucReserved2[64]; */ + /* UINT_8 aucReserved3[64]; */ + /* UINT_8 aucReserved4[64]; */ + } + + prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + + kalMemCopy(&prWfdCfgSettings->u4WfdCmdType, &prParams->WfdCmdType, sizeof(WFD_CFG_SETTINGS_T)); + + prMsgWfdCfgUpdate = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); + + if (prMsgWfdCfgUpdate == NULL) { + ASSERT(FALSE); + return status; + } + + prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; + prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); +#if 0 /* Test Only */ +/* prWfdCfgSettings->ucWfdEnable = 1; */ +/* prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; */ + prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_DEV_INFO_VALID; + prWfdCfgSettings->u2WfdDevInfo = 123; + prWfdCfgSettings->u2WfdControlPort = 456; + prWfdCfgSettings->u2WfdMaximumTp = 789; + + prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_SINK_INFO_VALID; + prWfdCfgSettings->ucWfdCoupleSinkStatus = 0xAB; + { + UINT_8 aucTestAddr[MAC_ADDR_LEN] = { 0x77, 0x66, 0x55, 0x44, 0x33, 0x22 }; + + COPY_MAC_ADDR(prWfdCfgSettings->aucWfdCoupleSinkAddress, aucTestAddr); + } + + prWfdCfgSettings->u4WfdFlag |= WFD_FLAGS_EXT_CAPABILITY_VALID; + prWfdCfgSettings->u2WfdExtendCap = 0xCDE; + +#endif + + return status; + +} +#endif /* CFG_SUPPORT_WFD */ + +int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) NULL; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + + if (data && len) { + prParams = (P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS) data; + } else { + DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd, data is NULL or len is 0\n"); + return -EINVAL; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_hotspot_block_cmd\n"); + + return kalP2PSetBlackList(prGlueInfo, prParams->aucBssid, prParams->ucblocked); +} + +int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_SW_CMD_PARAMS prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + UINT_32 u4SetInfoLen = 0; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy)); + +#if 1 + DBGLOG(P2P, TRACE, "--> %s()\n", __func__); +#endif + + if (data && len) + prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS) data; + + if (prParams) { + if (prParams->set == 1) { + rstatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC) wlanoidSetSwCtrlWrite, + &prParams->adr, (UINT_32) 8, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + } + } + + if (WLAN_STATUS_SUCCESS != rstatus) + fgIsValid = -EFAULT; + + return fgIsValid; +} + +#endif + +#endif /* CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c new file mode 100644 index 0000000000000..d0f2d25a4529f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_init.c @@ -0,0 +1,433 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +/* +** Id: @(#) gl_p2p_init.c@@ +*/ + +/*! \file gl_p2p_init.c + \brief init and exit routines of Linux driver interface for Wi-Fi Direct + + This file contains the main routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define P2P_MODE_INF_NAME "p2p%d" +#if CFG_TC1_FEATURE +#define AP_MODE_INF_NAME "wlan%d" +#else +#define AP_MODE_INF_NAME "ap%d" +#endif +/* #define MAX_INF_NAME_LEN 15 */ +/* #define MIN_INF_NAME_LEN 1 */ + +#define RUNNING_P2P_MODE 0 +#define RUNNING_AP_MODE 1 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* Get interface name and running mode from module insertion parameter +* Usage: insmod p2p.ko mode=1 +* default: interface name is p2p%d +* running mode is P2P +*/ +static PUCHAR ifname = P2P_MODE_INF_NAME; +static UINT_16 mode = RUNNING_P2P_MODE; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief check interface name parameter is valid or not +* if invalid, set ifname to P2P_MODE_INF_NAME +* +* +* \retval +*/ +/*----------------------------------------------------------------------------*/ +VOID p2pCheckInterfaceName(VOID) +{ + + if (mode) { + mode = RUNNING_AP_MODE; + ifname = AP_MODE_INF_NAME; + } +#if 0 + UINT_32 ifLen = 0; + + if (ifname) { + ifLen = strlen(ifname); + + if (ifLen > MAX_INF_NAME_LEN) + ifname[MAX_INF_NAME_LEN] = '\0'; + else if (ifLen < MIN_INF_NAME_LEN) + ifname = P2P_MODE_INF_NAME; + } else { + ifname = P2P_MODE_INF_NAME; + } +#endif +} + +void p2pHandleSystemSuspend(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ + UINT_32 u4NumIPv6 = 0; +#endif + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + + + if (!wlanExportGlueInfo(&prGlueInfo)) { + DBGLOG(P2P, INFO, "No glue info\n"); + return; + } + + ASSERT(prGlueInfo); + /* <1> Sanity check and acquire the net_device */ + prDev = prGlueInfo->prP2PInfo->prDevHandler; + ASSERT(prDev); + + /* <3> get the IPv4 address */ + if (!prDev || !(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { + DBGLOG(P2P, INFO, "ip is not available.\n"); + return; + } + /* <4> copy the IPv4 address */ + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + + /* todo: traverse between list to find whole sets of IPv4 addresses */ + if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) + u4NumIPv4++; +#ifdef CONFIG_IPV6 + /* <5> get the IPv6 address */ + if (!prDev || !(prDev->ip6_ptr) || + !((struct in_device *)(prDev->ip6_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { + DBGLOG(P2P, INFO, "ipv6 is not available.\n"); + return; + } + /* <6> copy the IPv6 address */ + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0], ip6[1], ip6[2], ip6[3], + ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); + /* todo: traverse between list to find whole sets of IPv6 addresses */ + + if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) + ; /* Do nothing */ +#endif + /* <7> set up the ARP filter */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +/* UINT_8 aucBuf[32] = {0}; */ + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; + /* aucBuf; */ + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = u4NumIPv4; +#ifdef CONFIG_IPV6 + prParamNetAddrList->u4AddressCount += u4NumIPv6; +#endif + + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; +#if 0 + kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((UINT_32) prParamNetAddr + sizeof(ip)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); +#else + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + +/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); +// TODO: frog. The pointer is not right. */ + + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + + (ULONG) (prParamNetAddr->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, + aucAddress))); + + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS_IP); +#endif + } +#ifdef CONFIG_IPV6 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); +/* prParamNetAddr = (P_PARAM_NETWORK_ADDRESS)((UINT_32)prParamNetAddr + sizeof(ip6)); */ + + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((ULONG) prParamNetAddr + + (ULONG) (prParamNetAddr->u2AddressLength + + OFFSET_OF(PARAM_NETWORK_ADDRESS, + aucAddress))); + + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSetNetworkAddress, + (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); + } +} + +void p2pHandleSystemResume(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_8 ip[4] = { 0 }; +#ifdef CONFIG_IPV6 + UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ +#endif + + if (!wlanExportGlueInfo(&prGlueInfo)) { + DBGLOG(P2P, WARN, "no glue info\n"); + return; + } + + ASSERT(prGlueInfo); + /* <1> Sanity check and acquire the net_device */ + prDev = prGlueInfo->prP2PInfo->prDevHandler; + ASSERT(prDev); + + /* <3> get the IPv4 address */ + if (!prDev || !(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { + DBGLOG(P2P, INFO, "ip is not available.\n"); + return; + } + /* <4> copy the IPv4 address */ + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + +#ifdef CONFIG_IPV6 + /* <5> get the IPv6 address */ + if (!prDev || !(prDev->ip6_ptr) || + !((struct in_device *)(prDev->ip6_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { + DBGLOG(P2P, INFO, "ipv6 is not available.\n"); + return; + } + /* <6> copy the IPv6 address */ + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(P2P, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0], ip6[1], ip6[2], ip6[3], + ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); +#endif + /* <7> clear the ARP filter */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; +/* UINT_8 aucBuf[32] = {0}; */ + UINT_32 u4Len = sizeof(PARAM_NETWORK_ADDRESS_LIST); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) g_aucBufIpAddr; + /* aucBuf; */ + + kalMemZero(g_aucBufIpAddr, sizeof(g_aucBufIpAddr)); + + prParamNetAddrList->u4AddressCount = 0; + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + + ASSERT(u4Len <= sizeof(g_aucBufIpAddr /*aucBuf */)); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetP2pSetNetworkAddress, + (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, TRUE, &u4SetInfoLen); + + DBGLOG(INIT, INFO, "IP: %d.%d.%d.%d, rStatus: %u\n", ip[0], ip[1], ip[2], ip[3], rStatus); + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* run p2p init procedure, include register pointer to wlan +* glue register p2p +* set p2p registered flag +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo) +{ + + DBGLOG(P2P, TRACE, "p2pLaunch\n"); + + if (prGlueInfo->prAdapter->fgIsP2PRegistered == TRUE) { + DBGLOG(P2P, INFO, "p2p already registered\n"); + return FALSE; + } else if (glRegisterP2P(prGlueInfo, ifname, (BOOLEAN) mode)) { + prGlueInfo->prAdapter->fgIsP2PRegistered = TRUE; + + DBGLOG(P2P, TRACE, "Launch success, fgIsP2PRegistered TRUE.\n"); + return TRUE; + } + DBGLOG(P2P, ERROR, "Launch Fail\n"); + + return FALSE; +} + +VOID p2pSetMode(IN BOOLEAN fgIsAPMOde) +{ + if (fgIsAPMOde) { + mode = RUNNING_AP_MODE; + ifname = AP_MODE_INF_NAME; + } else { + mode = RUNNING_P2P_MODE; + ifname = P2P_MODE_INF_NAME; + } + +} /* p2pSetMode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* run p2p exit procedure, include unregister pointer to wlan +* glue unregister p2p +* set p2p registered flag + +* \retval 1 Success +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo) +{ + if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) { + DBGLOG(P2P, INFO, "p2p is not Registered.\n"); + return FALSE; + } + /*Check p2p fsm is stop or not. If not then stop now */ + if (IS_P2P_ACTIVE(prGlueInfo->prAdapter)) + p2pStopImmediate(prGlueInfo); + prGlueInfo->prAdapter->fgIsP2PRegistered = FALSE; + glUnregisterP2P(prGlueInfo); + /*p2p is removed successfully */ + return TRUE; + +} + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver entry point when the driver is configured as a Linux Module, and +* is called once at module load time, by the user-level modutils +* application: insmod or modprobe. +* +* \retval 0 Success +*/ +/*----------------------------------------------------------------------------*/ +static int initP2P(void) +{ + P_GLUE_INFO_T prGlueInfo; + + /*check interface name validation */ + p2pCheckInterfaceName(); + + DBGLOG(P2P, INFO, "InitP2P, Ifname: %s, Mode: %s\n", ifname, mode ? "AP" : "P2P"); + + /*register p2p init & exit function to wlan sub module handler */ + wlanSubModRegisterInitExit(p2pLaunch, p2pRemove, P2P_MODULE); + + /*if wlan is not start yet, do nothing + * p2pLaunch will be called by txthread while wlan start + */ + /*if wlan is not started yet, return FALSE */ + if (wlanExportGlueInfo(&prGlueInfo)) { + wlanSubModInit(prGlueInfo); + return prGlueInfo->prAdapter->fgIsP2PRegistered ? 0 : -EIO; + } + + return 0; +} /* end of initP2P() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Driver exit point when the driver as a Linux Module is removed. Called +* at module unload time, by the user level modutils application: rmmod. +* This is our last chance to clean up after ourselves. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +/* 1 Module Leave Point */ +static VOID __exit exitP2P(void) +{ + P_GLUE_INFO_T prGlueInfo; + + DBGLOG(P2P, INFO, KERN_INFO DRV_NAME "ExitP2P\n"); + + /*if wlan is not started yet, return FALSE */ + if (wlanExportGlueInfo(&prGlueInfo)) + wlanSubModExit(prGlueInfo); + /*UNregister p2p init & exit function to wlan sub module handler */ + wlanSubModRegisterInitExit(NULL, NULL, P2P_MODULE); +} /* end of exitP2P() */ +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c new file mode 100644 index 0000000000000..11a417e4c74c9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_p2p_kal.c @@ -0,0 +1,1314 @@ +/* +** Id: @(#) gl_p2p_cfg80211.c@@ +*/ + +/*! \file gl_p2p_kal.c + \brief + +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "net/cfg80211.h" +#include "precomp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Wi-Fi Direct state from glue layer +* +* \param[in] +* prGlueInfo +* rPeerAddr +* \return +* ENUM_BOW_DEVICE_STATE +*/ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->eState; +} /* end of kalP2PGetState() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to update the assoc req to p2p +* +* \param[in] +* prGlueInfo +* pucFrameBody +* u4FrameBodyLen +* fgReassocRequest +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) +{ + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; + unsigned char *pucDesiredIE = NULL; +/* unsigned char aucExtraInfoBuf[200]; */ + PUINT_8 cp; + + memset(&wrqu, 0, sizeof(wrqu)); + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } else { + if (u4FrameBodyLen < 9) { + /* + printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2 */ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } else { + /* Capability information field 2 */ + /* Listen interval field 2 */ + cp += 4; + u4FrameBodyLen -= 4; + } + + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPSIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + /* printk("wextSrchDesiredWPSIE!!\n"); */ + /* WPS IE found */ + } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0x30, &pucDesiredIE)) { + /* printk("wextSrchDesiredWPAIE!!\n"); */ + /* RSN IE found */ + } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + /* printk("wextSrchDesiredWPAIE!!\n"); */ + /* WPA IE found */ + } else { + /* no WPA/RSN IE found, skip this event */ + goto skip_indicate_event; + } + + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; + + /* Send event to user space */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVASSOCREQIE, &wrqu, pucExtraInfo); + +skip_indicate_event: + return; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Wi-Fi Direct state in glue layer +* +* \param[in] +* prGlueInfo +* eBowState +* rPeerAddr +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + if (eState == PARAM_MEDIA_STATE_CONNECTED) { + prGlueInfo->prP2PInfo->eState = PARAM_MEDIA_STATE_CONNECTED; + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_CONNECT=%pM ", rPeerAddr); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + + } else if (eState == PARAM_MEDIA_STATE_DISCONNECTED) { + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_STA_DISCONNECT=%pM ", rPeerAddr); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + } else { + ASSERT(0); + } + +} /* end of kalP2PSetState() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Wi-Fi Direct operating frequency +* +* \param[in] +* prGlueInfo +* +* \return +* in unit of KHz +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->u4FreqInKHz; +} /* end of kalP2PGetFreqInKHz() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to retrieve Bluetooth-over-Wi-Fi role +* +* \param[in] +* prGlueInfo +* +* \return +* 0: P2P Device +* 1: Group Client +* 2: Group Owner +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo->ucRole; +} /* end of kalP2PGetRole() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set Wi-Fi Direct role +* +* \param[in] +* prGlueInfo +* ucResult +* 0: successful +* 1: error +* ucRole +* 0: P2P Device +* 1: Group Client +* 2: Group Owner +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + ASSERT(ucRole <= 2); + + memset(&evt, 0, sizeof(evt)); + + if (ucResult == 0) + prGlueInfo->prP2PInfo->ucRole = ucRole; + + if (pucSSID) + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, + 1 /* persistence or not */ , pucSSID[7], pucSSID[8]); + else + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_FORMATION_RST=%d%d%d%c%c", ucResult, ucRole, + 1 /* persistence or not */ , '0', '0'); + + evt.data.length = strlen(aucBuffer); + + /* if (pucSSID) */ + /* printk("P2P GO SSID DIRECT-%c%c\n", pucSSID[7], pucSSID[8]); */ + + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* end of kalP2PSetRole() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set the cipher for p2p +* +* \param[in] +* prGlueInfo +* u4Cipher +* +* \return +* none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return; + } + + prGlueInfo->prP2PInfo->u4CipherPairwise = u4Cipher; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the cipher, return for cipher is ccmp +* +* \param[in] +* prGlueInfo +* +* \return +* TRUE: cipher is ccmp +* FALSE: cipher is none +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return FALSE; + } + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return TRUE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return TRUE; + + return FALSE; +} + +BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return FALSE; + } + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return TRUE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return FALSE; + + return FALSE; +} + +BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return FALSE; + } + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_CCMP) + return FALSE; + + if (prGlueInfo->prP2PInfo->u4CipherPairwise == IW_AUTH_CIPHER_TKIP) + return TRUE; + + return FALSE; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set the status of WSC +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return; + } + + prGlueInfo->prP2PInfo->ucWSCRunning = ucWscMode; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the status of WSC +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return 0; + } + + return prGlueInfo->prP2PInfo->ucWSCRunning; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to get the wsc ie length +* +* \param[in] +* prGlueInfo +* ucType : 0 for beacon, 1 for probe req, 2 for probe resp +* +* \return +* The WSC IE length +*/ +/*----------------------------------------------------------------------------*/ +UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType) +{ + ASSERT(prGlueInfo); + + ASSERT(ucType < 3); + + return prGlueInfo->prP2PInfo->u2WSCIELen[ucType]; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to copy the wsc ie setting from p2p supplicant +* +* \param[in] +* prGlueInfo +* +* \return +* The WPS IE length +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; + + do { + if ((prGlueInfo == NULL) || (ucType >= 3) || (pucBuffer == NULL)) + break; + + prGlP2pInfo = prGlueInfo->prP2PInfo; + + kalMemCopy(pucBuffer, prGlP2pInfo->aucWSCIE[ucType], prGlP2pInfo->u2WSCIELen[ucType]); + + } while (FALSE); + +} + +VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T) NULL; + + do { + if ((prGlueInfo == NULL) || (ucType >= 3) || ((u2BufferLength > 0) && (pucBuffer == NULL))) + break; + + if (u2BufferLength > 400) { + DBGLOG(P2P, ERROR, + "Buffer length is not enough, GLUE only 400 bytes but %d received\n", u2BufferLength); + ASSERT(FALSE); + break; + } + + prGlP2pInfo = prGlueInfo->prP2PInfo; + + kalMemCopy(prGlP2pInfo->aucWSCIE[ucType], pucBuffer, u2BufferLength); + + prGlP2pInfo->u2WSCIELen[ucType] = u2BufferLength; + + } while (FALSE); + +} /* kalP2PUpdateWSC_IE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief indicate an event to supplicant for device connection request +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, + IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ + IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_REQ_DEVICE_INFO access */ + prGlueInfo->prP2PInfo->u4ConnReqNameLength = u4NameLength > 32 ? 32 : u4NameLength; + kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, pucDevName, prGlueInfo->prP2PInfo->u4ConnReqNameLength); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, rPeerAddr); + prGlueInfo->prP2PInfo->ucConnReqDevType = ucDevType; + prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = i4ConfigMethod; + prGlueInfo->prP2PInfo->i4ConnReqActiveConfigMethod = i4ActiveConfigMethod; + + /* prepare event structure */ + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_DVC_REQ"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* end of kalP2PIndicateConnReq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for device connection request from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* \param[in] pucGroupBssid Only valid when invitation Type equals to 0. +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_DEVICE_DESC_T prP2pDevDesc, + IN PUINT_8 pucSsid, + IN UINT_8 ucSsidLen, + IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid) +{ +#if 1 + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_STRUCT access */ + prGlueInfo->prP2PInfo->u4ConnReqNameLength = + (UINT_32) ((prP2pDevDesc->u2NameLength > 32) ? 32 : prP2pDevDesc->u2NameLength); + kalMemCopy(prGlueInfo->prP2PInfo->aucConnReqDevName, prP2pDevDesc->aucName, + prGlueInfo->prP2PInfo->u4ConnReqNameLength); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqPeerAddr, prP2pDevDesc->aucDeviceAddr); + COPY_MAC_ADDR(prGlueInfo->prP2PInfo->rConnReqGroupAddr, pucGroupBssid); + prGlueInfo->prP2PInfo->i4ConnReqConfigMethod = (INT_32) (prP2pDevDesc->u2ConfigMethod); + prGlueInfo->prP2PInfo->ucOperatingChnl = ucOperatingChnl; + prGlueInfo->prP2PInfo->ucInvitationType = ucInvitationType; + + /* prepare event structure */ + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_INDICATE"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + return; + +#else + P_MSG_P2P_CONNECTION_REQUEST_T prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = (P_P2P_CONNECTION_SETTINGS_T) NULL; + + do { + ASSERT_BREAK((prGlueInfo != NULL) && (prP2pDevDesc != NULL)); + + /* Not a real solution */ + + prP2pSpecificBssInfo = prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo; + prP2pConnSettings = prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; + + prP2pConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T) cnmMemAlloc(prGlueInfo->prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + if (prP2pConnReq == NULL) + break; + + kalMemZero(prP2pConnReq, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + + prP2pConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + prP2pConnReq->eFormationPolicy = ENUM_P2P_FORMATION_POLICY_AUTO; + + COPY_MAC_ADDR(prP2pConnReq->aucDeviceID, prP2pDevDesc->aucDeviceAddr); + + prP2pConnReq->u2ConfigMethod = prP2pDevDesc->u2ConfigMethod; + + if (ucInvitationType == P2P_INVITATION_TYPE_INVITATION) { + prP2pConnReq->fgIsPersistentGroup = FALSE; + prP2pConnReq->fgIsTobeGO = FALSE; + + } + + else if (ucInvitationType == P2P_INVITATION_TYPE_REINVOKE) { + DBGLOG(P2P, TRACE, "Re-invoke Persistent Group\n"); + prP2pConnReq->fgIsPersistentGroup = TRUE; + prP2pConnReq->fgIsTobeGO = (prGlueInfo->prP2PInfo->ucRole == 2) ? TRUE : FALSE; + + } + + p2pFsmRunEventDeviceDiscoveryAbort(prGlueInfo->prAdapter, NULL); + + if (ucOperatingChnl != 0) + prP2pSpecificBssInfo->ucPreferredChannel = ucOperatingChnl; + + if ((ucSsidLen < 32) && (pucSsid != NULL)) + COPY_SSID(prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen, pucSsid, ucSsidLen); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pConnReq, MSG_SEND_METHOD_BUF); + + } while (FALSE); + + /* frog add. */ + /* TODO: Invitation Indication */ + + return; +#endif + +} /* kalP2PInvitationIndication */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an status to supplicant for device invitation status. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + /* buffer peer information for later IOC_P2P_GET_STRUCT access */ + prGlueInfo->prP2PInfo->u4InvStatus = u4InvStatus; + + /* prepare event structure */ + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_INV_STATUS"); + evt.data.length = strlen(aucBuffer); + + /* indicate in IWEVCUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* kalP2PInvitationStatus */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery request from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_REQ %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* end of kalP2PIndicateSDRequest() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery response +* from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_RESP %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* end of kalP2PIndicateSDResponse() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Indicate an event to supplicant for Service Discovery TX Done +* from other device. +* +* \param[in] prGlueInfo Pointer of GLUE_INFO_T +* \param[in] ucSeqNum Sequence number of the frame +* \param[in] ucStatus Status code for TX +* +* \retval none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_XMITTED: %d %d", ucSeqNum, ucStatus); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); + +} /* end of kalP2PIndicateSDResponse() */ + +struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return NULL; + } + + return prGlueInfo->prP2PInfo->prDevHandler; +} + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen) +{ + union iwreq_data evt; + UINT_8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SEC_CHECK_RSP="); + + kalMemCopy(prGlueInfo->prP2PInfo->aucSecCheckRsp, pucRsp, u2RspLen); + evt.data.length = strlen(aucBuffer); + +#if DBG + DBGLOG_MEM8(SEC, LOUD, prGlueInfo->prP2PInfo->aucSecCheckRsp, u2RspLen); +#endif + /* indicate in IWECUSTOM event */ + wireless_send_event(prGlueInfo->prP2PInfo->prDevHandler, IWEVCUSTOM, &evt, aucBuffer); +} /* p2pFsmRunEventRxDisassociation */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief +* +* \param[in] prAdapter Pointer of ADAPTER_T +* +* \return none +*/ +/*----------------------------------------------------------------------------*/ +VOID +kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, FALSE, ucMaxChannelNum, + pucNumOfChannel, paucChannelList); +} /* kalGetChnlList */ + +/* ////////////////////////////////////ICS SUPPORT////////////////////////////////////// */ + +VOID +kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8SeqNum, + IN UINT_32 u4ChannelNum, + IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration) +{ + struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; + RF_CHANNEL_INFO_T rChannelInfo; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + + do { + if (prGlueInfo == NULL) + break; + + kalMemZero(&rChannelInfo, sizeof(RF_CHANNEL_INFO_T)); + + rChannelInfo.ucChannelNum = u4ChannelNum; + rChannelInfo.eBand = eBand; + + prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueInfo->prP2PInfo, &rChannelInfo); + + kalP2pFuncGetChannelType(eSco, &eChnlType); + + cfg80211_ready_on_channel(prGlueInfo->prP2PInfo->prWdev, /* struct wireless_dev, */ + u8SeqNum, /* u64 cookie, */ + prIEEE80211ChnlStruct, /* struct ieee80211_channel * chan, */ + u4Duration, /* unsigned int duration, */ + GFP_KERNEL); /* gfp_t gfp */ /* allocation flags */ + } while (FALSE); + +} /* kalP2PIndicateChannelReady */ + +VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + struct ieee80211_channel *prIEEE80211ChnlStruct = (struct ieee80211_channel *)NULL; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + RF_CHANNEL_INFO_T rRfChannelInfo; + + do { + if ((prGlueInfo == NULL) || (prChnlReqInfo == NULL)) { + + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + DBGLOG(P2P, TRACE, "kalP2PIndicateChannelExpired\n"); + + rRfChannelInfo.eBand = prChnlReqInfo->eBand; + rRfChannelInfo.ucChannelNum = prChnlReqInfo->ucReqChnlNum; + + prIEEE80211ChnlStruct = kalP2pFuncGetChannelEntry(prGlueP2pInfo, &rRfChannelInfo); + + kalP2pFuncGetChannelType(prChnlReqInfo->eChnlSco, &eChnlType); + + cfg80211_remain_on_channel_expired(prGlueP2pInfo->prWdev, /* struct wireless_dev, */ + prChnlReqInfo->u8Cookie, prIEEE80211ChnlStruct, GFP_KERNEL); + } while (FALSE); + +} /* kalP2PIndicateChannelExpired */ + +VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + struct cfg80211_scan_request *prScanRequest = NULL; + struct cfg80211_scan_info info = { + .aborted = true, + }; + + GLUE_SPIN_LOCK_DECLARATION(); + + do { + if (prGlueInfo == NULL) { + + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + DBGLOG(INIT, TRACE, "[p2p] scan complete %p\n", prGlueP2pInfo->prScanRequest); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueP2pInfo->prScanRequest != NULL) { + prScanRequest = prGlueP2pInfo->prScanRequest; + prGlueP2pInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + /* 2. then CFG80211 Indication */ + + if (prScanRequest != NULL) { + + /* report all queued beacon/probe response frames to upper layer */ + scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_P2P_DEVICE, NULL); + + info.aborted = fgIsAbort; + DBGLOG(INIT, TRACE, "DBG:p2p_cfg_scan_done\n"); + cfg80211_scan_done(prScanRequest, &info); + } + + } while (FALSE); + +} /* kalP2PIndicateScanDone */ + +VOID +kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + struct ieee80211_channel *prChannelEntry = (struct ieee80211_channel *)NULL; + struct ieee80211_mgmt *prBcnProbeRspFrame = (struct ieee80211_mgmt *)pucFrameBuf; + struct cfg80211_bss *prCfg80211Bss = (struct cfg80211_bss *)NULL; + + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (prChannelInfo == NULL)) { + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prGlueP2pInfo == NULL) { + ASSERT(FALSE); + break; + } + + prChannelEntry = kalP2pFuncGetChannelEntry(prGlueP2pInfo, prChannelInfo); + + if (prChannelEntry == NULL) { + DBGLOG(P2P, WARN, "Unknown channel info\n"); + break; + } + /* rChannelInfo.center_freq = nicChannelNum2Freq((UINT_32)prChannelInfo->ucChannelNum) / 1000; */ + + prCfg80211Bss = cfg80211_inform_bss_frame(prGlueP2pInfo->prWdev->wiphy, /* struct wiphy * wiphy, */ + prChannelEntry, + prBcnProbeRspFrame, u4BufLen, i4SignalStrength, GFP_KERNEL); + + /* Return this structure. */ + if (!prCfg80211Bss) { + DBGLOG(P2P, WARN, "inform bss to cfg80211 failed, bss channel %d, rcpi %d\n", + prChannelInfo->ucChannelNum, i4SignalStrength); + } else { + cfg80211_put_bss(prGlueP2pInfo->prWdev->wiphy, prCfg80211Bss); + DBGLOG(P2P, TRACE, "inform bss to cfg80211, bss channel %d, rcpi %d\n", + prChannelInfo->ucChannelNum, i4SignalStrength); + } + } while (FALSE); + +} /* kalP2PIndicateBssInfo */ + +VOID +kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || (u4FrameLen == 0)) { + DBGLOG(P2P, TRACE, "Unexpected pointer PARAM. %p, %p, %u.", + prGlueInfo, pucFrameBuf, u4FrameLen); + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + cfg80211_mgmt_tx_status(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ + u8Cookie, pucFrameBuf, u4FrameLen, fgIsAck, GFP_KERNEL); + + } while (FALSE); + +} /* kalP2PIndicateMgmtTxStatus */ + +VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb) +{ +#define DBG_P2P_MGMT_FRAME_INDICATION 0 + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + INT_32 i4Freq = 0; + UINT_8 ucChnlNum = 0; +#if DBG_P2P_MGMT_FRAME_INDICATION + P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T) NULL; +#endif + + do { + if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; + +#if DBG_P2P_MGMT_FRAME_INDICATION + + prWlanHeader = (P_WLAN_MAC_HEADER_T) prSwRfb->pvHeader; + + switch (prWlanHeader->u2FrameCtrl) { + case MAC_FRAME_PROBE_REQ: + DBGLOG(P2P, TRACE, "RX Probe Req at channel %d ", ucChnlNum); + break; + case MAC_FRAME_PROBE_RSP: + DBGLOG(P2P, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); + break; + case MAC_FRAME_ACTION: + DBGLOG(P2P, TRACE, "RX Action frame at channel %d ", ucChnlNum); + break; + default: + DBGLOG(P2P, TRACE, "RX Packet:%d at channel %d ", prWlanHeader->u2FrameCtrl, ucChnlNum); + break; + } + + DBGLOG(P2P, TRACE, "from: %pM\n", prWlanHeader->aucAddr2); +#endif + i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; + + cfg80211_rx_mgmt(prGlueP2pInfo->prWdev, /* struct net_device * dev, */ + i4Freq, + RCPI_TO_dBm(prSwRfb->prHifRxHdr->ucRcpi), + prSwRfb->pvHeader, prSwRfb->u2PacketLen, GFP_ATOMIC); + } while (FALSE); + +} /* kalP2PIndicateRxMgmtFrame */ + +VOID +kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, + IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, + IN WLAN_STATUS eStatus) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; + + do { + if (prGlueInfo == NULL) { + ASSERT(FALSE); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo; + + if (prP2pConnInfo) { + cfg80211_connect_result(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ + prP2pConnInfo->aucBssid, prP2pConnInfo->aucIEBuf, + prP2pConnInfo->u4BufLength, + pucRxIEBuf, u2RxIELen, u2StatusReason, GFP_KERNEL); + /* gfp_t gfp */ /* allocation flags */ + prP2pConnInfo->fgIsConnRequest = FALSE; + } else { + /* Disconnect, what if u2StatusReason == 0? */ + cfg80211_disconnected(prGlueP2pInfo->prDevHandler, /* struct net_device * dev, */ + u2StatusReason, pucRxIEBuf, u2RxIELen, + eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ? true : false, + GFP_KERNEL); + } + + } while (FALSE); + +} /* kalP2PGCIndicateConnectionStatus */ + +VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew) +{ + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T) NULL; + struct station_info rStationInfo; + + memset(&rStationInfo, 0, sizeof(struct station_info)); + + do { + if ((prGlueInfo == NULL) || (prCliStaRec == NULL)) + break; + + prP2pGlueInfo = prGlueInfo->prP2PInfo; + + if (fgIsNew) { + //rStationInfo.filled = STATION_INFO_ASSOC_REQ_IES; + rStationInfo.generation = ++prP2pGlueInfo->i4Generation; + + rStationInfo.assoc_req_ies = prCliStaRec->pucAssocReqIe; + rStationInfo.assoc_req_ies_len = prCliStaRec->u2AssocReqIeLen; +/* rStationInfo.filled |= STATION_INFO_ASSOC_REQ_IES; */ + + cfg80211_new_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ + prCliStaRec->aucMacAddr, &rStationInfo, GFP_KERNEL); + } else { + ++prP2pGlueInfo->i4Generation; + + cfg80211_del_sta(prGlueInfo->prP2PInfo->prDevHandler, /* struct net_device * dev, */ + prCliStaRec->aucMacAddr, GFP_KERNEL); + } + + } while (FALSE); + + return; + +} /* kalP2PGOStationUpdate */ + +BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type) +{ + BOOLEAN fgIsValid = FALSE; + + do { + if (channel_type) { + + switch (rChnlSco) { + case CHNL_EXT_SCN: + *channel_type = NL80211_CHAN_NO_HT; + break; + case CHNL_EXT_SCA: + *channel_type = NL80211_CHAN_HT40MINUS; + break; + case CHNL_EXT_SCB: + *channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + ASSERT(FALSE); + *channel_type = NL80211_CHAN_NO_HT; + break; + } + + } + + fgIsValid = TRUE; + } while (FALSE); + + return fgIsValid; +} /* kalP2pFuncGetChannelType */ + +struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo) +{ + struct ieee80211_channel *prTargetChannelEntry = (struct ieee80211_channel *)NULL; + UINT_32 u4TblSize = 0, u4Idx = 0; + struct ieee80211_supported_band **bands; + + do { + if ((prP2pInfo == NULL) || (prChannelInfo == NULL)) + break; + bands = &prP2pInfo->prWdev->wiphy->bands[0]; + switch (prChannelInfo->eBand) { + case BAND_2G4: + prTargetChannelEntry = bands[NL80211_BAND_2GHZ]->channels; + u4TblSize = bands[NL80211_BAND_2GHZ]->n_channels; + break; + case BAND_5G: + prTargetChannelEntry = bands[NL80211_BAND_5GHZ]->channels; + u4TblSize = bands[NL80211_BAND_5GHZ]->n_channels; + break; + default: + break; + } + + if (prTargetChannelEntry == NULL) + break; + + for (u4Idx = 0; u4Idx < u4TblSize; u4Idx++, prTargetChannelEntry++) { + if (prTargetChannelEntry->hw_value == prChannelInfo->ucChannelNum) + break; + } + + if (u4Idx == u4TblSize) { + prTargetChannelEntry = NULL; + break; + } + + } while (FALSE); + + return prTargetChannelEntry; +} /* kalP2pFuncGetChannelEntry */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to set the block list of Hotspot +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock) +{ + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + UINT_32 i; + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + if (EQUAL_MAC_ADDR(rbssid, aucNullAddr)) + return -EINVAL; + + if (fgIsblock) { + for (i = 0; i < 8; i++) { + if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { + break; + } else if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr)) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid); + break; + } + } + if (i >= 8) { + DBGLOG(P2P, ERROR, "AP black list is full, cannot block more STA!!\n"); + return -ENOBUFS; + } + } else { + for (i = 0; i < 8; i++) { + if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), aucNullAddr); + break; + } + } + if (i >= 8) + DBGLOG(P2P, ERROR, "The STA is not found in black list!!\n"); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to compare the black list of Hotspot +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid) +{ + UINT_8 aucNullAddr[] = NULL_MAC_ADDR; + BOOLEAN fgIsExsit = FALSE; + UINT_32 i; + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo); + + for (i = 0; i < 8; i++) { + if (UNEQUAL_MAC_ADDR(rbssid, aucNullAddr)) { + if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo->aucblackMACList[i]), rbssid)) { + fgIsExsit = TRUE; + return fgIsExsit; + } + } + } + + return fgIsExsit; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to return the max clients of Hotspot +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return; + } + + if (u4MaxClient == 0 || prGlueInfo->prP2PInfo->ucMaxClients >= P2P_MAXIMUM_CLIENT_COUNT) + prGlueInfo->prP2PInfo->ucMaxClients = P2P_MAXIMUM_CLIENT_COUNT; + else + prGlueInfo->prP2PInfo->ucMaxClients = u4MaxClient; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief to return the max clients of Hotspot +* +* \param[in] +* prGlueInfo +* +* \return +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient) +{ + if ((!prGlueInfo) || (!prGlueInfo->prP2PInfo)) { + ASSERT(FALSE); + return FALSE; + } + + if (prGlueInfo->prP2PInfo->ucMaxClients) { + if ((UINT_8) u4NumClient > prGlueInfo->prP2PInfo->ucMaxClients) + return TRUE; + else + return FALSE; + } + + return FALSE; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c new file mode 100644 index 0000000000000..075045f547b7c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_proc.c @@ -0,0 +1,1020 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_proc.c#1 +*/ + +/*! \file "gl_proc.c" + \brief This file defines the interface which can interact with users in /proc fs. + + Detail description. +*/ + +/* +** Log: gl_proc.c + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support +** \main\maintrunk.MT5921\19 2008-09-02 21:08:37 GMT mtk01461 +** Fix the compile error of SPRINTF() +** \main\maintrunk.MT5921\18 2008-08-10 18:48:28 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\17 2008-08-04 16:52:01 GMT mtk01461 +** Add proc dbg print message of DOMAIN_INDEX level +** \main\maintrunk.MT5921\16 2008-07-10 00:45:16 GMT mtk01461 +** Remove the check of MCR offset, we may use the MCR address which is not align to DW boundary or proprietary usage. +** \main\maintrunk.MT5921\15 2008-06-03 20:49:44 GMT mtk01461 +** \main\maintrunk.MT5921\14 2008-06-02 22:56:00 GMT mtk01461 +** Rename some functions for linux proc +** \main\maintrunk.MT5921\13 2008-06-02 20:23:18 GMT mtk01461 +** Revise PROC mcr read / write for supporting TELNET +** \main\maintrunk.MT5921\12 2008-03-28 10:40:25 GMT mtk01461 +** Remove temporary set desired rate in linux proc +** \main\maintrunk.MT5921\11 2008-01-07 15:07:29 GMT mtk01461 +** Add User Update Desired Rate Set for QA in Linux +** \main\maintrunk.MT5921\10 2007-12-11 00:11:14 GMT mtk01461 +** Fix SPIN_LOCK protection +** \main\maintrunk.MT5921\9 2007-12-04 18:07:57 GMT mtk01461 +** Add additional debug category to proc +** \main\maintrunk.MT5921\8 2007-11-02 01:03:23 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** \main\maintrunk.MT5921\7 2007-10-25 18:08:14 GMT mtk01461 +** Add VOIP SCAN Support & Refine Roaming +** Revision 1.3 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.2 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "precomp.h" + +/* #include "wlan_lib.h" */ +/* #include "debug.h" */ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define PROC_WLAN_THERMO "wlanThermo" +#define PROC_DRV_STATUS "status" +#define PROC_RX_STATISTICS "rx_statistics" +#define PROC_TX_STATISTICS "tx_statistics" +#define PROC_DBG_LEVEL_NAME "dbgLevel" +#define PROC_NEED_TX_DONE "TxDoneCfg" +#define PROC_AUTO_PER_CFG "autoPerCfg" +#define PROC_ROOT_NAME "wlan" +#define PROC_CMD_DEBUG_NAME "cmdDebug" + +#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20 +#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN (20*10) +#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 8 + +#define PROC_UID_SHELL 2000 +#define PROC_GID_WIFI 1010 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +/* static UINT_32 u4McrOffset; */ +#if CFG_SUPPORT_THERMO_THROTTLING +static P_GLUE_INFO_T g_prGlueInfo_proc; +#endif +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading MCR register to User Space, the offset of +* the MCR is specified in u4McrOffset. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +#if 0 +static int procMCRRead(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + P_GLUE_INFO_T prGlueInfo; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + UINT_32 u4BufLen; + char *p = page; + UINT_32 u4Count; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(data); + + /* Kevin: Apply PROC read method 1. */ + if (off != 0) + return 0; /* To indicate end of file. */ + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); + + rMcrInfo.u4McrOffset = u4McrOffset; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryMcrRead, + (PVOID)&rMcrInfo, sizeof(rMcrInfo), TRUE, TRUE, TRUE, FALSE, &u4BufLen); + + /* SPRINTF(p, ("MCR (0x%08lxh): 0x%08lx\n", */ + /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData)); */ + + u4Count = (UINT_32) (p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procMCRRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for writing MCR register to HW or update u4McrOffset +* for reading MCR later. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procMCRWrite(struct file *file, const char *buffer, unsigned long count, void *data) +{ + P_GLUE_INFO_T prGlueInfo; + char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ + int i4CopySize; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + UINT_32 u4BufLen; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(data); + + i4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, i4CopySize)) + return 0; + acBuf[i4CopySize] = '\0'; + + if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 2) { + /* NOTE: Sometimes we want to test if bus will still be ok, after accessing + * the MCR which is not align to DW boundary. + */ + /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv((struct net_device *)data)); + + u4McrOffset = rMcrInfo.u4McrOffset; + + /* printk("Write 0x%lx to MCR 0x%04lx\n", */ + /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetMcrWrite, + (PVOID)&rMcrInfo, sizeof(rMcrInfo), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + } + + if (sscanf(acBuf, "0x%lx 0x%lx", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData) == 1) { + /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ + u4McrOffset = rMcrInfo.u4McrOffset; + } + + return count; + +} /* end of procMCRWrite() */ +#endif + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver Status to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procDrvStatusRead(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(data); + + /* Kevin: Apply PROC read method 1. */ + if (off != 0) + return 0; /* To indicate end of file. */ + + SPRINTF(p, ("GLUE LAYER STATUS:")); + SPRINTF(p, ("\n==================")); + + SPRINTF(p, ("\n* Number of Pending Frames: %ld\n", prGlueInfo->u4TxPendingFrameNum)); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryDrvStatusForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32) (p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procDrvStatusRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver RX Statistic Counters to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procRxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(data); + + /* Kevin: Apply PROC read method 1. */ + if (off != 0) + return 0; /* To indicate end of file. */ + + SPRINTF(p, ("RX STATISTICS (Write 1 to clear):")); + SPRINTF(p, ("\n=================================\n")); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryRxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32) (p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procRxStatisticsRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reset Driver RX Statistic Counters. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procRxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ + UINT_32 u4CopySize; + UINT_32 u4ClearCounter; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(data); + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + copy_from_user(acBuf, buffer, u4CopySize); + acBuf[u4CopySize] = '\0'; + + if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { + if (u4ClearCounter == 1) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidSetRxStatisticsForLinuxProc(prGlueInfo->prAdapter); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + } + } + + return count; + +} /* end of procRxStatisticsWrite() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reading Driver TX Statistic Counters to User Space. +* +* \param[in] page Buffer provided by kernel. +* \param[in out] start Start Address to read(3 methods). +* \param[in] off Offset. +* \param[in] count Allowable number to read. +* \param[out] eof End of File indication. +* \param[in] data Pointer to the private data structure. +* +* \return number of characters print to the buffer from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procTxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char *p = page; + UINT_32 u4Count; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(data); + + /* Kevin: Apply PROC read method 1. */ + if (off != 0) + return 0; /* To indicate end of file. */ + + SPRINTF(p, ("TX STATISTICS (Write 1 to clear):")); + SPRINTF(p, ("\n=================================\n")); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidQueryTxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + u4Count += (UINT_32) (p - page); + + *eof = 1; + + return (int)u4Count; + +} /* end of procTxStatisticsRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The PROC function for reset Driver TX Statistic Counters. +* +* \param[in] file pointer to file. +* \param[in] buffer Buffer from user space. +* \param[in] count Number of characters to write +* \param[in] data Pointer to the private data structure. +* +* \return number of characters write from User Space. +*/ +/*----------------------------------------------------------------------------*/ +static int procTxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data) +{ + P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv; + char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ + UINT_32 u4CopySize; + UINT_32 u4ClearCounter; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(data); + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1); + copy_from_user(acBuf, buffer, u4CopySize); + acBuf[u4CopySize] = '\0'; + + if (kstrtoint(acBuf, 10, &u4ClearCounter) == 1) { + if (u4ClearCounter == 1) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + + wlanoidSetTxStatisticsForLinuxProc(prGlueInfo->prAdapter); + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM); + } + } + + return count; + +} /* end of procTxStatisticsWrite() */ +#endif +static struct proc_dir_entry *gprProcRoot; +static UINT_8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = { + "INIT", "HAL", "INTR", "REQ", "TX", "RX", "RFTEST", "EMU", "SW1", "SW2", + "SW3", "SW4", "HEM", "AIS", "RLM", "MEM", "CNM", "RSN", "BSS", "SCN", + "SAA", "AAA", "P2P", "QM", "SEC", "BOW", "WAPI", "ROAMING", "TDLS", "OID", + "NIC" +}; +static UINT_8 aucProcBuf[1536]; +static ssize_t procDbgLevelRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + UINT_8 *temp = &aucProcBuf[0]; + UINT_32 u4CopySize = 0; + UINT_16 i; + UINT_16 u2ModuleNum = 0; + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0) + return 0; + + kalStrCpy(temp, "\nTEMP |LOUD |INFO |TRACE|EVENT|STATE|WARN |ERROR\n" + "bit7 |bit6 |bit5 |bit4 |bit3 |bit2 |bit1 |bit0\n\n" + "Debug Module\tIndex\tLevel\tDebug Module\tIndex\tLevel\n\n"); + temp += kalStrLen(temp); + + u2ModuleNum = (sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0xfe; + for (i = 0; i < u2ModuleNum; i += 2) + SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\tDBG_%s_IDX\t(0x%02x):\t0x%02x\n", + &aucDbModuleName[i][0], i, aucDebugModule[i], + &aucDbModuleName[i+1][0], i+1, aucDebugModule[i+1])); + + if ((sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0x1) + SPRINTF(temp, ("DBG_%s_IDX\t(0x%02x):\t0x%02x\n", + &aucDbModuleName[u2ModuleNum][0], u2ModuleNum, aucDebugModule[u2ModuleNum])); + + u4CopySize = kalStrLen(aucProcBuf); + if (u4CopySize > count) + u4CopySize = count; + if (copy_to_user(buf, aucProcBuf, u4CopySize)) { + kalPrint("copy to user failed\n"); + return -EFAULT; + } + + *f_pos += u4CopySize; + return (ssize_t)u4CopySize; +} + +static ssize_t procDbgLevelWrite(struct file *file, const char *buffer, size_t count, loff_t *data) +{ + UINT_32 u4NewDbgModule, u4NewDbgLevel; + UINT_8 i = 0; + UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); + UINT_8 *temp = &aucProcBuf[0]; + + if (u4CopySize >= count + 1) + u4CopySize = count; + + kalMemSet(aucProcBuf, 0, u4CopySize); + + if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { + kalPrint("error of copy from user\n"); + return -EFAULT; + } + aucProcBuf[u4CopySize] = '\0'; + + while (temp) { + if (sscanf(temp, "0x%x:0x%x", &u4NewDbgModule, &u4NewDbgLevel) != 2) { + kalPrint("debug module and debug level should be one byte in length\n"); + break; + } + if (u4NewDbgModule == 0xFF) { + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = u4NewDbgLevel & DBG_CLASS_MASK; + + break; + } else if (u4NewDbgModule >= DBG_MODULE_NUM) { + kalPrint("debug module index should less than %d\n", DBG_MODULE_NUM); + break; + } + aucDebugModule[u4NewDbgModule] = u4NewDbgLevel & DBG_CLASS_MASK; + temp = kalStrChr(temp, ','); + if (!temp) + break; + temp++; /* skip ',' */ + } + return count; +} + + +static const struct file_operations dbglevel_ops = { + .owner = THIS_MODULE, + .read = procDbgLevelRead, + .write = procDbgLevelWrite, +}; + +static ssize_t procTxDoneCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + UINT_8 *temp = &aucProcBuf[0]; + UINT_32 u4CopySize = 0; + UINT_16 u2TxDoneCfg = 0; + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0) + return 0; + + u2TxDoneCfg = StatsGetCfgTxDone(); + SPRINTF(temp, ("Tx Done Configure:\nARP %d\tDNS %d\nTCP %d\tUDP %d\nEAPOL %d\tDHCP %d\nICMP %d\n", + !!(u2TxDoneCfg & CFG_ARP), !!(u2TxDoneCfg & CFG_DNS), !!(u2TxDoneCfg & CFG_TCP), + !!(u2TxDoneCfg & CFG_UDP), !!(u2TxDoneCfg & CFG_EAPOL), !!(u2TxDoneCfg & CFG_DHCP), + !!(u2TxDoneCfg & CFG_ICMP))); + + u4CopySize = kalStrLen(aucProcBuf); + if (u4CopySize > count) + u4CopySize = count; + if (copy_to_user(buf, aucProcBuf, u4CopySize)) { + kalPrint("copy to user failed\n"); + return -EFAULT; + } + + *f_pos += u4CopySize; + return (ssize_t)u4CopySize; +} + +static ssize_t procTxDoneCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) +{ +#define MODULE_NAME_LENGTH 6 + + UINT_8 i = 0; + UINT_32 u4CopySize = kalStrLen(aucProcBuf);//sizeof(aucProcBuf); + UINT_8 *temp = &aucProcBuf[0]; + UINT_16 u2SetTxDoneCfg = 0; + UINT_16 u2ClsTxDoneCfg = 0; + UINT_8 aucModule[MODULE_NAME_LENGTH]; + UINT_32 u4Enabled; + UINT_8 aucModuleArray[][MODULE_NAME_LENGTH] = {"ARP", "DNS", "TCP", "UDP", "EAPOL", "DHCP", "ICMP"}; + + if (u4CopySize >= count + 1) + u4CopySize = count; + + kalMemSet(aucProcBuf, 0, u4CopySize); + if (copy_from_user(aucProcBuf, buffer, u4CopySize)) { + kalPrint("error of copy from user\n"); + return -EFAULT; + } + aucProcBuf[u4CopySize] = '\0'; + temp = &aucProcBuf[0]; + while (temp) { + /* pick up a string and teminated after meet : */ + if (sscanf(temp, "%s %d", aucModule, &u4Enabled) != 2) { + kalPrint("read param fail, aucModule=%s\n", aucModule); + break; + } + for (i = 0; i < sizeof(aucModuleArray)/MODULE_NAME_LENGTH; i++) { + if (kalStrniCmp(aucModule, aucModuleArray[i], MODULE_NAME_LENGTH) == 0) { + if (u4Enabled) + u2SetTxDoneCfg |= 1 << i; + else + u2ClsTxDoneCfg |= 1 << i; + break; + } + } + temp = kalStrChr(temp, ','); + if (!temp) + break; + temp++; /* skip ',' */ + } + if (u2SetTxDoneCfg) + StatsSetCfgTxDone(u2SetTxDoneCfg, TRUE); + + if (u2ClsTxDoneCfg) + StatsSetCfgTxDone(u2ClsTxDoneCfg, FALSE); + return count; +} + +static const struct file_operations proc_txdone_ops = { + .owner = THIS_MODULE, + .read = procTxDoneCfgRead, + .write = procTxDoneCfgWrite, +}; + +static ssize_t procAutoPerCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + UINT_8 *temp = &aucProcBuf[0]; + UINT_32 u4CopySize = 0; + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0) + return 0; + + SPRINTF(temp, ("Auto Performance Configure:\nperiod\tL1\nL2\tL3\n")); + + u4CopySize = kalStrLen(aucProcBuf); + if (u4CopySize > count) + u4CopySize = count; + if (copy_to_user(buf, aucProcBuf, u4CopySize)) { + kalPrint("copy to user failed\n"); + return -EFAULT; + } + + *f_pos += u4CopySize; + return (ssize_t)u4CopySize; +} + +static ssize_t procAutoPerCfgWrite(struct file *file, const char *buffer, size_t count, loff_t *data) +{ + DBGLOG(INIT, WARN, "%s\n", __func__); + return 0; +} + +static const struct file_operations auto_per_ops = { + .owner = THIS_MODULE, + .read = procAutoPerCfgRead, + .write = procAutoPerCfgWrite, +}; + + +static ssize_t procCmdDebug(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + UINT_32 u4CopySize = 0; + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0) + return 0; + + wlanDumpTcResAndTxedCmd(aucProcBuf, sizeof(aucProcBuf)); + + u4CopySize = kalStrLen(aucProcBuf); + if (u4CopySize > count) + u4CopySize = count; + if (copy_to_user(buf, aucProcBuf, u4CopySize)) { + kalPrint("copy to user failed\n"); + return -EFAULT; + } + + *f_pos += u4CopySize; + return (ssize_t)u4CopySize; +} + +static const struct file_operations proc_CmdDebug_ops = { + .owner = THIS_MODULE, + .read = procCmdDebug, +}; + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function create a PROC fs in linux /proc/net subdirectory. +* +* \param[in] prDev Pointer to the struct net_device. +* \param[in] pucDevName Pointer to the name of net_device. +* +* \return N/A +*/ +/*----------------------------------------------------------------------------*/ + +#if CFG_SUPPORT_THERMO_THROTTLING + +/** + * This function is called then the /proc file is read + * + */ +typedef struct _COEX_BUF1 { + UINT8 buffer[128]; + INT32 availSize; +} COEX_BUF1, *P_COEX_BUF1; + +COEX_BUF1 gCoexBuf1; + +static ssize_t procfile_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + + INT32 retval = 0; + INT32 i_ret = 0; + CHAR *warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; + + if (*f_pos > 0) { + retval = 0; + } else { + /*len = sprintf(page, "%d\n", g_psm_enable); */ +#if 1 + if (gCoexBuf1.availSize <= 0) { + DBGLOG(INIT, WARN, "no data available\n"); + retval = strlen(warn_msg) + 1; + if (count < retval) + retval = count; + i_ret = copy_to_user(buf, warn_msg, retval); + if (i_ret) { + DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + } else +#endif + { + INT32 i = 0; + INT32 len = 0; + CHAR msg_info[128]; + INT32 max_num = 0; + /*we do not check page buffer, because there are only 100 bytes in g_coex_buf, no reason page + buffer is not enough, a bomb is placed here on unexpected condition */ + + DBGLOG(INIT, TRACE, "%d bytes available\n", gCoexBuf1.availSize); + max_num = ((sizeof(msg_info) > count ? sizeof(msg_info) : count) - 1) / 5; + + if (max_num > gCoexBuf1.availSize) + max_num = gCoexBuf1.availSize; + else + DBGLOG(INIT, TRACE, + "round to %d bytes due to local buffer size limitation\n", max_num); + + for (i = 0; i < max_num; i++) + len += sprintf(msg_info + len, "%d", gCoexBuf1.buffer[i]); + + len += sprintf(msg_info + len, "\n"); + retval = len; + + i_ret = copy_to_user(buf, msg_info, retval); + if (i_ret) { + DBGLOG(INIT, ERROR, "copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + } + } + gCoexBuf1.availSize = 0; +err_exit: + + return retval; +} + +#if 1 +typedef INT32 (*WLAN_DEV_DBG_FUNC)(void); +static INT32 wlan_get_thermo_power(void); +static INT32 wlan_get_link_mode(void); + +static const WLAN_DEV_DBG_FUNC wlan_dev_dbg_func[] = { + [0] = wlan_get_thermo_power, + [1] = wlan_get_link_mode, + +}; + +INT32 wlan_get_thermo_power(void) +{ + P_ADAPTER_T prAdapter; + + prAdapter = g_prGlueInfo_proc->prAdapter; + + if (prAdapter->u4AirDelayTotal > 100) + gCoexBuf1.buffer[0] = 100; + else + gCoexBuf1.buffer[0] = prAdapter->u4AirDelayTotal; + gCoexBuf1.availSize = 1; + DBGLOG(RLM, TRACE, "PROC %s thrmo_power(%d)\n", __func__, gCoexBuf1.buffer[0]); + + return 0; +} + +INT32 wlan_get_link_mode(void) +{ + UINT_8 ucLinkMode = 0; + P_ADAPTER_T prAdapter; + BOOLEAN fgIsAPmode; + + prAdapter = g_prGlueInfo_proc->prAdapter; + fgIsAPmode = p2pFuncIsAPMode(prAdapter->rWifiVar.prP2pFsmInfo); + + DBGLOG(RLM, TRACE, "PROC %s AIS(%d)P2P(%d)AP(%d)\n", + __func__, + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState, + prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState, fgIsAPmode); + +#if 1 + + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_AIS_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) + ucLinkMode |= BIT(0); + if (prAdapter->rWifiVar.arBssInfo[NETWORK_TYPE_P2P_INDEX].eConnectionState == PARAM_MEDIA_STATE_CONNECTED) + ucLinkMode |= BIT(1); + if (fgIsAPmode) + ucLinkMode |= BIT(2); + +#endif + gCoexBuf1.buffer[0] = ucLinkMode; + gCoexBuf1.availSize = 1; + + return 0; +} + +static ssize_t procfile_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) +{ + char buf[256]; + char *pBuf; + ULONG len = count; + INT32 x = 0, y = 0, z = 0; + char *pToken = NULL; + char *pDelimiter = " \t"; + INT32 i4Ret = 0; + + if (copy_from_user(gCoexBuf1.buffer, buffer, count)) + return -EFAULT; + /* gCoexBuf1.availSize = count; */ + + /* return gCoexBuf1.availSize; */ +#if 1 + DBGLOG(INIT, TRACE, "write parameter len = %d\n\r", (INT32) len); + if (len >= sizeof(buf)) { + DBGLOG(INIT, ERROR, "input handling fail!\n"); + len = sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = '\0'; + DBGLOG(INIT, TRACE, "write parameter data = %s\n\r", buf); + + pBuf = buf; + pToken = strsep(&pBuf, pDelimiter); + + if (pToken) /* x = NULL != pToken ? simple_strtol(pToken, NULL, 16) : 0; */ + i4Ret = kalkStrtos32(pToken, 16, &x); + if (!i4Ret) + DBGLOG(INIT, TRACE, "x = 0x%x\n", x); + +#if 1 + pToken = strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + i4Ret = kalkStrtos32(pToken, 16, &y); /* y = simple_strtol(pToken, NULL, 16); */ + if (!i4Ret) + DBGLOG(INIT, TRACE, "y = 0x%08x\n\r", y); + } else { + y = 3000; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + y = 0x80000000; + } + + pToken = strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + i4Ret = kalkStrtos32(pToken, 16, &z); /* z = simple_strtol(pToken, NULL, 16); */ + if (!i4Ret) + DBGLOG(INIT, TRACE, "z = 0x%08x\n\r", z); + } else { + z = 10; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + z = 0xffffffff; + } + + DBGLOG(INIT, TRACE, " x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); +#endif + + if (((sizeof(wlan_dev_dbg_func) / sizeof(wlan_dev_dbg_func[0])) > x) && NULL != wlan_dev_dbg_func[x]) + (*wlan_dev_dbg_func[x]) (); + else + DBGLOG(INIT, ERROR, "no handler defined for command id(0x%08x)\n\r", x); +#endif + + /* len = gCoexBuf1.availSize; */ + return len; +} +#endif + static const struct file_operations proc_fops = { + .owner = THIS_MODULE, + .read = procfile_read, + .write = procfile_write, + }; +#endif + +INT_32 procInitFs(VOID) +{ + struct proc_dir_entry *prEntry; + + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + kalPrint("init proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + + /* + * Directory: Root (/proc/net/wlan0) + */ + + gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net); + if (!gprProcRoot) { + kalPrint("gprProcRoot == NULL\n"); + return -ENOENT; + } + proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); + + prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops); + if (prEntry == NULL) { + kalPrint("Unable to create /proc entry dbgLevel\n\r"); + return -1; + } + proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); + + prEntry = proc_create(PROC_NEED_TX_DONE, 0664, gprProcRoot, &proc_txdone_ops); + if (prEntry == NULL) { + kalPrint("Unable to create /proc entry dbgLevel\n\r"); + return -1; + } + proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); + + prEntry = proc_create(PROC_AUTO_PER_CFG, 0664, gprProcRoot, &auto_per_ops); + if (prEntry == NULL) { + kalPrint("Unable to create /proc entry autoPerCfg\n\r"); + return -1; + } + proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); + + return 0; +} /* end of procInitProcfs() */ + +INT_32 procUninitProcFs(VOID) +{ + remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot); + remove_proc_subtree(PROC_ROOT_NAME, init_net.proc_net); + remove_proc_entry(PROC_AUTO_PER_CFG, gprProcRoot); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function clean up a PROC fs created by procInitProcfs(). +* +* \param[in] prDev Pointer to the struct net_device. +* \param[in] pucDevName Pointer to the name of net_device. +* +* \return N/A +*/ +/*----------------------------------------------------------------------------*/ +INT_32 procRemoveProcfs(VOID) +{ + /* remove root directory (proc/net/wlan0) */ + /* remove_proc_entry(pucDevName, init_net.proc_net); */ + remove_proc_entry(PROC_WLAN_THERMO, gprProcRoot); + remove_proc_entry(PROC_CMD_DEBUG_NAME, gprProcRoot); +#if CFG_SUPPORT_THERMO_THROTTLING + g_prGlueInfo_proc = NULL; +#endif + return 0; +} /* end of procRemoveProcfs() */ + +INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo) +{ + struct proc_dir_entry *prEntry; + + DBGLOG(INIT, TRACE, "[%s]\n", __func__); + +#if CFG_SUPPORT_THERMO_THROTTLING + g_prGlueInfo_proc = prGlueInfo; +#endif + + prGlueInfo->pProcRoot = gprProcRoot; + + prEntry = proc_create(PROC_WLAN_THERMO, 0664, gprProcRoot, &proc_fops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r"); + return -1; + } + + prEntry = proc_create(PROC_CMD_DEBUG_NAME, 0444, gprProcRoot, &proc_CmdDebug_ops); + if (prEntry == NULL) { + kalPrint("Unable to create /proc entry dbgLevel\n\r"); + return -1; + } + proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI)); + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c new file mode 100644 index 0000000000000..f97db8a69fd21 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_rst.c @@ -0,0 +1,228 @@ +/* +** Id: @(#) gl_rst.c@@ +*/ + +/*! \file gl_rst.c + \brief Main routines for supporintg MT6620 whole-chip reset mechanism + + This file contains the support routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_rst.c + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 04 22 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * skip power-off handshaking when RESET indication is received. + * + * 04 14 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * 1. add code to put whole-chip resetting trigger when abnormal firmware assertion is detected + * 2. add dummy function for both Win32 and Linux part. + * + * 03 30 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * use netlink unicast instead of broadcast + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include + +#include "precomp.h" +#include "gl_rst.h" + +#if CFG_CHIP_RESET_SUPPORT + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +BOOLEAN fgIsResetting = FALSE; +UINT_32 g_IsNeedDoChipReset = 0; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static RESET_STRUCT_T wifi_rst; + +static void mtk_wifi_reset(struct work_struct *work); + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, + ENUM_WMTDRV_TYPE_T eDstType, + ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for + * 1. register wifi reset callback + * 2. initialize wifi reset work + * + * @param none + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +VOID glResetInit(VOID) +{ +#if (MTK_WCN_SINGLE_MODULE == 0) + /* 1. Register reset callback */ + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_WIFI, (PF_WMT_CB) glResetCallback); +#endif /* MTK_WCN_SINGLE_MODULE */ + + /* 2. Initialize reset work */ + INIT_WORK(&(wifi_rst.rst_work), mtk_wifi_reset); + +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for + * 1. deregister wifi reset callback + * + * @param none + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +VOID glResetUninit(VOID) +{ +#if (MTK_WCN_SINGLE_MODULE == 0) + /* 1. Deregister reset callback */ + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_WIFI); +#endif /* MTK_WCN_SINGLE_MODULE */ + +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is invoked when there is reset messages indicated + * + * @param eSrcType + * eDstType + * eMsgType + * prMsgBody + * u4MsgLength + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +static void *glResetCallback(ENUM_WMTDRV_TYPE_T eSrcType, + ENUM_WMTDRV_TYPE_T eDstType, + ENUM_WMTMSG_TYPE_T eMsgType, void *prMsgBody, unsigned int u4MsgLength) +{ + switch (eMsgType) { + case WMTMSG_TYPE_RESET: + if (u4MsgLength == sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + P_ENUM_WMTRSTMSG_TYPE_T prRstMsg = (P_ENUM_WMTRSTMSG_TYPE_T) prMsgBody; + + switch (*prRstMsg) { + case WMTRSTMSG_RESET_START: + DBGLOG(INIT, WARN, "Whole chip reset start!\n"); + fgIsResetting = TRUE; + wifi_reset_start(); + break; + + case WMTRSTMSG_RESET_END: + DBGLOG(INIT, WARN, "Whole chip reset end!\n"); + fgIsResetting = FALSE; + wifi_rst.rst_data = RESET_SUCCESS; + schedule_work(&(wifi_rst.rst_work)); + break; + + case WMTRSTMSG_RESET_END_FAIL: + DBGLOG(INIT, WARN, "Whole chip reset fail!\n"); + fgIsResetting = FALSE; + wifi_rst.rst_data = RESET_FAIL; + schedule_work(&(wifi_rst.rst_work)); + break; + + default: + break; + } + } + break; + + default: + break; + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for wifi reset + * + * @param skb + * info + * + * @retval 0 + * nonzero + */ +/*----------------------------------------------------------------------------*/ +static void mtk_wifi_reset(struct work_struct *work) +{ + RESET_STRUCT_T *rst = container_of(work, RESET_STRUCT_T, rst_work); + + wifi_reset_end(rst->rst_data); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for generating reset request to WMT + * + * @param None + * + * @retval None + */ +/*----------------------------------------------------------------------------*/ +VOID glSendResetRequest(VOID) +{ + /* WMT thread would trigger whole chip reset itself */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called for checking if connectivity chip is resetting + * + * @param None + * + * @retval TRUE + * FALSE + */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsResetting(VOID) +{ + return fgIsResetting; +} + +#endif /* CFG_CHIP_RESET_SUPPORT */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c new file mode 100644 index 0000000000000..862d011a43df3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_vendor.c @@ -0,0 +1,1220 @@ +/* +** Id: @(#) gl_cfg80211.c@@ +*/ + +/*! \file gl_cfg80211.c + \brief Main routines for supporintg MT6620 cfg80211 control interface + + This file contains the support routines of Linux driver for MediaTek Inc. 802.11 + Wireless LAN Adapters. +*/ + +/* +** Log: gl_cfg80211.c +** +** 09 05 2013 cp.wu +** correct length to pass to wlanoidSetBssid() +** +** 09 04 2013 cp.wu +** fix typo +** +** 09 03 2013 cp.wu +** add path for reassociation +** +** 11 23 2012 yuche.tsai +** [ALPS00398671] [Acer-Tablet] Remove Wi-Fi Direct completely +** Fix bug of WiFi may reboot under user load, when WiFi Direct is removed.. +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 30 2012 chinglan.wang +** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only +** . + * +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include + +#include "gl_os.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include "gl_cfg80211.h" +#include "gl_vendor.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +static struct nla_policy nla_parse_policy[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1] = { + [GSCAN_ATTRIBUTE_NUM_BUCKETS] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BASE_PERIOD] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BUCKETS_BAND] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BUCKET_ID] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BUCKET_PERIOD] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BUCKET_CHANNELS] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_REPORT_THRESHOLD] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_REPORT_EVENTS] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_BSSID] = {.type = NLA_UNSPEC}, + [GSCAN_ATTRIBUTE_RSSI_LOW] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_RSSI_HIGH] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE] = {.type = NLA_U16}, + [GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE] = {.type = NLA_U32}, + [GSCAN_ATTRIBUTE_MIN_BREACHING] = {.type = NLA_U16}, + [GSCAN_ATTRIBUTE_NUM_AP] = {.type = NLA_U16}, + [GSCAN_ATTRIBUTE_HOTLIST_FLUSH] = {.type = NLA_U8}, + [GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH] = {.type = NLA_U8}, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + P_GLUE_INFO_T prGlueInfo; + struct nlattr *attr; + UINT_32 band = 0; + UINT_8 ucNumOfChannel, i, j; + RF_CHANNEL_INFO_T aucChannelList[64]; + UINT_32 num_channels; + wifi_channel channels[64]; + struct sk_buff *skb; + + ASSERT(wiphy && wdev); + if ((data == NULL) || !data_len) + return -EINVAL; + + DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); + + attr = (struct nlattr *)data; + if (attr->nla_type == WIFI_ATTRIBUTE_BAND) + band = nla_get_u32(attr); + + DBGLOG(REQ, INFO, "Get channel list for band: %d\n", band); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + if (!prGlueInfo) + return -EFAULT; + + if (band == 0) { /* 2.4G band */ + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, TRUE, + 64, &ucNumOfChannel, aucChannelList); + } else { /* 5G band */ + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, TRUE, + 64, &ucNumOfChannel, aucChannelList); + } + + kalMemZero(channels, sizeof(channels)); + for (i = 0, j = 0; i < ucNumOfChannel; i++) { + /* We need to report frequency list to HAL */ + channels[j] = nicChannelNum2Freq(aucChannelList[i].ucChannelNum) / 1000; + if (channels[j] == 0) + continue; + else if ((prGlueInfo->prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_TW) && + (channels[j] >= 5180 && channels[j] <= 5260)) { + /* Taiwan NCC has resolution to follow FCC spec to support 5G Band 1/2/3/4 + * (CH36~CH48, CH52~CH64, CH100~CH140, CH149~CH165) + * Filter CH36~CH52 for compatible with some old devices. + */ + continue; + } else { + DBGLOG(REQ, INFO, "channels[%d] = %d\n", j, channels[j]); + j++; + } + } + num_channels = j; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(channels)); + if (!skb) { + DBGLOG(REQ, ERROR, "Allocate skb failed\n"); + return -ENOMEM; + } + + if (unlikely(nla_put_u32(skb, WIFI_ATTRIBUTE_NUM_CHANNELS, num_channels) < 0)) + goto nla_put_failure; + + if (unlikely(nla_put(skb, WIFI_ATTRIBUTE_CHANNEL_LIST, + (sizeof(wifi_channel) * num_channels), channels) < 0)) + goto nla_put_failure; + + return cfg80211_vendor_cmd_reply(skb); + +nla_put_failure: + kfree_skb(skb); + return -EFAULT; +} + +int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + struct nlattr *attr; + UINT_8 country[2] = {0, 0}; + + ASSERT(wiphy && wdev); + if ((data == NULL) || (data_len == 0)) + return -EINVAL; + + DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); + + attr = (struct nlattr *)data; + if (attr->nla_type == WIFI_ATTRIBUTE_COUNTRY_CODE) { + country[0] = *((PUINT_8)nla_data(attr)); + country[1] = *((PUINT_8)nla_data(attr) + 1); + } + + DBGLOG(REQ, INFO, "Set country code: %c%c\n", country[0], country[1]); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + if (!prGlueInfo) + return -EFAULT; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, country, 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Status = -EINVAL; + PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T rGscanCapabilities; + struct sk_buff *skb; + /* UINT_32 u4BufLen; */ + + DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); + + ASSERT(wiphy); + ASSERT(wdev); + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rGscanCapabilities)); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); + return -ENOMEM; + } + + kalMemZero(&rGscanCapabilities, sizeof(rGscanCapabilities)); + + /*rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStatistics, + &rGscanCapabilities, + sizeof(rGscanCapabilities), + TRUE, + TRUE, + TRUE, + FALSE, + &u4BufLen); */ + rGscanCapabilities.max_scan_cache_size = PSCAN_MAX_SCAN_CACHE_SIZE; + rGscanCapabilities.max_scan_buckets = GSCAN_MAX_BUCKETS; + rGscanCapabilities.max_ap_cache_per_scan = PSCAN_MAX_AP_CACHE_PER_SCAN; + rGscanCapabilities.max_rssi_sample_size = 10; + rGscanCapabilities.max_scan_reporting_threshold = GSCAN_MAX_REPORT_THRESHOLD; + rGscanCapabilities.max_hotlist_aps = MAX_HOTLIST_APS; + rGscanCapabilities.max_significant_wifi_change_aps = MAX_SIGNIFICANT_CHANGE_APS; + rGscanCapabilities.max_bssid_history_entries = PSCAN_MAX_AP_CACHE_PER_SCAN * PSCAN_MAX_SCAN_CACHE_SIZE; + + /* NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0); */ + /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_ID, GOOGLE_OUI); */ + /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_SUBCMD, GSCAN_SUBCMD_GET_CAPABILITIES); */ + /*NLA_PUT(skb, GSCAN_ATTRIBUTE_CAPABILITIES, sizeof(rGscanCapabilities), &rGscanCapabilities);*/ + if (unlikely(nla_put(skb, GSCAN_ATTRIBUTE_CAPABILITIES, + sizeof(rGscanCapabilities), &rGscanCapabilities) < 0)) + goto nla_put_failure; + + i4Status = cfg80211_vendor_cmd_reply(skb); + return i4Status; + +nla_put_failure: + kfree_skb(skb); + return i4Status; +} + +int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_GLUE_INFO_T prGlueInfo = NULL; + /* CMD_GSCN_REQ_T rCmdGscnParam; */ + + /* INT_32 i4Status = -EINVAL; */ + P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; + struct nlattr *attr[GSCAN_ATTRIBUTE_REPORT_EVENTS + 1]; + struct nlattr *pbucket, *pchannel; + UINT_32 len_basic, len_bucket, len_channel; + int i, j, k; + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + + prWifiScanCmd = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); + if (!prWifiScanCmd) { + DBGLOG(REQ, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); + return -ENOMEM; + } + + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); + kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_REPORT_EVENTS + 1)); + + nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL); + len_basic = 0; + for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_BASE_PERIOD: + prWifiScanCmd->base_period = nla_get_u32(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_NUM_BUCKETS: + prWifiScanCmd->num_buckets = nla_get_u32(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + DBGLOG(REQ, TRACE, "attr=0x%x, num_buckets=%d nla_len=%d, \r\n", + *(UINT_32 *) attr[k], prWifiScanCmd->num_buckets, attr[k]->nla_len); + break; + } + } + } + pbucket = (struct nlattr *)((UINT_8 *) data + len_basic); + DBGLOG(REQ, TRACE, "+++basic attribute size=%d pbucket=%p\r\n", len_basic, pbucket); + + for (i = 0; i < prWifiScanCmd->num_buckets; i++) { + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)pbucket, + nla_parse_policy,NULL) < 0) + goto nla_put_failure; + len_bucket = 0; + for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_BUCKETS_BAND: + prWifiScanCmd->buckets[i].band = nla_get_u32(attr[k]); + len_bucket += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_BUCKET_ID: + prWifiScanCmd->buckets[i].bucket = nla_get_u32(attr[k]); + len_bucket += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_BUCKET_PERIOD: + prWifiScanCmd->buckets[i].period = nla_get_u32(attr[k]); + len_bucket += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_REPORT_EVENTS: + prWifiScanCmd->buckets[i].report_events = nla_get_u32(attr[k]); + len_bucket += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: + prWifiScanCmd->buckets[i].num_channels = nla_get_u32(attr[k]); + len_bucket += NLA_ALIGN(attr[k]->nla_len); + DBGLOG(REQ, TRACE, "bucket%d: attr=0x%x, num_channels=%d nla_len = %d, \r\n", + i, *(UINT_32 *) attr[k], nla_get_u32(attr[k]), attr[k]->nla_len); + break; + } + } + } + pbucket = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); + /* request.attr_start(i) as nested attribute */ + DBGLOG(REQ, TRACE, "+++pure bucket size=%d pbucket=%p \r\n", len_bucket, pbucket); + pbucket = (struct nlattr *)((UINT_8 *) pbucket + len_bucket); + /* pure bucket payload, not include channels */ + + /*don't need to use nla_parse_nested to parse channels */ + /* the header of channel in bucket i */ + pchannel = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); + for (j = 0; j < prWifiScanCmd->buckets[i].num_channels; j++) { + prWifiScanCmd->buckets[i].channels[j].channel = nla_get_u32(pchannel); + len_channel = NLA_ALIGN(pchannel->nla_len); + DBGLOG(REQ, TRACE, + "attr=0x%x, channel=%d, \r\n", *(UINT_32 *) pchannel, nla_get_u32(pchannel)); + + pchannel = (struct nlattr *)((UINT_8 *) pchannel + len_channel); + } + pbucket = pchannel; + } + + DBGLOG(REQ, TRACE, "base_period=%d, num_buckets=%d, bucket0: %d %d %d %d", + prWifiScanCmd->base_period, prWifiScanCmd->num_buckets, + prWifiScanCmd->buckets[0].bucket, prWifiScanCmd->buckets[0].period, + prWifiScanCmd->buckets[0].band, prWifiScanCmd->buckets[0].report_events); + + DBGLOG(REQ, TRACE, "num_channels=%d, channel0=%d, channel1=%d; num_channels=%d, channel0=%d, channel1=%d", + prWifiScanCmd->buckets[0].num_channels, + prWifiScanCmd->buckets[0].channels[0].channel, prWifiScanCmd->buckets[0].channels[1].channel, + prWifiScanCmd->buckets[1].num_channels, + prWifiScanCmd->buckets[1].channels[0].channel, prWifiScanCmd->buckets[1].channels[1].channel); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetGSCNAParam, + prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + return 0; + +nla_put_failure: + if (prWifiScanCmd != NULL) + kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + return -1; +} + +int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_GLUE_INFO_T prGlueInfo = NULL; + + INT_32 i4Status = -EINVAL; + /*PARAM_WIFI_GSCAN_CMD_PARAMS rWifiScanCmd;*/ + P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd = NULL; + struct nlattr *attr[GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1]; + /* UINT_32 num_scans = 0; */ /* another attribute */ + int k; + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); + /*kalMemZero(&rWifiScanCmd, sizeof(rWifiScanCmd));*/ + prWifiScanCmd = kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); + if (prWifiScanCmd == NULL) + goto nla_put_failure; + kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1)); + + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, + (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) + goto nla_put_failure; + for (k = GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN; k <= GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: + prWifiScanCmd->max_ap_per_scan = nla_get_u32(attr[k]); + break; + case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: + prWifiScanCmd->report_threshold = nla_get_u32(attr[k]); + break; + case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: + prWifiScanCmd->num_scans = nla_get_u32(attr[k]); + break; + } + } + } + DBGLOG(REQ, TRACE, "attr=0x%x, attr2=0x%x ", *(UINT_32 *) attr[GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN], + *(UINT_32 *) attr[GSCAN_ATTRIBUTE_REPORT_THRESHOLD]); + + DBGLOG(REQ, TRACE, "max_ap_per_scan=%d, report_threshold=%d num_scans=%d \r\n", + prWifiScanCmd->max_ap_per_scan, prWifiScanCmd->report_threshold, prWifiScanCmd->num_scans); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetGSCNAConfig, + prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + return 0; + +nla_put_failure: + if (prWifiScanCmd != NULL) + kalMemFree(prWifiScanCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); + return i4Status; +} + +int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + INT_32 i4Status = -EINVAL; + P_PARAM_WIFI_SIGNIFICANT_CHANGE prWifiChangeCmd = NULL; + UINT_8 flush = 0; + /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ + struct nlattr **attr = NULL; + struct nlattr *paplist; + int i, k; + UINT_32 len_basic, len_aplist; + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); + for (i = 0; i < 6; i++) + DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", + *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), + *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); + prWifiChangeCmd = kalMemAlloc(sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE), VIR_MEM_TYPE); + if (prWifiChangeCmd == NULL) + goto nla_put_failure; + kalMemZero(prWifiChangeCmd, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); + attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); + if (attr == NULL) + goto nla_put_failure; + kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, + (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) + goto nla_put_failure; + len_basic = 0; + for (k = GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE; k <= GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: + prWifiChangeCmd->rssi_sample_size = nla_get_u16(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + prWifiChangeCmd->lost_ap_sample_size = nla_get_u16(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_MIN_BREACHING: + prWifiChangeCmd->min_breaching = nla_get_u16(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_NUM_AP: + prWifiChangeCmd->num_ap = nla_get_u16(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", + *(UINT_32 *) attr[k], prWifiChangeCmd->num_ap, attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: + flush = nla_get_u8(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + } + } + } + paplist = (struct nlattr *)((UINT_8 *) data + len_basic); + DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); + + if (paplist->nla_type == GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS) + paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); + + for (i = 0; i < prWifiChangeCmd->num_ap; i++) { + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) + goto nla_put_failure; + paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); + /* request.attr_start(i) as nested attribute */ + len_aplist = 0; + for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_BSSID: + kalMemCopy(prWifiChangeCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + prWifiChangeCmd->ap[i].low = nla_get_u32(attr[k]); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + prWifiChangeCmd->ap[i].high = nla_get_u32(attr[k]); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + } + } + } + if (((i + 1) % 4 == 0) || (i == prWifiChangeCmd->num_ap - 1)) + DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); + else + DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); + paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); + } + + DBGLOG(REQ, TRACE, + "flush=%d, rssi_sample_size=%d lost_ap_sample_size=%d min_breaching=%d", + flush, prWifiChangeCmd->rssi_sample_size, prWifiChangeCmd->lost_ap_sample_size, + prWifiChangeCmd->min_breaching); + DBGLOG(REQ, TRACE, + "ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", + prWifiChangeCmd->ap[0].channel, prWifiChangeCmd->ap[0].low, prWifiChangeCmd->ap[0].high, + prWifiChangeCmd->ap[1].channel, prWifiChangeCmd->ap[1].low, prWifiChangeCmd->ap[1].high); + kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); + kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + return 0; + +nla_put_failure: + if (prWifiChangeCmd) + kalMemFree(prWifiChangeCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_SIGNIFICANT_CHANGE)); + if (attr) + kalMemFree(attr, VIR_MEM_TYPE, + sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + return i4Status; +} + +int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + /*WLAN_STATUS rStatus;*/ + P_GLUE_INFO_T prGlueInfo = NULL; + CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; + + INT_32 i4Status = -EINVAL; + P_PARAM_WIFI_BSSID_HOTLIST prWifiHotlistCmd = NULL; + UINT_8 flush = 0; + /* struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; */ + struct nlattr **attr = NULL; + struct nlattr *paplist; + int i, k; + UINT_32 len_basic, len_aplist; + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); + for (i = 0; i < 5; i++) + DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", + *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), + *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); + prWifiHotlistCmd = kalMemAlloc(sizeof(PARAM_WIFI_BSSID_HOTLIST), VIR_MEM_TYPE); + if (prWifiHotlistCmd == NULL) + goto nla_put_failure; + kalMemZero(prWifiHotlistCmd, sizeof(PARAM_WIFI_BSSID_HOTLIST)); + attr = kalMemAlloc(sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1), VIR_MEM_TYPE); + if (attr == NULL) + goto nla_put_failure; + kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_AP, (struct nlattr *)(data - NLA_HDRLEN), nla_parse_policy,NULL) < 0) + goto nla_put_failure; + len_basic = 0; + for (k = GSCAN_ATTRIBUTE_HOTLIST_FLUSH; k <= GSCAN_ATTRIBUTE_NUM_AP; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: + prWifiHotlistCmd->lost_ap_sample_size = nla_get_u32(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_NUM_AP: + prWifiHotlistCmd->num_ap = nla_get_u16(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d, \r\n", + *(UINT_32 *) attr[k], prWifiHotlistCmd->num_ap, attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: + flush = nla_get_u8(attr[k]); + len_basic += NLA_ALIGN(attr[k]->nla_len); + break; + } + } + } + paplist = (struct nlattr *)((UINT_8 *) data + len_basic); + DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); + + if (paplist->nla_type == GSCAN_ATTRIBUTE_HOTLIST_BSSIDS) + paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); + + for (i = 0; i < prWifiHotlistCmd->num_ap; i++) { + if (nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, nla_parse_policy,NULL) < 0) + goto nla_put_failure; + paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); + /* request.attr_start(i) as nested attribute */ + len_aplist = 0; + for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { + if (attr[k]) { + switch (k) { + case GSCAN_ATTRIBUTE_BSSID: + kalMemCopy(prWifiHotlistCmd->ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_RSSI_LOW: + prWifiHotlistCmd->ap[i].low = nla_get_u32(attr[k]); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + case GSCAN_ATTRIBUTE_RSSI_HIGH: + prWifiHotlistCmd->ap[i].high = nla_get_u32(attr[k]); + len_aplist += NLA_ALIGN(attr[k]->nla_len); + break; + } + } + } + if (((i + 1) % 4 == 0) || (i == prWifiHotlistCmd->num_ap - 1)) + DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); + else + DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d \t", i, len_aplist); + paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); + } + + DBGLOG(REQ, TRACE, + "flush=%d, lost_ap_sample_size=%d, Hotlist:ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", + flush, prWifiHotlistCmd->lost_ap_sample_size, + prWifiHotlistCmd->ap[0].channel, prWifiHotlistCmd->ap[0].low, prWifiHotlistCmd->ap[0].high, + prWifiHotlistCmd->ap[1].channel, prWifiHotlistCmd->ap[1].low, prWifiHotlistCmd->ap[1].high); + + memcpy(&(rCmdPscnAddHotlist.aucMacAddr), &(prWifiHotlistCmd->ap[0].bssid), 6 * sizeof(UINT_8)); + rCmdPscnAddHotlist.ucFlags = (UINT_8) TRUE; + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); + kalMemFree(attr, VIR_MEM_TYPE, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + return 0; + +nla_put_failure: + if (prWifiHotlistCmd) + kalMemFree(prWifiHotlistCmd, VIR_MEM_TYPE, sizeof(PARAM_WIFI_BSSID_HOTLIST)); + if (attr) + kalMemFree(attr, VIR_MEM_TYPE, + sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); + return i4Status; +} + +int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS rWifiScanActionCmd; + + INT_32 i4Status = -EINVAL; + struct nlattr *attr; + UINT_8 gGScanEn = 0; + + static UINT_8 k; /* only for test */ + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", + __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); + + attr = (struct nlattr *)data; + if (attr->nla_type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) + gGScanEn = nla_get_u32(attr); + DBGLOG(REQ, INFO, "gGScanEn=%d, \r\n", gGScanEn); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + if (gGScanEn == TRUE) + rWifiScanActionCmd.ucPscanAct = ENABLE; + else + rWifiScanActionCmd.ucPscanAct = DISABLE; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetGSCNAction, + &rWifiScanActionCmd, + sizeof(PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + /* mtk_cfg80211_vendor_get_scan_results(wiphy, wdev, data, data_len ); */ + + return 0; + + /* only for test */ + if (k % 3 == 1) { + mtk_cfg80211_vendor_event_significant_change_results(wiphy, wdev, NULL, 0); + mtk_cfg80211_vendor_event_hotlist_ap_found(wiphy, wdev, NULL, 0); + mtk_cfg80211_vendor_event_hotlist_ap_lost(wiphy, wdev, NULL, 0); + } + k++; + + return 0; + +nla_put_failure: + return i4Status; +} + +int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + INT_32 i4Status = -EINVAL; + struct nlattr *attr; + UINT_8 gFullScanResultsEn = 0; + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", + __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); + + attr = (struct nlattr *)data; + if (attr->nla_type == GSCAN_ENABLE_FULL_SCAN_RESULTS) + gFullScanResultsEn = nla_get_u32(attr); + DBGLOG(REQ, INFO, "gFullScanResultsEn=%d, \r\n", gFullScanResultsEn); + + return 0; + + /* only for test */ + mtk_cfg80211_vendor_event_complete_scan(wiphy, wdev, WIFI_SCAN_COMPLETE); + mtk_cfg80211_vendor_event_scan_results_available(wiphy, wdev, 4); + if (gFullScanResultsEn == TRUE) + mtk_cfg80211_vendor_event_full_scan_results(wiphy, wdev, NULL, 0); + + return 0; + +nla_put_failure: + return i4Status; +} + +int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + /*WLAN_STATUS rStatus;*/ + UINT_32 u4BufLen; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_WIFI_GSCAN_GET_RESULT_PARAMS rGSscnResultParm; + + INT_32 i4Status = -EINVAL; + struct nlattr *attr; + UINT_32 get_num = 0, real_num = 0; + UINT_8 flush = 0; + /*PARAM_WIFI_GSCAN_RESULT result[4], *pResult; + struct sk_buff *skb;*/ + int i; /*int j;*/ + /*UINT_32 scan_id;*/ + + ASSERT(wiphy); + ASSERT(wdev); + if ((data == NULL) || !data_len) + goto nla_put_failure; + DBGLOG(REQ, TRACE, "%s for vendor command: data_len=%d \r\n", __func__, data_len); + for (i = 0; i < 2; i++) + DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x \r\n", *((UINT_32 *) data + i * 4), + *((UINT_32 *) data + i * 4 + 1), *((UINT_32 *) data + i * 4 + 2), + *((UINT_32 *) data + i * 4 + 3)); + + attr = (struct nlattr *)data; + if (attr->nla_type == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { + get_num = nla_get_u32(attr); + attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); + } + if (attr->nla_type == GSCAN_ATTRIBUTE_FLUSH_RESULTS) { + flush = nla_get_u8(attr); + attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); + } + DBGLOG(REQ, TRACE, "number=%d, flush=%d \r\n", get_num, flush); + + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + real_num = (get_num < PSCAN_MAX_SCAN_CACHE_SIZE) ? get_num : PSCAN_MAX_SCAN_CACHE_SIZE; + get_num = real_num; + +#if 0 /* driver buffer FW results and reports by buffer workaround for FW mismatch with hal results numbers */ + g_GetResultsCmdCnt++; + DBGLOG(REQ, INFO, + "(g_GetResultsCmdCnt [%d], g_GetResultsBufferedCnt [%d]\n", g_GetResultsCmdCnt, + g_GetResultsBufferedCnt); + + BOOLEAN fgIsGetResultFromBuffer = FALSE; + UINT_8 BufferedResultReportIndex = 0; + + if (g_GetResultsBufferedCnt > 0) { + + DBGLOG(REQ, INFO, + "(g_GetResultsBufferedCnt > 0), report buffered results instead of ask from FW\n"); + + /* reply the results to wifi_hal */ + for (i = 0; i < MAX_BUFFERED_GSCN_RESULTS; i++) { + + if (g_arGscanResultsIndicateNumber[i] > 0) { + real_num = g_arGscanResultsIndicateNumber[i]; + get_num = real_num; + g_arGscanResultsIndicateNumber[i] = 0; + fgIsGetResultFromBuffer = TRUE; + BufferedResultReportIndex = i; + break; + } + } + if (i == MAX_BUFFERED_GSCN_RESULTS) + DBGLOG(REQ, TRACE, "all buffered results are invalid, unexpected case \r\n"); + DBGLOG(REQ, TRACE, "BufferedResultReportIndex[%d] i = %d real_num[%d] get_num[%d] \r\n", + BufferedResultReportIndex, i, real_num, get_num); + } +#endif + + rGSscnResultParm.get_num = get_num; + rGSscnResultParm.flush = flush; +#if 0/* //driver buffer FW results and reports by buffer workaround for FW results mismatch with hal results number */ + if (fgIsGetResultFromBuffer) { + nicRxProcessGSCNEvent(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); + g_GetResultsBufferedCnt--; + g_GetResultsCmdCnt--; + nicRxReturnRFB(prGlueInfo->prAdapter, g_arGscnResultsTempBuffer[BufferedResultReportIndex]); + } else +#endif + { + kalIoctl(prGlueInfo, + wlanoidGetGSCNResult, + &rGSscnResultParm, + sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + } + return 0; + +nla_put_failure: + return i4Status; +} + +int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4Status = -EINVAL; + PARAM_WIFI_RTT_CAPABILITIES rRttCapabilities; + struct sk_buff *skb; + + DBGLOG(REQ, TRACE, "%s for vendor command \r\n", __func__); + + ASSERT(wiphy); + ASSERT(wdev); + prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rRttCapabilities)); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); + return -ENOMEM; + } + + kalMemZero(&rRttCapabilities, sizeof(rRttCapabilities)); + + /*rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStatistics, + &rRttCapabilities, + sizeof(rRttCapabilities), + TRUE, + TRUE, + TRUE, + FALSE, + &u4BufLen); */ + rRttCapabilities.rtt_one_sided_supported = 0; + rRttCapabilities.rtt_ftm_supported = 0; + rRttCapabilities.lci_support = 0; + rRttCapabilities.lcr_support = 0; + rRttCapabilities.preamble_support = 0; + rRttCapabilities.bw_support = 0; + + if (unlikely(nla_put(skb, RTT_ATTRIBUTE_CAPABILITIES, + sizeof(rRttCapabilities), &rRttCapabilities) < 0)) + goto nla_put_failure; + + i4Status = cfg80211_vendor_cmd_reply(skb); + return i4Status; + +nla_put_failure: + kfree_skb(skb); + return i4Status; +} + +int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) +{ + INT_32 i4Status = -EINVAL; + WIFI_RADIO_STAT *pRadioStat; + struct sk_buff *skb; + UINT_32 u4BufLen; + + ASSERT(wiphy); + ASSERT(wdev); + + u4BufLen = sizeof(WIFI_RADIO_STAT) + sizeof(WIFI_IFACE_STAT); + pRadioStat = kalMemAlloc(u4BufLen, VIR_MEM_TYPE); + if (!pRadioStat) { + DBGLOG(REQ, ERROR, "%s kalMemAlloc pRadioStat failed\n", __func__); + return -ENOMEM; + } + kalMemZero(pRadioStat, u4BufLen); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, u4BufLen); + if (!skb) { + DBGLOG(REQ, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); + return -ENOMEM; + } + + /*rStatus = kalIoctl(prGlueInfo, + wlanoidQueryStatistics, + &rRadioStat, + sizeof(rRadioStat), + TRUE, + TRUE, + TRUE, + FALSE, + &u4BufLen); */ + /* only for test */ + pRadioStat->radio = 10; + pRadioStat->on_time = 11; + pRadioStat->tx_time = 12; + pRadioStat->num_channels = 4; + + /*NLA_PUT(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat);*/ + if (unlikely(nla_put(skb, LSTATS_ATTRIBUTE_STATS, u4BufLen, pRadioStat) < 0)) + goto nla_put_failure; + + i4Status = cfg80211_vendor_cmd_reply(skb); + kalMemFree(pRadioStat, VIR_MEM_TYPE, u4BufLen); + return -1; /* not support LLS now*/ + /* return i4Status; */ + +nla_put_failure: + kfree_skb(skb); + return i4Status; +} + +int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete) +{ + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(wdev); + /* WIFI_SCAN_EVENT complete_scan; */ + + DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(complete), GSCAN_EVENT_COMPLETE_SCAN, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + /* complete_scan = WIFI_SCAN_COMPLETE; */ + /*NLA_PUT_U32(skb, GSCAN_EVENT_COMPLETE_SCAN, complete);*/ + { + unsigned int __tmp = complete; + + if (unlikely(nla_put(skb, GSCAN_EVENT_COMPLETE_SCAN, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} + +int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num) +{ + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(wdev); + /* UINT_32 scan_result; */ + + DBGLOG(REQ, INFO, "%s for vendor command %d \r\n", __func__, num); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(num), GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + /* scan_result = 2; */ + /*NLA_PUT_U32(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, num);*/ + { + unsigned int __tmp = num; + + if (unlikely(nla_put(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, + sizeof(unsigned int), &__tmp) < 0)) + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} + +int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) +{ + struct sk_buff *skb; + PARAM_WIFI_GSCAN_RESULT result; + + ASSERT(wiphy); + ASSERT(wdev); + DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(result), GSCAN_EVENT_FULL_SCAN_RESULTS, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + + kalMemZero(&result, sizeof(result)); + kalMemCopy(result.ssid, "Gscan_full_test", sizeof("Gscan_full_test")); + result.channel = 2437; + + /* kalMemCopy(&result, pdata, sizeof(PARAM_WIFI_GSCAN_RESULT); */ + /*NLA_PUT(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, sizeof(result), &result);*/ + if (unlikely(nla_put(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, + sizeof(result), &result) < 0)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} + +int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len) +{ + struct sk_buff *skb; + PARAM_WIFI_CHANGE_RESULT result[2], *presult; + + ASSERT(wiphy); + ASSERT(wdev); + DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_CHANGE_RESULT), + GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + + presult = result; + kalMemZero(presult, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2)); + /* only for test */ + kalMemCopy(presult->bssid, "213123", sizeof(mac_addr)); + presult->channel = 2437; + presult->rssi[0] = -45; + presult->rssi[1] = -46; + presult++; + presult->channel = 2439; + presult->rssi[0] = -47; + presult->rssi[1] = -48; + /*NLA_PUT(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result);*/ + if (unlikely(nla_put(skb, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, + (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2), result) < 0)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} + +int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) +{ + struct sk_buff *skb; + PARAM_WIFI_GSCAN_RESULT result[2], *presult; + + ASSERT(wiphy); + ASSERT(wdev); + DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), + GSCAN_EVENT_HOTLIST_RESULTS_FOUND, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + + presult = result; + kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); + /* only for test */ + kalMemCopy(presult->bssid, "123123", sizeof(mac_addr)); + presult->channel = 2441; + presult->rssi = -45; + presult++; + presult->channel = 2443; + presult->rssi = -47; + /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ + if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_FOUND, + (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} + +int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) +{ + struct sk_buff *skb; + PARAM_WIFI_GSCAN_RESULT result[2], *presult; + + ASSERT(wiphy); + ASSERT(wdev); + DBGLOG(REQ, INFO, "%s for vendor command \r\n", __func__); + + skb = cfg80211_vendor_event_alloc(wiphy, wdev, sizeof(PARAM_WIFI_GSCAN_RESULT), + GSCAN_EVENT_HOTLIST_RESULTS_LOST, GFP_KERNEL); + if (!skb) { + DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); + return -ENOMEM; + } + + presult = result; + kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); + /* only for test */ + kalMemCopy(presult->bssid, "321321", sizeof(mac_addr)); + presult->channel = 2445; + presult->rssi = -46; + presult++; + presult->channel = 2447; + presult->rssi = -48; + /*NLA_PUT(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result);*/ + if (unlikely(nla_put(skb, GSCAN_EVENT_HOTLIST_RESULTS_LOST, + (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2), result) < 0)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -1; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c new file mode 100644 index 0000000000000..1793742e98022 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext.c @@ -0,0 +1,4158 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext.c#3 +*/ + +/*! \file gl_wext.c + \brief ioctl() (mostly Linux Wireless Extensions) routines for STA driver. +*/ + +/* +** Log: gl_wext.c + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 01 16 2012 wh.su + * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl + * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 23 2011 tsaiyuan.hsu + * [WCXRP00000979] [MT6620 Wi-Fi][DRV]] stop attempting to connect to config AP after D3 state + * avoid entering D3 state after deep sleep. + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 27 2011 wh.su + * [WCXRP00000877] [MT6620 Wi-Fi][Driver] Remove the netif_carry_ok check for avoid the wpa_supplicant fail to query + * the ap address + * Remove the netif check while query bssid and ssid + * + * 07 26 2011 chinglan.wang + * NULL + * [MT6620][WiFi Driver] Do not include the WSC IE in the association info packet when not do the wps connection.. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 05 17 2011 eddie.chen + * [WCXRP00000603] [MT6620 Wi-Fi][DRV] Fix Klocwork warning + * Initialize the vairlabes. + * + * 05 11 2011 jeffrey.chang + * [WCXRP00000718] [MT6620 Wi-Fi] modify the behavior of setting tx power + * modify set_tx_pow ioctl + * + * 03 29 2011 terry.wu + * [WCXRP00000610] [MT 6620 Wi-Fi][Driver] Fix klocwork waring + * [MT6620 Wi-Fi][Driver] Fix klocwork warning. Add Null pointer check on wext_get_essid. Limit the upper bound of + * essid storage array. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * improve portability for awareness of early version of linux kernel and wireless extension. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 02 21 2011 wh.su + * [WCXRP00000483] [MT6620 Wi-Fi][Driver] Check the kalIoctl return value before doing the memory copy at linux get + * essid + * fixed the potential error to do a larget memory copy while wlanoid get essid not actually running. + * + * 02 08 2011 george.huang + * [WCXRP00000422] [MT6620 Wi-Fi][Driver] support query power mode OID handler + * Support querying power mode OID. + * + * 01 29 2011 wh.su + * [WCXRP00000408] [MT6620 Wi-Fi][Driver] Not doing memory alloc while ioctl set ie with length 0 + * not doing mem alloc. while set ie length already 0 + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Remove debug text. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Adjust OID order. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish + * successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. . + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous types + * to ease slab system pressure + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Support set PS profile and set WMM-PS related iwpriv. + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Allow change PS profile function (through wext_set_power()). + * + * 12 14 2010 jeffrey.chang + * [WCXRP00000262] [MT6620 Wi-Fi][Driver] modify the scan request ioctl to handle hidden SSID + * handle hidden SSID + * + * 12 13 2010 chinglan.wang + * NULL + * Add WPS 1.0 feature flag to enable the WPS 1.0 function. + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * Fix compiling error + * + * 12 07 2010 cm.chang + * [WCXRP00000238] MT6620 Wi-Fi][Driver][FW] Support regulation domain setting from NVRAM and supplicant + * 1. Country code is from NVRAM or supplicant + * 2. Change band definition in CMD/EVENT. + * + * 11 30 2010 cp.wu + * [WCXRP00000213] [MT6620 Wi-Fi][Driver] Implement scanning with specified SSID for wpa_supplicant with ap_scan=1 + * . + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000121] [MT6620 Wi-Fi][Driver] Temporarily disable set power mode ioctl which may cause 6620 to enter power + * saving + * Temporarily disable set power mode ioctl which may cause MT6620 to enter power saving + * + * 10 18 2010 jeffrey.chang + * [WCXRP00000116] [MT6620 Wi-Fi][Driver] Refine the set_scan ioctl to resolve the Android UI hanging issue + * refine the scan ioctl to prevent hanging of Android UI + * + * 10 01 2010 wh.su + * [WCXRP00000067] [MT6620 Wi-Fi][Driver] Support the android+ WAPI function + * add the scan result with wapi ie. + * + * 09 30 2010 wh.su + * [WCXRP00000072] [MT6620 Wi-Fi][Driver] Fix TKIP Counter Measure EAPoL callback register issue + * fixed the wapi ie assigned issue. + * + * 09 27 2010 wh.su + * NULL + * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 09 2010 cp.wu + * NULL + * add WPS/WPA/RSN IE for Wi-Fi Direct scanning result. + * + * 09 06 2010 cp.wu + * NULL + * Androi/Linux: return current operating channel information + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 02 2010 jeffrey.chang + * NULL + * enable remove key ioctl + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) enable encyption ioctls + * 2) temporarily disable remove keys ioctl to prevent TX1 busy + * + * 07 28 2010 jeffrey.chang + * NULL + * 1) remove unused spinlocks + * 2) enable encyption ioctls + * 3) fix scan ioctl which may cause supplicant to hang + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * for linux driver migration + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove unused macro and debug messages + * + * 05 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add dissassoication support for wpa supplicant + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Add ioctl of power management + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug message + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) prGlueInfo->pvInformationBuffer and prGlueInfo->u4InformationBufferLength are no longer used + * * 2) fix ioctl + * + * 04 12 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug messages for pre-release + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * are done in adapter layer. + * + * 04 02 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl type + * + * 04 01 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * enable pmksa cache operation + * + * 03 31 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix ioctl which may cause cmdinfo memory leak + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\38 2009-10-08 10:33:22 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). +** Add more checking for input parameters and pointers. +** \main\maintrunk.MT5921\37 2009-09-29 16:49:48 GMT mtk01090 +** Remove unused variables +** \main\maintrunk.MT5921\36 2009-09-28 20:19:11 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\35 2009-09-03 11:42:30 GMT mtk01088 +** adding the wapi ioctl support +** \main\maintrunk.MT5921\34 2009-08-18 22:56:50 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\33 2009-05-14 22:43:47 GMT mtk01089 +** fix compiling warning +** \main\maintrunk.MT5921\32 2009-05-07 22:26:18 GMT mtk01089 +** Add mandatory and private IO control for Linux BWCS +** \main\maintrunk.MT5921\31 2009-02-07 15:11:14 GMT mtk01088 +** fixed the compiling error +** \main\maintrunk.MT5921\30 2009-02-07 14:46:51 GMT mtk01088 +** add the privacy setting from linux supplicant ap selection +** \main\maintrunk.MT5921\29 2008-11-19 15:18:50 GMT mtk01088 +** fixed the compling error +** \main\maintrunk.MT5921\28 2008-11-19 11:56:18 GMT mtk01088 +** rename some variable with pre-fix to avoid the misunderstanding +** \main\maintrunk.MT5921\27 2008-08-29 16:59:43 GMT mtk01088 +** fixed compiling error +** \main\maintrunk.MT5921\26 2008-08-29 14:55:53 GMT mtk01088 +** adjust the code for meet the coding style, and add assert check +** \main\maintrunk.MT5921\25 2008-06-02 11:15:19 GMT mtk01461 +** Update after wlanoidSetPowerMode changed +** \main\maintrunk.MT5921\24 2008-05-30 15:13:12 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\23 2008-03-28 10:40:28 GMT mtk01461 +** Add set desired rate in Linux STD IOCTL +** \main\maintrunk.MT5921\22 2008-03-18 10:31:24 GMT mtk01088 +** add pmkid ioctl and indicate +** \main\maintrunk.MT5921\21 2008-03-11 15:21:24 GMT mtk01461 +** \main\maintrunk.MT5921\20 2008-03-11 14:50:55 GMT mtk01461 +** Refine WPS related priv ioctl for unified interface +** +** \main\maintrunk.MT5921\19 2008-03-06 16:30:41 GMT mtk01088 +** move the configuration code from set essid function, +** remove the non-used code +** \main\maintrunk.MT5921\18 2008-02-21 15:47:09 GMT mtk01461 +** Fix CR[489] +** \main\maintrunk.MT5921\17 2008-02-12 23:38:31 GMT mtk01461 +** Add Set Frequency & Channel oid support for Linux +** \main\maintrunk.MT5921\16 2008-01-24 12:07:34 GMT mtk01461 +** \main\maintrunk.MT5921\15 2008-01-24 12:00:10 GMT mtk01461 +** Modify the wext_essid for set up correct information for IBSS, and fix the wrong input ptr for prAdapter +** \main\maintrunk.MT5921\14 2007-12-06 09:30:12 GMT mtk01425 +** 1. Branch Test +** \main\maintrunk.MT5921\13 2007-12-04 18:07:59 GMT mtk01461 +** fix typo +** \main\maintrunk.MT5921\12 2007-11-30 17:10:21 GMT mtk01425 +** 1. Fix compiling erros +** +** \main\maintrunk.MT5921\11 2007-11-27 10:43:22 GMT mtk01425 +** 1. Add WMM-PS setting +** \main\maintrunk.MT5921\10 2007-11-06 20:33:32 GMT mtk01088 +** fixed the compiler error +** \main\maintrunk.MT5921\9 2007-11-06 19:33:15 GMT mtk01088 +** add WPS code +** \main\maintrunk.MT5921\8 2007-10-30 12:00:44 GMT MTK01425 +** 1. Update wlanQueryInformation +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "gl_os.h" + +#include "config.h" +#include "wlan_oid.h" + +#include "gl_wext.h" +#include "gl_wext_priv.h" + +#include "precomp.h" + +#if CFG_SUPPORT_WAPI +#include "gl_sec.h" +#endif + +/* compatibility to wireless extensions */ +#ifdef WIRELESS_EXT + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const long channel_freq[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + + +#define NUM_CHANNELS (sizeof(channel_freq) / sizeof(channel_freq[0])) + +#define MAX_SSID_LEN 32 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/* NOTE: name in iwpriv_args only have 16 bytes */ +static const struct iw_priv_args rIwPrivTable[] = { + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, ""}, + {IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, ""}, + + {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + {IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ""}, + + {IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, ""}, + {IOCTL_GET_INT, 0, IW_PRIV_TYPE_CHAR | 16, ""}, + + {IOCTL_SET_STRING, IW_PRIV_TYPE_CHAR | 256, 0, ""}, + + /* added for set_oid and get_oid */ + {IOCTL_SET_STRUCT, 256, 0, ""}, + {IOCTL_GET_STRUCT, 0, 256, ""}, + + /* sub-ioctl definitions */ +#if 0 + {PRIV_CMD_REG_DOMAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_reg_domain"}, + {PRIV_CMD_REG_DOMAIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_reg_domain"}, +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + {PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_tcp_csum"}, +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + {PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power_mode"}, + {PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_power_mode"}, + + {PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_wmm_ps"}, + + {PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_test_mode"}, + {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_test_cmd"}, + {PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_test_result"}, +#if CFG_SUPPORT_PRIV_MCR_RW + {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_mcr"}, + {PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_mcr"}, +#endif + {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_sw_ctrl"}, + {PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_sw_ctrl"}, + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_bwcs"}, + /* GET STRUCT sub-ioctls commands */ + {PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_bwcs"}, +#endif + + /* SET STRUCT sub-ioctls commands */ + {PRIV_CMD_OID, 256, 0, "set_oid"}, + /* GET STRUCT sub-ioctls commands */ + {PRIV_CMD_OID, 0, 256, "get_oid"}, + + {PRIV_CMD_BAND_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_band"}, + {PRIV_CMD_BAND_CONFIG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_band"}, + + {PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower"}, + {PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list"}, + {PRIV_CMD_DUMP_MEM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_mem"}, + +#if CFG_ENABLE_WIFI_DIRECT + {PRIV_CMD_P2P_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_p2p_mode"}, +#endif + {PRIV_CMD_GET_BUILD_DATE_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_date_code"}, + {PRIV_CMD_GET_DEBUG_CODE, 0, IW_PRIV_TYPE_CHAR | 16, "get_dbg_code"}, + /* handle any command with many input parameters */ + {PRIV_CMD_OTHER, IW_PRIV_TYPE_CHAR | 256, 0, "set_str_cmd"}, + + {PRIV_CMD_WFD_DEBUG_CODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_wfd_dbg_code"}, +}; + +static const iw_handler rIwPrivHandler[] = { + [IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int, + [IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int, + [IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STRUCT - SIOCIWFIRSTPRIV] = priv_set_struct, + [IOCTL_GET_STRUCT - SIOCIWFIRSTPRIV] = priv_get_struct, + [IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct, + [IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints, + [IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints, + [IOCTL_SET_STRING - SIOCIWFIRSTPRIV] = priv_set_string, +}; + +const struct iw_handler_def wext_handler_def = { + .num_standard = 0, + .num_private = (__u16) sizeof(rIwPrivHandler) / sizeof(iw_handler), + .num_private_args = (__u16) sizeof(rIwPrivTable) / sizeof(struct iw_priv_args), + .standard = (iw_handler *) NULL, + .private = rIwPrivHandler, + .private_args = rIwPrivTable, + .get_wireless_stats = wext_get_wireless_stats, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WPA/RSN Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + /* EID == 0xDD, check WPA IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + } /* check WPA IE length */ + /* check EID == 0xDD */ + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* parseSearchDesiredWPAIE */ + +#if CFG_SUPPORT_WAPI +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WAPI Information Element . +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_WAPI && i4InfoElemLen <= i4TotalIeLen) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredWAPIIE */ +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief Check if exist the desired HS2.0 Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextIsDesiredHS20IE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucCurIE); + + i4InfoElemLen = (INT_32) pucCurIE[1] + 2; + + if (pucCurIE[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { + if (pucCurIE[1] >= ELEM_MIN_LEN_HS20_INDICATION) { + if (memcmp(&pucCurIE[2], "\x50\x6f\x9a\x10", 4) == 0) + return TRUE; + } + } + /* check desired EID */ + return FALSE; +} /* wextIsDesiredHS20IE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Check if exist the desired interworking Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextIsDesiredInterworkingIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucCurIE); + + i4InfoElemLen = (INT_32) pucCurIE[1] + 2; + + if (pucCurIE[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { + switch (pucCurIE[1]) { + case IW_IE_LENGTH_ANO: + case IW_IE_LENGTH_ANO_HESSID: + case IW_IE_LENGTH_ANO_VENUE: + case IW_IE_LENGTH_ANO_VENUE_HESSID: + return TRUE; + + default: + break; + } + + } + /* check desired EID */ + return FALSE; +} /* wextIsDesiredInterworkingIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Check if exist the desired Adv Protocol Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextIsDesiredAdvProtocolIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucCurIE); + + i4InfoElemLen = (INT_32) pucCurIE[1] + 2; + + if (pucCurIE[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) + return TRUE; + /* check desired EID */ + return FALSE; +} /* wextIsDesiredAdvProtocolIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Check if exist the desired Roaming Consortium Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextIsDesiredRoamingConsortiumIE(IN PUINT_8 pucCurIE, IN INT_32 i4TotalIeLen) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucCurIE); + + i4InfoElemLen = (INT_32) pucCurIE[1] + 2; + + if (pucCurIE[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) + return TRUE; + /* check desired EID */ + return FALSE; +} /* wextIsDesiredRoamingConsortiumIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired HS2.0 Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_VENDOR && i4InfoElemLen <= i4TotalIeLen) { + if (pucIEStart[1] >= ELEM_MIN_LEN_HS20_INDICATION) { + if (memcmp(&pucIEStart[2], "\x50\x6f\x9a\x10", 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + } + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredHS20IE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired interworking Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_INTERWORKING && i4InfoElemLen <= i4TotalIeLen) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredInterworkingIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired Adv Protocol Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_ADVERTISEMENT_PROTOCOL && i4InfoElemLen <= i4TotalIeLen) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredAdvProtocolIE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired Roaming Consortium Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ELEM_ID_ROAMING_CONSORTIUM && i4InfoElemLen <= i4TotalIeLen) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* wextSrchDesiredRoamingConsortiumIE */ +#endif + +#if CFG_SUPPORT_WPS +/*----------------------------------------------------------------------------*/ +/*! +* \brief Find the desired WPS Information Element according to desiredElemID. +* +* \param[in] pucIEStart IE starting address. +* \param[in] i4TotalIeLen Total length of all the IE. +* \param[in] ucDesiredElemId Desired element ID. +* \param[out] ppucDesiredIE Pointer to the desired IE. +* +* \retval TRUE Find the desired IE. +* \retval FALSE Desired IE not found. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE) +{ + INT_32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (INT_32) pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + /* EID == 0xDD, check WPS IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return TRUE; + } + } /* check WPS IE length */ + /* check EID == 0xDD */ + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return FALSE; +} /* parseSearchDesiredWPSIE */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Get the name of the protocol used on the air. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] pcName Buffer to store protocol name string +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* +* \note If netif_carrier_ok, protocol name is returned; +* otherwise, "disconnected" is returned. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_name(IN struct net_device *prNetDev, IN struct iw_request_info *prIwrInfo, OUT char *pcName, IN char *pcExtra) +{ + ENUM_PARAM_NETWORK_TYPE_T eNetWorkType = PARAM_NETWORK_TYPE_NUM; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcName); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcName)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (netif_carrier_ok(prNetDev)) { + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryNetworkTypeInUse, + &eNetWorkType, sizeof(eNetWorkType), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + switch (eNetWorkType) { + case PARAM_NETWORK_TYPE_DS: + strcpy(pcName, "IEEE 802.11b"); + break; + case PARAM_NETWORK_TYPE_OFDM24: + strcpy(pcName, "IEEE 802.11bgn"); + break; + case PARAM_NETWORK_TYPE_AUTOMODE: + case PARAM_NETWORK_TYPE_OFDM5: + strcpy(pcName, "IEEE 802.11abgn"); + break; + case PARAM_NETWORK_TYPE_FH: + default: + strcpy(pcName, "IEEE 802.11"); + break; + } + } else { + strcpy(pcName, "Disconnected"); + } + + return 0; +} /* wext_get_name */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set the operating channel in the wireless device. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL +* \param[in] prFreq Buffer to store frequency information +* \param[in] pcExtra NULL +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS. +* \retval -EINVAL Invalid channel frequency. +* +* \note If infrastructure mode is IBSS, new channel frequency is set to device. +* The range of channel number depends on different regulatory domain. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_freq(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN struct iw_freq *prIwFreq, IN char *pcExtra) +{ + +#if 0 + UINT_32 u4ChnlFreq; /* Store channel or frequency information */ + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prIwFreq); + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* + printk("set m:%d, e:%d, i:%d, flags:%d\n", + prIwFreq->m, prIwFreq->e, prIwFreq->i, prIwFreq->flags); + */ + + /* If setting by frequency, convert to a channel */ + if ((prIwFreq->e == 1) && (prIwFreq->m >= (int)2.412e8) && (prIwFreq->m <= (int)2.484e8)) { + + /* Change to KHz format */ + u4ChnlFreq = (UINT_32) (prIwFreq->m / (KILO / 10)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetFrequency, + &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); + + if (WLAN_STATUS_SUCCESS != rStatus) + return -EINVAL; + } + /* Setting by channel number */ + else if ((prIwFreq->m > KILO) || (prIwFreq->e > 0)) + return -EOPNOTSUPP; + + /* Change to channel number format */ + u4ChnlFreq = (UINT_32) prIwFreq->m; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetChannel, &u4ChnlFreq, sizeof(u4ChnlFreq), FALSE, FALSE, FALSE, &u4BufLen); + + if (WLAN_STATUS_SUCCESS != rStatus) + return -EINVAL; + +#endif + + return 0; + +} /* wext_set_freq */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get the operating channel in the wireless device. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prFreq Buffer to store frequency information. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise +* +* \note If netif_carrier_ok, channel frequency information is stored in pFreq. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_freq(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_freq *prIwFreq, IN char *pcExtra) +{ + UINT_32 u4Channel = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prIwFreq); + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwFreq)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* GeorgeKuo: TODO skip checking in IBSS mode */ + if (!netif_carrier_ok(prNetDev)) + return -ENOTCONN; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryFrequency, &u4Channel, sizeof(u4Channel), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + prIwFreq->m = (int)u4Channel; /* freq in KHz */ + prIwFreq->e = 3; + + return 0; + +} /* wext_get_freq */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set operating mode. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] pu4Mode Pointer to new operation mode. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If new mode is not supported. +* +* \note Device will run in new operation mode if it is valid. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_mode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN unsigned int *pu4Mode, IN char *pcExtra) +{ + ENUM_PARAM_OP_MODE_T eOpMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + switch (*pu4Mode) { + case IW_MODE_AUTO: + eOpMode = NET_TYPE_AUTO_SWITCH; + break; + + case IW_MODE_ADHOC: + eOpMode = NET_TYPE_IBSS; + break; + + case IW_MODE_INFRA: + eOpMode = NET_TYPE_INFRA; + break; + + default: + DBGLOG(REQ, ERROR, "%s(): Set UNSUPPORTED Mode = %d.\n", __func__, *pu4Mode); + return -EOPNOTSUPP; + } + + /* printk("%s(): Set Mode = %d\n", __FUNCTION__, *pu4Mode); */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetInfrastructureMode, + &eOpMode, sizeof(eOpMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + /* after set operation mode, key table are cleared */ + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + return 0; +} /* wext_set_mode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get operating mode. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo NULL. +* \param[out] pu4Mode Buffer to store operating mode information. +* \param[in] pcExtra NULL. +* +* \retval 0 If data is valid. +* \retval -EINVAL Otherwise. +* +* \note If netif_carrier_ok, operating mode information is stored in pu4Mode. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_mode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, OUT unsigned int *pu4Mode, IN char *pcExtra) +{ + ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_NUM; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (FALSE == GLUE_CHK_PR2(prNetDev, pu4Mode)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryInfrastructureMode, + &eOpMode, sizeof(eOpMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + switch (eOpMode) { + case NET_TYPE_IBSS: + *pu4Mode = IW_MODE_ADHOC; + break; + + case NET_TYPE_INFRA: + *pu4Mode = IW_MODE_INFRA; + break; + + case NET_TYPE_AUTO_SWITCH: + *pu4Mode = IW_MODE_AUTO; + break; + + default: + DBGLOG(REQ, ERROR, "%s(): Get UNKNOWN Mode.\n", __func__); + return -EINVAL; + } + + return 0; +} /* wext_get_mode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get the valid range for each configurable STA setting value. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData Pointer to iw_point structure, not used. +* \param[out] pcExtra Pointer to buffer which is allocated by caller of this +* function, wext_support_ioctl() or ioctl_standard_call() in +* wireless.c. +* +* \retval 0 If data is valid. +* +* \note The extra buffer (pcExtra) is filled with information from driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_range(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, OUT char *pcExtra) +{ + struct iw_range *prRange = NULL; + PARAM_RATES_EX aucSuppRate = { 0 }; /* data buffers */ + int i = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + prRange = (struct iw_range *)pcExtra; + + memset(prRange, 0, sizeof(*prRange)); + prRange->throughput = 20000000; /* 20Mbps */ + prRange->min_nwid = 0; /* not used */ + prRange->max_nwid = 0; /* not used */ + + /* scan_capa not implemented */ + + /* event_capa[6]: kernel + driver capabilities */ + prRange->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) + | IW_EVENT_CAPA_MASK(SIOCGIWSCAN) + /* can't display meaningful string in iwlist + | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW) + | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE) + | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE) + | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND) + */ + ); + prRange->event_capa[1] = IW_EVENT_CAPA_K_1; + + /* report 2.4G channel and frequency only */ + prRange->num_channels = (__u16) NUM_CHANNELS; + prRange->num_frequency = (__u8) NUM_CHANNELS; + for (i = 0; i < NUM_CHANNELS; i++) { + /* iwlib takes this number as channel number */ + prRange->freq[i].i = i + 1; + prRange->freq[i].m = channel_freq[i]; + prRange->freq[i].e = 6; /* Values in table in MHz */ + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQuerySupportedRates, + &aucSuppRate, sizeof(aucSuppRate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX; i++) { + if (aucSuppRate[i] == 0) + break; + prRange->bitrate[i] = (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps */ + } + prRange->num_bitrates = i; + + prRange->min_rts = 0; + prRange->max_rts = 2347; + prRange->min_frag = 256; + prRange->max_frag = 2346; + + prRange->min_pmp = 0; /* power management by driver */ + prRange->max_pmp = 0; /* power management by driver */ + prRange->min_pmt = 0; /* power management by driver */ + prRange->max_pmt = 0; /* power management by driver */ + prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */ + prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */ + prRange->pm_capa = IW_POWER_ON; /* power management by driver */ + + prRange->encoding_size[0] = 5; /* wep40 */ + prRange->encoding_size[1] = 16; /* tkip */ + prRange->encoding_size[2] = 16; /* ckip */ + prRange->encoding_size[3] = 16; /* ccmp */ + prRange->encoding_size[4] = 13; /* wep104 */ + prRange->encoding_size[5] = 16; /* wep128 */ + prRange->num_encoding_sizes = 6; + prRange->max_encoding_tokens = 6; /* token? */ + +#if WIRELESS_EXT < 17 + prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prRange->txpower_capa = IW_TXPOW_RELATIVE; +#endif + prRange->num_txpower = 5; + prRange->txpower[0] = 0; /* minimum */ + prRange->txpower[1] = 25; /* 25% */ + prRange->txpower[2] = 50; /* 50% */ + prRange->txpower[3] = 100; /* 100% */ + + prRange->we_version_compiled = WIRELESS_EXT; + prRange->we_version_source = WIRELESS_EXT; + + prRange->retry_capa = IW_RETRY_LIMIT; + prRange->retry_flags = IW_RETRY_LIMIT; + prRange->min_retry = 7; + prRange->max_retry = 7; + prRange->r_time_flags = IW_RETRY_ON; + prRange->min_r_time = 0; + prRange->max_r_time = 0; + + /* signal strength and link quality */ + /* Just define range here, reporting value moved to wext_get_stats() */ + prRange->sensitivity = -83; /* fixed value */ + prRange->max_qual.qual = 100; /* max 100% */ + prRange->max_qual.level = (__u8) (0x100 - 0); /* max 0 dbm */ + prRange->max_qual.noise = (__u8) (0x100 - 0); /* max 0 dbm */ + + /* enc_capa */ +#if WIRELESS_EXT > 17 + prRange->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; +#endif + + /* min_pms; Minimal PM saving */ + /* max_pms; Maximal PM saving */ + /* pms_flags; How to decode max/min PM saving */ + + /* modul_capa; IW_MODUL_* bit field */ + /* bitrate_capa; Types of bitrates supported */ + + return 0; +} /* wext_get_range */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set BSSID of AP to connect. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* +* \note Desired AP's BSSID is set to driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_ap(IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, IN struct sockaddr *prAddr, IN char *pcExtra) +{ + return 0; +} /* wext_set_ap */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get AP MAC address. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_ap(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct sockaddr *prAddr, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prAddr); + if (FALSE == GLUE_CHK_PR2(prNetDev, prAddr)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* if (!netif_carrier_ok(prNetDev)) { */ + /* return -ENOTCONN; */ + /* } */ + + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED) { + /*memset(prAddr, 0, 6);*/ + memset(prAddr, 0, sizeof(struct sockaddr)); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssid, prAddr->sa_data, ETH_ALEN, TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + return 0; +} /* wext_get_ap */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set mlme operation request. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData Pointer of iw_point header. +* \param[in] pcExtra Pointer to iw_mlme structure mlme request information. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP unsupported IW_MLME_ command. +* \retval -EINVAL Set MLME Fail, different bssid. +* +* \note Driver will start mlme operation if valid. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_mlme(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prData, IN char *pcExtra) +{ + struct iw_mlme *prMlme = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + prMlme = (struct iw_mlme *)pcExtra; + if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) { + if (!netif_carrier_ok(prNetDev)) { + DBGLOG(REQ, WARN, "[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n"); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + return 0; + } + DBGLOG(REQ, WARN, "[wifi] unsupported IW_MLME_ command :%d\n", prMlme->cmd); + return -EOPNOTSUPP; + +} /* wext_set_mlme */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To issue scan request. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prData NULL. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EFAULT Tx power is off. +* +* \note Device will start scanning. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_scan(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN union iwreq_data *prData, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + int essid_len = 0; + + ASSERT(prNetDev); + if (FALSE == GLUE_CHK_DEV(prNetDev)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + +#if WIRELESS_EXT > 17 + /* retrieve SSID */ + if (prData) + essid_len = ((struct iw_scan_req *)(((struct iw_point *)prData)->pointer))->essid_len; +#endif + + init_completion(&prGlueInfo->rScanComp); + + /* TODO: parse flags and issue different scan requests? */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetBssidListScan, pcExtra, essid_len, FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * KAL_HZ); */ + /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ + + return 0; +} /* wext_set_scan */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To write the ie to buffer +* +*/ +/*----------------------------------------------------------------------------*/ +static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) + return 0; + + for (i = 0; i < len; i++) { + ret = snprintf(pos, end - pos, "%02x", data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1] = '\0'; + return pos - buf; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get scan results, transform results from driver's format to WE's. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prData Pointer to iw_point structure, pData->length is the size of +* pcExtra buffer before used, and is updated after filling scan +* results. +* \param[out] pcExtra Pointer to buffer which is allocated by caller of this +* function, wext_support_ioctl() or ioctl_standard_call() in +* wireless.c. +* +* \retval 0 For success. +* \retval -ENOMEM If dynamic memory allocation fail. +* \retval -E2BIG Invalid length. +* +* \note Scan results is filled into pcExtra buffer, data size is updated in +* pData->length. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_scan(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN OUT struct iw_point *prData, IN char *pcExtra) +{ + UINT_32 i = 0; + UINT_32 j = 0; + P_PARAM_BSSID_LIST_EX_T prList = NULL; + P_PARAM_BSSID_EX_T prBss = NULL; + P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; + struct iw_event iwEvent; /* local iw_event buffer */ + + /* write pointer of extra buffer */ + char *pcCur = NULL; + /* pointer to the end of last full entry in extra buffer */ + char *pcValidEntryEnd = NULL; + char *pcEnd = NULL; /* end of extra buffer */ + + UINT_32 u4AllocBufLen = 0; + + /* arrange rate information */ + UINT_32 u4HighestRate = 0; + char aucRatesBuf[64]; + UINT_32 u4BufIndex; + + /* return value */ + int ret = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prData, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* Initialize local variables */ + pcCur = pcExtra; + pcValidEntryEnd = pcExtra; + pcEnd = pcExtra + prData->length; /* end of extra buffer */ + + /* Allocate another query buffer with the same size of extra buffer */ + u4AllocBufLen = prData->length; + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(REQ, ERROR, "[wifi] no memory for scan list:%d\n", prData->length); + ret = -ENOMEM; + goto error; + } + prList->u4NumberOfItems = 0; + + /* wait scan done */ + /* printk ("wait for scan results\n"); */ + /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * KAL_HZ); */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + /* Buffer length is not large enough. */ + /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ + +#if WIRELESS_EXT >= 17 + /* This feature is supported in WE-17 or above, limited by iwlist. + ** Return -E2BIG and iwlist will request again with a larger buffer. + */ + ret = -E2BIG; + /* Update length to give application a hint on result length */ + prData->length = (__u16) u4BufLen; + goto error; +#else + /* Realloc a larger query buffer here, but don't write too much to extra + ** buffer when filling it later. + */ + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + + u4AllocBufLen = u4BufLen; + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(REQ, ERROR, "[wifi] no memory for larger scan list :%u\n", u4BufLen); + ret = -ENOMEM; + goto error; + } + prList->NumberOfItems = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryBssidList, prList, u4AllocBufLen, TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + DBGLOG(REQ, ERROR, "[wifi] larger buf:%u result:%u\n", u4AllocBufLen, u4BufLen); + ret = -E2BIG; + prData->length = (__u16) u4BufLen; + goto error; + } +#endif /* WIRELESS_EXT >= 17 */ + + } + + if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) { + DBGLOG(REQ, WARN, "[wifi] strange scan result count:%u\n", prList->u4NumberOfItems); + goto error; + } + + /* Copy required data from pList to pcExtra */ + prBss = &prList->arBssid[0]; /* set to the first entry */ + for (i = 0; i < prList->u4NumberOfItems; ++i) { + /* BSSID */ + iwEvent.cmd = SIOCGIWAP; + iwEvent.len = IW_EV_ADDR_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER; + ether_addr_copy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress); + memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN); + pcCur += IW_EV_ADDR_LEN; + + /* SSID */ + iwEvent.cmd = SIOCGIWESSID; + /* Modification to user space pointer(essid.pointer) is not needed. */ + iwEvent.u.essid.length = (__u16) prBss->rSsid.u4SsidLen; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length; + + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.essid.flags = 1; + iwEvent.u.essid.pointer = NULL; + +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, iwEvent.len); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, iwEvent.u.essid.length); + pcCur += iwEvent.len; + /* Frequency */ + iwEvent.cmd = SIOCGIWFREQ; + iwEvent.len = IW_EV_FREQ_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig; + iwEvent.u.freq.e = 3; /* (in KHz) */ + iwEvent.u.freq.i = 0; + memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN); + pcCur += IW_EV_FREQ_LEN; + + /* Operation Mode */ + iwEvent.cmd = SIOCGIWMODE; + iwEvent.len = IW_EV_UINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + if (prBss->eOpMode == NET_TYPE_IBSS) + iwEvent.u.mode = IW_MODE_ADHOC; + else if (prBss->eOpMode == NET_TYPE_INFRA) + iwEvent.u.mode = IW_MODE_INFRA; + else + iwEvent.u.mode = IW_MODE_AUTO; + memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN); + pcCur += IW_EV_UINT_LEN; + + /* Quality */ + iwEvent.cmd = IWEVQUAL; + iwEvent.len = IW_EV_QUAL_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.qual.qual = 0; /* Quality not available now */ + /* -100 < Rssi < -10, normalized by adding 0x100 */ + iwEvent.u.qual.level = 0x100 + prBss->rRssi; + iwEvent.u.qual.noise = 0; /* Noise not available now */ + iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; + memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN); + pcCur += IW_EV_QUAL_LEN; + + /* Security Mode */ + iwEvent.cmd = SIOCGIWENCODE; + iwEvent.len = IW_EV_POINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.pointer = NULL; + iwEvent.u.data.flags = 0; + iwEvent.u.data.length = 0; + if (!prBss->u4Privacy) + iwEvent.u.data.flags |= IW_ENCODE_DISABLED; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + pcCur += IW_EV_POINT_LEN; + + /* rearrange rate information */ + u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):"); + u4HighestRate = 0; + for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) { + UINT_8 curRate = prBss->rSupportedRates[j] & 0x7F; + + if (curRate == 0) + break; + + if (curRate > u4HighestRate) + u4HighestRate = curRate; + + if (curRate == RATE_5_5M) + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " 5.5"); + else + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, " %d", curRate / 2); +#if DBG + if (u4BufIndex > sizeof(aucRatesBuf)) { + /* printk("rate info too long\n"); */ + break; + } +#endif + } + /* Report Highest Rates */ + iwEvent.cmd = SIOCGIWRATE; + iwEvent.len = IW_EV_PARAM_LEN; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.bitrate.value = u4HighestRate * 500000; + iwEvent.u.bitrate.fixed = 0; + iwEvent.u.bitrate.disabled = 0; + iwEvent.u.bitrate.flags = 0; + memcpy(pcCur, &iwEvent, iwEvent.len); + pcCur += iwEvent.len; + +#if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */ + /* Report Residual Rates */ + iwEvent.cmd = IWEVCUSTOM; + iwEvent.u.data.length = u4BufIndex; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.flags = 0; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex); + pcCur += iwEvent.len; +#endif /* WIRELESS_EXT >= 15 */ + + if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), + 0xDD, (PUINT_8 *) &prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */ + if (wextSrchDesiredWPSIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), + 0xDD, (PUINT_8 *) &prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#endif + + /* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */ + /* pBss->IEs starts from timestamp */ + if (wextSrchDesiredWPAIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), + 0x30, (PUINT_8 *) &prDesiredIE)) { + + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#if CFG_SUPPORT_WAPI /* Android+ */ + if (wextSrchDesiredWAPIIE(&prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), (PUINT_8 *) &prDesiredIE)) { + +#if 0 + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = 2 + (__u16) prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; +#else + iwEvent.cmd = IWEVCUSTOM; + iwEvent.u.data.length = (2 + prDesiredIE->ucLength) * 2 + 8 /* wapi_ie= */; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) + break; + iwEvent.u.data.flags = 1; + + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, + &iwEvent.u.data.length, sizeof(struct iw_point) - IW_EV_POINT_OFF); + + pcCur += (IW_EV_POINT_LEN); + + pcCur += sprintf(pcCur, "wapi_ie="); + + snprintf_hex(pcCur, pcEnd - pcCur, (UINT_8 *) prDesiredIE, prDesiredIE->ucLength + 2); + + pcCur += (2 + prDesiredIE->ucLength) * 2 /* iwEvent.len */; +#endif + } +#endif + /* Complete an entry. Update end of valid entry */ + pcValidEntryEnd = pcCur; + /* Extract next bss */ + prBss = (P_PARAM_BSSID_EX_T) ((char *)prBss + prBss->u4Length); + } + + /* Update valid data length for caller function and upper layer + * applications. + */ + prData->length = (pcValidEntryEnd - pcExtra); + /* printk(KERN_INFO "[wifi] buf:%d result:%ld\n", pData->length, u4BufLen); */ + + /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ + +error: + /* free local query buffer */ + if (prList) + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + + return ret; +} /* wext_get_scan */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set desired network name ESSID. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEssid Pointer of iw_point header. +* \param[in] pcExtra Pointer to buffer srtoring essid string. +* +* \retval 0 If netif_carrier_ok. +* \retval -E2BIG Essid string length is too big. +* \retval -EINVAL pcExtra is null pointer. +* \retval -EFAULT Driver fail to set new essid. +* +* \note If string length is ok, device will try connecting to the new network. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_essid(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, IN char *pcExtra) +{ + PARAM_SSID_T rNewSsid; + UINT_32 cipher; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (prEssid->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + /* set auth mode */ + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : AUTH_MODE_AUTO_SWITCH; + /* printk(KERN_INFO "IW_AUTH_WPA_VERSION_DISABLED->Param_AuthMode%s\n", */ + /* (eAuthMode == AUTH_MODE_OPEN) ? "Open" : "Shared"); */ + } else { + /* set auth mode */ + switch (prGlueInfo->rWpaInfo.u4KeyMgmt) { + case IW_AUTH_KEY_MGMT_802_1X: + eAuthMode = + (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA : AUTH_MODE_WPA2; + /* printk("IW_AUTH_KEY_MGMT_802_1X->AUTH_MODE_WPA%s\n", */ + /* (eAuthMode == AUTH_MODE_WPA) ? "" : "2"); */ + break; + case IW_AUTH_KEY_MGMT_PSK: + eAuthMode = + (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA_PSK : AUTH_MODE_WPA2_PSK; + /* printk("IW_AUTH_KEY_MGMT_PSK->AUTH_MODE_WPA%sPSK\n", */ + /* (eAuthMode == AUTH_MODE_WPA_PSK) ? "" : "2"); */ + break; +#if CFG_SUPPORT_WAPI /* Android+ */ + case IW_AUTH_KEY_MGMT_WAPI_PSK: + break; + case IW_AUTH_KEY_MGMT_WAPI_CERT: + break; +#endif + +/* #if defined (IW_AUTH_KEY_MGMT_WPA_NONE) */ +/* case IW_AUTH_KEY_MGMT_WPA_NONE: */ +/* eAuthMode = AUTH_MODE_WPA_NONE; */ +/* //printk("IW_AUTH_KEY_MGMT_WPA_NONE->AUTH_MODE_WPA_NONE\n"); */ +/* break; */ +/* #endif */ +#if CFG_SUPPORT_802_11W + case IW_AUTH_KEY_MGMT_802_1X_SHA256: + eAuthMode = AUTH_MODE_WPA2; + break; + case IW_AUTH_KEY_MGMT_PSK_SHA256: + eAuthMode = AUTH_MODE_WPA2_PSK; + break; +#endif + default: + /* printk(KERN_INFO DRV_NAME"strange IW_AUTH_KEY_MGMT : %ld set auto switch\n", */ + /* prGlueInfo->rWpaInfo.u4KeyMgmt); */ + eAuthMode = AUTH_MODE_AUTO_SWITCH; + break; + } + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + /* set encryption status */ + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | prGlueInfo->rWpaInfo.u4CipherPairwise; + if (cipher & IW_AUTH_CIPHER_CCMP) { + /* printk("IW_AUTH_CIPHER_CCMP->ENUM_ENCRYPTION3_ENABLED\n"); */ + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_TKIP) { + /* printk("IW_AUTH_CIPHER_TKIP->ENUM_ENCRYPTION2_ENABLED\n"); */ + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + /* printk("IW_AUTH_CIPHER_WEPx->ENUM_ENCRYPTION1_ENABLED\n"); */ + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_NONE) { + /* printk("IW_AUTH_CIPHER_NONE->ENUM_ENCRYPTION_DISABLED\n"); */ + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + else + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } else { + /* printk("unknown IW_AUTH_CIPHER->Param_EncryptionDisabled\n"); */ + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + +#if WIRELESS_EXT < 21 + /* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel before + ** 2.6.19. Cut the trailing '\0'. + */ + rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0; +#else + rNewSsid.u4SsidLen = prEssid->length; +#endif + kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen); + + /* + rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0'; + printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid); + */ + + if (kalIoctl(prGlueInfo, + wlanoidSetSsid, + (PVOID)&rNewSsid, + sizeof(PARAM_SSID_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen) != WLAN_STATUS_SUCCESS) { + /* printk(KERN_WARNING "Fail to set ssid\n"); */ + return -EFAULT; + } + + return 0; +} /* wext_set_essid */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get current network name ESSID. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEssid Pointer to iw_point structure containing essid information. +* \param[out] pcExtra Pointer to buffer srtoring essid string. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, network essid is stored in pcExtra. +*/ +/*----------------------------------------------------------------------------*/ +/* static PARAM_SSID_T ssid; */ +static int +wext_get_essid(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEssid, OUT char *pcExtra) +{ + /* PARAM_SSID_T ssid; */ + + P_PARAM_SSID_T prSsid; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prEssid, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* if (!netif_carrier_ok(prNetDev)) { */ + /* return -ENOTCONN; */ + /* } */ + + prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE); + + if (!prSsid) + return -ENOMEM; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQuerySsid, prSsid, sizeof(PARAM_SSID_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + if ((rStatus == WLAN_STATUS_SUCCESS) && (prSsid->u4SsidLen <= MAX_SSID_LEN)) { + kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen); + prEssid->length = prSsid->u4SsidLen; + prEssid->flags = 1; + } + + kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T)); + + return 0; +} /* wext_get_essid */ + +#if 0 + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set tx desired bit rate. Three cases here +* iwconfig wlan0 auto -> Set to origianl supported rate set. +* iwconfig wlan0 18M -> Imply "fixed" case, set to 18Mbps as desired rate. +* iwconfig wlan0 18M auto -> Set to auto rate lower and equal to 18Mbps +* +* \param[in] prNetDev Pointer to the net_device handler. +* \param[in] prIwReqInfo Pointer to the Request Info. +* \param[in] prRate Pointer to the Rate Parameter. +* \param[in] pcExtra Pointer to the extra buffer. +* +* \retval 0 Update desired rate. +* \retval -EINVAL Wrong parameter +*/ +/*----------------------------------------------------------------------------*/ +int +wext_set_rate(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra) +{ + PARAM_RATES_EX aucSuppRate = { 0 }; + PARAM_RATES_EX aucNewRate = { 0 }; + UINT_32 u4NewRateLen = 0; + UINT_32 i; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRate); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* + printk("value = %d, fixed = %d, disable = %d, flags = %d\n", + prRate->value, prRate->fixed, prRate->disabled, prRate->flags); + */ + + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuerySupportedRates, &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); + + /* Case: AUTO */ + if (prRate->value < 0) { + if (prRate->fixed == 0) { + /* iwconfig wlan0 rate auto */ + + /* set full supported rate to device */ + /* printk("wlanoidQuerySupportedRates():u4BufLen = %ld\n", u4BufLen); */ + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetDesiredRates, + &aucSuppRate, sizeof(aucSuppRate), &u4BufLen); + return 0; + } + /* iwconfig wlan0 rate fixed */ + + /* fix rate to what? DO NOTHING */ + return -EINVAL; + } + + aucNewRate[0] = prRate->value / 500000; /* In unit of 500k */ + + for (i = 0; i < PARAM_MAX_LEN_RATES_EX; i++) { + /* check the given value is supported */ + if (aucSuppRate[i] == 0) + break; + + if (aucNewRate[0] == aucSuppRate[i]) { + u4NewRateLen = 1; + break; + } + } + + if (u4NewRateLen == 0) { + /* the given value is not supported */ + /* return error or use given rate as upper bound? */ + return -EINVAL; + } + + if (prRate->fixed == 0) { + /* add all rates lower than desired rate */ + for (i = 0; i < PARAM_MAX_LEN_RATES_EX; ++i) { + if (aucSuppRate[i] == 0) + break; + + if (aucSuppRate[i] < aucNewRate[0]) + aucNewRate[u4NewRateLen++] = aucSuppRate[i]; + } + } + + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetDesiredRates, &aucNewRate, sizeof(aucNewRate), &u4BufLen); + return 0; +} /* wext_set_rate */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get current tx bit rate. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prRate Pointer to iw_param structure to store current tx rate. +* \param[in] pcExtra NULL. +* +* \retval 0 If netif_carrier_ok. +* \retval -ENOTCONN Otherwise. +* +* \note If netif_carrier_ok, current tx rate is stored in pRate. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_rate(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRate, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + UINT_32 u4Rate = 0; + + ASSERT(prNetDev); + ASSERT(prRate); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRate)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (!netif_carrier_ok(prNetDev)) + return -ENOTCONN; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryLinkSpeed, &u4Rate, sizeof(u4Rate), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + + prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */ + prRate->fixed = 0; + + return 0; +} /* wext_get_rate */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set RTS/CTS theshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prRts Pointer to iw_param structure containing rts threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 For success. +* \retval -EINVAL Given value is out of range. +* +* \note If given value is valid, device will follow the new setting. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_rts(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_param *prRts, IN char *pcExtra) +{ + PARAM_RTS_THRESHOLD u4RtsThresh; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (prRts->disabled == 1) + u4RtsThresh = 2347; + else if (prRts->value < 0 || prRts->value > 2347) + return -EINVAL; + + u4RtsThresh = (PARAM_RTS_THRESHOLD) prRts->value; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRtsThreshold, + &u4RtsThresh, sizeof(u4RtsThresh), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + prRts->value = (typeof(prRts->value)) u4RtsThresh; + prRts->disabled = (prRts->value > 2347) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} /* wext_set_rts */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get RTS/CTS theshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prRts Pointer to iw_param structure containing rts threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note RTS threshold is stored in pRts. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_rts(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prRts, IN char *pcExtra) +{ + PARAM_RTS_THRESHOLD u4RtsThresh = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (FALSE == GLUE_CHK_PR2(prNetDev, prRts)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryRtsThreshold, + &u4RtsThresh, sizeof(u4RtsThresh), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + prRts->value = (typeof(prRts->value)) u4RtsThresh; + prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} /* wext_get_rts */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get fragmentation threshold. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prFrag Pointer to iw_param structure containing frag threshold. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note RTS threshold is stored in pFrag. Fragmentation is disabled. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_frag(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prFrag, IN char *pcExtra) +{ + ASSERT(prFrag); + + prFrag->value = 2346; + prFrag->fixed = 1; + prFrag->disabled = 1; + return 0; +} /* wext_get_frag */ + +#if 1 +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set TX power, or enable/disable the radio. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prTxPow Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used +* to enable/disable the radio. +*/ +/*----------------------------------------------------------------------------*/ + +static int +wext_set_txpow(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_param *prTxPow, IN char *pcExtra) +{ + int ret = 0; + /* PARAM_DEVICE_POWER_STATE ePowerState; */ + ENUM_ACPI_STATE_T ePowerState; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (prTxPow->disabled) { + /* <1> disconnect */ + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, ERROR, "######set disassoc failed\n"); + else + DBGLOG(REQ, TRACE, "######set assoc ok\n"); + /* <2> mark to power state flag */ + ePowerState = ACPI_STATE_D0; + DBGLOG(REQ, INFO, "set to acpi d3(0)\n"); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + + } else { + ePowerState = ACPI_STATE_D0; + DBGLOG(REQ, INFO, "set to acpi d0\n"); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + } + + prGlueInfo->ePowerState = ePowerState; + + return ret; +} /* wext_set_txpow */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get TX power. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prTxPow Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Tx power is stored in pTxPow. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_txpow(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prTxPow, IN char *pcExtra) +{ + /* PARAM_DEVICE_POWER_STATE ePowerState; */ + + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (FALSE == GLUE_CHK_PR2(prNetDev, prTxPow)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not + * current state. Use GLUE_INFO_T to store state. + */ + /* ePowerState = prGlueInfo->ePowerState; */ + + /* TxPow parameters: Fixed at relative 100% */ +#if WIRELESS_EXT < 17 + prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prTxPow->flags = IW_TXPOW_RELATIVE; +#endif + prTxPow->value = 100; + prTxPow->fixed = 1; + /* prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? FALSE : TRUE; */ + prTxPow->disabled = TRUE; + + return 0; +} /* wext_get_txpow */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Buffer to store key content. +* +* \retval 0 Success. +* +* \note Securiry information is stored in pEnc except key content. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_encode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_point *prEnc, IN char *pcExtra) +{ +#if 1 + /* ENUM_ENCRYPTION_STATUS_T eEncMode; */ + ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode = ENUM_WEP_ENABLED; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (FALSE == GLUE_CHK_PR2(prNetDev, prEnc)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryEncryptionStatus, + &eEncMode, sizeof(eEncMode), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + + switch (eEncMode) { + case ENUM_WEP_DISABLED: + prEnc->flags = IW_ENCODE_DISABLED; + break; + case ENUM_WEP_ENABLED: + prEnc->flags = IW_ENCODE_ENABLED; + break; + case ENUM_WEP_KEY_ABSENT: + prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + break; + default: + prEnc->flags = IW_ENCODE_ENABLED; + break; + } + + /* Cipher, Key Content, Key ID can't be queried */ + prEnc->flags |= IW_ENCODE_NOKEY; +#endif + return 0; +} /* wext_get_encode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +static UINT_8 wepBuf[48]; + +static int +wext_set_encode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) +{ +#if 1 + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + /* UINT_8 wepBuf[48]; */ + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* reset to default mode */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + /* iwconfig wlan0 key off */ + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { + eAuthMode = AUTH_MODE_OPEN; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + eEncStatus = ENUM_ENCRYPTION_DISABLED; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, sizeof(eEncStatus), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + return 0; + } + + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + return -EINVAL; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prEnc->length; + prWepKey->u4KeyLength = prEnc->length; + kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddWep, + prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); + return -EFAULT; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO DRV_NAME"wlanoidSetAuthMode fail 0x%lx\n", rStatus); */ + return -EFAULT; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO DRV_NAME"wlanoidSetEncryptionStatus fail 0x%lx\n", rStatus); */ + return -EFAULT; + } + + return 0; + } +#endif + return -EOPNOTSUPP; +} /* wext_set_encode */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set power management. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prPower Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note New Power Management Mode is set to driver. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_power(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_param *prPower, IN char *pcExtra) +{ +#if 1 + + PARAM_POWER_MODE ePowerMode; + INT_32 i4PowerValue; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* printk(KERN_INFO "wext_set_power value(%d) disabled(%d) flag(0x%x)\n", */ + /* prPower->value, prPower->disabled, prPower->flags); */ + + if (prPower->disabled) { + ePowerMode = Param_PowerModeCAM; + } else { + i4PowerValue = prPower->value; +#if WIRELESS_EXT < 21 + i4PowerValue /= 1000000; +#endif + if (i4PowerValue == 0) { + ePowerMode = Param_PowerModeCAM; + } else if (i4PowerValue == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (i4PowerValue == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } else { + DBGLOG(REQ, ERROR, "%s(): unsupported power management mode value = %d.\n", + __func__, prPower->value); + + return -EINVAL; + } + } + + rStatus = kalIoctl(prGlueInfo, + wlanoidSet802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO DRV_NAME"wlanoidSet802dot11PowerSaveProfile fail 0x%lx\n", rStatus); */ + return -EFAULT; + } +#endif + return 0; +} /* wext_set_power */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To get power management. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[out] prPower Pointer to iw_param structure containing tx power setting. +* \param[in] pcExtra NULL. +* +* \retval 0 Success. +* +* \note Power management mode is stored in pTxPow->value. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_get_power(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT struct iw_param *prPower, IN char *pcExtra) +{ + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM; + + ASSERT(prNetDev); + ASSERT(prPower); + if (FALSE == GLUE_CHK_PR2(prNetDev, prPower)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + +#if 0 +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), TRUE, TRUE, &u4BufLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), &u4BufLen); +#endif +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), &u4BufLen); +#endif + + if (rStatus != WLAN_STATUS_SUCCESS) + return -EFAULT; + + prPower->value = 0; + prPower->disabled = 1; + + if (Param_PowerModeCAM == ePowerMode) { + prPower->value = 0; + prPower->disabled = 1; + } else if (Param_PowerModeMAX_PSP == ePowerMode) { + prPower->value = 1; + prPower->disabled = 0; + } else if (Param_PowerModeFast_PSP == ePowerMode) { + prPower->value = 2; + prPower->disabled = 0; + } + + prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; +#if WIRELESS_EXT < 21 + prPower->value *= 1000000; +#endif + + /* printk(KERN_INFO "wext_get_power value(%d) disabled(%d) flag(0x%x)\n", */ + /* prPower->value, prPower->disabled, prPower->flags); */ + + return 0; +} /* wext_get_power */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set authentication parameters. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] rpAuth Pointer to iw_param structure containing authentication information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +static int +wext_set_auth(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_param *prAuth, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prAuth); + if (FALSE == GLUE_CHK_PR2(prNetDev, prAuth)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + /* Save information to glue info and process later when ssid is set. */ + switch (prAuth->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: +#if CFG_SUPPORT_WAPI + if (wlanQueryWapiMode(prGlueInfo->prAdapter)) { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + } else { + prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; + } +#else + prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; +#endif + break; + + case IW_AUTH_CIPHER_PAIRWISE: + prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value; + break; + + case IW_AUTH_CIPHER_GROUP: + prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value; + break; + + case IW_AUTH_KEY_MGMT: + prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value; +#if CFG_SUPPORT_WAPI + if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_PSK || + prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WAPI_CERT) { + UINT_32 u4BufLen; + WLAN_STATUS rStatus; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiMode, + &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); + } +#endif + if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS) + prGlueInfo->fgWpsActive = TRUE; + else + prGlueInfo->fgWpsActive = FALSE; + break; + + case IW_AUTH_80211_AUTH_ALG: + prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value; + break; + + case IW_AUTH_PRIVACY_INVOKED: + prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value; + break; +#if CFG_SUPPORT_802_11W + case IW_AUTH_MFP: + /* printk("wext_set_auth IW_AUTH_MFP=%d\n", prAuth->value); */ + prGlueInfo->rWpaInfo.u4Mfp = prAuth->value; + break; +#endif +#if CFG_SUPPORT_WAPI + case IW_AUTH_WAPI_ENABLED: + { + UINT_32 u4BufLen; + WLAN_STATUS rStatus; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiMode, + &prAuth->value, sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + } + DBGLOG(REQ, INFO, "IW_AUTH_WAPI_ENABLED :%d\n", prAuth->value); + break; +#endif + default: + /* + printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", prAuth->flags); + */ + break; + } + return 0; +} /* wext_set_auth */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To set encryption cipher and key. +* +* \param[in] prDev Net device requested. +* \param[in] prIwrInfo NULL. +* \param[in] prEnc Pointer to iw_point structure containing securiry information. +* \param[in] pcExtra Pointer to key string buffer. +* +* \retval 0 Success. +* \retval -EINVAL Key ID error for WEP. +* \retval -EFAULT Setting parameters to driver fail. +* \retval -EOPNOTSUPP Key size not supported. +* +* \note Securiry information is stored in pEnc. +*/ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_WAPI +UINT_8 keyStructBuf[320]; /* add/remove key shared buffer */ +#else +UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ +#endif + +static int +wext_set_encode_ext(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, IN struct iw_point *prEnc, IN char *pcExtra) +{ + P_PARAM_REMOVE_KEY_T prRemoveKey = (P_PARAM_REMOVE_KEY_T) keyStructBuf; + P_PARAM_KEY_T prKey = (P_PARAM_KEY_T) keyStructBuf; + + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T) wepBuf; + + struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *)pcExtra; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + /* ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; */ + +#if CFG_SUPPORT_WAPI + P_PARAM_WPI_KEY_T prWpiKey = (P_PARAM_WPI_KEY_T) keyStructBuf; +#endif + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (FALSE == GLUE_CHK_PR3(prNetDev, prEnc, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + memset(keyStructBuf, 0, sizeof(keyStructBuf)); + +#if CFG_SUPPORT_WAPI + if (prIWEncExt->alg == IW_ENCODE_ALG_SMS4) { + if (prEnc->flags & IW_ENCODE_DISABLED) { + /* printk(KERN_INFO "[wapi] IW_ENCODE_DISABLED\n"); */ + return 0; + } + /* KeyID */ + prWpiKey->ucKeyID = (prEnc->flags & IW_ENCODE_INDEX); + prWpiKey->ucKeyID--; + if (prWpiKey->ucKeyID > 1) { + /* key id is out of range */ + /* printk(KERN_INFO "[wapi] add key error: key_id invalid %d\n", prWpiKey->ucKeyID); */ + return -EINVAL; + } + + if (prIWEncExt->key_len != 32) { + /* key length not valid */ + /* printk(KERN_INFO "[wapi] add key error: key_len invalid %d\n", prIWEncExt->key_len); */ + return -EINVAL; + } + /* printk(KERN_INFO "[wapi] %d ext_flags %d\n", prEnc->flags, prIWEncExt->ext_flags); */ + + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + prWpiKey->eKeyType = ENUM_WPI_GROUP_KEY; + prWpiKey->eDirection = ENUM_WPI_RX; + } else if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prWpiKey->eKeyType = ENUM_WPI_PAIRWISE_KEY; + prWpiKey->eDirection = ENUM_WPI_RX_TX; + } + + /* PN */ + { + UINT_32 i; + + for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) + prWpiKey->aucPN[i] = prIWEncExt->tx_seq[i]; + for (i = 0; i < IW_ENCODE_SEQ_MAX_SIZE; i++) + prWpiKey->aucPN[IW_ENCODE_SEQ_MAX_SIZE + i] = prIWEncExt->rx_seq[i]; + } + + /* BSSID */ + memcpy(prWpiKey->aucAddrIndex, prIWEncExt->addr.sa_data, 6); + + memcpy(prWpiKey->aucWPIEK, prIWEncExt->key, 16); + prWpiKey->u4LenWPIEK = 16; + + memcpy(prWpiKey->aucWPICK, &prIWEncExt->key[16], 16); + prWpiKey->u4LenWPICK = 16; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiKey, + prWpiKey, sizeof(PARAM_WPI_KEY_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* printk(KERN_INFO "[wapi] add key error:%lx\n", rStatus); */ + } + } else +#endif + { + + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { + prRemoveKey->u4Length = sizeof(*prRemoveKey); + memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, 6); + /* + printk("IW_ENCODE_DISABLED: ID:%d, Addr:[ %pM ]\n", + prRemoveKey->KeyIndex, prRemoveKey->BSSID); + */ + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetRemoveKey, + prRemoveKey, prRemoveKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, INFO, "remove key error:%x\n", rStatus); + return 0; + } + /* return 0; */ + /* printk ("alg %x\n", prIWEncExt->alg); */ + + switch (prIWEncExt->alg) { + case IW_ENCODE_ALG_NONE: + break; + case IW_ENCODE_ALG_WEP: + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prIWEncExt->key_len == 5 || prIWEncExt->key_len == 13 || prIWEncExt->key_len == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + return -EINVAL; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prIWEncExt->key_len; + prWepKey->u4KeyLength = prIWEncExt->key_len; + /* kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prIWEncExt->key_len); */ + kalMemCopy(prWepKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddWep, + prWepKey, prWepKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetAddWep fail 0x%x\n", rStatus); + return -EFAULT; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetAuthMode fail 0x%x\n", rStatus); + return -EFAULT; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), + FALSE, FALSE, FALSE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidSetEncryptionStatus fail 0x%x\n", rStatus); + return -EFAULT; + } + + } else { + DBGLOG(REQ, INFO, "key length %x\n", prIWEncExt->key_len); + DBGLOG(REQ, INFO, "key error\n"); + } + + break; + case IW_ENCODE_ALG_TKIP: + case IW_ENCODE_ALG_CCMP: +#if CFG_SUPPORT_802_11W + case IW_ENCODE_ALG_AES_CMAC: +#endif + { + + /* KeyID */ + prKey->u4KeyIndex = (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) - 1 : 0; +#if CFG_SUPPORT_802_11W + if (prKey->u4KeyIndex > 5) { +#else + if (prKey->u4KeyIndex > 3) { +#endif + DBGLOG(REQ, ERROR, "key index error:0x%x\n", prKey->u4KeyIndex); + /* key id is out of range */ + return -EINVAL; + } + + /* bit(31) and bit(30) are shared by pKey and pRemoveKey */ + /* Tx Key Bit(31) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prKey->u4KeyIndex |= 0x1UL << 31; + /* Code style */ + } + /* Pairwise Key Bit(30) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* Do nothing */ + /* group key */ + } else { + /* pairwise key */ + prKey->u4KeyIndex |= 0x1UL << 30; + } + } + /* Rx SC Bit(29) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + prKey->u4KeyIndex |= 0x1UL << 29; + memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); + } + + /* BSSID */ + memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); + + /* switch tx/rx MIC key for sta */ + if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && prIWEncExt->key_len == 32) { + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, 16); + memcpy(((PUINT_8) prKey->aucKeyMaterial) + 16, prIWEncExt->key + 24, 8); + memcpy((prKey->aucKeyMaterial) + 24, prIWEncExt->key + 16, 8); + } else { + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, prIWEncExt->key_len); + } + + prKey->u4KeyLength = prIWEncExt->key_len; + prKey->u4Length = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + prKey->u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAddKey, + prKey, prKey->u4Length, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "add key error:%x\n", rStatus); + return -EFAULT; + } + break; + } + } + + return 0; +} /* wext_set_encode_ext */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Set country code +* +* \param[in] prNetDev Net device requested. +* \param[in] prData iwreq.u.data carries country code value. +* +* \retval 0 For success. +* \retval -EEFAULT For fail. +* +* \note Country code is stored and channel list is updated based on current country domain. +*/ +/*----------------------------------------------------------------------------*/ +static int wext_set_country(IN struct net_device *prNetDev, IN struct iw_point *prData) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + UINT_8 aucCountry[2]; + + ASSERT(prNetDev); + + /* prData->pointer should be like "COUNTRY US", "COUNTRY EU" + * and "COUNTRY JP" + */ + if (FALSE == GLUE_CHK_PR2(prNetDev, prData) || !prData->pointer || prData->length < 10) + return -EINVAL; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + aucCountry[0] = *((PUINT_8)prData->pointer + 8); + aucCountry[1] = *((PUINT_8)prData->pointer + 9); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To report the iw private args table to user space. +* +* \param[in] prNetDev Net device requested. +* \param[out] prData iwreq.u.data to carry the private args table. +* +* \retval 0 For success. +* \retval -E2BIG For user's buffer size is too small. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +static int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData) +{ + UINT_16 u2BufferSize = prData->length; + + /* Update our private args table size */ + prData->length = (__u16)sizeof(rIwPrivTable); + if (u2BufferSize < prData->length) + return -E2BIG; + + if (prData->length) { + if (copy_to_user(prData->pointer, rIwPrivTable, sizeof(rIwPrivTable))) + return -EFAULT; + } + + return 0; +} /* wext_get_priv */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief ioctl() (Linux Wireless Extensions) routines +* +* \param[in] prDev Net device requested. +* \param[in] ifr The ifreq structure for seeting the wireless extension. +* \param[in] i4Cmd The wireless extension ioctl command. +* +* \retval zero On success. +* \retval -EOPNOTSUPP If the cmd is not supported. +* \retval -EFAULT If copy_to_user goes wrong. +* \retval -EINVAL If any value's out of range. +* +* \note +*/ +/*----------------------------------------------------------------------------*/ +int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd) +{ + struct iwreq *iwr = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + int ret = 0; + char *prExtraBuf = NULL; + UINT_32 u4ExtraSize = 0; + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + WLAN_STATUS rStatus; + UINT_32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + /* printk("%d CMD:0x%x\n", jiffies_to_msecs(jiffies), i4Cmd); */ + + rIwReqInfo.cmd = (__u16) i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */ + ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, NULL); + break; + + /* case SIOCSIWNWID: 0x8B02, deprecated */ + /* case SIOCGIWNWID: 0x8B03, deprecated */ + + case SIOCSIWFREQ: /* 0x8B04, set channel */ + ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCGIWFREQ: /* 0x8B05, get channel */ + ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCSIWMODE: /* 0x8B06, set operation mode */ + ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL); + /* ret = 0; */ + break; + + case SIOCGIWMODE: /* 0x8B07, get operation mode */ + ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL); + break; + + /* case SIOCSIWSENS: 0x8B08, unsupported */ + /* case SIOCGIWSENS: 0x8B09, unsupported */ + + /* case SIOCSIWRANGE: 0x8B0A, unused */ + case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */ + if (iwr->u.data.pointer != NULL) { + /* Buffer size should be large enough */ + if (iwr->u.data.length < sizeof(struct iw_range)) { + ret = -E2BIG; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_range), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* reset all fields */ + memset(prExtraBuf, 0, sizeof(struct iw_range)); + iwr->u.data.length = sizeof(struct iw_range); + + ret = wext_get_range(prDev, NULL, &iwr->u.data, prExtraBuf); + /* Push up to the caller */ + if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) + ret = -EFAULT; + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_range)); + prExtraBuf = NULL; + } else { + ret = -EINVAL; + } + break; + + case SIOCSIWPRIV: /* 0x8B0C, set country code */ + ret = wext_set_country(prDev, &iwr->u.data); + break; + + case SIOCGIWPRIV: /* 0x8B0D, get private args table */ + ret = wext_get_priv(prDev, &iwr->u.data); + break; + + /* case SIOCSIWSTATS: 0x8B0E, unused */ + /* case SIOCGIWSTATS: + get statistics, intercepted by wireless_process_ioctl() in wireless.c, + redirected to dev_iwstats(), dev->get_wireless_stats(). + */ + /* case SIOCSIWSPY: 0x8B10, unsupported */ + /* case SIOCGIWSPY: 0x8B11, unsupported */ + /* case SIOCSIWTHRSPY: 0x8B12, unsupported */ + /* case SIOCGIWTHRSPY: 0x8B13, unsupported */ + + case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */ + if (iwr->u.ap_addr.sa_data[0] == 0 && + iwr->u.ap_addr.sa_data[1] == 0 && + iwr->u.ap_addr.sa_data[2] == 0 && + iwr->u.ap_addr.sa_data[3] == 0 && + iwr->u.ap_addr.sa_data[4] == 0 && iwr->u.ap_addr.sa_data[5] == 0) { + /* WPA Supplicant will set 000000000000 in + ** wpa_driver_wext_deinit(), do nothing here or disassoc again? + */ + ret = 0; + break; + } + ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + + break; + + case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */ + ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + break; + + case SIOCSIWMLME: /* 0x8B16, request MLME operation */ + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_mlme)) { + DBGLOG(REQ, ERROR, "MLME buffer strange:%d\n", iwr->u.data.length); + ret = -EINVAL; + break; + } + + if (!iwr->u.data.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_mlme))) + ret = -EFAULT; + else + ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), prExtraBuf); + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); + prExtraBuf = NULL; + break; + + /* case SIOCGIWAPLIST: 0x8B17, deprecated */ + case SIOCSIWSCAN: /* 0x8B18, scan request */ + if (iwr->u.data.pointer == NULL) + ret = wext_set_scan(prDev, NULL, NULL, NULL); +#if WIRELESS_EXT > 17 + else if (iwr->u.data.length == sizeof(struct iw_scan_req)) { + prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + if (copy_from_user(prExtraBuf, ((struct iw_scan_req *)(iwr->u.data.pointer))->essid, + ((struct iw_scan_req *)(iwr->u.data.pointer))->essid_len)) { + ret = -EFAULT; + } else { + ret = wext_set_scan(prDev, NULL, (union iwreq_data *)&(iwr->u.data), prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN); + prExtraBuf = NULL; + } +#endif + else + ret = -EINVAL; + break; +#if 1 + case SIOCGIWSCAN: /* 0x8B19, get scan results */ + if (!iwr->u.data.pointer || !iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + u4ExtraSize = iwr->u.data.length; + /* allocate the same size of kernel buffer to store scan results. */ + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* iwr->u.data.length may be updated by wext_get_scan() */ + ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf); + if (ret != 0) { + if (ret == -E2BIG) + DBGLOG(REQ, WARN, "[wifi] wext_get_scan -E2BIG\n"); + } else { + /* check updated length is valid */ + ASSERT(iwr->u.data.length <= u4ExtraSize); + if (iwr->u.data.length > u4ExtraSize) { + DBGLOG(REQ, INFO, "Updated result length is larger than allocated (%d > %u)\n", + iwr->u.data.length, u4ExtraSize); + iwr->u.data.length = u4ExtraSize; + } + + if (copy_to_user(iwr->u.data.pointer, prExtraBuf, iwr->u.data.length)) + ret = -EFAULT; + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + + break; + +#endif + +#if 1 + case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */ + if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + break; + } + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.essid.pointer, iwr->u.essid.length)) { + ret = -EFAULT; + } else { + /* Add trailing '\0' for printk */ + /* prExtraBuf[iwr->u.essid.length] = 0; */ + /* printk(KERN_INFO "wext_set_essid: %s (%d)\n", prExtraBuf, iwr->u.essid.length); */ + ret = wext_set_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); + /* printk ("set essid %d\n", ret); */ + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4); + prExtraBuf = NULL; + break; + +#endif + + case SIOCGIWESSID: /* 0x8B1B, get SSID */ + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + if (iwr->u.essid.length < IW_ESSID_MAX_SIZE) { + DBGLOG(REQ, ERROR, "[wifi] iwr->u.essid.length:%d too small\n", iwr->u.essid.length); + ret = -E2BIG; /* let caller try larger buffer */ + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* iwr->u.essid.length is updated by wext_get_essid() */ + + ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); + if (ret == 0) { + if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, iwr->u.essid.length)) + ret = -EFAULT; + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE); + prExtraBuf = NULL; + + break; + + /* case SIOCSIWNICKN: 0x8B1C, not supported */ + /* case SIOCGIWNICKN: 0x8B1D, not supported */ + + case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */ + /* ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, NULL); */ + break; + + case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */ + ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL); + break; + + case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */ + ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */ + ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + /* case SIOCSIWFRAG: 0x8B24, unsupported */ + case SIOCGIWFRAG: /* 0x8B25, get frag threshold */ + ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL); + break; + + case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */ + ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */ + ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + /* case SIOCSIWRETRY: 0x8B28, unsupported */ + /* case SIOCGIWRETRY: 0x8B29, unsupported */ + +#if 1 + case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */ + /* Only DISABLED case has NULL pointer and length == 0 */ + if (iwr->u.encoding.pointer) { + if (iwr->u.encoding.length > 16) { + ret = -E2BIG; + break; + } + + u4ExtraSize = iwr->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) + ret = -EFAULT; + } else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) + ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, prExtraBuf); + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */ + /* check pointer */ + ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL); + break; + + case SIOCSIWPOWER: /* 0x8B2C, set power management */ + ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL); + break; + + case SIOCGIWPOWER: /* 0x8B2D, get power management */ + ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL); + break; + +#if WIRELESS_EXT > 17 + case SIOCSIWGENIE: /* 0x8B30, set gen ie */ + if (iwr->u.data.pointer == NULL) + break; + + if (0 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */) + break; + + /* Fixed length structure */ +#if CFG_SUPPORT_WAPI + if (iwr->u.data.length > 42 /* The max wapi ie buffer */) { + ret = -EINVAL; + break; + } +#endif + u4ExtraSize = iwr->u.data.length; + if (u4ExtraSize == 0) + break; + + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, iwr->u.data.length)) { + ret = -EFAULT; + } else { +#if CFG_SUPPORT_WAPI + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWapiAssocInfo, + prExtraBuf, + u4ExtraSize, FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO "[wapi] set wapi assoc info error:%lx\n", + rStatus); */ +#endif +#if CFG_SUPPORT_WPS2 + PUINT_8 prDesiredIE = NULL; + + if (wextSrchDesiredWPSIE(prExtraBuf, + u4ExtraSize, + 0xDD, (PUINT_8 *) &prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, + wlanoidSetWSCAssocInfo, + prDesiredIE, + IE_SIZE(prDesiredIE), + FALSE, + FALSE, TRUE, FALSE, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* printk(KERN_INFO "[WSC] set WSC assoc info + error:%lx\n", rStatus); */ + } + } +#endif +#if CFG_SUPPORT_WAPI + } +#endif + } + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + break; + + case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */ + break; + +#endif + + case SIOCSIWAUTH: /* 0x8B32, set auth mode params */ + ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL); + break; + + /* case SIOCGIWAUTH: 0x8B33, unused? */ + case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */ + if (iwr->u.encoding.pointer) { + u4ExtraSize = iwr->u.encoding.length; + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, iwr->u.encoding.length)) + ret = -EFAULT; + } else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) + ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, prExtraBuf); + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + /* case SIOCGIWENCODEEXT: 0x8B35, unused? */ + + case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */ +#if 1 + if (iwr->u.data.pointer) { + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_pmksa)) { + ret = -EINVAL; + break; + } + + u4ExtraSize = sizeof(struct iw_pmksa); + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, sizeof(struct iw_pmksa))) { + ret = -EFAULT; + } else { + switch (((struct iw_pmksa *)prExtraBuf)->cmd) { + case IW_PMKSA_ADD: + /* + printk(KERN_INFO "IW_PMKSA_ADD [ %pM ]\n", + (((struct iw_pmksa *)pExtraBuf)->bssid.sa_data)); + */ + prPmkid = + (P_PARAM_PMKID_T) kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), + VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(REQ, ERROR, "Can not alloc memory for IW_PMKSA_ADD\n"); + ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); + prPmkid->u4BSSIDInfoCount = 1; + kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, + ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, 6); + kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, + ((struct iw_pmksa *)prExtraBuf)->pmkid, IW_PMKID_LEN); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, + prPmkid, + sizeof(PARAM_PMKID_T), + FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, ERROR, "add pmkid error:%x\n", rStatus); + kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); + break; + case IW_PMKSA_REMOVE: + /* + printk(KERN_INFO "IW_PMKSA_REMOVE [ %pM ]\n", + (((struct iw_pmksa *)buf)->bssid.sa_data)); + */ + break; + case IW_PMKSA_FLUSH: + /* + printk(KERN_INFO "IW_PMKSA_FLUSH\n"); + */ + prPmkid = (P_PARAM_PMKID_T) kalMemAlloc(8, VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(REQ, ERROR, + "Can not alloc memory for IW_PMKSA_FLUSH\n"); + ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8; + prPmkid->u4BSSIDInfoCount = 0; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetPmkid, + prPmkid, + sizeof(PARAM_PMKID_T), + FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, ERROR, "flush pmkid error:%x\n", rStatus); + kalMemFree(prPmkid, VIR_MEM_TYPE, 8); + break; + default: + DBGLOG(REQ, WARN, "UNKNOWN iw_pmksa command:%d\n", + ((struct iw_pmksa *)prExtraBuf)->cmd); + ret = -EFAULT; + break; + } + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + } else if (iwr->u.data.length != 0) { + ret = -EINVAL; + break; + } +#endif + break; + +#endif + + default: + /* printk(KERN_NOTICE "unsupported IOCTL: 0x%x\n", i4Cmd); */ + ret = -EOPNOTSUPP; + break; + } + + /* printk("%ld CMD:0x%x ret:%d\n", jiffies_to_msecs(jiffies), i4Cmd, ret); */ + + return ret; +} /* wext_support_ioctl */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief To send an event (RAW socket pacekt) to user process actively. +* +* \param[in] prGlueInfo Glue layer info. +* \param[in] u4cmd Whcih event command we want to indicate to user process. +* \param[in] pData Data buffer to be indicated. +* \param[in] dataLen Available data size in pData. +* +* \return (none) +* +* \note Event is indicated to upper layer if cmd is supported and data is valid. +* Using of kernel symbol wireless_send_event(), which is defined in +* after WE-14 (2.4.20). +*/ +/*----------------------------------------------------------------------------*/ +void +wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4dataLen) +{ + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; +#if WIRELESS_EXT >= 15 + unsigned char *pucDesiredIE = NULL; + unsigned char aucExtraInfoBuf[200]; +#endif +#if WIRELESS_EXT < 18 + int i; +#endif + + memset(&wrqu, 0, sizeof(wrqu)); + + switch (u4Cmd) { + case SIOCGIWTXPOW: + memcpy(&wrqu.power, pucData, u4dataLen); + break; + case SIOCGIWSCAN: + complete_all(&prGlueInfo->rScanComp); + break; + + case SIOCGIWAP: + if (pucData) + ether_addr_copy((u8 *)&(wrqu.ap_addr.sa_data), pucData); + /*memcpy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN);*/ + else + memset(&wrqu.ap_addr.sa_data, 0, ETH_ALEN); + break; + + case IWEVASSOCREQIE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, &pucDesiredIE)) { + /* RSN IE found */ + /* Do nothing */ +#if 0 + } else if (wextSrchDesiredWPSIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { + /* WPS IE found */ + /* Do nothing */ +#endif + } else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, &pucDesiredIE)) { + /* WPA IE found */ + /* Do nothing*/ +#if CFG_SUPPORT_WAPI /* Android+ */ + } else if (wextSrchDesiredWAPIIE(pucData, u4dataLen, &pucDesiredIE)) { + /* WAPI IE found */ + /* printk("wextSrchDesiredWAPIIE!!\n"); */ +#endif + } else { + /* no WPA/RSN IE found, skip this event */ + goto skip_indicate_event; + } +#if WIRELESS_EXT < 18 + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + pucExtraInfo += sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs="); + /* printk(KERN_DEBUG "assoc info buffer size needed:%d\n", infoElemLen * 2 + 17); */ + /* translate binary string to hex string, requirement of IWEVCUSTOM */ + for (i = 0; i < pucDesiredIE[1] + 2; ++i) + pucExtraInfo += sprintf(pucExtraInfo, "%02x", pucDesiredIE[i]); + pucExtraInfo = aucExtraInfoBuf; + wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2; +#else + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; +#endif +#endif /* WIRELESS_EXT < 15 */ + break; + + case IWEVMICHAELMICFAILURE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + if (pucData) { + P_PARAM_AUTH_REQUEST_T pAuthReq = (P_PARAM_AUTH_REQUEST_T) pucData; + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + pucExtraInfo += sprintf(pucExtraInfo, "MLME-MICHAELMICFAILURE.indication "); + pucExtraInfo += sprintf(pucExtraInfo, + "%s", + (pAuthReq->u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR) ? + "groupcast " : "unicast "); + + wrqu.data.length = pucExtraInfo - aucExtraInfoBuf; + pucExtraInfo = aucExtraInfoBuf; + } +#endif /* WIRELESS_EXT < 15 */ + break; + + case IWEVPMKIDCAND: + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA2 && + prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) { + + /* only used in WPA2 */ +#if WIRELESS_EXT >= 18 + P_PARAM_PMKID_CANDIDATE_T prPmkidCand = (P_PARAM_PMKID_CANDIDATE_T) pucData; + + struct iw_pmkid_cand rPmkidCand; + + pucExtraInfo = aucExtraInfoBuf; + + rPmkidCand.flags = prPmkidCand->u4Flags; + rPmkidCand.index = 0; + rPmkidCand.bssid.sa_family = 0; + kalMemCopy(rPmkidCand.bssid.sa_data, prPmkidCand->arBSSID, 6); + + kalMemCopy(pucExtraInfo, (PUINT_8) &rPmkidCand, sizeof(struct iw_pmkid_cand)); + wrqu.data.length = sizeof(struct iw_pmkid_cand); + + /* pmkid canadidate list is supported after WE-18 */ + /* indicate struct iw_pmkid_cand */ +#else + /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, WE < 18\n"); */ + goto skip_indicate_event; +#endif + } else { + /* printk(KERN_INFO "IWEVPMKIDCAND event skipped, NOT WPA2\n"); */ + goto skip_indicate_event; + } + break; + + case IWEVCUSTOM: + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T)); + wrqu.data.length = sizeof(PTA_IPC_T); + break; + + default: + /* printk(KERN_INFO "Unsupported wext event:%x\n", cmd); */ + goto skip_indicate_event; + } + + /* Send event to user space */ + wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, pucExtraInfo); + +skip_indicate_event: + return; +} /* wext_indicate_wext_event */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief A method of struct net_device, to get the network interface statistical +* information. +* +* Whenever an application needs to get statistics for the interface, this method +* is called. This happens, for example, when ifconfig or netstat -i is run. +* +* \param[in] pDev Pointer to struct net_device. +* +* \return net_device_stats buffer pointer. +* +*/ +/*----------------------------------------------------------------------------*/ +struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev) +{ + + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_statistics *pStats = NULL; + INT_32 i4Rssi; + UINT_32 bufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) + goto stat_out; + + pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); + + if (!prDev || !netif_carrier_ok(prDev)) { + /* network not connected */ + goto stat_out; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, sizeof(i4Rssi), TRUE, TRUE, TRUE, FALSE, &bufLen); + +stat_out: + return pStats; +} /* wlan_get_wireless_stats */ + + +#endif /* WIRELESS_EXT */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c new file mode 100644 index 0000000000000..2b6c3df845942 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/gl_wext_priv.c @@ -0,0 +1,3142 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_wext_priv.c#4 +*/ + +/*! \file gl_wext_priv.c + \brief This file includes private ioctl support. +*/ + +/* +** Log: gl_wext_priv.c + * + * 07 17 2012 yuche.tsai + * NULL + * Let netdev bring up. + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 03 20 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * [WCXRP00001202] [MT6628 Wi-Fi][FW] Adding the New PN init code + * use return to avoid the ioctl return not supported + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 01 16 2012 wh.su + * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl + * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 11 02 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Fixed typo. + * + * 09 20 2011 chinglan.wang + * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. + * . + * + * 07 28 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings + * Add BWCS cmd and event. + * + * 07 18 2011 chinghwa.yu + * [WCXRP00000063] Update BCM CoEx design and settings[WCXRP00000612] [MT6620 Wi-Fi] [FW] CSD update SWRDD algorithm + * Add CMD/Event for RDD and BWCS. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 26 2011 wh.su + * [WCXRP00000396] [MT6620 Wi-Fi][Driver] Support Sw Ctrl ioctl at linux + * adding the SW cmd ioctl support, use set/get structure ioctl. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Adjust OID order. + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 12 15 2010 george.huang + * [WCXRP00000152] [MT6620 Wi-Fi] AP mode power saving function + * Support set PS profile and set WMM-PS related iwpriv. + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * [WCXRP00000086] [MT6620 Wi-Fi][Driver] The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 24 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * correct typo for NVRAM access. + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * enable OID_CUSTOM_MTK_WIFI_TEST for RFTest & META tool + * + * 05 29 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * fix private ioctl for rftest + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support +** \main\maintrunk.MT5921\32 2009-10-08 10:33:25 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input +** parameters and pointers. +** \main\maintrunk.MT5921\31 2009-09-29 16:46:21 GMT mtk01090 +** Remove unused functions +** \main\maintrunk.MT5921\30 2009-09-29 14:46:47 GMT mtk01090 +** Fix compile warning +** \main\maintrunk.MT5921\29 2009-09-29 14:28:48 GMT mtk01090 +** Fix compile warning +** \main\maintrunk.MT5921\28 2009-09-28 22:21:38 GMT mtk01090 +** Refine lines to suppress compile warning +** \main\maintrunk.MT5921\27 2009-09-28 20:19:14 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\26 2009-08-18 22:56:53 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\25 2009-05-07 22:26:15 GMT mtk01089 +** Add mandatory and private IO control for Linux BWCS +** \main\maintrunk.MT5921\24 2009-04-29 10:07:05 GMT mtk01088 +** fixed the compiling error at linux +** \main\maintrunk.MT5921\23 2009-04-24 09:09:45 GMT mtk01088 +** mark the code not used at linux supplicant v0.6.7 +** \main\maintrunk.MT5921\22 2008-11-24 21:03:51 GMT mtk01425 +** 1. Add PTA_ENABLED flag +** \main\maintrunk.MT5921\21 2008-08-29 14:55:59 GMT mtk01088 +** adjust the code for meet the coding style, and add assert check +** \main\maintrunk.MT5921\20 2008-07-16 15:23:20 GMT mtk01104 +** Support GPIO2 mode +** \main\maintrunk.MT5921\19 2008-07-15 17:43:11 GMT mtk01084 +** modify variable name +** \main\maintrunk.MT5921\18 2008-07-14 14:37:58 GMT mtk01104 +** Add exception handle about length in function priv_set_struct() +** \main\maintrunk.MT5921\17 2008-07-14 13:55:32 GMT mtk01104 +** Support PRIV_CMD_BT_COEXIST +** \main\maintrunk.MT5921\16 2008-07-09 00:20:15 GMT mtk01461 +** Add priv oid to support WMM_PS_TEST +** \main\maintrunk.MT5921\15 2008-06-02 11:15:22 GMT mtk01461 +** Update after wlanoidSetPowerMode changed +** \main\maintrunk.MT5921\14 2008-05-30 19:31:07 GMT mtk01461 +** Add IOCTL for Power Mode +** \main\maintrunk.MT5921\13 2008-05-30 18:57:15 GMT mtk01461 +** Not use wlanoidSetCSUMOffloadForLinux() +** \main\maintrunk.MT5921\12 2008-05-30 15:13:18 GMT mtk01084 +** rename wlanoid +** \main\maintrunk.MT5921\11 2008-05-29 14:16:31 GMT mtk01084 +** rename for wlanoidSetBeaconIntervalForLinux +** \main\maintrunk.MT5921\10 2008-04-17 23:06:37 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\9 2008-03-31 21:00:55 GMT mtk01461 +** Add priv IOCTL for VOIP setting +** \main\maintrunk.MT5921\8 2008-03-31 13:49:43 GMT mtk01461 +** Add priv ioctl to turn on / off roaming +** \main\maintrunk.MT5921\7 2008-03-26 15:35:14 GMT mtk01461 +** Add CSUM offload priv ioctl for Linux +** \main\maintrunk.MT5921\6 2008-03-11 14:50:59 GMT mtk01461 +** Unify priv ioctl +** \main\maintrunk.MT5921\5 2007-11-06 19:32:30 GMT mtk01088 +** add WPS code +** \main\maintrunk.MT5921\4 2007-10-30 12:01:39 GMT MTK01425 +** 1. Update wlanQueryInformation and wlanSetInformation +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "precomp.h" + +#include "gl_os.h" +#include "gl_wext_priv.h" +#if CFG_SUPPORT_WAPI +#include "gl_sec.h" +#endif +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_os.h" +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define NUM_SUPPORTED_OIDS (sizeof(arWlanOidReqTable) / sizeof(WLAN_REQ_ENTRY)) +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_RXFILTER_ADD "RXFILTER-ADD" +#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" +#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" +#define CMD_SETFWPATH "SETFWPATH" +#define CMD_SETBAND "SETBAND" +#define CMD_GETBAND "GETBAND" +#define CMD_COUNTRY "COUNTRY" +#define CMD_P2P_SET_NOA "P2P_SET_NOA" +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#define CMD_P2P_SET_PS "P2P_SET_PS" +#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" +#define CMD_SETROAMMODE "SETROAMMODE" +#define CMD_MIRACAST "MIRACAST" + +#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" +#define CMD_PNOSETUP_SET "PNOSETUP " +#define CMD_PNOENABLE_SET "PNOFORCE" +#define CMD_PNODEBUG_SET "PNODEBUG" +#define CMD_WLS_BATCHING "WLS_BATCHING" + +#define CMD_OKC_SET_PMK "SET_PMK" +#define CMD_OKC_ENABLE "OKC_ENABLE" + +/* miracast related definition */ +#define MIRACAST_MODE_OFF 0 +#define MIRACAST_MODE_SOURCE 1 +#define MIRACAST_MODE_SINK 2 + +#ifndef MIRACAST_AMPDU_SIZE +#define MIRACAST_AMPDU_SIZE 8 +#endif + +#ifndef MIRACAST_MCHAN_ALGO +#define MIRACAST_MCHAN_ALGO 1 +#endif + +#ifndef MIRACAST_MCHAN_BW +#define MIRACAST_MCHAN_BW 25 +#endif + +#define CMD_BAND_AUTO 0 +#define CMD_BAND_5G 1 +#define CMD_BAND_2G 2 +#define CMD_BAND_ALL 3 + +/* Mediatek private command */ + +#define CMD_SET_SW_CTRL "SET_SW_CTRL" +#define CMD_GET_SW_CTRL "GET_SW_CTRL" +#define CMD_SET_CFG "SET_CFG" +#define CMD_GET_CFG "GET_CFG" +#define CMD_SET_CHIP "SET_CHIP" +#define CMD_GET_CHIP "GET_CHIP" +#define CMD_SET_DBG_LEVEL "SET_DBG_LEVEL" +#define CMD_GET_DBG_LEVEL "GET_DBG_LEVEL" +#define PRIV_CMD_SIZE 512 + +static UINT_32 g_ucMiracastMode = MIRACAST_MODE_OFF; + +typedef struct cmd_tlv { + char prefix; + char version; + char subver; + char reserved; +} cmd_tlv_t; + +typedef struct priv_driver_cmd_s { + char buf[PRIV_CMD_SIZE]; + int used_len; + int total_len; +} priv_driver_cmd_t; + +#if CFG_SUPPORT_BATCH_SCAN +#define CMD_BATCH_SET "WLS_BATCHING SET" +#define CMD_BATCH_GET "WLS_BATCHING GET" +#define CMD_BATCH_STOP "WLS_BATCHING STOP" +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int +priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); + +static int +priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen); + +#if 0 /* CFG_SUPPORT_WPS */ +static int +priv_set_appie(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); + +static int +priv_set_filter(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, OUT char *pcExtra); +#endif /* CFG_SUPPORT_WPS */ + +static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY * ppWlanReqEntry); + +#if 0 +static WLAN_STATUS +reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +static WLAN_STATUS +reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); +#endif + +static WLAN_STATUS +reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static UINT_8 aucOidBuf[4096] = { 0 }; + +/* OID processing table */ +/* Order is important here because the OIDs should be in order of + increasing value for binary searching. */ +static WLAN_REQ_ENTRY arWlanOidReqTable[] = { + /* + {(NDIS_OID)rOid, + (PUINT_8)pucOidName, + fgQryBufLenChecking, fgSetBufLenChecking, fgIsHandleInGlueLayerOnly, u4InfoBufLen, + pfOidQueryHandler, + pfOidSetHandler} + */ + /* General Operational Characteristics */ + + /* Ethernet Operational Characteristics */ + {OID_802_3_CURRENT_ADDRESS, + DISP_STRING("OID_802_3_CURRENT_ADDRESS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 6, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCurrentAddr, + NULL}, + + /* OID_802_3_MULTICAST_LIST */ + /* OID_802_3_MAXIMUM_LIST_SIZE */ + /* Ethernet Statistics */ + + /* NDIS 802.11 Wireless LAN OIDs */ + {OID_802_11_SUPPORTED_RATES, + DISP_STRING("OID_802_11_SUPPORTED_RATES"), + TRUE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_RATES_EX), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySupportedRates, + NULL} + , + /* + {OID_802_11_CONFIGURATION, + DISP_STRING("OID_802_11_CONFIGURATION"), + TRUE, TRUE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_802_11_CONFIG_T), + (PFN_OID_HANDLER_FUNC_REQ)reqExtQueryConfiguration, + (PFN_OID_HANDLER_FUNC_REQ)reqExtSetConfiguration}, + */ + {OID_PNP_SET_POWER, + DISP_STRING("OID_PNP_SET_POWER"), + TRUE, FALSE, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_DEVICE_POWER_STATE), + NULL, + (PFN_OID_HANDLER_FUNC_REQ) reqExtSetAcpiDevicePowerState} + , + + /* Custom OIDs */ + {OID_CUSTOM_OID_INTERFACE_VERSION, + DISP_STRING("OID_CUSTOM_OID_INTERFACE_VERSION"), + TRUE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryOidInterfaceVersion, + NULL} + , + + /* + #if PTA_ENABLED + {OID_CUSTOM_BT_COEXIST_CTRL, + DISP_STRING("OID_CUSTOM_BT_COEXIST_CTRL"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_BT_COEXIST_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtCoexistCtrl}, + #endif + */ + + /* + {OID_CUSTOM_POWER_MANAGEMENT_PROFILE, + DISP_STRING("OID_CUSTOM_POWER_MANAGEMENT_PROFILE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPwrMgmtProfParam, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPwrMgmtProfParam}, + {OID_CUSTOM_PATTERN_CONFIG, + DISP_STRING("OID_CUSTOM_PATTERN_CONFIG"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_PATTERN_SEARCH_CONFIG_STRUCT_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPatternConfig}, + {OID_CUSTOM_BG_SSID_SEARCH_CONFIG, + DISP_STRING("OID_CUSTOM_BG_SSID_SEARCH_CONFIG"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBgSsidParam}, + {OID_CUSTOM_VOIP_SETUP, + DISP_STRING("OID_CUSTOM_VOIP_SETUP"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryVoipConnectionStatus, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetVoipConnectionStatus}, + {OID_CUSTOM_ADD_TS, + DISP_STRING("OID_CUSTOM_ADD_TS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidAddTS}, + {OID_CUSTOM_DEL_TS, + DISP_STRING("OID_CUSTOM_DEL_TS"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidDelTS}, + */ + + /* + #if CFG_LP_PATTERN_SEARCH_SLT + {OID_CUSTOM_SLT, + DISP_STRING("OID_CUSTOM_SLT"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySltResult, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSltMode}, + #endif + + {OID_CUSTOM_ROAMING_EN, + DISP_STRING("OID_CUSTOM_ROAMING_EN"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRoamingFunction, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetRoamingFunction}, + {OID_CUSTOM_WMM_PS_TEST, + DISP_STRING("OID_CUSTOM_WMM_PS_TEST"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWiFiWmmPsTest}, + {OID_CUSTOM_COUNTRY_STRING, + DISP_STRING("OID_CUSTOM_COUNTRY_STRING"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentCountry, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetCurrentCountry}, + + #if CFG_SUPPORT_802_11D + {OID_CUSTOM_MULTI_DOMAIN_CAPABILITY, + DISP_STRING("OID_CUSTOM_MULTI_DOMAIN_CAPABILITY"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMultiDomainCap, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMultiDomainCap}, + #endif + + {OID_CUSTOM_GPIO2_MODE, + DISP_STRING("OID_CUSTOM_GPIO2_MODE"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_PARAM_GPIO2_MODE_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetGPIO2Mode}, + {OID_CUSTOM_CONTINUOUS_POLL, + DISP_STRING("OID_CUSTOM_CONTINUOUS_POLL"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CONTINUOUS_POLL_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryContinuousPollInterval, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetContinuousPollProfile}, + {OID_CUSTOM_DISABLE_BEACON_DETECTION, + DISP_STRING("OID_CUSTOM_DISABLE_BEACON_DETECTION"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryDisableBeaconDetectionFunc, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisableBeaconDetectionFunc}, + */ + + /* WPS */ + /* + {OID_CUSTOM_DISABLE_PRIVACY_CHECK, + DISP_STRING("OID_CUSTOM_DISABLE_PRIVACY_CHECK"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetDisablePriavcyCheck}, + */ + + {OID_CUSTOM_MCR_RW, + DISP_STRING("OID_CUSTOM_MCR_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMcrRead, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetMcrWrite} + , + + {OID_CUSTOM_EEPROM_RW, + DISP_STRING("OID_CUSTOM_EEPROM_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromRead, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetEepromWrite} + , + + {OID_CUSTOM_SW_CTRL, + DISP_STRING("OID_CUSTOM_SW_CTRL"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQuerySwCtrlRead, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetSwCtrlWrite} + , + + {OID_CUSTOM_MEM_DUMP, + DISP_STRING("OID_CUSTOM_MEM_DUMP"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryMemDump, + NULL} + , + + {OID_CUSTOM_TEST_MODE, + DISP_STRING("OID_CUSTOM_TEST_MODE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetTestMode} + , + + /* + {OID_CUSTOM_TEST_RX_STATUS, + DISP_STRING("OID_CUSTOM_TEST_RX_STATUS"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestRxStatus, + NULL}, + {OID_CUSTOM_TEST_TX_STATUS, + DISP_STRING("OID_CUSTOM_TEST_TX_STATUS"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryRfTestTxStatus, + NULL}, + */ + {OID_CUSTOM_ABORT_TEST_MODE, + DISP_STRING("OID_CUSTOM_ABORT_TEST_MODE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAbortTestMode} + , + {OID_CUSTOM_MTK_WIFI_TEST, + DISP_STRING("OID_CUSTOM_MTK_WIFI_TEST"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestQueryAutoTest, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidRftestSetAutoTest} + , + + /* OID_CUSTOM_EMULATION_VERSION_CONTROL */ + + /* BWCS */ +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + {OID_CUSTOM_BWCS_CMD, + DISP_STRING("OID_CUSTOM_BWCS_CMD"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PTA_IPC_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryBT, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetBT} + , +#endif + +/* {OID_CUSTOM_SINGLE_ANTENNA, + DISP_STRING("OID_CUSTOM_SINGLE_ANTENNA"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBtSingleAntenna, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBtSingleAntenna}, + {OID_CUSTOM_SET_PTA, + DISP_STRING("OID_CUSTOM_SET_PTA"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryPta, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetPta}, + */ + + {OID_CUSTOM_MTK_NVRAM_RW, + DISP_STRING("OID_CUSTOM_MTK_NVRAM_RW"), + TRUE, TRUE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryNvramRead, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetNvramWrite} + , + + {OID_CUSTOM_CFG_SRC_TYPE, + DISP_STRING("OID_CUSTOM_CFG_SRC_TYPE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_CFG_SRC_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryCfgSrcType, + NULL} + , + + {OID_CUSTOM_EEPROM_TYPE, + DISP_STRING("OID_CUSTOM_EEPROM_TYPE"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(ENUM_EEPROM_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ) wlanoidQueryEepromType, + NULL} + , + +#if CFG_SUPPORT_WAPI + {OID_802_11_WAPI_MODE, + DISP_STRING("OID_802_11_WAPI_MODE"), + FALSE, TRUE, ENUM_OID_DRIVER_CORE, 4, + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiMode} + , + {OID_802_11_WAPI_ASSOC_INFO, + DISP_STRING("OID_802_11_WAPI_ASSOC_INFO"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiAssocInfo} + , + {OID_802_11_SET_WAPI_KEY, + DISP_STRING("OID_802_11_SET_WAPI_KEY"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, sizeof(PARAM_WPI_KEY_T), + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWapiKey} + , +#endif + +#if CFG_SUPPORT_WPS2 + {OID_802_11_WSC_ASSOC_INFO, + DISP_STRING("OID_802_11_WSC_ASSOC_INFO"), + FALSE, FALSE, ENUM_OID_DRIVER_CORE, 0, + NULL, + (PFN_OID_HANDLER_FUNC_REQ) wlanoidSetWSCAssocInfo} + , +#endif +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dispatching function for private ioctl region (SIOCIWFIRSTPRIV ~ +* SIOCIWLASTPRIV). +* +* \param[in] prNetDev Net device requested. +* \param[in] prIfReq Pointer to ifreq structure. +* \param[in] i4Cmd Command ID between SIOCIWFIRSTPRIV and SIOCIWLASTPRIV. +* +* \retval 0 for success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +int priv_support_ioctl(IN struct net_device *prNetDev, IN OUT struct ifreq *prIfReq, IN int i4Cmd) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + + /* prDev is verified in the caller function wlanDoIOCTL() */ + + /* Prepare the call */ + rIwReqInfo.cmd = (__u16) i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case IOCTL_SET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ + return priv_set_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); + + case IOCTL_GET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need copy_from/to_user() */ + return priv_get_int(prNetDev, &rIwReqInfo, &(prIwReq->u), (char *)&(prIwReq->u)); + + case IOCTL_SET_STRUCT: + case IOCTL_SET_STRUCT_FOR_EM: + return priv_set_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); + + case IOCTL_GET_STRUCT: + return priv_get_struct(prNetDev, &rIwReqInfo, &prIwReq->u, (char *)&(prIwReq->u)); + + default: + return -EOPNOTSUPP; + + } /* end of switch */ + +} /* priv_support_ioctl */ + +#if CFG_SUPPORT_BATCH_SCAN + +EVENT_BATCH_RESULT_T g_rEventBatchResult[CFG_BATCH_MAX_MSCAN]; + +UINT_32 batchChannelNum2Freq(UINT_32 u4ChannelNum) +{ + UINT_32 u4ChannelInMHz; + + if (u4ChannelNum >= 1 && u4ChannelNum <= 13) + u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; + else if (u4ChannelNum == 14) + u4ChannelInMHz = 2484; + else if (u4ChannelNum == 133) + u4ChannelInMHz = 3665; /* 802.11y */ + else if (u4ChannelNum == 137) + u4ChannelInMHz = 3685; /* 802.11y */ + else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) + u4ChannelInMHz = 5000 + u4ChannelNum * 5; + else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) + u4ChannelInMHz = 4000 + u4ChannelNum * 5; + else + u4ChannelInMHz = 0; + + return u4ChannelInMHz; +} + +#define TMP_TEXT_LEN_S 40 +#define TMP_TEXT_LEN_L 60 +static UCHAR text1[TMP_TEXT_LEN_S], text2[TMP_TEXT_LEN_L], text3[TMP_TEXT_LEN_L]; /* A safe len */ + +WLAN_STATUS +batchConvertResult(IN P_EVENT_BATCH_RESULT_T prEventBatchResult, + OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) +{ + CHAR *p = pvBuffer; + CHAR ssid[ELEM_MAX_LEN_SSID + 1]; + INT_32 nsize = 0, nsize1, nsize2, nsize3, scancount; + INT_32 i, j, nleft; + UINT_32 freq; + + P_EVENT_BATCH_RESULT_ENTRY_T prEntry; + P_EVENT_BATCH_RESULT_T pBr; + + nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ + + pBr = prEventBatchResult; + scancount = 0; + for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { + scancount += pBr->ucScanCount; + pBr++; + } + + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "scancount=%x\nnextcount=%x\n", scancount, scancount); + if (nsize1 < nleft) { + p += nsize1 = kalSprintf(p, "%s", text1); + nleft -= nsize1; + } else + goto short_buf; + + pBr = prEventBatchResult; + for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { + DBGLOG(SCN, TRACE, "convert mscan = %d, apcount=%d, nleft=%d\n", j, pBr->ucScanCount, nleft); + + if (pBr->ucScanCount == 0) { + pBr++; + continue; + } + + nleft -= 5; /* -5 for "####\n" */ + + /* We only support one round scan result now. */ + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "apcount=%d\n", pBr->ucScanCount); + if (nsize1 < nleft) { + p += nsize1 = kalSprintf(p, "%s", text1); + nleft -= nsize1; + } else + goto short_buf; + + for (i = 0; i < pBr->ucScanCount; i++) { + prEntry = &pBr->arBatchResult[i]; + + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "bssid=" MACSTR "\n", + prEntry->aucBssid[0], + prEntry->aucBssid[1], + prEntry->aucBssid[2], + prEntry->aucBssid[3], + prEntry->aucBssid[4], prEntry->aucBssid[5]); + + kalMemCopy(ssid, + prEntry->aucSSID, + (prEntry->ucSSIDLen < ELEM_MAX_LEN_SSID ? prEntry->ucSSIDLen : ELEM_MAX_LEN_SSID)); + ssid[(prEntry->ucSSIDLen < + (ELEM_MAX_LEN_SSID - 1) ? prEntry->ucSSIDLen : (ELEM_MAX_LEN_SSID - 1))] = '\0'; + nsize2 = kalSnprintf(text2, TMP_TEXT_LEN_L, "ssid=%s\n", ssid); + + freq = batchChannelNum2Freq(prEntry->ucFreq); + nsize3 = + kalSnprintf(text3, TMP_TEXT_LEN_L, + "freq=%u\nlevel=%d\ndist=%u\ndistSd=%u\n====\n", freq, + prEntry->cRssi, prEntry->u4Dist, prEntry->u4Distsd); + + nsize = nsize1 + nsize2 + nsize3; + if (nsize < nleft) { + + kalStrnCpy(p, text1, TMP_TEXT_LEN_S); + p += nsize1; + + kalStrnCpy(p, text2, TMP_TEXT_LEN_L); + p += nsize2; + + kalStrnCpy(p, text3, TMP_TEXT_LEN_L); + p += nsize3; + + nleft -= nsize; + } else { + DBGLOG(SCN, TRACE, "Warning: Early break! (%d)\n", i); + break; /* discard following entries, TODO: apcount? */ + } + } + + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "####\n"); + p += kalSprintf(p, "%s", text1); + + pBr++; + } + + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "----\n"); + kalSprintf(p, "%s", text1); + + *pu4RetLen = u4MaxBufferLen - nleft; + DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); + + return WLAN_STATUS_SUCCESS; + +short_buf: + DBGLOG(SCN, TRACE, + "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), + u4MaxBufferLen, (char *)pvBuffer); + return WLAN_STATUS_INVALID_LENGTH; +} +#endif + +#if CFG_SUPPORT_GET_CH_ENV +WLAN_STATUS +scanEnvResult(P_GLUE_INFO_T prGlueInfo, OUT PVOID pvBuffer, IN UINT_32 u4MaxBufferLen, OUT PUINT_32 pu4RetLen) +{ + P_ADAPTER_T prAdapter = NULL; + CHAR *p = pvBuffer; + INT_32 nsize; + INT_32 i, nleft; + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + CH_ENV_T chEnvInfo[54]; /* 54: from FW define; TODO: sync MAXIMUM_OPERATION_CHANNEL_LIST */ + UINT_32 i4GetCh = 0; + INT_32 i4Argc = 0; + PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + UINT_8 ucTextLen = 40; + UCHAR text[ucTextLen]; + INT_32 u4Ret; + + prAdapter = prGlueInfo->prAdapter; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + kalMemZero(chEnvInfo, sizeof(chEnvInfo)); + + DBGLOG(SCN, TRACE, "pvBuffer:%s, pu4RetLen:%d\n", (char *)pvBuffer, *pu4RetLen); + + wlanCfgParseArgument(pvBuffer, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &i4GetCh); + if (u4Ret) + DBGLOG(SCN, TRACE, "parse pvBuffer error u4Ret=%d\n", u4Ret); + /* i4GetCh = kalStrtoul(apcArgv[1], NULL, 0); */ + } + + nleft = u4MaxBufferLen - 5; /* -5 for "----\n" */ + + nsize = kalSnprintf(text, ucTextLen, "%s", "scanEnvResult\nResult:1\n");/* Always return 1 for alpha version. */ + + if (nsize < nleft) { + p += nsize = kalSnprintf(p, ucTextLen, "%s", text); + nleft -= nsize; + } else + goto short_buf; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + if (prBssDesc->ucChannelNum > 0) { + if (prBssDesc->ucChannelNum <= 14) { /* 1~14 */ + chEnvInfo[prBssDesc->ucChannelNum - 1].ucChNum = prBssDesc->ucChannelNum; + chEnvInfo[prBssDesc->ucChannelNum - 1].ucApNum++; + } else if (prBssDesc->ucChannelNum <= 64) { /* 15~22 */ + chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucChNum = prBssDesc->ucChannelNum; + chEnvInfo[prBssDesc->ucChannelNum / 4 + 5].ucApNum++; + } else if (prBssDesc->ucChannelNum <= 116) { /* 23~27 */ + chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucChNum = prBssDesc->ucChannelNum; + chEnvInfo[prBssDesc->ucChannelNum / 4 - 3].ucApNum++; + } else if (prBssDesc->ucChannelNum <= 140) { /* 28~30 */ + chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucChNum = prBssDesc->ucChannelNum; + chEnvInfo[prBssDesc->ucChannelNum / 4 - 6].ucApNum++; + } else if (prBssDesc->ucChannelNum <= 165) { /* 31~35 */ + chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucChNum = prBssDesc->ucChannelNum; + chEnvInfo[(prBssDesc->ucChannelNum - 1) / 4 - 7].ucApNum++; + } + } + } + + for (i = 0; i < 54; i++) { + if (chEnvInfo[i].ucChNum != 0) { + if (i4GetCh == 0 || (chEnvInfo[i].ucChNum == (UINT_8)i4GetCh)) { + DBGLOG(SCN, TRACE, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, chEnvInfo[i].ucApNum); + p += nsize = + kalSnprintf(p, ucTextLen, "chNum=%d,apNum=%d\n", chEnvInfo[i].ucChNum, + chEnvInfo[i].ucApNum); + nleft -= nsize; + } + } + } + + p += nsize = kalSnprintf(p, ucTextLen, "%s", "----\n"); + nleft -= nsize; + + *pu4RetLen = u4MaxBufferLen - nleft; + DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, u4MaxBufferLen); + + return WLAN_STATUS_SUCCESS; + +short_buf: + DBGLOG(SCN, TRACE, "Short buffer issue! %d > %d, %s\n", u4MaxBufferLen + (nsize - nleft), u4MaxBufferLen, p); + return WLAN_STATUS_INVALID_LENGTH; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set int handler. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. +* \param[in] pcExtra The buffer with input value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + UINT_32 u4SubCmd; + PUINT_32 pu4IntBuf; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4BufLen = 0; + int status = 0; + P_PTA_IPC_T prPtaIpc; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + u4SubCmd = (UINT_32) prIwReqData->mode; + pu4IntBuf = (PUINT_32) pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_MODE: + /* printk("TestMode=%ld\n", pu4IntBuf[1]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY) { + prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_MODE; + } else if (pu4IntBuf[1] == 0) { + prNdisReq->ndisOidCmd = OID_CUSTOM_ABORT_TEST_MODE; + } else { + status = 0; + break; + } + prNdisReq->inNdisOidlength = 0; + prNdisReq->outNdisOidLength = 0; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + case PRIV_CMD_TEST_CMD: + /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) + prGlueInfo->fgMcrAccessAllowed = TRUE; + status = 0; + break; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; +#endif + + case PRIV_CMD_SW_CTRL: + /* printk("addr=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + +#if 0 + case PRIV_CMD_BEACON_PERIOD: + rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetBeaconInterval, + (PVOID)&pu4IntBuf[1],/* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), &u4BufLen); + break; +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + case PRIV_CMD_CSUM_OFFLOAD: + { + UINT_32 u4CSUMFlags; + + if (pu4IntBuf[1] == 1) + u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + else if (pu4IntBuf[1] == 0) + u4CSUMFlags = 0; + else + return -EINVAL; + + if (kalIoctl(prGlueInfo, + wlanoidSetCSUMOffload, + (PVOID)&u4CSUMFlags, + sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { + if (pu4IntBuf[1] == 1) + prNetDev->features |= NETIF_F_HW_CSUM; + else if (pu4IntBuf[1] == 0) + prNetDev->features &= ~NETIF_F_HW_CSUM; + } + } + break; +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + + case PRIV_CMD_POWER_MODE: + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + break; + + case PRIV_CMD_WMM_PS: + { + PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T rWmmPsTest; + + rWmmPsTest.bmfgApsdEnAc = (UINT_8) pu4IntBuf[1]; + rWmmPsTest.ucIsEnterPsAtOnce = (UINT_8) pu4IntBuf[2]; + rWmmPsTest.ucIsDisableUcTrigger = (UINT_8) pu4IntBuf[3]; + rWmmPsTest.reserved = 0; + + kalIoctl(prGlueInfo, + wlanoidSetWiFiWmmPsTest, + (PVOID)&rWmmPsTest, + sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + } + break; + +#if 0 + case PRIV_CMD_ADHOC_MODE: + rStatus = wlanSetInformation(prGlueInfo->prAdapter, wlanoidSetAdHocMode, + (PVOID)&pu4IntBuf[1], /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(UINT_32), &u4BufLen); + break; +#endif + + case PRIV_CUSTOM_BWCS_CMD: + + DBGLOG(REQ, INFO, "pu4IntBuf[1] = %x, size of PTA_IPC_T = %zu.\n", + pu4IntBuf[1], sizeof(PARAM_PTA_IPC_T)); + + prPtaIpc = (P_PTA_IPC_T) aucOidBuf; + prPtaIpc->u.aucBTPParams[0] = (UINT_8) (pu4IntBuf[1] >> 24); + prPtaIpc->u.aucBTPParams[1] = (UINT_8) (pu4IntBuf[1] >> 16); + prPtaIpc->u.aucBTPParams[2] = (UINT_8) (pu4IntBuf[1] >> 8); + prPtaIpc->u.aucBTPParams[3] = (UINT_8) (pu4IntBuf[1]); + + DBGLOG(REQ, INFO, + "BCM BWCS CMD : BTPParams[0]=%02x, BTPParams[1]=%02x, BTPParams[2]=%02x, BTPParams[3]=%02x.\n", + prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], prPtaIpc->u.aucBTPParams[2], + prPtaIpc->u.aucBTPParams[3]); + +#if 0 + status = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); +#endif + + status = wlanoidSetBT(prGlueInfo->prAdapter, + (PVOID)&aucOidBuf[0], sizeof(PARAM_PTA_IPC_T), &u4BufLen); + + if (WLAN_STATUS_SUCCESS != status) + status = -EFAULT; + + break; + + case PRIV_CMD_BAND_CONFIG: + { + DBGLOG(REQ, INFO, "CMD set_band=%u\n", (UINT_32) pu4IntBuf[1]); + } + break; + +#if CFG_ENABLE_WIFI_DIRECT + case PRIV_CMD_P2P_MODE: + { + /* no use, move to set_p2p_mode_handler() */ + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode; + + p2pmode.u4Enable = pu4IntBuf[1]; + p2pmode.u4Mode = pu4IntBuf[2]; + set_p2p_mode_handler(prNetDev, p2pmode); +#if 0 + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + BOOLEAN fgIsP2PEnding; + + GLUE_SPIN_LOCK_DECLARATION(); + + /* avoid remove & p2p off command simultaneously */ + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + fgIsP2PEnding = g_u4P2PEnding; + g_u4P2POnOffing = 1; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + + if (fgIsP2PEnding == 1) { + /* skip the command if we are removing */ + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2POnOffing = 0; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); + break; + } + rSetP2P.u4Enable = pu4IntBuf[1]; + rSetP2P.u4Mode = pu4IntBuf[2]; + + if (!rSetP2P.u4Enable) + p2pNetUnregister(prGlueInfo, TRUE); + + /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ + /* + Scenario: + 1. System enters suspend/resume but not yet enter wlanearlysuspend() + or wlanlateresume(); + + 2. System switches to do PRIV_CMD_P2P_MODE and execute kalIoctl() + and get g_halt_sem then do glRegisterEarlySuspend() or + glUnregisterEarlySuspend(); + + But system suspend/resume procedure is not yet finished so we + suspend; + + 3. System switches back to do suspend/resume procedure and execute + kalIoctl(). But driver does not yet release g_halt_sem so system + suspend in wlanearlysuspend() or wlanlateresume(); + + ==> deadlock occurs. + */ + if ((!rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { + /* fgIsP2PRegistered == TRUE means P2P is enabled */ + DBGLOG(P2P, INFO, "p2pEalySuspendReg\n"); + p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p remove */ + } + + DBGLOG(P2P, INFO, + "wlanoidSetP2pMode 0x%p %d %d\n", &rSetP2P, rSetP2P.u4Enable, rSetP2P.u4Mode); + rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, + (PVOID)&rSetP2P, /* pu4IntBuf[0] is used as input SubCmd */ + sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), + FALSE, FALSE, TRUE, FALSE, &u4BufLen); + DBGLOG(P2P, INFO, "wlanoidSetP2pMode ok\n"); + + /* move out to caller to avoid kalIoctrl & suspend/resume deadlock problem ALPS00844864 */ + if ((rSetP2P.u4Enable) && (g_u4HaltFlag == 0) && (fgIsResetting == FALSE)) { + /* fgIsP2PRegistered == TRUE means P2P on successfully */ + p2pEalySuspendReg(prGlueInfo, rSetP2P.u4Enable); /* p2p on */ + } + + if (rSetP2P.u4Enable) + p2pNetRegister(prGlueInfo, TRUE); + + GLUE_ACQUIRE_THE_SPIN_LOCK(&g_p2p_lock); + g_u4P2POnOffing = 0; + GLUE_RELEASE_THE_SPIN_LOCK(&g_p2p_lock); +#endif + } + break; +#endif + +#if (CFG_SUPPORT_MET_PROFILING == 1) + case PRIV_CMD_MET_PROFILING: + { + /* PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; */ + /* rWfdDebugModeInfo.ucWFDDebugMode=(UINT_8)pu4IntBuf[1]; */ + /* rWfdDebugModeInfo.u2SNPeriod=(UINT_16)pu4IntBuf[2]; */ + /* DBGLOG(REQ, INFO,("WFD Debug Mode:%d Period:%d\n", + rWfdDebugModeInfo.ucWFDDebugMode,rWfdDebugModeInfo.u2SNPeriod)); */ + prGlueInfo->u8MetProfEnable = (UINT_8) pu4IntBuf[1]; + prGlueInfo->u16MetUdpPort = (UINT_16) pu4IntBuf[2]; + DBGLOG(REQ, INFO, "MET_PROF: Enable=%d UDP_PORT=%d\n", prGlueInfo->u8MetProfEnable, + prGlueInfo->u16MetUdpPort); + + } + break; + +#endif + case PRIV_CMD_WFD_DEBUG_CODE: + { + PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; + + rWfdDebugModeInfo.ucWFDDebugMode = (UINT_8) pu4IntBuf[1]; + rWfdDebugModeInfo.u2SNPeriod = (UINT_16) pu4IntBuf[2]; + DBGLOG(REQ, INFO, "WFD Debug Mode:%d Period:%d\n", rWfdDebugModeInfo.ucWFDDebugMode, + rWfdDebugModeInfo.u2SNPeriod); + kalIoctl(prGlueInfo, wlanoidSetWfdDebugMode, (PVOID)&rWfdDebugModeInfo, + sizeof(PARAM_CUSTOM_WFD_DEBUG_STRUCT_T), FALSE, FALSE, TRUE, FALSE, &u4BufLen); + + } + break; + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get int handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. +* \param[out] pcExtra The buffer with put the return value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +UINT_8 gucBufDbgCode[1000]; + +static int +_priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + UINT_32 u4SubCmd; + PUINT_32 pu4IntBuf; + P_GLUE_INFO_T prGlueInfo; + UINT_32 u4BufLen = 0; + int status = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + u4SubCmd = (UINT_32) prIwReqData->mode; + pu4IntBuf = (PUINT_32) pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_CMD: + /* printk("CMD=0x%08lx, data=0x%08lx\n", pu4IntBuf[1], pu4IntBuf[2]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ + prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; + /* + if (copy_to_user(prIwReqData->data.pointer, + &prNdisReq->ndisOidContent[4], 4)) { + printk(KERN_NOTICE "priv_get_int() copy_to_user oidBuf fail(3)\n"); + return -EFAULT; + } + */ + } + return status; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + /* printk("addr=0x%08lx\n", pu4IntBuf[1]); */ + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + status = 0; + return status; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ + prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; + } + return status; +#endif + + case PRIV_CMD_DUMP_MEM: + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + +#if 1 + if (!prGlueInfo->fgMcrAccessAllowed) { + status = 0; + return status; + } +#endif + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MEM_DUMP; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) + prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[0]; + return status; + + case PRIV_CMD_SW_CTRL: + /* printk(" addr=0x%08lx\n", pu4IntBuf[1]); */ + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + /* printk("Result=%ld\n", *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ + prIwReqData->mode = *(PUINT_32) &prNdisReq->ndisOidContent[4]; + } + return status; + +#if 0 + case PRIV_CMD_BEACON_PERIOD: + status = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryBeaconInterval, + (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); + return status; + + case PRIV_CMD_POWER_MODE: + status = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); + return status; + + case PRIV_CMD_ADHOC_MODE: + status = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryAdHocMode, (PVOID) pu4IntBuf, sizeof(UINT_32), &u4BufLen); + return status; +#endif + + case PRIV_CMD_BAND_CONFIG: + DBGLOG(REQ, INFO, "CMD get_band=\n"); + prIwReqData->mode = 0; + return status; + + default: + break; + } + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: + { + UINT_16 i, j = 0; + UINT_8 NumOfChannel = 50; + UINT_8 ucMaxChannelNum = 50; + INT_32 ch[50]; + /*RF_CHANNEL_INFO_T aucChannelList[50];*/ + P_RF_CHANNEL_INFO_T paucChannelList; + P_RF_CHANNEL_INFO_T ChannelList_t; + + paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); + if (paucChannelList == NULL) { + DBGLOG(REQ, INFO, "alloc ChannelList fail\n"); + return -EFAULT; + } + kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); + if (NumOfChannel > 50) { + ASSERT(0); + NumOfChannel = 50; + } + + ChannelList_t = paucChannelList; + if (kalIsAPmode(prGlueInfo)) { + for (i = 0; i < NumOfChannel; i++) { + if ((ChannelList_t->ucChannelNum <= 13) + || (ChannelList_t->ucChannelNum == 36 + || ChannelList_t->ucChannelNum == 40 + || ChannelList_t->ucChannelNum == 44 + || ChannelList_t->ucChannelNum == 48)) { + ch[j] = (INT_32) ChannelList_t->ucChannelNum; + ChannelList_t++; + j++; + } + } + } else { + for (j = 0; j < NumOfChannel; j++) { + ch[j] = (INT_32) ChannelList_t->ucChannelNum; + ChannelList_t++; + } + } + + kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); + + prIwReqData->data.length = j; + if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) + return -EFAULT; + else + return status; + } + + case PRIV_CMD_GET_BUILD_DATE_CODE: + { + UINT_8 aucBuffer[16]; + + if (kalIoctl(prGlueInfo, + wlanoidQueryBuildDateCode, + (PVOID) aucBuffer, + sizeof(UINT_8) * 16, TRUE, TRUE, TRUE, FALSE, &u4BufLen) == WLAN_STATUS_SUCCESS) { + prIwReqData->data.length = sizeof(UINT_8) * 16; + + if (copy_to_user(prIwReqData->data.pointer, aucBuffer, prIwReqData->data.length)) + return -EFAULT; + else + return status; + } else { + return -EFAULT; + } + } + + case PRIV_CMD_GET_DEBUG_CODE: + { + wlanQueryDebugCode(prGlueInfo->prAdapter); + + kalMemSet(gucBufDbgCode, '.', sizeof(gucBufDbgCode)); + if (copy_to_user(prIwReqData->data.pointer, gucBufDbgCode, prIwReqData->data.length)) + return -EFAULT; + else + return status; + } + + default: + return -EOPNOTSUPP; + } + + return status; +} /* priv_get_int */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set int array handler. +* +* \param[in] prNetDev Net device requested. +* \param[in] prIwReqInfo Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl data structure, use the field of sub-command. +* \param[in] pcExtra The buffer with input value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_set_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + UINT_32 u4SubCmd, u4BufLen; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_SET_TXPWR_CTRL_T prTxpwr; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_SET_TX_POWER: + { + INT_32 *setting = prIwReqData->data.pointer; + UINT_16 i; + +#if 0 + DBGLOG(REQ, INFO, "Tx power num = %d\n", prIwReqData->data.length); + + DBGLOG(REQ, INFO, "Tx power setting = %d %d %d %d\n", + setting[0], setting[1], setting[2], setting[3]); +#endif + prTxpwr = &prGlueInfo->rTxPwr; + if (setting[0] == 0 && prIwReqData->data.length == 4 /* argc num */) { + /* 0 (All networks), 1 (legacy STA), 2 (Hotspot AP), 3 (P2P), 4 (BT over Wi-Fi) */ + if (setting[1] == 1 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GLegacyStaPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GLegacyStaPwrOffset = setting[3]; + } + if (setting[1] == 2 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GHotspotPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GHotspotPwrOffset = setting[3]; + } + if (setting[1] == 3 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GP2pPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GP2pPwrOffset = setting[3]; + } + if (setting[1] == 4 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) + prTxpwr->c2GBowPwrOffset = setting[3]; + if (setting[2] == 0 || setting[2] == 2) + prTxpwr->c5GBowPwrOffset = setting[3]; + } + } else if (setting[0] == 1 && prIwReqData->data.length == 2) { + prTxpwr->ucConcurrencePolicy = setting[1]; + } else if (setting[0] == 2 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i = 0; i < 14; i++) + prTxpwr->acTxPwrLimit2G[i] = setting[2]; + } else if (setting[1] <= 14) + prTxpwr->acTxPwrLimit2G[setting[1] - 1] = setting[2]; + } else if (setting[0] == 3 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i = 0; i < 4; i++) + prTxpwr->acTxPwrLimit5G[i] = setting[2]; + } else if (setting[1] <= 4) + prTxpwr->acTxPwrLimit5G[setting[1] - 1] = setting[2]; + } else if (setting[0] == 4 && prIwReqData->data.length == 2) { + if (setting[1] == 0) + wlanDefTxPowerCfg(prGlueInfo->prAdapter); + rStatus = kalIoctl(prGlueInfo, + wlanoidSetTxPower, + prTxpwr, + sizeof(SET_TXPWR_CTRL_T), TRUE, FALSE, FALSE, FALSE, &u4BufLen); + } else + return -EFAULT; + } + return status; + default: + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get int array handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] prIwReqData The ioctl req structure, use the field of sub-command. +* \param[out] pcExtra The buffer with put the return value +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EFAULT For fail. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_get_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + UINT_32 u4SubCmd; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + INT_32 ch[50]; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: + { + UINT_16 i; + UINT_8 NumOfChannel = 50; + UINT_8 ucMaxChannelNum = 50; + /*RF_CHANNEL_INFO_T aucChannelList[50];*/ + P_RF_CHANNEL_INFO_T paucChannelList; + P_RF_CHANNEL_INFO_T ChannelList_t; + + paucChannelList = kalMemAlloc(sizeof(RF_CHANNEL_INFO_T) * 50, VIR_MEM_TYPE); + if (paucChannelList == NULL) { + DBGLOG(REQ, INFO, "alloc fail\n"); + return -EINVAL; + } + kalMemZero(paucChannelList, sizeof(RF_CHANNEL_INFO_T) * 50); + + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, &NumOfChannel, paucChannelList); + if (NumOfChannel > 50) + NumOfChannel = 50; + + ChannelList_t = paucChannelList; + for (i = 0; i < NumOfChannel; i++) { + ch[i] = (INT_32) ChannelList_t->ucChannelNum; + ChannelList_t++; + } + + kalMemFree(paucChannelList, VIR_MEM_TYPE, sizeof(RF_CHANNEL_INFO_T) * 50); + prIwReqData->data.length = NumOfChannel; + if (copy_to_user(prIwReqData->data.pointer, ch, NumOfChannel * sizeof(INT_32))) + return -EFAULT; + else + return status; + } + default: + break; + } + + return status; +} /* priv_get_int */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl set structure handler. +* +* \param[in] pDev Net device requested. +* \param[in] prIwReqData Pointer to iwreq_data structure. +* +* \retval 0 For success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL If a value is out of range. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + UINT_32 u4SubCmd = 0; + int status = 0; + /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ + UINT_32 u4CmdLen = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + PUINT_32 pu4IntBuf = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4BufLen = 0; + + ASSERT(prNetDev); + /* ASSERT(prIwReqInfo); */ + ASSERT(prIwReqData); + /* ASSERT(pcExtra); */ + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + if (FALSE == GLUE_CHK_PR2(prNetDev, prIwReqData)) + return -EINVAL; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + +#if 0 + DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, u4SubCmd); +#endif + + switch (u4SubCmd) { +#if 0 /* PTA_ENABLED */ + case PRIV_CMD_BT_COEXIST: + u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); + ASSERT(sizeof(PARAM_CUSTOM_BT_COEXIST_T) >= u4CmdLen); + if (sizeof(PARAM_CUSTOM_BT_COEXIST_T) < u4CmdLen) + return -EFAULT; + + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { + status = -EFAULT; /* return -EFAULT; */ + break; + } + + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBtCoexistCtrl, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); + if (WLAN_STATUS_SUCCESS != rStatus) + status = -EFAULT; + break; +#endif + + case PRIV_CUSTOM_BWCS_CMD: + u4CmdLen = prIwReqData->data.length * sizeof(UINT_32); + ASSERT(sizeof(PARAM_PTA_IPC_T) >= u4CmdLen); + if (sizeof(PARAM_PTA_IPC_T) < u4CmdLen) + return -EFAULT; +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, INFO, + "ucCmdLen = %d, size of PTA_IPC_T = %d, prIwReqData->data = 0x%x.\n", u4CmdLen, + sizeof(PARAM_PTA_IPC_T), prIwReqData->data); + + DBGLOG(REQ, INFO, "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%u)\n", + prIwReqInfo->cmd, u4SubCmd); + + DBGLOG(REQ, INFO, "*pcExtra = 0x%x\n", *pcExtra); +#endif + + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, u4CmdLen)) { + status = -EFAULT; /* return -EFAULT; */ + break; + } +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, INFO, "priv_set_struct(): BWCS CMD = %02x%02x%02x%02x\n", + aucOidBuf[2], aucOidBuf[3], aucOidBuf[4], aucOidBuf[5]); +#endif + +#if 0 + status = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBT, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); +#endif + +#if 1 + status = wlanoidSetBT(prGlueInfo->prAdapter, (PVOID)&aucOidBuf[0], u4CmdLen, &u4BufLen); +#endif + + if (WLAN_STATUS_SUCCESS != status) + status = -EFAULT; + + break; + +#if CFG_SUPPORT_WPS2 + case PRIV_CMD_WSC_PROBE_REQ: + { + /* retrieve IE for Probe Request */ + if (prIwReqData->data.length > 0) { + if (copy_from_user(prGlueInfo->aucWSCIE, prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prGlueInfo->u2WSCIELen = prIwReqData->data.length; + } else { + prGlueInfo->u2WSCIELen = 0; + } + } + break; +#endif + case PRIV_CMD_OID: + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, prIwReqData->data.length)) { + status = -EFAULT; + break; + } + if (!kalMemCmp(&aucOidBuf[0], pcExtra, prIwReqData->data.length)) + DBGLOG(REQ, INFO, "pcExtra buffer is valid\n"); + else + DBGLOG(REQ, INFO, "pcExtra 0x%p\n", pcExtra); + /* Execute this OID */ + status = priv_set_ndis(prNetDev, (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0], &u4BufLen); + /* Copy result to user space */ + ((P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0])->outNdisOidLength = u4BufLen; + + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, "copy_to_user oidBuf fail\n"); + status = -EFAULT; + } + + break; + + case PRIV_CMD_SW_CTRL: + pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + /* kalMemCopy(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, 8); */ + if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Private ioctl get struct handler. +* +* \param[in] pDev Net device requested. +* \param[out] pIwReq Pointer to iwreq structure. +* \param[in] cmd Private sub-command. +* +* \retval 0 For success. +* \retval -EFAULT If copy from user space buffer fail. +* \retval -EOPNOTSUPP Parameter "cmd" not recognized. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + UINT_32 u4SubCmd = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4BufLen = 0; + PUINT_32 pu4IntBuf = NULL; + int status = 0; + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + ASSERT(prNetDev); + ASSERT(prIwReqData); + if (!prNetDev || !prIwReqData) { + DBGLOG(REQ, INFO, "priv_get_struct(): invalid param(0x%p, 0x%p)\n", prNetDev, prIwReqData); + return -EINVAL; + } + + u4SubCmd = (UINT_32) prIwReqData->data.flags; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, "priv_get_struct(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); + return -EINVAL; + } +#if 0 + DBGLOG(REQ, INFO, "priv_get_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, u4SubCmd); +#endif + memset(aucOidBuf, 0, sizeof(aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, sizeof(NDIS_TRANSPORT_STRUCT))) { + DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); + return -EFAULT; + } + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; +#if 0 + DBGLOG(REQ, INFO, "\n priv_get_struct cmd 0x%02x len:%d OID:0x%08x OID Len:%d\n", + cmd, pIwReq->u.data.length, ndisReq->ndisOidCmd, ndisReq->inNdisOidlength); +#endif + if (priv_get_ndis(prNetDev, prNdisReq, &u4BufLen) == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], + u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - + sizeof(prNdisReq->ndisOidContent))) { + DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(1)\n"); + return -EFAULT; + } + return 0; + } + prNdisReq->outNdisOidLength = u4BufLen; + if (copy_to_user(prIwReqData->data.pointer, + &aucOidBuf[0], OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); + } + return -EFAULT; + + case PRIV_CMD_SW_CTRL: + pu4IntBuf = (PUINT_32) prIwReqData->data.pointer; + prNdisReq = (P_NDIS_TRANSPORT_STRUCT) &aucOidBuf[0]; + + if (copy_from_user(&prNdisReq->ndisOidContent[0], prIwReqData->data.pointer, + prIwReqData->data.length)) { + DBGLOG(REQ, INFO, "priv_get_struct() copy_from_user oidBuf fail\n"); + return -EFAULT; + } + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + /* printk("len=%d Result=%08lx\n", u4BufLen, *(PUINT_32)&prNdisReq->ndisOidContent[4]); */ + + if (copy_to_user(prIwReqData->data.pointer, + &prNdisReq->ndisOidContent[4], + 4 /* OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent) */)) { + DBGLOG(REQ, INFO, "priv_get_struct() copy_to_user oidBuf fail(2)\n"); + } + } + return 0; + + default: + DBGLOG(REQ, WARN, "get struct cmd:0x%x\n", u4SubCmd); + return -EOPNOTSUPP; + } +} /* priv_get_struct */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The routine handles a set operation for a single OID. +* +* \param[in] pDev Net device requested. +* \param[in] ndisReq Ndis request OID information copy from user. +* \param[out] outputLen_p If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed.. +* +* \retval 0 On success. +* \retval -EOPNOTSUPP If cmd is not supported. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +priv_set_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 u4SetInfoLen = 0; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, "priv_set_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, "priv_set_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); + return -EINVAL; + } +#if 0 + DBGLOG(REQ, INFO, "priv_set_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); +#endif + + if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { + /* WARNLOG(("Set OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ + return -EOPNOTSUPP; + } + + if (NULL == prWlanReqEntry->pfOidSetHandler) { + /* WARNLOG(("Set %s: Null set handler\n", prWlanReqEntry->pucOidName)); */ + return -EOPNOTSUPP; + } +#if 0 + DBGLOG(REQ, INFO, "priv_set_ndis(): %s\n", prWlanReqEntry->pucOidName); +#endif + + if (prWlanReqEntry->fgSetBufLenChecking) { + if (prNdisReq->inNdisOidlength != prWlanReqEntry->u4InfoBufLen) { + DBGLOG(REQ, WARN, "Set %s: Invalid length (current=%u, needed=%u)\n", + prWlanReqEntry->pucOidName, + prNdisReq->inNdisOidlength, prWlanReqEntry->u4InfoBufLen); + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + return -EINVAL; + } + } + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4SetInfoLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidSetHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4SetInfoLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core */ + + status = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidSetHandler, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + } else { + DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4SetInfoLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* u4SetInfoLen)); */ + break; + } + + if (WLAN_STATUS_SUCCESS != status) + return -EFAULT; + + return 0; +} /* priv_set_ndis */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The routine handles a query operation for a single OID. Basically we +* return information about the current state of the OID in question. +* +* \param[in] pDev Net device requested. +* \param[in] ndisReq Ndis request OID information copy from user. +* \param[out] outputLen_p If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed.. +* +* \retval 0 On success. +* \retval -EOPNOTSUPP If cmd is not supported. +* \retval -EINVAL invalid input parameters +* +*/ +/*----------------------------------------------------------------------------*/ +static int +priv_get_ndis(IN struct net_device *prNetDev, IN NDIS_TRANSPORT_STRUCT * prNdisReq, OUT PUINT_32 pu4OutputLen) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + UINT_32 u4BufLen = 0; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, "priv_get_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, "priv_get_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *) netdev_priv(prNetDev))); + return -EINVAL; + } +#if 0 + DBGLOG(REQ, INFO, "priv_get_ndis(): prNdisReq->ndisOidCmd(0x%lX)\n", prNdisReq->ndisOidCmd); +#endif + + if (FALSE == reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, &prWlanReqEntry)) { + /* WARNLOG(("Query OID: 0x%08lx (unknown)\n", prNdisReq->ndisOidCmd)); */ + return -EOPNOTSUPP; + } + + if (NULL == prWlanReqEntry->pfOidQueryHandler) { + /* WARNLOG(("Query %s: Null query handler\n", prWlanReqEntry->pucOidName)); */ + return -EOPNOTSUPP; + } +#if 0 + DBGLOG(REQ, INFO, "priv_get_ndis(): %s\n", prWlanReqEntry->pucOidName); +#endif + + if (prWlanReqEntry->fgQryBufLenChecking) { + if (prNdisReq->inNdisOidlength < prWlanReqEntry->u4InfoBufLen) { + /* Not enough room in InformationBuffer. Punt */ + /* WARNLOG(("Query %s: Buffer too short (current=%ld, needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* prWlanReqEntry->u4InfoBufLen)); */ + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + + status = WLAN_STATUS_INVALID_LENGTH; + return -EINVAL; + } + } + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4BufLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidQueryHandler(prGlueInfo, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4BufLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core */ + + status = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC) prWlanReqEntry->pfOidQueryHandler, + prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, TRUE, TRUE, TRUE, FALSE, &u4BufLen); + } else { + DBGLOG(REQ, INFO, "priv_set_ndis(): unsupported OID method:0x%x\n", prWlanReqEntry->eOidMethod); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4BufLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + /* WARNLOG(("Set %s: Invalid length (current=%ld, needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* u4BufLen)); */ + break; + } + + if (WLAN_STATUS_SUCCESS != status) + return -EOPNOTSUPP; + + return 0; +} /* priv_get_ndis */ + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Parse command value in a string. +* +* @param InStr Pointer to the string buffer. +* @param OutStr Pointer to the next command value. +* @param OutLen Record the resident buffer length. +* +* @retval Command value. +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen) +{ + unsigned char Charc, *Buf; + unsigned int Num; + int Maxloop; + int ReadId; + int TotalLen; + + /* init */ + Num = 0; + Maxloop = 0; + ReadId = 0; + Buf = (unsigned char *)InStr; + TotalLen = *OutLen; + *OutStr = Buf; + + /* sanity check */ + if (Buf[0] == 0x00) + return 0; + + /* check the value is decimal or hex */ + if ((Buf[ReadId] == 'x') || ((Buf[ReadId] == '0') && (Buf[ReadId + 1] == 'x'))) { + /* skip x or 0x */ + if (Buf[ReadId] == 'x') + ReadId++; + else + ReadId += 2; + + /* translate the hex number */ + while (Maxloop++ < 10) { + Charc = Buf[ReadId]; + if ((Charc >= 0x30) && (Charc <= 0x39)) + Charc -= 0x30; + else if ((Charc >= 'a') && (Charc <= 'f')) + Charc -= 'a'; + else if ((Charc >= 'A') && (Charc <= 'F')) + Charc -= 'A'; + else + break; /* exit the parsing */ + Num = Num * 16 + Charc + 10; + ReadId++; + TotalLen--; + } + } else { + /* translate the decimal number */ + while (Maxloop++ < 10) { + Charc = Buf[ReadId]; + if ((Charc < 0x30) || (Charc > 0x39)) + break; /* exit the parsing */ + Charc -= 0x30; + Num = Num * 10 + Charc; + ReadId++; + TotalLen--; + } + } + + if (Buf[ReadId] == 0x00) + *OutStr = &Buf[ReadId]; + else + *OutStr = &Buf[ReadId + 1]; /* skip the character: _ */ + + *OutLen = TotalLen - 1; /* skip the character: _ */ + return Num; +} + +/*----------------------------------------------------------------------------*/ +/*! +* @brief Parse command MAC address in a string. +* +* @param InStr Pointer to the string buffer. +* @param OutStr Pointer to the next command value. +* @param OutLen Record the resident buffer length. +* +* @retval Command value. +*/ +/*----------------------------------------------------------------------------*/ +UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac) +{ + unsigned char Charc, *Buf; + unsigned int Num; + int Maxloop; + int ReadId; + int TotalLen; + + /* init */ + Num = 0; + Maxloop = 0; + ReadId = 0; + Buf = (unsigned char *)InStr; + TotalLen = *OutLen; + *OutStr = Buf; + + /* sanity check */ + if (Buf[0] == 0x00) + return 0; + + /* parse MAC */ + while (Maxloop < 6) { + Charc = Buf[ReadId]; + if ((Charc >= 0x30) && (Charc <= 0x39)) + Charc -= 0x30; + else if ((Charc >= 'a') && (Charc <= 'f')) + Charc = Charc - 'a' + 10; + else if ((Charc >= 'A') && (Charc <= 'F')) + Charc = Charc - 'A' + 10; + else + return -1; /* error, exit the parsing */ + + Num = Charc; + ReadId++; + TotalLen--; + + Charc = Buf[ReadId]; + if ((Charc >= 0x30) && (Charc <= 0x39)) + Charc -= 0x30; + else if ((Charc >= 'a') && (Charc <= 'f')) + Charc = Charc - 'a' + 10; + else if ((Charc >= 'A') && (Charc <= 'F')) + Charc = Charc - 'A' + 10; + else + return -1; /* error, exit the parsing */ + + Num = Num * 16 + Charc; + ReadId += 2; /* skip the character and ':' */ + TotalLen -= 2; + + OutMac[Maxloop] = Num; + Maxloop++; + } + + *OutStr = &Buf[ReadId]; /* skip the character: _ */ + *OutLen = TotalLen; /* skip the character: _ */ + return Num; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief The routine handles a set operation for a single OID. +* +* \param[in] pDev Net device requested. +* \param[in] ndisReq Ndis request OID information copy from user. +* \param[out] outputLen_p If the call is successful, returns the number of +* bytes written into the query buffer. If the +* call failed due to invalid length of the query +* buffer, returns the amount of storage needed.. +* +* \retval 0 On success. +* \retval -EOPNOTSUPP If cmd is not supported. +* +*/ +/*----------------------------------------------------------------------------*/ +static int +_priv_set_string(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + P_GLUE_INFO_T GlueInfo; + INT_32 Status; + UINT_32 Subcmd; + UINT_8 *InBuf; + UINT_32 InBufLen; + + /* sanity check */ + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + /* init */ + DBGLOG(REQ, INFO, "priv_set_string (%s)(%d)\n", + (UINT8 *) prIwReqData->data.pointer, (INT32) prIwReqData->data.length); + + if (FALSE == GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra)) + return -EINVAL; + GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + InBuf = aucOidBuf; + InBufLen = prIwReqData->data.length; + Status = 0; + + if (copy_from_user(InBuf, prIwReqData->data.pointer, prIwReqData->data.length)) + return -EFAULT; + + Subcmd = CmdStringDecParse(prIwReqData->data.pointer, &InBuf, &InBufLen); + DBGLOG(REQ, INFO, "priv_set_string> command = %u\n", (UINT32) Subcmd); + + /* handle the command */ + switch (Subcmd) { +#if (CFG_SUPPORT_TDLS == 1) + case PRIV_CMD_OTHER_TDLS: + TdlsexCmd(GlueInfo, InBuf, InBufLen); + break; +#endif /* CFG_SUPPORT_TDLS */ + +#if (CFG_SUPPORT_TXR_ENC == 1) + case PRIV_CMD_OTHER_TAR: + { + rlmCmd(GlueInfo, InBuf, InBufLen); + break; + } +#endif /* CFG_SUPPORT_TXR_ENC */ + default: + break; + } + + return Status; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to search desired OID. +* +* \param rOid[in] Desired NDIS_OID +* \param ppWlanReqEntry[out] Found registered OID entry +* +* \retval TRUE: Matched OID is found +* \retval FALSE: No matched OID is found +*/ +/*----------------------------------------------------------------------------*/ +static BOOLEAN reqSearchSupportedOidEntry(IN UINT_32 rOid, OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry) +{ + INT_32 i, j, k; + + i = 0; + j = NUM_SUPPORTED_OIDS - 1; + + while (i <= j) { + k = (i + j) / 2; + + if (rOid == arWlanOidReqTable[k].rOid) { + *ppWlanReqEntry = &arWlanOidReqTable[k]; + return TRUE; + } else if (rOid < arWlanOidReqTable[k].rOid) { + j = k - 1; + } else { + i = k + 1; + } + } + + return FALSE; +} /* reqSearchSupportedOidEntry */ + +#if 0 +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to query the radio configuration used in IBSS +* mode and RF test mode. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[out] pvQueryBuffer Pointer to the buffer that holds the result of the query. +* \param[in] u4QueryBufferLen The length of the query buffer. +* \param[out] pu4QueryInfoLen If the call is successful, returns the number of +* bytes written into the query buffer. If the call +* failed due to invalid length of the query buffer, +* returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtQueryConfiguration(IN P_GLUE_INFO_T prGlueInfo, + OUT PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen) +{ + P_PARAM_802_11_CONFIG_T prQueryConfig = (P_PARAM_802_11_CONFIG_T) pvQueryBuffer; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + UINT_32 u4QueryInfoLen = 0; + + DEBUGFUNC("wlanoidQueryConfiguration"); + + ASSERT(prGlueInfo); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_CONFIG_T); + if (u4QueryBufferLen < sizeof(PARAM_802_11_CONFIG_T)) + return WLAN_STATUS_INVALID_LENGTH; + + ASSERT(pvQueryBuffer); + + kalMemZero(prQueryConfig, sizeof(PARAM_802_11_CONFIG_T)); + + /* Update the current radio configuration. */ + prQueryConfig->u4Length = sizeof(PARAM_802_11_CONFIG_T); + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetBeaconInterval, + &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryBeaconInterval, + &prQueryConfig->u4BeaconPeriod, sizeof(UINT_32), &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQueryAtimWindow, + &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryAtimWindow, + &prQueryConfig->u4ATIMWindow, sizeof(UINT_32), &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidQueryFrequency, + &prQueryConfig->u4DSConfig, sizeof(UINT_32), TRUE, TRUE, &u4QueryInfoLen); +#else + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQueryFrequency, + &prQueryConfig->u4DSConfig, sizeof(UINT_32), &u4QueryInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; + + prQueryConfig->rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + return rStatus; + +} /* end of reqExtQueryConfiguration() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set the radio configuration used in IBSS +* mode. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. +* \param[in] u4SetBufferLen The length of the set buffer. +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed +* due to invalid length of the set buffer, returns +* the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_LENGTH +* \retval WLAN_STATUS_NOT_ACCEPTED +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtSetConfiguration(IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_PARAM_802_11_CONFIG_T prNewConfig = (P_PARAM_802_11_CONFIG_T) pvSetBuffer; + UINT_32 u4SetInfoLen = 0; + + DEBUGFUNC("wlanoidSetConfiguration"); + + ASSERT(prGlueInfo); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_802_11_CONFIG_T); + + if (u4SetBufferLen < *pu4SetInfoLen) + return WLAN_STATUS_INVALID_LENGTH; + + /* OID_802_11_CONFIGURATION. If associated, NOT_ACCEPTED shall be returned. */ + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) + return WLAN_STATUS_NOT_ACCEPTED; + + ASSERT(pvSetBuffer); + +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetBeaconInterval, + &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetBeaconInterval, + &prNewConfig->u4BeaconPeriod, sizeof(UINT_32), &u4SetInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetAtimWindow, + &prNewConfig->u4ATIMWindow, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetAtimWindow, &prNewConfig->u4ATIMWindow, sizeof(UINT_32), &u4SetInfoLen); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; +#if defined(_HIF_SDIO) + rStatus = sdio_io_ctrl(prGlueInfo, + wlanoidSetFrequency, + &prNewConfig->u4DSConfig, sizeof(UINT_32), FALSE, TRUE, &u4SetInfoLen); +#else + rStatus = wlanSetInformation(prGlueInfo->prAdapter, + wlanoidSetFrequency, &prNewConfig->u4DSConfig, sizeof(UINT_32), &u4SetInfoLen); +#endif + + if (rStatus != WLAN_STATUS_SUCCESS) + return rStatus; + + return rStatus; + +} /* end of reqExtSetConfiguration() */ + +#endif +/*----------------------------------------------------------------------------*/ +/*! +* \brief This routine is called to set beacon detection function enable/disable state +* This is mainly designed for usage under BT inquiry state (disable function). +* +* \param[in] pvAdapter Pointer to the Adapter structure +* \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set +* \param[in] u4SetBufferLen The length of the set buffer +* \param[out] pu4SetInfoLen If the call is successful, returns the number of +* bytes read from the set buffer. If the call failed due to invalid length of +* the set buffer, returns the amount of storage needed. +* +* \retval WLAN_STATUS_SUCCESS +* \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. +* \retval WLAN_STATUS_INVALID_LENGTH +* +*/ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS +reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prGlueInfo); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + /* WIFI is enabled, when ACPI is D0 (ParamDeviceStateD0 = 1). And vice versa */ + + /* rStatus = wlanSetInformation(prGlueInfo->prAdapter, */ + /* wlanoidSetAcpiDevicePowerState, */ + /* pvSetBuffer, */ + /* u4SetBufferLen, */ + /* pu4SetInfoLen); */ + return rStatus; +} + +int priv_driver_set_chip_config(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + UINT_32 u4BufLen = 0; + INT_32 i4BytesWritten = 0; + UINT_32 u4CmdLen = 0; + UINT_32 u4PrefixLen = 0; + /* INT_32 i4Argc = 0; */ + /* PCHAR apcArgv[WLAN_CFG_ARGV_MAX] = {0}; */ + + PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; + + ASSERT(prNetDev); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) + return -1; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + DBGLOG(REQ, INFO, "priv_driver_set_chip_config command is %s\n", pcCommand); + /* wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); */ + /* DBGLOG(REQ, LOUD,("argc is %i\n",i4Argc)); */ + /* */ + u4CmdLen = kalStrnLen(pcCommand, i4TotalLen); + u4PrefixLen = kalStrLen(CMD_SET_CHIP) + 1 /*space */; + + kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); + + /* if(i4Argc >= 2) { */ + if (u4CmdLen > u4PrefixLen) { + + rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; + /* rChipConfigInfo.u2MsgSize = kalStrnLen(apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ + rChipConfigInfo.u2MsgSize = u4CmdLen - u4PrefixLen; + /* kalStrnCpy(rChipConfigInfo.aucCmd,apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ + if (u4PrefixLen <= CHIP_CONFIG_RESP_SIZE) { + kalStrnCpy(rChipConfigInfo.aucCmd, pcCommand + u4PrefixLen, + CHIP_CONFIG_RESP_SIZE - u4PrefixLen); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetChipConfig, + &rChipConfigInfo, + sizeof(rChipConfigInfo), FALSE, FALSE, TRUE, TRUE, &u4BufLen); + } else { + + DBGLOG(REQ, INFO, "%s: kalIoctl Command Len > %d\n", __func__, CHIP_CONFIG_RESP_SIZE); + rStatus = WLAN_STATUS_FAILURE; + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, INFO, "%s: kalIoctl ret=%d\n", __func__, rStatus); + i4BytesWritten = -1; + } + } + + return i4BytesWritten; + +} + +int priv_driver_set_miracast(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + UINT_32 i4BytesWritten = 0; + /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ + /* UINT_32 u4BufLen = 0; */ + INT_32 i4Argc = 0; + UINT_32 ucMode = 0; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T) NULL; + P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T) NULL; + PCHAR apcArgv[WLAN_CFG_ARGV_MAX]; + INT_32 u4Ret; + + ASSERT(prNetDev); + if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) + return -1; + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + prAdapter = prGlueInfo->prAdapter; + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &ucMode); /* ucMode = kalStrtoul(apcArgv[1], NULL, 0); */ + if (u4Ret) + DBGLOG(REQ, LOUD, "parse pcCommand error u4Ret=%d\n", u4Ret); + + if (g_ucMiracastMode == ucMode) + ; + /* XXX: continue or skip */ + + g_ucMiracastMode = ucMode; + prMsgWfdCfgUpdate = cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); + + if (prMsgWfdCfgUpdate != NULL) { + + prWfdCfgSettings = &(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rWfdConfigureSettings); + prMsgWfdCfgUpdate->rMsgHdr.eMsgId = MID_MNY_P2P_WFD_CFG_UPDATE; + prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; + + if (ucMode == MIRACAST_MODE_OFF) { + prWfdCfgSettings->ucWfdEnable = 0; + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); + } else if (ucMode == MIRACAST_MODE_SOURCE) { + prWfdCfgSettings->ucWfdEnable = 1; + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 1"); + } else if (ucMode == MIRACAST_MODE_SINK) { + prWfdCfgSettings->ucWfdEnable = 2; + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 2"); + } else { + prWfdCfgSettings->ucWfdEnable = 0; + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mira 0"); + } + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prMsgWfdCfgUpdate, MSG_SEND_METHOD_BUF); + + priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); + + } /* prMsgWfdCfgUpdate */ + else { + ASSERT(FALSE); + i4BytesWritten = -1; + } + } + + /* i4Argc */ + return i4BytesWritten; +} + +int priv_support_driver_cmd(IN struct net_device *prNetDev, IN OUT struct ifreq *prReq, IN int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + char *pcCommand = NULL; + priv_driver_cmd_t *priv_cmd = NULL; + int i4BytesWritten = 0; + int i4TotalLen = 0; + + if (!prReq->ifr_data) { + ret = -EINVAL; + goto exit; + } + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (!prGlueInfo) { + DBGLOG(REQ, WARN, "No glue info\n"); + ret = -EFAULT; + goto exit; + } + if (prGlueInfo->u4ReadyFlag == 0) { + ret = -EINVAL; + goto exit; + } + + priv_cmd = kzalloc(sizeof(priv_driver_cmd_t), GFP_KERNEL); + if (!priv_cmd) { + DBGLOG(REQ, WARN, "%s, alloc mem failed\n", __func__); + return -ENOMEM; + } + + if (copy_from_user(priv_cmd, prReq->ifr_data, sizeof(priv_driver_cmd_t))) { + DBGLOG(REQ, INFO, "%s: copy_from_user fail\n", __func__); + ret = -EFAULT; + goto exit; + } + + i4TotalLen = priv_cmd->total_len; + + if (i4TotalLen <= 0) { + ret = -EINVAL; + DBGLOG(REQ, INFO, "%s: i4TotalLen invalid\n", __func__); + goto exit; + } + + pcCommand = priv_cmd->buf; + + DBGLOG(REQ, INFO, "%s: driver cmd \"%s\" on %s\n", __func__, pcCommand, prReq->ifr_name); + + i4BytesWritten = priv_driver_cmds(prNetDev, pcCommand, i4TotalLen); + + if (i4BytesWritten < 0) { + DBGLOG(REQ, INFO, "%s: command %s failed; Written is %d\n", + __func__, pcCommand, i4BytesWritten); + ret = -EFAULT; + } + +exit: + kfree(priv_cmd); + + return ret; +} + +#if CFG_SUPPORT_BATCH_SCAN +#define CMD_BATCH_SET "WLS_BATCHING SET" +#define CMD_BATCH_GET "WLS_BATCHING GET" +#define CMD_BATCH_STOP "WLS_BATCHING STOP" +#endif + +#if CFG_SUPPORT_GET_CH_ENV +#define CMD_CH_ENV_GET "CH_ENV_GET" +#endif + +INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + INT_32 i4BytesWritten = 0; + INT_32 i4CmdFound = 0; + + if (FALSE == GLUE_CHK_PR2(prNetDev, pcCommand)) + return -1; + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev)); + + if (i4CmdFound == 0) { + i4CmdFound = 1; + + if (strnicmp(pcCommand, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0) + i4BytesWritten = priv_driver_set_miracast(prNetDev, pcCommand, i4TotalLen); +#if CFG_SUPPORT_BATCH_SCAN + else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { + kalIoctl(prGlueInfo, + wlanoidSetBatchScanReq, + (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); + } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { + /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ + /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ + /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ + + UINT_32 u4BufLen; + int i; + /* int rlen=0; */ + + for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { + g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ + kalIoctl(prGlueInfo, + wlanoidQueryBatchScanResult, + (PVOID)&g_rEventBatchResult[i], + sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, FALSE, &u4BufLen); + } + +#if 0 + DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); + for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { + prEntry = &g_rEventBatchResult.arBatchResult[i]; + DBGLOG(SCN, INFO, "Entry %u\n", i); + DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); + DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); + DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); + DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); + DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); + } +#endif + + batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); + + /* Dump for debug */ + /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, + i4BytesWritten, TRUE); */ + + } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { + kalIoctl(prGlueInfo, + wlanoidSetBatchScanReq, + (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, FALSE, &i4BytesWritten); + } +#endif +#if CFG_SUPPORT_GET_CH_ENV + else if (strnicmp(pcCommand, CMD_CH_ENV_GET, strlen(CMD_CH_ENV_GET)) == 0) + scanEnvResult(prGlueInfo, pcCommand, i4TotalLen, &i4BytesWritten); +#endif + +#if 0 + + else if (strnicmp(pcCommand, CMD_RSSI, strlen(CMD_RSSI)) == 0) { + /* i4BytesWritten = wl_android_get_rssi(net, command, i4TotalLen); */ + } else if (strnicmp(pcCommand, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { + i4BytesWritten = priv_driver_get_linkspeed(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { + /* Do nothing */ + } else if (strnicmp(pcCommand, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { + /* Do nothing */ + } else if (strnicmp(pcCommand, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { + /* Do nothing */ + } else if (strnicmp(pcCommand, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { + /* i4BytesWritten = wl_android_set_suspendopt(net, pcCommand, i4TotalLen); */ + } else if (strnicmp(pcCommand, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { + i4BytesWritten = priv_driver_set_suspend_mode(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { + i4BytesWritten = priv_driver_set_band(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { + /* i4BytesWritten = wl_android_get_band(net, pcCommand, i4TotalLen); */ + } else if (strnicmp(pcCommand, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { + i4BytesWritten = priv_driver_set_country(prNetDev, pcCommand, i4TotalLen); + } + /* Mediatek private command */ + else if (strnicmp(pcCommand, CMD_SET_SW_CTRL, strlen(CMD_SET_SW_CTRL)) == 0) { + i4BytesWritten = priv_driver_set_sw_ctrl(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_SW_CTRL, strlen(CMD_GET_SW_CTRL)) == 0) { + i4BytesWritten = priv_driver_get_sw_ctrl(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_CFG, strlen(CMD_SET_CFG)) == 0) { + i4BytesWritten = priv_driver_set_cfg(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CFG, strlen(CMD_GET_CFG)) == 0) { + i4BytesWritten = priv_driver_get_cfg(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_CHIP, strlen(CMD_SET_CHIP)) == 0) { + i4BytesWritten = priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CHIP, strlen(CMD_GET_CHIP)) == 0) { + i4BytesWritten = priv_driver_get_chip_config(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_DBG_LEVEL, strlen(CMD_SET_DBG_LEVEL)) == 0) { + i4BytesWritten = priv_driver_set_dbg_level(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DBG_LEVEL, strlen(CMD_GET_DBG_LEVEL)) == 0) { + i4BytesWritten = priv_driver_get_dbg_level(prNetDev, pcCommand, i4TotalLen); + } +#if CFG_SUPPORT_BATCH_SCAN + else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == 0) { + kalIoctl(prGlueInfo, + wlanoidSetBatchScanReq, + (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); + } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == 0) { + /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ + /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; */ + /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, pcCommand, i4TotalLen); */ + + UINT_32 u4BufLen; + int i; + /* int rlen=0; */ + + for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { + g_rEventBatchResult[i].ucScanCount = i + 1; /* for get which mscan */ + kalIoctl(prGlueInfo, + wlanoidQueryBatchScanResult, + (PVOID)&g_rEventBatchResult[i], + sizeof(EVENT_BATCH_RESULT_T), TRUE, TRUE, TRUE, &u4BufLen); + } + +#if 0 + DBGLOG(SCN, INFO, "Batch Scan Results, scan count = %u\n", g_rEventBatchResult.ucScanCount); + for (i = 0; i < g_rEventBatchResult.ucScanCount; i++) { + prEntry = &g_rEventBatchResult.arBatchResult[i]; + DBGLOG(SCN, INFO, "Entry %u\n", i); + DBGLOG(SCN, INFO, " BSSID = %pM\n", prEntry->aucBssid); + DBGLOG(SCN, INFO, " SSID = %s\n", prEntry->aucSSID); + DBGLOG(SCN, INFO, " SSID len = %u\n", prEntry->ucSSIDLen); + DBGLOG(SCN, INFO, " RSSI = %d\n", prEntry->cRssi); + DBGLOG(SCN, INFO, " Freq = %u\n", prEntry->ucFreq); + } +#endif + + batchConvertResult(&g_rEventBatchResult[0], pcCommand, i4TotalLen, &i4BytesWritten); + + /* Dump for debug */ + /* print_hex_dump(KERN_INFO, "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, i4BytesWritten, + TRUE); */ + + } else if (strnicmp(pcCommand, CMD_BATCH_STOP, strlen(CMD_BATCH_STOP)) == 0) { + kalIoctl(prGlueInfo, + wlanoidSetBatchScanReq, + (PVOID) pcCommand, i4TotalLen, FALSE, FALSE, TRUE, &i4BytesWritten); + } +#endif + +#endif + + else + i4CmdFound = 0; + } + + /* i4CmdFound */ + if (i4CmdFound == 0) + DBGLOG(REQ, TRACE, "Unknown driver command %s - ignored\n", pcCommand); + + if (i4BytesWritten >= 0) { + if ((i4BytesWritten == 0) && (i4TotalLen > 0)) { + /* reset the command buffer */ + pcCommand[0] = '\0'; + } + + if (i4BytesWritten >= i4TotalLen) { + DBGLOG(REQ, INFO, + "%s: i4BytesWritten %d > i4TotalLen < %d\n", __func__, i4BytesWritten, i4TotalLen); + i4BytesWritten = i4TotalLen; + } else { + pcCommand[i4BytesWritten] = '\0'; + i4BytesWritten++; + } + } + + return i4BytesWritten; + +} + +static int compat_priv(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra, + int (*priv_func)(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra)) +{ + struct iw_point *prIwp; + int ret = 0; +#ifdef CONFIG_COMPAT + struct compat_iw_point *iwp_compat = NULL; + struct iw_point iwp; +#endif + + if (!prIwReqData) + return -EINVAL; + +#ifdef CONFIG_COMPAT + if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { + iwp_compat = (struct compat_iw_point *) &prIwReqData->data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + prIwp = &iwp; + } else +#endif + prIwp = &prIwReqData->data; + + + ret = priv_func(prNetDev, prIwReqInfo, (union iwreq_data *)prIwp, pcExtra); + +#ifdef CONFIG_COMPAT + if (prIwReqInfo->flags & IW_REQUEST_FLAG_COMPAT) { + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + } +#endif + return ret; +} + +int +priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_int); +} + +int +priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_int); +} + +int +priv_set_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_ints); +} + +int +priv_get_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_ints); +} + +int +priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_struct); +} + +int +priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_get_struct); +} + +int +priv_set_string(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + return compat_priv(prNetDev, prIwReqInfo, prIwReqData, pcExtra, _priv_set_string); +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c new file mode 100644 index 0000000000000..c13d24906bf88 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/ahb.c @@ -0,0 +1,1643 @@ +/****************************************************************************** +*[File] ahb.c +*[Version] v1.0 +*[Revision Date] 2013-01-16 +*[Author] +*[Description] +* The program provides AHB HIF driver +*[Copyright] +* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + +/* +** Log: ahb.c + * + * 01 16 2013 vend_samp.lin + * Port sdio.c to ahb.c on MT6572/MT6582 + * 1) Initial version + * + * 04 12 2012 terry.wu + * NULL + * Add AEE message support + * 1) Show AEE warning(red screen) if SDIO access error occurs + * + * 02 14 2012 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * include correct header file upon setting. + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 09 20 2011 cp.wu + * [WCXRP00000994] [MT6620 Wi-Fi][Driver] dump message for bus error and reset bus error flag while re-initialized + * 1. always show error message for SDIO bus errors. + * 2. reset bus error flag when re-initialization + * + * 08 17 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * add MT6628 related definitions for Linux/Android driver. + * + * 05 18 2011 cp.wu + * [WCXRP00000702] [MT5931][Driver] Modify initialization sequence for E1 ASIC + * add device ID for MT5931. + * + * 04 08 2011 pat.lu + * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver + * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver + * + * 03 22 2011 pat.lu + * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build + * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. + * + * 03 18 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK. + * + * 03 15 2011 cp.wu + * [WCXRP00000559] [MT6620 Wi-Fi][Driver] Combine TX/RX DMA buffers into a single one to reduce physically continuous + * memory consumption + * 1. deprecate CFG_HANDLE_IST_IN_SDIO_CALLBACK + * 2. Use common coalescing buffer for both TX/RX directions + * + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 11 15 2010 jeffrey.chang + * [WCXRP00000181] [MT6620 Wi-Fi][Driver] fix the driver message "GLUE_FLAG_HALT skip INT" during unloading + * Fix GLUE_FALG_HALT message which cause driver to hang + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * correct typo + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add code to run WlanIST in SDIO callback. + * + * 10 19 2010 cp.wu + * [WCXRP00000122] [MT6620 Wi-Fi][Driver] Preparation for YuSu source tree integration + * remove HIF_SDIO_ONE flags because the settings could be merged for runtime detection instead of compile-time. + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK + * HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 08 21 2010 jeffrey.chang + * NULL + * 1) add sdio two setting + * 2) bug fix of sdio glue + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 18 2010 cp.wu + * NULL + * #if defined(__X86__) is not working, change to use #ifdef CONFIG_X86. + * + * 08 17 2010 cp.wu + * NULL + * add ENE SDIO host workaround for x86 linux platform. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Fix hotplug bug + * + * 03 28 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * clear sdio interrupt + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +/* #include */ +#include +/* #include */ +#include +/* #include */ +/* #include */ +/* #include */ + +#include +#ifndef CONFIG_X86 +#include +#endif + +#ifdef CONFIG_OF +#include +#include +#include +#else + +#endif + +/* #include +#include */ + +#include "gl_os.h" + +#if defined(MT6620) +#include "mt6620_reg.h" +#elif defined(MT6628) +#include "mtreg.h" +#endif + +#if !defined(CONFIG_MTK_CLKMGR) +#include +#endif + +/* #define MTK_DMA_BUF_MEMCPY_SUP */ /* no virt_to_phys() use */ +/* #define HIF_DEBUG_SUP */ +/* #define HIF_DEBUG_SUP_TX */ + +#ifdef HIF_DEBUG_SUP +#define HIF_DBG(msg) (printk msg) +#else +#define HIF_DBG(msg) +#endif /* HIF_DEBUG_SUP */ + +#ifdef HIF_DEBUG_SUP_TX +#define HIF_DBG_TX(msg) (printk msg) +#else +#define HIF_DBG_TX(msg) +#endif /* HIF_DEBUG_SUP */ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static UINT_32 +HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T *GlueInfo, IN UINT_32 BurstLen, IN UINT_32 PortId, IN UINT_32 TransByte); + +static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg); + +static int HifAhbProbe(VOID); + +static int HifAhbRemove(VOID); + +#if (MTK_WCN_SINGLE_MODULE == 0) +static int HifAhbBusCntGet(VOID); + +static int HifAhbBusCntClr(VOID); + +static int HifTxCnt; +#endif /* MTK_WCN_SINGLE_MODULE */ + +#if (CONF_HIF_DEV_MISC == 1) +static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos); + +static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos); + +static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg); + +static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp); + +static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp); +#else + +static int HifAhbPltmProbe(IN struct platform_device *PDev); + +static int __exit HifAhbPltmRemove(IN struct platform_device *PDev); + +#ifdef CONFIG_PM +static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message); + +static int HifAhbPltmResume(IN struct platform_device *PDev); +#endif /* CONFIG_PM */ + +#endif /* CONF_HIF_DEV_MISC */ + +#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ +static VOID HifAhbLoopbkAuto(IN unsigned long arg); +#endif /* CONF_HIF_LOOPBACK_AUTO */ + +#if (CONF_HIF_DMA_INT == 1) +static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg); +#endif /* CONF_HIF_DMA_INT */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* initialiation function from other module */ +static probe_card pfWlanProbe; + +/* release function from other module */ +static remove_card pfWlanRemove; + +static BOOLEAN WlanDmaFatalErr; + +#if (CONF_HIF_DEV_MISC == 1) +static const struct file_operations MtkAhbOps = { + .owner = THIS_MODULE, + .read = HifAhbMiscRead, + .write = HifAhbMiscWrite, + .unlocked_ioctl = HifAhbMiscIoctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = HifAhbMiscIoctl, +#endif + .open = HifAhbMiscOpen, + .release = HifAhbMiscClose, +}; + +static struct miscdevice MtkAhbDriver = { + .minor = MISC_DYNAMIC_MINOR, /* any minor number */ + .name = HIF_MOD_NAME, + .fops = &MtkAhbOps, +}; +#else + +#ifdef CONFIG_OF +static const struct of_device_id apwifi_of_ids[] = { + {.compatible = "mediatek,wifi", .data = (void *)0}, + {.compatible = "mediatek,mt7623-wifi", .data = (void *)0x7623}, + {} +}; +#endif + +struct platform_driver MtkPltmAhbDriver = { + .driver = { + .name = "mt-wifi", + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = apwifi_of_ids, +#endif + }, + .probe = HifAhbPltmProbe, +#ifdef CONFIG_PM + .suspend = HifAhbPltmSuspend, + .resume = HifAhbPltmResume, +#else + .suspend = NULL, + .resume = NULL, +#endif /* CONFIG_PM */ + .remove = __exit_p(HifAhbPltmRemove), +}; + +static struct platform_device *HifAhbPDev; + +#endif /* CONF_HIF_DEV_MISC */ + +/******************************************************************************* +* P U B L I C F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will register sdio bus to the os +* +* \param[in] pfProbe Function pointer to detect card +* \param[in] pfRemove Function pointer to remove card +* +* \return The result of registering HIF driver (WLAN_STATUS_SUCCESS = 0) +*/ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove) +{ + WLAN_STATUS Ret; + + ASSERT(pfProbe); + ASSERT(pfRemove); + + pfWlanProbe = pfProbe; /* wlan card initialization in other modules = wlanProbe() */ + pfWlanRemove = pfRemove; + +#if (CONF_HIF_DEV_MISC == 1) + Ret = misc_register(&MtkAhbDriver); + if (Ret != 0) + return Ret; + HifAhbProbe(); +#else + Ret = platform_driver_register(&MtkPltmAhbDriver); +#endif /* CONF_HIF_DEV_MISC */ + + return Ret; + +} /* end of glRegisterBus() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will unregister sdio bus to the os +* +* \param[in] pfRemove Function pointer to remove card +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glUnregisterBus(remove_card pfRemove) +{ + ASSERT(pfRemove); + + pfRemove(); + +#if (CONF_HIF_DEV_MISC == 1) + HifAhbRemove(); + + if ((misc_deregister(&MtkAhbDriver)) != 0) + ; +#else + + platform_driver_unregister(&MtkPltmAhbDriver); +#endif /* CONF_HIF_DEV_MISC */ + + return; + +} /* end of glUnregisterBus() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will inform us whole chip reset start event. +* +* \param[in] GlueInfo Pointer to glue info structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glResetHif(GLUE_INFO_T *GlueInfo) +{ + GL_HIF_INFO_T *HifInfo; + + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; + if (HifInfo->DmaOps) + HifInfo->DmaOps->DmaReset(HifInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function stores hif related info, which is initialized before. +* +* \param[in] GlueInfo Pointer to glue info structure +* \param[in] u4Cookie Pointer to UINT_32 memory base variable for _HIF_HPI +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glSetHifInfo(GLUE_INFO_T *GlueInfo, ULONG ulCookie) +{ + GL_HIF_INFO_T *HifInfo; + const struct of_device_id *of_id; + + /* Init HIF */ + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; +#if (CONF_HIF_DEV_MISC == 1) + HifInfo->Dev = MtkAhbDriver.this_device; +#else + HifInfo->Dev = &HifAhbPDev->dev; +#endif /* CONF_HIF_DEV_MISC */ + SET_NETDEV_DEV(GlueInfo->prDevHandler, HifInfo->Dev); + + HifInfo->HifRegBaseAddr = ioremap(HIF_DRV_BASE, HIF_DRV_LENGTH); + HifInfo->McuRegBaseAddr = ioremap(CONN_MCU_DRV_BASE, CONN_MCU_REG_LENGTH); + DBGLOG(INIT, INFO, "[WiFi/HIF]HifInfo->HifRegBaseAddr=0x%p, HifInfo->McuRegBaseAddr=0x%p\n", + HifInfo->HifRegBaseAddr, HifInfo->McuRegBaseAddr); + + /* default disable DMA */ + HifInfo->fgDmaEnable = FALSE; + HifInfo->DmaRegBaseAddr = 0; + HifInfo->DmaOps = NULL; + of_id = of_match_node(apwifi_of_ids, HifAhbPDev->dev.of_node); + if (of_id && of_id->data) { + HifInfo->ChipID = (UINT_32)(unsigned long)of_id->data; + } else { + /* read chip ID */ + HifInfo->ChipID = HIF_REG_READL(HifInfo, MCR_WCIR) & 0xFFFF; + if (HifInfo->ChipID == 0x0321 || HifInfo->ChipID == 0x0335 || HifInfo->ChipID == 0x0337) + HifInfo->ChipID = 0x6735; /* Denali ChipID transition */ + if (HifInfo->ChipID == 0x0326) + HifInfo->ChipID = 0x6755; + } + DBGLOG(INIT, INFO, "[WiFi/HIF] ChipID = 0x%x\n", HifInfo->ChipID); +#ifdef CONFIG_OF +#if !defined(CONFIG_MTK_CLKMGR) + HifInfo->clk_wifi_dma = devm_clk_get(&HifAhbPDev->dev, "wifi-dma"); + if (IS_ERR(HifInfo->clk_wifi_dma)) + DBGLOG(INIT, ERROR, "[WiFi/HIF][CCF]cannot get HIF clk_wifi_dma clock.\n"); + DBGLOG(INIT, TRACE, "[WiFi/HIF][CCF]HIF clk_wifi_dma=0x%p\n", HifInfo->clk_wifi_dma); +#endif +#endif + + /* Init DMA */ + WlanDmaFatalErr = 0; /* reset error flag */ + +#if (CONF_MTK_AHB_DMA == 1) + spin_lock_init(&HifInfo->DdmaLock); + + HifPdmaInit(HifInfo); +#endif /* CONF_MTK_AHB_DMA */ + + /* Start loopback test after 10 seconds */ +#if (CONF_HIF_LOOPBACK_AUTO == 1) /* only for development test */ + { + init_timer(&(HifInfo->HifTmrLoopbkFn)); + HifInfo->HifTmrLoopbkFn.function = HifAhbLoopbkAuto; + HifInfo->HifTmrLoopbkFn.data = (unsigned long)GlueInfo; + + init_waitqueue_head(&HifInfo->HifWaitq); + HifInfo->HifTaskLoopbkFn = kthread_run(kalDevLoopbkThread, GlueInfo->prDevHandler, "LoopbkThread"); + HifInfo->HifLoopbkFlg = 0; + + /* Note: in FPGA, clock is not accuracy so 3000 here, not 10000 */ + HifInfo->HifTmrLoopbkFn.expires = jiffies + MSEC_TO_SYSTIME(30000); + add_timer(&(HifInfo->HifTmrLoopbkFn)); + + HIF_DBG(("[WiFi/HIF] Start loopback test after 10 seconds (jiffies = %u)...\n", jiffies)); + } +#endif /* CONF_HIF_LOOPBACK_AUTO */ + +#if (CONF_HIF_DMA_INT == 1) + init_waitqueue_head(&HifInfo->HifDmaWaitq); + HifInfo->HifDmaWaitFlg = 0; +#endif /* CONF_HIF_DMA_INT */ + +} /* end of glSetHifInfo() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function clears hif related info. +* +* \param[in] GlueInfo Pointer to glue info structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glClearHifInfo(GLUE_INFO_T *GlueInfo) +{ + iounmap(GlueInfo->rHifInfo.HifRegBaseAddr); + iounmap(GlueInfo->rHifInfo.DmaRegBaseAddr); + iounmap(GlueInfo->rHifInfo.McuRegBaseAddr); + return; + +} /* end of glClearHifInfo() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function clears hif related info. +* +* \param[in] GlueInfo Pointer to glue info structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf) +{ + GL_HIF_INFO_T *HifInfo; + + HifInfo = &GlueInfo->rHifInfo; + DBGLOG(INIT, TRACE, "glGetChipInfo ChipID = 0x%x\n", HifInfo->ChipID); + switch (HifInfo->ChipID) { + case MTK_CHIP_ID_6571: + case MTK_CHIP_ID_8127: + case MTK_CHIP_ID_6752: + case MTK_CHIP_ID_8163: + case MTK_CHIP_ID_6735: + case MTK_CHIP_ID_6580: + case MTK_CHIP_ID_6755: + case MTK_CHIP_ID_7623: + kalSprintf(pucChipBuf, "%04x", HifInfo->ChipID); + break; + default: + kalMemCopy(pucChipBuf, "SOC", strlen("SOC")); + } +} /* end of glGetChipInfo() */ + +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function to check if we need wakelock under Hotspot mode. +* +* \param[in] GlueInfo Pointer to glue info structure +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo) +{ + GL_HIF_INFO_T *HifInfo; + + HifInfo = &GlueInfo->rHifInfo; + if (HifInfo->ChipID == MTK_CHIP_ID_6572 || HifInfo->ChipID == MTK_CHIP_ID_6582) + return TRUE; + else + return FALSE; +} /* end of glIsChipNeedWakelock() */ +#endif /* CFG_SPM_WORKAROUND_FOR_HOTSPOT */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Initialize bus operation and hif related information, request resources. +* +* \param[out] pvData A pointer to HIF-specific data type buffer. +* For eHPI, pvData is a pointer to UINT_32 type and stores a +* mapped base address. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN glBusInit(PVOID pvData) +{ + return TRUE; +} /* end of glBusInit() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Stop bus operation and release resources. +* +* \param[in] pvData A pointer to struct net_device. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glBusRelease(PVOID pvData) +{ +} /* end of glBusRelease() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Setup bus interrupt operation and interrupt handler for os. +* +* \param[in] pvData A pointer to struct net_device. +* \param[in] pfnIsr A pointer to interrupt handler function. +* \param[in] pvCookie Private data for pfnIsr function. +* +* \retval WLAN_STATUS_SUCCESS if success +* NEGATIVE_VALUE if fail +*/ +/*----------------------------------------------------------------------------*/ +#ifdef CONFIG_OF +INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = { 0, 0, 0 }; + /* unsigned int phy_base; */ + unsigned int irq_id = 0; + unsigned int irq_flags = 0; + + struct net_device *prNetDevice; + + ASSERT(pvData); + if (!pvData) + return -1; + prNetDevice = (struct net_device *)pvData; + + node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); + if (node) { + irq_id = irq_of_parse_and_map(node, 0); + DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); + } else { + DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); + } + + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); + } else { + irq_flags = irq_info[2]; + DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); + } + + /* Register AHB IRQ */ + if (request_irq(irq_id, HifAhbISR, irq_flags, HIF_MOD_NAME, prNetDevice)) { + DBGLOG(INIT, ERROR, "WIFI-OF: request irq %d fail!\n", irq_id); + return -1; + } + + return 0; +} + +VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = { 0, 0, 0 }; + /* unsigned int phy_base; */ + unsigned int irq_id = 0; + unsigned int irq_flags = 0; + + struct net_device *prNetDevice; + + /* Init */ + ASSERT(pvData); + if (!pvData) + return; + prNetDevice = (struct net_device *)pvData; + + node = of_find_compatible_node(NULL, NULL, "mediatek,wifi"); + if (node) { + irq_id = irq_of_parse_and_map(node, 0); + DBGLOG(INIT, INFO, "WIFI-OF: get wifi irq(%d)\n", irq_id); + } else { + DBGLOG(INIT, ERROR, "WIFI-OF: get wifi device node fail\n"); + } + + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + DBGLOG(INIT, ERROR, "WIFI-OF: get interrupt flag from DTS fail\n"); + } else { + irq_flags = irq_info[2]; + DBGLOG(INIT, LOUD, "WIFI-OF: get interrupt flag(0x%x)\n", irq_flags); + } + + /* Free the IRQ */ + free_irq(irq_id, prNetDevice); + return; + +} +#else +/* the name is different in 72 and 82 */ +#ifndef MT_WF_HIF_IRQ_ID /* for MT6572/82/92 */ +#define MT_WF_HIF_IRQ_ID WF_HIF_IRQ_ID +#endif /* MT_WF_HIF_IRQ_ID */ + +INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie) +{ + int ret = 0; + struct net_device *prNetDevice; + GLUE_INFO_T *GlueInfo; + GL_HIF_INFO_T *HifInfo; + + /* Init */ + ASSERT(pvData); + if (!pvData) + return -1; + + prNetDevice = (struct net_device *)pvData; + GlueInfo = (GLUE_INFO_T *) pvCookie; + ASSERT(GlueInfo); + if (!GlueInfo) { + DBGLOG(INIT, ERROR, "GlueInfo == NULL!\n"); + return -1; + } + + HifInfo = &GlueInfo->rHifInfo; + + /* Register AHB IRQ */ + if (request_irq(MT_WF_HIF_IRQ_ID, HifAhbISR, IRQF_TRIGGER_LOW, HIF_MOD_NAME, prNetDevice)) { + DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_WF_HIF_IRQ_ID); + return -1; + } +#if (CONF_HIF_DMA_INT == 1) + if (request_irq(MT_GDMA2_IRQ_ID, HifDmaISR, IRQF_TRIGGER_LOW, "AHB_DMA", prNetDevice)) { + DBGLOG(INIT, ERROR, "request irq %d fail!\n", MT_GDMA2_IRQ_ID); + free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); + return -1; + } +#endif /* CONF_HIF_DMA_INT */ + + return ret; + +} /* end of glBusSetIrq() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Stop bus interrupt operation and disable interrupt handling for os. +* +* \param[in] pvData A pointer to struct net_device. +* \param[in] pvCookie Private data for pfnIsr function. +* +* \return (none) +*/ +/*----------------------------------------------------------------------------*/ +VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie) +{ + struct net_device *prNetDevice; + GLUE_INFO_T *GlueInfo; + GL_HIF_INFO_T *HifInfo; + + /* Init */ + ASSERT(pvData); + if (!pvData) + return; + + prNetDevice = (struct net_device *)pvData; + GlueInfo = (GLUE_INFO_T *) pvCookie; + ASSERT(GlueInfo); + if (!GlueInfo) + return; + + HifInfo = &GlueInfo->rHifInfo; + + /* Free the IRQ */ + free_irq(MT_WF_HIF_IRQ_ID, prNetDevice); + return; + +} /* end of glBusreeIrq() */ +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read a 32-bit device register +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] RegOffset Register offset +* \param[in] pu4Value Pointer to variable used to store read value +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalDevRegRead(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, OUT UINT_32 *pu4Value) +{ + GL_HIF_INFO_T *HifInfo; + + /* sanity check and init */ + ASSERT(GlueInfo); + ASSERT(pu4Value); + HifInfo = &GlueInfo->rHifInfo; + + /* use PIO mode to read register */ + if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) + return FALSE; + *pu4Value = HIF_REG_READL(HifInfo, RegOffset); + + if ((RegOffset == MCR_WRDR0) || (RegOffset == MCR_WRDR1)) + HIF_DBG(("[WiFi/HIF] kalDevRegRead from Data Port 0 or 1\n")); + + return TRUE; + +} /* end of kalDevRegRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Write a 32-bit device register +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] RegOffset Register offset +* \param[in] RegValue RegValue to be written +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalDevRegWrite(IN GLUE_INFO_T *GlueInfo, IN UINT_32 RegOffset, IN UINT_32 RegValue) +{ + GL_HIF_INFO_T *HifInfo; + + /* sanity check and init */ + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; + + /* use PIO mode to write register */ + if (WlanDmaFatalErr && RegOffset != MCR_WCIR && RegOffset != MCR_WHLPCR) + return FALSE; + HIF_REG_WRITEL(HifInfo, RegOffset, RegValue); + + if ((RegOffset == MCR_WTDR0) || (RegOffset == MCR_WTDR1)) + HIF_DBG(("[WiFi/HIF] kalDevRegWrite to Data Port 0 or 1\n")); + + return TRUE; + +} /* end of kalDevRegWrite() */ + + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Read device I/O port +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] Port I/O port offset +* \param[in] Size Length to be read +* \param[out] Buf Pointer to read buffer +* \param[in] MaxBufSize Length of the buffer valid to be accessed +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalDevPortRead(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, OUT PUINT_8 Buf, IN UINT_32 MaxBufSize) +{ + GL_HIF_INFO_T *HifInfo; + UINT_32 u4HSTCRValue = 0; + UINT_32 RegWHLPCR = 0; + + /* sanity check */ + if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { + DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", + WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); + return FALSE; + } + /* Init */ + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; + + ASSERT(Buf); + ASSERT(Size <= MaxBufSize); + + /* Note: burst length should be equal to the one used in DMA */ + if (Port == MCR_WRDR0) + u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD0, Size); + else if (Port == MCR_WRDR1) + u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_RXD1, Size); + else if (Port == MCR_WHISR) + u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_WHISR, Size); + + RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + /* Read */ +#if (CONF_MTK_AHB_DMA == 1) + if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) + && ((Port == MCR_WRDR0) || (Port == MCR_WRDR1))) { + /* only for data port */ +#ifdef MTK_DMA_BUF_MEMCPY_SUP + VOID *DmaVBuf = NULL, *DmaPBuf = NULL; +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; + MTK_WCN_HIF_DMA_CONF DmaConf; + UINT_32 LoopCnt; + unsigned long PollTimeout; +#if (CONF_HIF_DMA_INT == 1) + INT_32 RtnVal = 0; +#endif + /* config DMA, Port = MCR_WRDR0 or MCR_WRDR1 */ + DmaConf.Count = Size; + DmaConf.Dir = HIF_DMA_DIR_RX; + DmaConf.Src = HIF_DRV_BASE + Port; /* must be physical addr */ + +#ifdef MTK_DMA_BUF_MEMCPY_SUP + DmaConf.Dst = kalIOPhyAddrGet(Buf); /* must be physical addr */ + + /* TODO: use virt_to_phys() */ + if (DmaConf.Dst == NULL) { + HIF_DBG(("[WiFi/HIF] Use Dma Buffer to RX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); + ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); + + kalDmaBufGet(&DmaVBuf, &DmaPBuf); + DmaConf.Dst = (ULONG) DmaPBuf; + } +#else + /* + http://kernelnewbies.org/KernelMemoryAllocation + Since the cache-coherent mapping may be expensive, also a streaming allocation exists. + + This is a buffer for one-way communication, which means coherency is limited to + flushing the data from the cache after a write finishes. The buffer has to be + pre-allocated (e.g. using kmalloc()). DMA for it is set up with dma_map_single(). + + When the DMA is finished (e.g. when the device has sent an interrupt signaling end of + DMA), call dma_unmap_single(). Between map and unmap, the device is in control of the + buffer: if you write to the device, do it before dma_map_single(), if you read from + it, do it after dma_unmap_single(). + */ + /* DMA_FROM_DEVICE invalidated (without writeback) the cache */ + /* TODO: if dst_off was not cacheline aligned */ + DmaConf.Dst = dma_map_single(HifInfo->Dev, Buf, Size, DMA_FROM_DEVICE); +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + + /* start to read data */ + AP_DMA_HIF_LOCK(HifInfo); /* lock to avoid other codes config GDMA */ + + prDmaOps->DmaClockCtrl(TRUE); + prDmaOps->DmaConfig(HifInfo, &DmaConf); + prDmaOps->DmaStart(HifInfo); + +#if (CONF_HIF_DMA_INT == 1) + RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); + if (RtnVal <= 0) + DBGLOG(RX, ERROR, "fatal error1! reset DMA!\n"); + HifInfo->HifDmaWaitFlg = 0; +#else + PollTimeout = jiffies + HZ * 5; + + do { + if (time_before(jiffies, PollTimeout)) + continue; + DBGLOG(RX, INFO, "RX DMA Timeout, HSTCR: 0x%08x, and dump WHISR EnhanceMode data\n", + u4HSTCRValue); + HifDumpEnhanceModeData(GlueInfo->prAdapter); + if (prDmaOps->DmaRegDump != NULL) + prDmaOps->DmaRegDump(HifInfo); + WlanDmaFatalErr = 1; + /* we still need complete dma progress even dma timeout */ + break; + } while (!prDmaOps->DmaPollIntr(HifInfo)); +#endif /* CONF_HIF_DMA_INT */ + /* we should disable dma interrupt then clear dma interrupt, otherwise, + for dma timeout case, interrupt may be set after we clear it */ + prDmaOps->DmaStop(HifInfo); + prDmaOps->DmaAckIntr(HifInfo); + + LoopCnt = 0; + do { + if (LoopCnt++ > 100000) { + /* TODO: impossible! reset DMA */ + DBGLOG(RX, ERROR, "fatal error2! reset DMA!\n"); + break; + } + } while (prDmaOps->DmaPollStart(HifInfo) != 0); + + prDmaOps->DmaClockCtrl(FALSE); + + AP_DMA_HIF_UNLOCK(HifInfo); + +#ifdef MTK_DMA_BUF_MEMCPY_SUP + if (DmaVBuf != NULL) + kalMemCopy(Buf, DmaVBuf, Size); +#else + dma_unmap_single(HifInfo->Dev, DmaConf.Dst, Size, DMA_FROM_DEVICE); +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); + + if (WlanDmaFatalErr) { + if (!fgIsResetting) + glDoChipReset(); + return FALSE; + } + HIF_DBG(("[WiFi/HIF] DMA RX OK!\n")); + } else +#endif /* CONF_MTK_AHB_DMA */ + { + UINT_32 IdLoop, MaxLoop; + UINT_32 *LoopBuf; + + /* default PIO mode */ + MaxLoop = Size >> 2; + if (Size & 0x3) + MaxLoop++; + LoopBuf = (UINT_32 *) Buf; + + for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { + + *LoopBuf = HIF_REG_READL(HifInfo, Port); + LoopBuf++; + } + + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); + } + + return TRUE; + +} /* end of kalDevPortRead() */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Write device I/O port +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] Port I/O port offset +* \param[in] Size Length to be write +* \param[in] Buf Pointer to write buffer +* \param[in] MaxBufSize Length of the buffer valid to be accessed +* +* \retval TRUE operation success +* \retval FALSE operation fail +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN +kalDevPortWrite(IN P_GLUE_INFO_T GlueInfo, IN UINT_16 Port, IN UINT_32 Size, IN PUINT_8 Buf, IN UINT_32 MaxBufSize) +{ + GL_HIF_INFO_T *HifInfo; + UINT_32 u4HSTCRValue = 0; + UINT_32 RegWHLPCR = 0; + + /* sanity check */ + if ((WlanDmaFatalErr == 1) || (fgIsResetting == TRUE) || (HifIsFwOwn(GlueInfo->prAdapter) == TRUE)) { + DBGLOG(RX, ERROR, "WlanDmaFatalErr: %d, fgIsResetting: %d, HifIsFwOwn: %d\n", + WlanDmaFatalErr, fgIsResetting, HifIsFwOwn(GlueInfo->prAdapter)); + return FALSE; + } + + /* Init */ + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; + + ASSERT(Buf); + ASSERT(Size <= MaxBufSize); + + HifTxCnt++; + + /* Note: burst length should be equal to the one used in DMA */ + if (Port == MCR_WTDR0) + u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD0, Size); + else if (Port == MCR_WTDR1) + u4HSTCRValue = HifAhbDmaEnhanceModeConf(GlueInfo, HIF_BURST_4DW, HIF_TARGET_TXD1, Size); + /* else other non-data port */ + + RegWHLPCR = HIF_REG_READL(HifInfo, MCR_WHLPCR); + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + /* Write */ +#if (CONF_MTK_AHB_DMA == 1) + if ((HifInfo->fgDmaEnable == TRUE) && (HifInfo->DmaOps != NULL) && ((Port == MCR_WTDR0) || + (Port == MCR_WTDR1))) { + /* only for data port */ +#ifdef MTK_DMA_BUF_MEMCPY_SUP + VOID *DmaVBuf = NULL, *DmaPBuf = NULL; +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + GL_HIF_DMA_OPS_T *prDmaOps = HifInfo->DmaOps; + MTK_WCN_HIF_DMA_CONF DmaConf; + UINT_32 LoopCnt; + unsigned long PollTimeout; +#if (CONF_HIF_DMA_INT == 1) + INT_32 RtnVal = 0; +#endif + + /* config GDMA */ + HIF_DBG_TX(("[WiFi/HIF/DMA] Prepare to send data...\n")); + DmaConf.Count = Size; + DmaConf.Dir = HIF_DMA_DIR_TX; + DmaConf.Dst = HIF_DRV_BASE + Port; /* must be physical addr */ + +#ifdef MTK_DMA_BUF_MEMCPY_SUP + DmaConf.Src = kalIOPhyAddrGet(Buf); /* must be physical addr */ + + /* TODO: use virt_to_phys() */ + if (DmaConf.Src == NULL) { + HIF_DBG_TX(("[WiFi/HIF] Use Dma Buffer to TX packet (%d %d)...\n", Size, CFG_RX_MAX_PKT_SIZE)); + ASSERT(Size <= CFG_RX_MAX_PKT_SIZE); + + kalDmaBufGet(&DmaVBuf, &DmaPBuf); + DmaConf.Src = (ULONG) DmaPBuf; + + kalMemCopy(DmaVBuf, Buf, Size); + } +#else + + /* DMA_TO_DEVICE writeback the cache */ + DmaConf.Src = dma_map_single(HifInfo->Dev, Buf, Size, DMA_TO_DEVICE); +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + + /* start to write */ + AP_DMA_HIF_LOCK(HifInfo); + + prDmaOps->DmaClockCtrl(TRUE); + prDmaOps->DmaConfig(HifInfo, &DmaConf); + prDmaOps->DmaStart(HifInfo); + +#if (CONF_HIF_DMA_INT == 1) + RtnVal = wait_event_interruptible_timeout(HifInfo->HifDmaWaitq, (HifInfo->HifDmaWaitFlg != 0), 1000); + if (RtnVal <= 0) + DBGLOG(TX, ERROR, "fatal error1! reset DMA!\n"); + HifInfo->HifDmaWaitFlg = 0; +#else + + LoopCnt = 0; + PollTimeout = jiffies + HZ * 5; + + do { + if (time_before(jiffies, PollTimeout)) + continue; + DBGLOG(TX, INFO, "TX DMA Timeout, HSTCR: 0x%08x\n", u4HSTCRValue); + if (prDmaOps->DmaRegDump != NULL) + prDmaOps->DmaRegDump(HifInfo); + WlanDmaFatalErr = 1; + /* we still need complete dma progress even dma timeout */ + break; + } while (!prDmaOps->DmaPollIntr(HifInfo)); +#endif /* CONF_HIF_DMA_INT */ + /* we should disable dma interrupt then clear dma interrupt, otherwise, + for dma timeout case, interrupt may be set after we clear it */ + prDmaOps->DmaStop(HifInfo); + prDmaOps->DmaAckIntr(HifInfo); + + LoopCnt = 0; + do { + if (LoopCnt++ > 100000) { + DBGLOG(TX, ERROR, "fatal error2! reset DMA!\n"); + break; + } + } while (prDmaOps->DmaPollStart(HifInfo) != 0); + + prDmaOps->DmaClockCtrl(FALSE); + + AP_DMA_HIF_UNLOCK(HifInfo); + +#ifndef MTK_DMA_BUF_MEMCPY_SUP + dma_unmap_single(HifInfo->Dev, DmaConf.Src, Size, DMA_TO_DEVICE); +#endif /* MTK_DMA_BUF_MEMCPY_SUP */ + + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); + + if (WlanDmaFatalErr) { + if (!fgIsResetting) + glDoChipReset(); + return FALSE; + } + HIF_DBG_TX(("[WiFi/HIF] DMA TX OK!\n")); + } else +#endif /* CONF_MTK_AHB_DMA */ + { + UINT_32 IdLoop, MaxLoop; + UINT_32 *LoopBuf; + + /* PIO mode */ + MaxLoop = Size >> 2; + LoopBuf = (UINT_32 *) Buf; + + HIF_DBG_TX(("[WiFi/HIF/PIO] Prepare to send data (%d 0x%p-0x%p)...\n", + Size, LoopBuf, (((UINT8 *) LoopBuf) + (Size & (~0x03))))); + + if (Size & 0x3) + MaxLoop++; + + for (IdLoop = 0; IdLoop < MaxLoop; IdLoop++) { + HIF_REG_WRITEL(HifInfo, Port, *LoopBuf); + LoopBuf++; + } + + if ((RegWHLPCR & WHLPCR_INT_EN_SET) == 1) + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_SET); + + HIF_DBG_TX(("\n\n")); + } + + return TRUE; + +} /* end of kalDevPortWrite() */ + +/******************************************************************************* +* P R I V A T E F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a SDIO interrupt callback function +* +* \param[in] func pointer to SDIO handle +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ +static irqreturn_t HifAhbISR(IN int Irq, IN void *Arg) +{ + struct net_device *prNetDevice = (struct net_device *)Arg; + GLUE_INFO_T *GlueInfo; + GL_HIF_INFO_T *HifInfo; + + /* Init */ + IsrCnt++; + ASSERT(prNetDevice); + GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); + ASSERT(GlueInfo); + + if (!GlueInfo) + return IRQ_HANDLED; + + HifInfo = &GlueInfo->rHifInfo; + + GlueInfo->IsrCnt++; + + if (GlueInfo->ulFlag & GLUE_FLAG_HALT) { + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + return IRQ_HANDLED; + } + + HIF_REG_WRITEL(HifInfo, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + /* lock 100ms to avoid suspend */ + kalHifAhbKalWakeLockTimeout(GlueInfo); + + /* Wake up main thread */ + set_bit(GLUE_FLAG_INT_BIT, &GlueInfo->ulFlag); + + /* when we got sdio interrupt, we wake up the tx servie thread */ + wake_up_interruptible(&GlueInfo->waitq); + + IsrPassCnt++; + GlueInfo->IsrPassCnt++; + return IRQ_HANDLED; + +} + +#if (CONF_HIF_DMA_INT == 1) +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a SDIO interrupt callback function +* +* \param[in] func pointer to SDIO handle +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ + +static irqreturn_t HifDmaISR(IN int Irq, IN void *Arg) +{ + struct net_device *prNetDevice = (struct net_device *)Arg; + GLUE_INFO_T *GlueInfo; + GL_HIF_INFO_T *HifInfo; + + /* Init */ + ASSERT(prNetDevice); + GlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDevice)); + ASSERT(GlueInfo); + + if (!GlueInfo) + return IRQ_HANDLED; + HifInfo = &GlueInfo->rHifInfo; + + /* disable interrupt */ + HifInfo->DmaOps->DmaAckIntr(HifInfo); + + /* Wake up main thread */ + set_bit(1, &HifInfo->HifDmaWaitFlg); + + /* when we got sdio interrupt, we wake up the tx servie thread */ + wake_up_interruptible(&HifInfo->HifDmaWaitq); + + return IRQ_HANDLED; + +} +#endif /* CONF_HIF_DMA_INT */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is a SDIO probe function +* +* \param[in] func pointer to SDIO handle +* \param[in] id pointer to SDIO device id table +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ +#if defined(CONFIG_MTK_CLKMGR) +#if defined(MTK_EXTERNAL_LDO) || defined(MTK_ALPS_BOX_SUPPORT) +#include +#endif +#endif + +static int HifAhbProbe(VOID) +{ + int Ret = 0; + + DBGLOG(INIT, INFO, "HifAhbProbe()\n"); + + /* power on WiFi TX PA 3.3V and HIF GDMA clock */ + { +#ifdef CONFIG_MTK_PMIC_MT6397 +#if defined(CONFIG_MTK_CLKMGR) +#ifdef MTK_EXTERNAL_LDO + /* for 8127 tablet */ + mt_set_gpio_mode(GPIO51, GPIO_MODE_04); + mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); + mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO51, GPIO_PULL_UP); +#elif defined(MTK_ALPS_BOX_SUPPORT) + /* for 8127 box */ + mt_set_gpio_mode(GPIO89, GPIO_MODE_04); + mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); + mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO89, GPIO_PULL_UP); +#else + hwPowerOn(MT65XX_POWER_LDO_VGP4, VOL_3300, "WLAN"); +#endif +#endif +#else +#ifdef CONFIG_OF /*for MT6752 */ + mtk_wcn_consys_hw_wifi_paldo_ctrl(1); /* switch to HW mode */ +#else /*for MT6572/82/92 */ + hwPowerOn(MT6323_POWER_LDO_VCN33_WIFI, VOL_3300, "WLAN"); + upmu_set_vcn33_on_ctrl_wifi(1); /* switch to HW mode */ +#endif +#endif + + } + +#if (CONF_HIF_DEV_MISC == 1) + if (pfWlanProbe((PVOID) &MtkAhbDriver.this_device) != WLAN_STATUS_SUCCESS) { +#else + if (pfWlanProbe((PVOID) &HifAhbPDev->dev) != WLAN_STATUS_SUCCESS) { +#endif /* CONF_HIF_DEV_MISC */ + + pfWlanRemove(); + Ret = -1; + } + + return Ret; + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function will do module remove. +* +* \param[in] None +* +* \return The result of remove (WLAN_STATUS_SUCCESS = 0) +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbRemove(VOID) +{ + DBGLOG(INIT, INFO, "HifAhbRemove()\n"); + + pfWlanRemove(); + + { +#ifdef CONFIG_MTK_PMIC_MT6397 +#if defined(CONFIG_MTK_CLKMGR) +#ifdef MTK_EXTERNAL_LDO + /* for 8127 tablet */ + mt_set_gpio_mode(GPIO51, GPIO_MODE_04); + mt_set_gpio_dir(GPIO51, GPIO_DIR_OUT); + mt_set_gpio_pull_enable(GPIO51, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO51, GPIO_PULL_DOWN); +#elif defined(MTK_ALPS_BOX_SUPPORT) + /* for 8127 box */ + mt_set_gpio_mode(GPIO89, GPIO_MODE_04); + mt_set_gpio_dir(GPIO89, GPIO_DIR_OUT); + mt_set_gpio_pull_enable(GPIO89, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO89, GPIO_PULL_DOWN); +#else + hwPowerDown(MT65XX_POWER_LDO_VGP4, "WLAN"); +#endif +#endif +#else +#ifdef CONFIG_OF /*for MT6752 */ + mtk_wcn_consys_hw_wifi_paldo_ctrl(0); /* switch to SW mode */ +#else /*for MT6572/82/92 */ + upmu_set_vcn33_on_ctrl_wifi(0); /* switch to SW mode */ + hwPowerDown(MT6323_POWER_LDO_VCN33_WIFI, "WLAN"); +#endif +#endif + + } + + return 0; +} + +#if (MTK_WCN_SINGLE_MODULE == 0) +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function gets the TX count pass through HIF AHB bus. +* +* \param[in] None +* +* \return TX count +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbBusCntGet(VOID) +{ + return HifTxCnt; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function resets the TX count pass through HIF AHB bus. +* +* \param[in] None +* +* \return 0 +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbBusCntClr(VOID) +{ + HifTxCnt = 0; + return 0; +} +#endif /* MTK_WCN_SINGLE_MODULE */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function configs the DMA TX/RX settings before any real TX/RX. +* +* \param[in] GlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] BurstLen 0(1DW), 1(4DW), 2(8DW), Others(Reserved) +* \param[in] PortId 0(TXD0), 1(TXD1), 2(RXD0), 3(RXD1), 4(WHISR enhance) +* \param[in] TransByte Should be 4-byte align. +* +* \return void +*/ +/*----------------------------------------------------------------------------*/ +static UINT_32 HifAhbDmaEnhanceModeConf(IN GLUE_INFO_T * GlueInfo, UINT_32 BurstLen, UINT_32 PortId, UINT_32 TransByte) +{ + GL_HIF_INFO_T *HifInfo; + UINT_32 RegHSTCR; + + ASSERT(GlueInfo); + HifInfo = &GlueInfo->rHifInfo; + + RegHSTCR = HIF_REG_READL(HifInfo, MCR_WHIER); + + RegHSTCR = HIF_REG_READL(HifInfo, MCR_HSTCR); + RegHSTCR = + ((BurstLen << HSTCR_AFF_BURST_LEN_OFFSET) & HSTCR_AFF_BURST_LEN) | + ((PortId << HSTCR_TRANS_TARGET_OFFSET) & HSTCR_TRANS_TARGET) | + (((TransByte & 0x3) == 0) ? (TransByte & HSTCR_HSIF_TRANS_CNT) : ((TransByte + 4) & HSTCR_HSIF_TRANS_CNT)); + HIF_REG_WRITEL(HifInfo, MCR_HSTCR, RegHSTCR); + return RegHSTCR; +} + +VOID glSetPowerState(IN GLUE_INFO_T *GlueInfo, IN UINT_32 ePowerMode) +{ + +} + +#if (CONF_HIF_DEV_MISC == 1) +/* no use */ +static ssize_t HifAhbMiscRead(IN struct file *Filp, OUT char __user *DstBuf, IN size_t Size, IN loff_t *Ppos) +{ + return 0; +} + +static ssize_t HifAhbMiscWrite(IN struct file *Filp, IN const char __user *SrcBuf, IN size_t Size, IN loff_t *Ppos) +{ + return 0; +} + +static int HifAhbMiscIoctl(IN struct file *Filp, IN unsigned int Cmd, IN unsigned long arg) +{ + return 0; +} + +static int HifAhbMiscOpen(IN struct inode *Inodep, IN struct file *Filp) +{ + return 0; +} + +static int HifAhbMiscClose(IN struct inode *Inodep, IN struct file *Filp) +{ + return 0; +} +#else + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by OS platform device module. +* +* \param[in] PDev Pointer to the platform device structure. +* +* \return 0 +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbPltmProbe(IN struct platform_device *PDev) +{ + HifAhbPDev = PDev; + + DBGLOG(INIT, INFO, "HifAhbPltmProbe\n"); + +#if (CONF_HIF_PMIC_TEST == 1) + wmt_set_jtag_for_mcu(); + wmt_set_jtag_for_gps(); + +#endif /* CONF_HIF_PMIC_TEST */ + +#if (MTK_WCN_SINGLE_MODULE == 1) + HifAhbProbe(); /* only for test purpose without WMT module */ + +#else + + /* register WiFi function to WMT */ + DBGLOG(INIT, INFO, "mtk_wcn_wmt_wlan_reg\n"); + { + MTK_WCN_WMT_WLAN_CB_INFO WmtCb; + + WmtCb.wlan_probe_cb = HifAhbProbe; + WmtCb.wlan_remove_cb = HifAhbRemove; + WmtCb.wlan_bus_cnt_get_cb = HifAhbBusCntGet; + WmtCb.wlan_bus_cnt_clr_cb = HifAhbBusCntClr; + mtk_wcn_wmt_wlan_reg(&WmtCb); + } +#endif /* MTK_WCN_SINGLE_MODULE */ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by OS platform device module. +* +* \param[in] PDev Pointer to the platform device structure. +* +* \return 0 +*/ +/*----------------------------------------------------------------------------*/ +static int __exit HifAhbPltmRemove(IN struct platform_device *PDev) +{ +#if (MTK_WCN_SINGLE_MODULE == 0) + mtk_wcn_wmt_wlan_unreg(); +#endif /* MTK_WCN_SINGLE_MODULE */ + return 0; +} + +#ifdef CONFIG_PM +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by OS platform device module. +* +* \param[in] PDev Pointer to the platform device structure. +* \param[in] Message +* +* \return 0 +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbPltmSuspend(IN struct platform_device *PDev, pm_message_t Message) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is called by OS platform device module. +* +* \param[in] PDev Pointer to the platform device structure. +* +* \return 0 +*/ +/*----------------------------------------------------------------------------*/ +static int HifAhbPltmResume(IN struct platform_device *PDev) +{ + return 0; +} +#endif /* CONFIG_PM */ + +#endif /* CONF_HIF_DEV_MISC */ + +#if (CONF_HIF_LOOPBACK_AUTO == 1) +/*----------------------------------------------------------------------------*/ +/*! +* \brief Trigger to do HIF loopback test. +* +* \param[in] arg Pointer to the GLUE_INFO_T structure. +* +* \retval None +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifAhbLoopbkAuto(IN unsigned long arg) +{ + + P_GLUE_INFO_T GlueInfo = (P_GLUE_INFO_T) arg; + GL_HIF_INFO_T *HifInfo = &GlueInfo->rHifInfo; + + ASSERT(GlueInfo); + + HIF_DBG(("[WiFi/HIF] Trigger to do loopback test...\n")); + + set_bit(GLUE_FLAG_HIF_LOOPBK_AUTO_BIT, &HifInfo->HifLoopbkFlg); + wake_up_interruptible(&HifInfo->HifWaitq); + +} +#endif /* CONF_HIF_LOOPBACK_AUTO */ + +VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo) +{ + GL_HIF_INFO_T *prHifInfo = &prGlueInfo->rHifInfo; + unsigned short j; + + for (j = 0; j < 512; j++) { + DBGLOG(INIT, WARN, "0x%08x ", MCU_REG_READL(prHifInfo, CONN_MCU_CPUPCR)); + if ((j + 1) % 16 == 0) + DBGLOG(INIT, WARN, "\n"); + } +} + +/* End of ahb.c */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c new file mode 100644 index 0000000000000..6b719028ae934 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/arm.c @@ -0,0 +1,31 @@ +/****************************************************************************** +*[File] mt6516-evb.c +*[Version] v1.0 +*[Revision Date] 2010-03-01 +*[Author] +*[Description] +* dummy file for build system +*[Copyright] +* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + +/* +** Log: mt6516-evb.c + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * remove debug message + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** +*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h new file mode 100644 index 0000000000000..1507d5560040e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif.h @@ -0,0 +1,340 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 +*/ + +/*! \file "hif.h" + \brief Functions for the driver to register bus and setup the IRQ + + Functions for the driver to register bus and setup the IRQ +*/ + +/* +** Log: hif.h + * + * 11 01 2010 yarco.yang + * [WCXRP00000149] [MT6620 WI-Fi][Driver]Fine tune performance on MT6516 platform + * Add GPIO debug function + * + * 10 19 2010 jeffrey.chang + * [WCXRP00000120] [MT6620 Wi-Fi][Driver] Refine linux kernel module to the license of MTK propietary and enable MTK + * HIF by default + * Refine linux kernel module to the license of MTK and enable MTK HIF + * + * 08 18 2010 jeffrey.chang + * NULL + * support multi-function sdio + * + * 08 17 2010 cp.wu + * NULL + * add ENE SDIO host workaround for x86 linux platform. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\4 2009-10-20 17:38:28 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, +** and then stop hw. +** \main\maintrunk.MT5921\3 2009-09-28 20:19:20 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\2 2009-08-18 22:57:05 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\2 2008-09-22 23:18:17 GMT mtk01461 +** Update driver for code review +** Revision 1.1 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +*/ + +#ifndef _HIF_H +#define _HIF_H + +#include "gl_typedef.h" +#include "mtk_porting.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CONF_MTK_AHB_DMA 1 /* PIO mode is default mode if DMA is disabled */ + +#define CONF_HIF_DEV_MISC 0 /* register as misc device */ +#define CONF_HIF_LOOPBACK_AUTO 0 /* hif loopback test triggered by open() */ + /* only for development test */ + +#define CONF_HIF_PMIC_TEST 0 /* test purpose: power on CONNSYS */ + +#define CONF_HIF_DMA_INT 0 /* DMA interrupt mode */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern phys_addr_t gConEmiPhyBase; +extern BOOLEAN fgIsResetting; +extern UINT_32 IsrCnt, IsrPassCnt; +extern int kalDevLoopbkThread(IN void *data); + +#ifdef CONFIG_MTK_PMIC_MT6397 +#else +#ifdef CONFIG_OF /*for MT6752 */ +extern INT_32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT_32 enable); +#else /*for MT6572/82/92 */ +extern void upmu_set_vcn33_on_ctrl_wifi(UINT_32 val); +#endif +#endif + +#if (CONF_HIF_DEV_MISC == 1) +#else +/* extern INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_en); */ +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#ifndef CONN_MCU_CONFIG_BASE +#define CONN_MCU_CONFIG_BASE 0xF8070000 /* MT6572 */ +#endif /* CONN_MCU_CONFIG_BASE */ + +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +#define CONSYS_REG_READ(addr) (*((volatile unsigned int *)(addr))) + +#define CONN_MCU_DRV_BASE 0x18070000 +#define CONN_MCU_REG_LENGTH 0x0200 +#define CONN_MCU_CPUPCR 0x0160 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* host interface's private data structure, which is attached to os glue +** layer info structure. + */ +typedef struct _GL_HIF_DMA_OPS_T { /* DMA Operators */ + VOID (*DmaConfig)(IN VOID *HifInfo, IN VOID *Conf); + + VOID (*DmaStart)(IN VOID *HifInfo); + + VOID (*DmaStop)(IN VOID *HifInfo); + + MTK_WCN_BOOL (*DmaPollStart)(IN VOID *HifInfo); + + MTK_WCN_BOOL (*DmaPollIntr)(IN VOID *HifInfo); + + VOID (*DmaAckIntr)(IN VOID *HifInfo); + + VOID (*DmaClockCtrl)(IN UINT_32 FlgIsEnabled); + + VOID (*DmaRegDump)(IN VOID *HifInfo); + + VOID (*DmaReset)(IN VOID *HifInfo); + +} GL_HIF_DMA_OPS_T; + +typedef struct _GL_HIF_INFO_T { + + /* General */ + VOID *Dev; /* struct device */ + +#define MTK_CHIP_ID_6571 0x6571 +#define MTK_CHIP_ID_6572 0x6572 +#define MTK_CHIP_ID_6582 0x6582 +#define MTK_CHIP_ID_8127 0x8127 +#define MTK_CHIP_ID_6752 0x6752 +#define MTK_CHIP_ID_8163 0x8163 +#define MTK_CHIP_ID_6735 0x6735 +#define MTK_CHIP_ID_6580 0x6580 +#define MTK_CHIP_ID_6755 0x6755 +#define MTK_CHIP_ID_7623 0x7623 + + UINT_32 ChipID; + + /* Control flag */ + BOOLEAN fgIntReadClear; + BOOLEAN fgMbxReadClear; + BOOLEAN fgDmaEnable; /* TRUE: DMA mode is used (default) */ + + /* HIF related */ + UINT_8 *HifRegBaseAddr; /* HIF register base */ + UINT_8 *McuRegBaseAddr; /* CONN MCU register base */ + +#if (CONF_HIF_LOOPBACK_AUTO == 1) + struct timer_list HifTmrLoopbkFn; /* HIF loopback test trigger timer */ + wait_queue_head_t HifWaitq; + UINT_32 HifLoopbkFlg; + struct task_struct *HifTaskLoopbkFn; /* HIF loopback test task */ +#endif /* CONF_HIF_LOOPBACK_AUTO */ + +#if (CONF_HIF_DMA_INT == 1) + wait_queue_head_t HifDmaWaitq; + UINT_32 HifDmaWaitFlg; +#endif /* CONF_HIF_DMA_INT */ + + /* DMA related */ +#define AP_DMA_HIF_LOCK(_lock) /* spin_lock_bh(&(_lock)->DdmaLock) */ +#define AP_DMA_HIF_UNLOCK(_lock) /* spin_unlock_bh(&(_lock)->DdmaLock) */ + spinlock_t DdmaLock; /* protect DMA access */ + + UINT_8 *DmaRegBaseAddr; /* DMA register base */ + GL_HIF_DMA_OPS_T *DmaOps; /* DMA Operators */ + +#if !defined(CONFIG_MTK_CLKMGR) + struct clk *clk_wifi_dma; +#endif +} GL_HIF_INFO_T, *P_GL_HIF_INFO_T; + +#define HIF_MOD_NAME "AHB_SLAVE_HIF" + +#define HIF_DRV_BASE 0x180F0000 +#define HIF_DRV_LENGTH 0x005c + +typedef enum _MTK_WCN_HIF_BURST_LEN { + HIF_BURST_1DW = 0, + HIF_BURST_4DW, + HIF_BURST_8DW +} MTK_WCN_HIF_BURST_LEN; + +typedef enum _MTK_WCN_HIF_TXRX_TARGET { + HIF_TARGET_TXD0 = 0, + HIF_TARGET_TXD1, + HIF_TARGET_RXD0, + HIF_TARGET_RXD1, + HIF_TARGET_WHISR +} MTK_WCN_HIF_TXRX_TARGET; + +typedef enum _MTK_WCN_HIF_DMA_DIR { + HIF_DMA_DIR_TX = 0, + HIF_DMA_DIR_RX +} MTK_WCN_HIF_DMA_DIR; + +typedef struct _MTK_WCN_HIF_DMA_CONF { + UINT_32 Count; + MTK_WCN_HIF_DMA_DIR Dir; + UINT_32 Burst; + UINT_32 Wsize; + UINT_32 Ratio; + UINT_32 Connect; + UINT_32 Fix_en; + ULONG Src; + ULONG Dst; +} MTK_WCN_HIF_DMA_CONF; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define MCU_REG_READL(_hif, _addr) \ + readl((volatile UINT_32 *)((_hif)->McuRegBaseAddr + _addr)) + +/* PIO mode HIF register read/write */ +#define HIF_REG_READL(_hif, _addr) \ + readl((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr)) + +#define HIF_REG_WRITEL(_hif, _addr, _val) \ + writel(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) + +#define HIF_REG_WRITEB(_hif, _addr, _val) \ + writeb(_val, ((volatile UINT_32 *)((_hif)->HifRegBaseAddr + _addr))) + +/* PIO mode DMA register read/write */ +#define HIF_DMAR_READL(_hif, _addr) \ + readl((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr)) + +#define HIF_DMAR_WRITEL(_hif, _addr, _val) \ + writel(_val, ((volatile UINT_32 *)((_hif)->DmaRegBaseAddr + _addr))) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#ifndef MODULE_AHB_DMA +VOID HifDumpEnhanceModeData(P_ADAPTER_T prAdapter); + +VOID HifRegDump(P_ADAPTER_T prAdapter); + +BOOLEAN HifIsFwOwn(P_ADAPTER_T prAdapter); + +WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove); + +VOID glUnregisterBus(remove_card pfRemove); + +VOID glResetHif(GLUE_INFO_T *GlueInfo); + +VOID glSetHifInfo(P_GLUE_INFO_T prGlueInfo, ULONG ulCookie); + +VOID glClearHifInfo(P_GLUE_INFO_T prGlueInfo); + +VOID glGetChipInfo(GLUE_INFO_T *GlueInfo, UINT_8 *pucChipBuf); + +#if CFG_SPM_WORKAROUND_FOR_HOTSPOT +BOOLEAN glIsChipNeedWakelock(GLUE_INFO_T *GlueInfo); +#endif + +BOOLEAN glBusInit(PVOID pvData); + +VOID glBusRelease(PVOID pData); + +INT_32 glBusSetIrq(PVOID pvData, PVOID pfnIsr, PVOID pvCookie); + +VOID glBusFreeIrq(PVOID pvData, PVOID pvCookie); + +VOID glSetPowerState(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 ePowerMode); + +VOID glDumpConnSysCpuInfo(P_GLUE_INFO_T prGlueInfo); + +#endif /* MODULE_AHB_DMA */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Config GDMA TX/RX. +* +* \param[in] DmaRegBaseAddr Pointer to the IO register base. +* \param[in] Conf Pointer to the DMA operator. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID HifGdmaInit(GL_HIF_INFO_T *HifInfo); + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Config PDMA TX/RX. +* +* \param[in] DmaRegBaseAddr Pointer to the IO register base. +* \param[in] Conf Pointer to the DMA operator. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h new file mode 100644 index 0000000000000..094c07f98eff2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_gdma.h @@ -0,0 +1,154 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 +*/ + +/*! \file "hif_gdma.h" + \brief MARCO, definition, structure for GDMA. + + MARCO, definition, structure for GDMA. +*/ + +/* +** Log: hif_gdma.h + * + * 01 16 2013 vend_samp.lin + * Add AHB GDMA support + * 1) Initial version +** +*/ + +#ifndef _HIF_GDMA_H +#define _HIF_GDMA_H + +#include "mtk_porting.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _MTK_WCN_HIF_GDMA_BURST_LEN { + HIF_GDMA_BURST_1_8 = 0, + HIF_GDMA_BURST_2_8, + HIF_GDMA_BURST_3_8, + HIF_GDMA_BURST_4_8, + HIF_GDMA_BURST_5_8, + HIF_GDMA_BURST_6_8, + HIF_GDMA_BURST_7_8, + HIF_GDMA_BURST_8_8 /* same as HIF_GDMA_BURST_7_8 */ +} MTK_WCN_HIF_GDMA_BURST_LEN; + +typedef enum _MTK_WCN_HIF_GDMA_WRITE_LEN { + HIF_GDMA_WRITE_0 = 0, /* transaction size is 1 byte */ + HIF_GDMA_WRITE_1, /* transaction size is 2 byte */ + HIF_GDMA_WRITE_2, /* transaction size is 4 byte */ + HIF_GDMA_WRITE_3 /* transaction size is 1 byte */ +} MTK_WCN_HIF_GDMA_WRITE_LEN; + +typedef enum _MTK_WCN_HIF_GDMA_RATIO { + HIF_GDMA_RATIO_0 = 0, /* 1/2 */ + HIF_GDMA_RATIO_1 /* 1/1 */ +} MTK_WCN_HIF_GDMA_RATIO; + +typedef enum _MTK_WCN_HIF_GDMA_CONNECT { + HIF_GDMA_CONNECT_NO = 0, /* no connect */ + HIF_GDMA_CONNECT_SET1, /* connect set1 (req/ack) */ + HIF_GDMA_CONNECT_SET2, /* connect set2 (req/ack) */ + HIF_GDMA_CONNECT_SET3 /* connect set3 (req/ack) */ +} MTK_WCN_HIF_GDMA_CONNECT; + +/* reference to MT6572_AP_P_DMA_Spec.doc */ +#define AP_DMA_HIF_BASE 0x11000100 + +#define AP_P_DMA_G_DMA_2_INT_FLAG (0x0000) +#define AP_P_DMA_G_DMA_2_CON (0x0018) +#define AP_P_DMA_G_DMA_2_CONNECT (0x0034) +#define AP_P_DMA_G_DMA_2_LEN1 (0x0024) +#define AP_P_DMA_G_DMA_2_SRC_ADDR (0x001C) +#define AP_P_DMA_G_DMA_2_DST_ADDR (0x0020) +#define AP_P_DMA_G_DMA_2_INT_EN (0x0004) +#define AP_P_DMA_G_DMA_2_EN (0x0008) +#define AP_P_DMA_G_DMA_2_RST (0x000C) +#define AP_P_DMA_G_DMA_2_STOP (0x0010) + +#define AP_DMA_HIF_0_LENGTH 0x0038 + +/* AP_DMA_HIF_0_INT_FLAG */ +#define ADH_CR_FLAG_0 BIT(0) + +/* AP_DMA_HIF_0_INT_EN */ +#define ADH_CR_INTEN_FLAG_0 BIT(0) + +/* AP_DMA_HIF_0_EN */ +#define ADH_CR_EN BIT(0) +#define ADH_CR_CONN_BUR_EN BIT(1) + +/* AP_DMA_HIF_0_STOP */ +#define ADH_CR_PAUSE BIT(1) +#define ADH_CR_STOP BIT(0) + +/* AP_P_DMA_G_DMA_2_CON */ +#define ADH_CR_FLAG_FINISH BIT(30) +#define ADH_CR_RSIZE BITS(28, 29) +#define ADH_CR_RSIZE_OFFSET 28 +#define ADH_CR_WSIZE BITS(24, 25) +#define ADH_CR_WSIZE_OFFSET 24 +#define ADH_CR_BURST_LEN BITS(16, 18) +#define ADH_CR_BURST_LEN_OFFSET 16 +#define ADH_CR_WADDR_FIX_EN BIT(3) +#define ADH_CR_WADDR_FIX_EN_OFFSET 3 +#define ADH_CR_RADDR_FIX_EN BIT(4) +#define ADH_CR_RADDR_FIX_EN_OFFSET 4 + +/* AP_P_DMA_G_DMA_2_CONNECT */ +#define ADH_CR_RATIO BIT(3) +#define ADH_CR_RATIO_OFFSET 3 +#define ADH_CR_DIR BIT(2) +#define ADH_CR_DIR_OFFSET 2 +#define ADH_CR_CONNECT BITS(0, 1) + +/* AP_DMA_HIF_0_LEN */ +#define ADH_CR_LEN BITS(0, 19) + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_GDMA_H */ + +/* End of hif_gdma.h */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h new file mode 100644 index 0000000000000..32224e8f17d85 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/hif_pdma.h @@ -0,0 +1,141 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/hif/sdio/include/hif.h#1 +*/ + +/*! \file "hif_pdma.h" + \brief MARCO, definition, structure for PDMA. + + MARCO, definition, structure for PDMA. +*/ + +/* +** Log: hif_pdma.h + * + * 01 16 2013 vend_samp.lin + * Add AHB PDMA support + * 1) Initial version +** +*/ + +#ifndef _HIF_PDMA_H +#define _HIF_PDMA_H + +#include "mtk_porting.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _MTK_WCN_HIF_PDMA_BURST_LEN { + HIF_PDMA_BURST_1_4 = 0, + HIF_PDMA_BURST_2_4, + HIF_PDMA_BURST_3_4, + HIF_PDMA_BURST_4_4 +} MTK_WCN_HIF_PDMA_BURST_LEN; + +/* reference to MT6572_AP_P_DMA_Spec.doc */ +#ifdef CONFIG_OF +/*for MT6752*/ +#define AP_DMA_HIF_BASE 0x11000080 +#else +/*for MT6572/82/92*/ +#define AP_DMA_HIF_BASE 0x11000180 +#endif + +#define AP_DMA_HIF_0_INT_FLAG (0x0000) +#define AP_DMA_HIF_0_INT_EN (0x0004) +#define AP_DMA_HIF_0_EN (0x0008) +#define AP_DMA_HIF_0_RST (0x000C) +#define AP_DMA_HIF_0_STOP (0x0010) +#define AP_DMA_HIF_0_FLUSH (0x0014) +#define AP_DMA_HIF_0_CON (0x0018) +#define AP_DMA_HIF_0_SRC_ADDR (0x001C) +#define AP_DMA_HIF_0_DST_ADDR (0x0020) +#define AP_DMA_HIF_0_LEN (0x0024) +#define AP_DMA_HIF_0_INT_BUF_SIZE (0x0038) +#define AP_DMA_HIF_0_DEBUG_STATUS (0x0050) +#define AP_DMA_HIF_0_SRC_ADDR2 (0x0054) +#define AP_DMA_HIF_0_DST_ADDR2 (0x0058) + +#define AP_DMA_HIF_0_LENGTH 0x0080 + +/* AP_DMA_HIF_0_INT_FLAG */ +#define ADH_CR_FLAG_0 BIT(0) + +/* AP_DMA_HIF_0_INT_EN */ +#define ADH_CR_INTEN_FLAG_0 BIT(0) + +/* AP_DMA_HIF_0_EN */ +#define ADH_CR_EN BIT(0) + +/* AP_DMA_HIF_0_RST */ +#define ADH_CR_HARD_RST BIT(1) +#define ADH_CR_WARM_RST BIT(0) + +/* AP_DMA_HIF_0_STOP */ +#define ADH_CR_PAUSE BIT(1) +#define ADH_CR_STOP BIT(0) + +/* AP_DMA_HIF_0_FLUSH */ +#define ADH_CR_FLUSH BIT(0) + +/* AP_DMA_HIF_0_CON */ +#define ADH_CR_BURST_LEN BITS(16, 17) +#define ADH_CR_BURST_LEN_OFFSET 16 +#define ADH_CR_SLOW_CNT BITS(5, 14) +#define ADH_CR_SLOW_EN BIT(2) +#define ADH_CR_FIX_EN BIT(1) +#define ADH_CR_FIX_EN_OFFSET 1 +#define ADH_CR_DIR BIT(0) + +/* AP_DMA_HIF_0_LEN */ +#define ADH_CR_LEN BITS(0, 19) + +/* AP_DMA_HIF_0_SRC_ADDR2 */ +#define ADH_CR_SRC_ADDR2 BIT(0) +/* AP_DMA_HIF_0_DST_ADDR2 */ +#define ADH_CR_DST_ADDR2 BIT(0) + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_PDMA_H */ + +/* End of hif_gdma.h */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h new file mode 100644 index 0000000000000..91557137af9af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/include/mtk_porting.h @@ -0,0 +1,91 @@ +/* porting layer */ +/* Android */ + +#ifndef _MTK_PORTING_H_ +#define _MTK_PORTING_H_ + +#include /* include stddef.h for NULL */ + +#define CONF_MTK_AHB_DMA 1 + +/* Type definition for signed integers */ +/*typedef signed char INT8, *PINT8; +typedef signed short INT16, *PINT16; +typedef signed int INT_32, *PINT32;*/ + +/* Type definition for unsigned integers */ +/*typedef unsigned char UINT8, *PUINT8; +typedef unsigned short UINT16, *PUINT16; +typedef unsigned int UINT32, *PUINT32;*/ + +#ifndef VOID +/*typedef void VOID, *PVOID;*/ +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef INTOUT +#define INOUT +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef BIT +#define BIT(n) ((UINT_32) 1U << (n)) +#endif /* BIT */ + +#ifndef BITS +/* bits range: for example BITS(16,23) = 0xFF0000 + * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 + * ==> (BIT(n+1)-1) = 0x00FFFFFF + */ +#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) +#endif /* BIT */ + +#ifndef BOOLEAN +#define BOOLEAN unsigned char +#endif + +typedef int MTK_WCN_BOOL; +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) +#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) +#endif + +typedef int MTK_WCN_MUTEX; + +typedef int MTK_WCN_TIMER; + +/* system APIs */ +/* mutex */ +typedef MTK_WCN_MUTEX(*MUTEX_CREATE) (const char *const name); +typedef INT_32(*MUTEX_DESTROY) (MTK_WCN_MUTEX mtx); +typedef INT_32(*MUTEX_LOCK) (MTK_WCN_MUTEX mtx); +typedef INT_32(*MUTEX_UNLOCK) (MTK_WCN_MUTEX mtx, unsigned long flags); +/* debug */ +typedef INT_32(*DBG_PRINT) (const char *str, ...); +typedef INT_32(*DBG_ASSERT) (INT_32 expr, const char *file, INT_32 line); +/* timer */ +typedef void (*MTK_WCN_TIMER_CB) (void); +typedef MTK_WCN_TIMER(*TIMER_CREATE) (const char *const name); +typedef INT_32(*TIMER_DESTROY) (MTK_WCN_TIMER tmr); +typedef INT_32(*TIMER_START) (MTK_WCN_TIMER tmr, UINT_32 timeout, MTK_WCN_TIMER_CB tmr_cb, void *param); +typedef INT_32(*TIMER_STOP) (MTK_WCN_TIMER tmr); +/* kernel lib */ +typedef void *(*SYS_MEMCPY) (void *dest, const void *src, UINT_32 n); +typedef void *(*SYS_MEMSET) (void *s, INT_32 c, UINT_32 n); +typedef INT_32(*SYS_SPRINTF) (char *str, const char *format, ...); + +#endif /* _MTK_PORTING_H_ */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c new file mode 100644 index 0000000000000..94cc05ba32249 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/hif/ahb/mt8127/ahb_pdma.c @@ -0,0 +1,480 @@ +/****************************************************************************** +*[File] ahb_pdma.c +*[Version] v1.0 +*[Revision Date] 2013-03-13 +*[Author] +*[Description] +* The program provides AHB PDMA driver +*[Copyright] +* Copyright (C) 2013 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + +/* +** Log: ahb_pdma.c + * + * 03 13 2013 vend_samp.lin + * Add AHB PDMA support + * 1) Initial version +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#define MODULE_AHB_DMA + +#include /* constant of kernel version */ + +#include /* bitops.h */ + +#include /* struct timer_list */ +#include /* jiffies */ +#include /* udelay and mdelay macro */ + +#if 0 +#if CONFIG_ANDROID +#include +#endif +#endif + +#include /* IRQT_FALLING */ + +#include /* struct net_device, struct net_device_stats */ +#include /* for eth_type_trans() function */ +#include /* struct iw_statistics */ +#include +#include /* struct in_device */ + +#include /* struct iphdr */ + +#include /* for memcpy()/memset() function */ +#include /* for offsetof() macro */ + +#include /* The proc filesystem constants/structures */ + +#include /* for rtnl_lock() and rtnl_unlock() */ +#include /* kthread_should_stop(), kthread_run() */ +#include /* for copy_from_user() */ +#include /* for firmware download */ +#include + +#include /* for kfifo interface */ +#include /* for cdev interface */ + +#include /* for firmware download */ + +#include + +#include /* readw and writew */ + +#include + +#if defined(CONFIG_MTK_CLKMGR) +#include +#else +#include +#endif /* defined(CONFIG_MTK_CLKMGR) */ + +#include "hif.h" +#include "hif_pdma.h" +#include "gl_os.h" + +/* #include */ + +/* #if (CONF_MTK_AHB_DMA == 1) */ + +/* #define PDMA_DEBUG_SUP */ + +#ifdef PDMA_DEBUG_SUP +#define PDMA_DBG pr_debug +#else +#define PDMA_DBG(_fmt, ...) +#endif /* PDMA_DEBUG_SUP */ + +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *g_clk_wifi_pdma; +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Conf); + +static VOID HifPdmaStart(IN void *HifInfoSrc); + +static VOID HifPdmaStop(IN void *HifInfoSrc); + +static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc); + +static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc); + +static VOID HifPdmaAckIntr(IN void *HifInfoSrc); + +static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled); + +static VOID HifPdmaRegDump(IN void *HifInfoSrc); + +static VOID HifPdmaReset(IN void *HifInfoSrc); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +GL_HIF_DMA_OPS_T HifPdmaOps = { + .DmaConfig = HifPdmaConfig, + .DmaStart = HifPdmaStart, + .DmaStop = HifPdmaStop, + .DmaPollStart = HifPdmaPollStart, + .DmaPollIntr = HifPdmaPollIntr, + .DmaAckIntr = HifPdmaAckIntr, + .DmaClockCtrl = HifPdmaClockCtrl, + .DmaRegDump = HifPdmaRegDump, + .DmaReset = HifPdmaReset +}; + +/******************************************************************************* +* P U B L I C F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Config PDMA TX/RX. +* +* \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. +* \param[in] Conf Pointer to the settings. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +VOID HifPdmaInit(GL_HIF_INFO_T *HifInfo) +{ + /* IO remap PDMA register memory */ +#ifdef AP_DMA_HIF_BASE +#undef AP_DMA_HIF_BASE +#define AP_DMA_HIF_BASE 0x11000180 +#endif + HifInfo->DmaRegBaseAddr = ioremap(AP_DMA_HIF_BASE, AP_DMA_HIF_0_LENGTH); + + /* assign PDMA operators */ + HifInfo->DmaOps = &HifPdmaOps; + + /* enable PDMA mode */ + HifInfo->fgDmaEnable = TRUE; + + /* Set EMI protection here */ +#if 0 +#ifdef MTK_TEE_CCCI_SECURE_SHARE_MEM_SUPPORT + DBGLOG(INIT, INFO, "WIFI set EMI MPU for TEE project\n"); + emi_mpu_set_region_protection(gConEmiPhyBase, + gConEmiPhyBase + SZ_1M / 2, + 5, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); +#else + DBGLOG(INIT, INFO, "WIFI set EMI MPU for non-TEE project\n"); + emi_mpu_set_region_protection(gConEmiPhyBase, + gConEmiPhyBase + SZ_1M / 2, + 4, SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN)); +#endif +#endif + +#if !defined(CONFIG_MTK_CLKMGR) + g_clk_wifi_pdma = HifInfo->clk_wifi_dma; +#endif + + PDMA_DBG("PDMA> HifPdmaInit ok!\n"); +} + +/******************************************************************************* +* P R I V A T E F U N C T I O N S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Config PDMA TX/RX. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* \param[in] Param Pointer to the settings. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaConfig(IN void *HifInfoSrc, IN void *Param) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + MTK_WCN_HIF_DMA_CONF *Conf = (MTK_WCN_HIF_DMA_CONF *) Param; + UINT32 RegVal; + + /* Assign fixed value */ + Conf->Burst = HIF_PDMA_BURST_4_4; /* vs. HIF_BURST_4DW */ + Conf->Fix_en = FALSE; + + /* AP_P_DMA_G_DMA_2_CON */ + PDMA_DBG("PDMA> Conf->Dir = %d\n", Conf->Dir); + + /* AP_DMA_HIF_0_CON */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_CON); + RegVal &= ~(ADH_CR_BURST_LEN | ADH_CR_FIX_EN | ADH_CR_DIR); + RegVal |= (((Conf->Burst << ADH_CR_BURST_LEN_OFFSET) & ADH_CR_BURST_LEN) | + (Conf->Fix_en << ADH_CR_FIX_EN_OFFSET) | (Conf->Dir)); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_CON, RegVal); + PDMA_DBG("PDMA> AP_DMA_HIF_0_CON = 0x%08x\n", RegVal); + + /* AP_DMA_HIF_0_SRC_ADDR */ + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_SRC_ADDR, Conf->Src); + PDMA_DBG("PDMA> AP_DMA_HIF_0_SRC_ADDR = 0x%08lx\n", Conf->Src); + + /* AP_DMA_HIF_0_DST_ADDR */ + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_DST_ADDR, Conf->Dst); + PDMA_DBG("PDMA> AP_DMA_HIF_0_DST_ADDR = 0x%08lx\n", Conf->Dst); + + /* AP_DMA_HIF_0_LEN */ + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_LEN, (Conf->Count & ADH_CR_LEN)); + PDMA_DBG("PDMA> AP_DMA_HIF_0_LEN = %u\n", (UINT_32)(Conf->Count & ADH_CR_LEN)); + +} /* End of HifPdmaConfig */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Start PDMA TX/RX. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaStart(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegVal; + + /* Enable interrupt */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal | ADH_CR_INTEN_FLAG_0)); + + /* Start DMA */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_EN, (RegVal | ADH_CR_EN)); + + PDMA_DBG("PDMA> HifPdmaStart...\n"); + +} /* End of HifPdmaStart */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Stop PDMA TX/RX. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaStop(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegVal; +/* UINT32 pollcnt; */ + + /* Disable interrupt */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_EN); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_EN, (RegVal & ~(ADH_CR_INTEN_FLAG_0))); + +#if 0 /* DE says we donot need to do it */ + /* Stop DMA */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_STOP); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_STOP, (RegVal | ADH_CR_STOP)); + + /* Polling START bit turn to 0 */ + pollcnt = 0; + do { + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); + if (pollcnt++ > 100000) + ; /* TODO: warm reset PDMA */ + } while (RegVal & ADH_CR_EN); +#endif + +} /* End of HifPdmaStop */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Enable PDMA TX/RX. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static MTK_WCN_BOOL HifPdmaPollStart(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegVal; + + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_EN); + return ((RegVal & ADH_CR_EN) != 0) ? TRUE : FALSE; + +} /* End of HifPdmaPollStart */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Poll PDMA TX/RX done. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static MTK_WCN_BOOL HifPdmaPollIntr(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegVal; + + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); + return ((RegVal & ADH_CR_FLAG_0) != 0) ? TRUE : FALSE; + +} /* End of HifPdmaPollIntr */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Acknowledge PDMA TX/RX done. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaAckIntr(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegVal; + + /* Write 0 to clear interrupt */ + RegVal = HIF_DMAR_READL(HifInfo, AP_DMA_HIF_0_INT_FLAG); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_INT_FLAG, (RegVal & ~ADH_CR_FLAG_0)); + +} /* End of HifPdmaAckIntr */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Acknowledge PDMA TX/RX done. +* +* \param[in] FlgIsEnabled TRUE: enable; FALSE: disable +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaClockCtrl(IN UINT32 FlgIsEnabled) +{ +#if !defined(CONFIG_MTK_CLKMGR) + int ret = 0; +#endif +#if defined(CONFIG_MTK_CLKMGR) + if (FlgIsEnabled == TRUE) + enable_clock(MT_CG_INFRA_APDMA, "WLAN"); + else + disable_clock(MT_CG_INFRA_APDMA, "WLAN"); +#else + if (FlgIsEnabled == TRUE) { + ret = clk_prepare_enable(g_clk_wifi_pdma); + if (ret) + DBGLOG(INIT, TRACE, "[CCF]clk_prepare_enable ret= %d\n", ret); + } else { + clk_disable_unprepare(g_clk_wifi_pdma); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Dump PDMA related registers. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaRegDump(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 RegId, RegVal; + UINT32 RegNum = 0; + + DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE); + for (RegId = 0; RegId < AP_DMA_HIF_0_LENGTH; RegId += 4) { + RegVal = HIF_DMAR_READL(HifInfo, RegId); + DBGLOG(INIT, INFO, "0x%08x ", RegVal); + + if (RegNum++ >= 3) { + DBGLOG(INIT, INFO, "\n"); + DBGLOG(INIT, INFO, "PDMA> Register content 0x%x=\n\t", AP_DMA_HIF_BASE + RegId + 4); + RegNum = 0; + } + } + +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Reset DMA. +* +* \param[in] HifInfo Pointer to the GL_HIF_INFO_T structure. +* +* \retval NONE +*/ +/*----------------------------------------------------------------------------*/ +static VOID HifPdmaReset(IN void *HifInfoSrc) +{ + GL_HIF_INFO_T *HifInfo = (GL_HIF_INFO_T *) HifInfoSrc; + UINT32 LoopCnt; + + /* do warm reset: DMA will wait for current traction finished */ + DBGLOG(INIT, INFO, "\nDMA> do warm reset...\n"); + + /* normally, we need to sure that bit0 of AP_P_DMA_G_DMA_2_EN is 1 here */ + + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x01); + + for (LoopCnt = 0; LoopCnt < 10000; LoopCnt++) { + if (!HifPdmaPollStart(HifInfo)) + break; /* reset ok */ + } + + if (HifPdmaPollStart(HifInfo)) { + /* do hard reset because warm reset fails */ + DBGLOG(INIT, INFO, "\nDMA> do hard reset...\n"); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x02); + mdelay(1); + HIF_DMAR_WRITEL(HifInfo, AP_DMA_HIF_0_RST, 0x00); + } +} + +/* #endif */ /* CONF_MTK_AHB_DMA */ + +/* End of ahb_pdma.c */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h new file mode 100644 index 0000000000000..ec9f46bdab2e4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_cfg80211.h @@ -0,0 +1,341 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_cfg80211.h#1 +*/ + +/*! \file gl_cfg80211.h + \brief This file is for Portable Driver linux cfg80211 support. +*/ + +/* +** Log: gl_cfg80211.h +** +** 09 03 2013 cp.wu +** add path for reassociation +** +** 09 12 2012 wcpadmin +** [ALPS00276400] Remove MTK copyright and legal header on GPL/LGPL related packages +** . +** +** 08 30 2012 chinglan.wang +** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only +** . + * +*/ + +#ifndef _GL_CFG80211_H +#define _GL_CFG80211_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include + +#include "gl_os.h" +extern void wlanHandleSystemResume(void); +extern void wlanHandleSystemSuspend(void); +extern void p2pHandleSystemResume(void); +extern void p2pHandleSystemSuspend(void); + +#if CFG_SUPPORT_WAPI +extern UINT_8 keyStructBuf[1024]; /* add/remove key shared buffer */ +#else +extern UINT_8 keyStructBuf[100]; /* add/remove key shared buffer */ +#endif + +extern struct delayed_work sched_workq; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#if CONFIG_NL80211_TESTMODE +#define NL80211_DRIVER_TESTMODE_VERSION 2 +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CONFIG_NL80211_TESTMODE + +typedef struct _NL80211_DRIVER_GET_STA_STATISTICS_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_32 u4Version; + UINT_32 u4Flag; + UINT_8 aucMacAddr[MAC_ADDR_LEN]; +} NL80211_DRIVER_GET_STA_STATISTICS_PARAMS, *P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS; + +typedef struct _NL80211_DRIVER_POORLINK_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + INT_8 cRssi; /* cRssi=0 means it is a invalid value. */ + UINT_8 ucLinkSpeed; /* ucLinkSpeed=0 means it is a invalid value */ + UINT_16 u2Reserved; +} NL80211_DRIVER_POORLINK_PARAMS, *P_NL80211_DRIVER_POORLINK_PARAMS; + +typedef enum _ENUM_TESTMODE_STA_STATISTICS_ATTR { + NL80211_TESTMODE_STA_STATISTICS_INVALID = 0, + NL80211_TESTMODE_STA_STATISTICS_VERSION, + NL80211_TESTMODE_STA_STATISTICS_MAC, + NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, + NL80211_TESTMODE_STA_STATISTICS_FLAG, + + NL80211_TESTMODE_STA_STATISTICS_PER, + NL80211_TESTMODE_STA_STATISTICS_RSSI, + NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, + NL80211_TESTMODE_STA_STATISTICS_TX_RATE, + + NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, + NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, + + NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, + NL80211_TESTMODE_STA_STATISTICS_MAX_PROCESS_TIME, + NL80211_TESTMODE_STA_STATISTICS_AVG_HIF_PROCESS_TIME, + NL80211_TESTMODE_STA_STATISTICS_MAX_HIF_PROCESS_TIME, + + NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, + NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, + NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, + + NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, + + /* + * how many packages TX during statistics interval + */ + NL80211_TESTMODE_STA_STATISTICS_ENQUEUE, + + /* + * how many packages this TX during statistics interval + */ + NL80211_TESTMODE_STA_STATISTICS_STA_ENQUEUE, + + /* + * how many packages dequeue during statistics interval + */ + NL80211_TESTMODE_STA_STATISTICS_DEQUEUE, + + /* + * how many packages this sta dequeue during statistics interval + */ + NL80211_TESTMODE_STA_STATISTICS_STA_DEQUEUE, + + /* + * how many TC[0-3] resource back from firmware during + * statistics interval + */ + NL80211_TESTMODE_STA_STATISTICS_RB_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_NO_TC_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_USED_BFCT_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_WANTED_BFCT_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_ISR_PASS_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_TASK_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_AB_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_SW_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_TX_CNT, + NL80211_TESTMODE_STA_STATISTICS_IRQ_RX_CNT, + + NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_NUM +} ENUM_TESTMODE_STA_STATISTICS_ATTR; +typedef struct _NL80211_DRIVER_SET_NFC_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_32 NFC_Enable; + +} NL80211_DRIVER_SET_NFC_PARAMS, *P_NL80211_DRIVER_SET_NFC_PARAMS; +typedef struct _NL80211_DRIVER_GET_SCANDONE_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_32 u4ScanDone; + +} NL80211_DRIVER_GET_SCANDONE_PARAMS, *P_NL80211_DRIVER_GET_SCANDONE_PARAMS; + +typedef enum _ENUM_TESTMODE_LINK_DETECTION_ATTR { + NL80211_TESTMODE_LINK_INVALID = 0, + NL80211_TESTMODE_LINK_TX_FAIL_CNT, + NL80211_TESTMODE_LINK_TX_RETRY_CNT, + NL80211_TESTMODE_LINK_TX_MULTI_RETRY_CNT, + NL80211_TESTMODE_LINK_ACK_FAIL_CNT, + NL80211_TESTMODE_LINK_FCS_ERR_CNT, + + NL80211_TESTMODE_LINK_DETECT_NUM, +} ENUM_TESTMODE_LINK_DETECTION_ATTR; + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + +typedef struct _NL80211_DRIVER_GET_LTE_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_32 u4Version; + UINT_32 u4Flag; + +} NL80211_DRIVER_GET_LTE_PARAMS, *P_NL80211_DRIVER_GET_LTE_PARAMS; + +/*typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR{ + NL80211_TESTMODE_AVAILABLE_CHAN_INVALID = 0, + NL80211_TESTMODE_AVAILABLE_CHAN_2G_BASE_1, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_34, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_149, + NL80211_TESTMODE_AVAILABLE_CHAN_5G_BASE_184, + + NL80211_TESTMODE_AVAILABLE_CHAN_NUM, +}ENUM_TESTMODE_AVAILABLE_CHAN_ATTR;*/ + +#endif +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* cfg80211 hooks */ +int +mtk_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); + +int +mtk_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); + +int +mtk_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) +); + +int +mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); + +int +mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool unicast, bool multicast); + +int mtk_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); + +int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo); + +int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params); + +int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params); + +int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, struct station_del_parameters *params); +//int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac); + +int mtk_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); + +int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme); + +int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code); + +int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ibss_params *params); + +int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev); + +int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, bool enabled, int timeout); + +int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); + +int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_pmksa *pmksa); + +int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev); + +int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie); + +int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); + +int +mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); + +void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + IN struct wireless_dev *wdev, + IN u16 frame_type, IN bool reg); + +int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); + +int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_assoc_request *req); + +int +mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, IN struct cfg80211_sched_scan_request *request); + +int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, IN struct net_device *ndev,u64 reqid); + +#if CONFIG_NL80211_TESTMODE +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +WLAN_STATUS +wlanoidQueryACSChannelList(IN P_ADAPTER_T prAdapter, + IN PVOID pvQueryBuffer, IN UINT_32 u4QueryBufferLen, OUT PUINT_32 pu4QueryInfoLen); + +int +mtk_cfg80211_testmode_get_lte_channel(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); +#endif +int +mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, + IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); + +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, IN int len, IN P_GLUE_INFO_T prGlueInfo); + +int mtk_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); + +int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +#if CFG_SUPPORT_WAPI +int mtk_cfg80211_testmode_set_key_ext(IN struct wiphy *wiphy, IN void *data, IN int len); +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 +int mtk_cfg80211_testmode_hs20_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +#endif + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 +int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +#endif + +#else +#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" +#endif +int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +int mtk_cfg80211_resume(struct wiphy *wiphy); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_CFG80211_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h new file mode 100644 index 0000000000000..512e149abf75c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_kal.h @@ -0,0 +1,1565 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_kal.h#1 +*/ + +/*! \file gl_kal.h + \brief Declaration of KAL functions - kal*() which is provided by GLUE Layer. + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/* +** Log: gl_kal.h + * + * 06 13 2012 yuche.tsai + * NULL + * Update maintrunk driver. + * Add support for driver compose assoc request frame. + * + * 04 12 2012 terry.wu + * NULL + * Add AEE message support + * 1) Show AEE warning(red screen) if SDIO access error occurs + + * + * 03 02 2012 terry.wu + * NULL + * Snc CFG80211 modification for ICS migration from branch 2.2. + * + * 02 06 2012 wh.su + * [WCXRP00001177] [MT6620 Wi-Fi][Driver][2.2] Adding the query channel filter for AP mode + * adding the channel query filter for AP mode. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 11 24 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adjust the code for Non-DBG and no XLOG. + * + * 11 22 2011 cp.wu + * [WCXRP00001120] [MT6620 Wi-Fi][Driver] Modify roaming to AIS state transition from synchronous to asynchronous + * approach to avoid incomplete state termination + * 1. change RDD related compile option brace position. + * 2. when roaming is triggered, ask AIS to transit immediately only when AIS is in Normal TR state without join + * timeout timer ticking + * 3. otherwise, insert AIS_REQUEST into pending request queue + * + * 11 11 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * modify the xlog related code. + * + * 11 10 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Modify the QM xlog level and remove LOG_FUNC. + * + * 11 10 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Using the new XLOG define for dum Memory. + * + * 11 08 2011 eddie.chen + * [WCXRP00001096] [MT6620 Wi-Fi][Driver/FW] Enhance the log function (xlog) + * Add xlog function. + * + * 11 08 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters, eCurPsProf, for PS. + * + * 11 08 2011 cm.chang + * NULL + * Add RLM and CNM debug message for XLOG + * + * 11 07 2011 tsaiyuan.hsu + * [WCXRP00001083] [MT6620 Wi-Fi][DRV]] dump debug counter or frames when debugging is triggered + * add debug counters and periodically dump counters for debugging. + * + * 11 03 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * Add dumpMemory8 at XLOG support. + * + * 11 02 2011 wh.su + * [WCXRP00001078] [MT6620 Wi-Fi][Driver] Adding the mediatek log improment support : XLOG + * adding the code for XLOG. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated + * network type + * include link.h for linux's port. + * + * 04 12 2011 cp.wu + * [WCXRP00000635] [MT6620 Wi-Fi][Driver] Clear pending security frames when QM clear pending data frames for dedicated + * network type + * clear pending security frames for dedicated network type when BSS is being deactivated/disconnected + * + * 04 01 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * 1. simplify config.h due to aggregation options could be also applied for eHPI/SPI interface + * 2. use spin-lock instead of semaphore for protecting eHPI access because of possible access from ISR + * 3. request_irq() API has some changes between linux kernel 2.6.12 and 2.6.26 + * + * 03 16 2011 cp.wu + * [WCXRP00000562] [MT6620 Wi-Fi][Driver] I/O buffer pre-allocation to avoid physically continuous memory shortage + * after system running for a long period + * 1. pre-allocate physical continuous buffer while module is being loaded + * 2. use pre-allocated physical continuous buffer for TX/RX DMA transfer + * + * The windows part remained the same as before, but added similar APIs to hide the difference. + * + * 03 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Add BOW table. + * + * 03 07 2011 terry.wu + * [WCXRP00000521] [MT6620 Wi-Fi][Driver] Remove non-standard debug message + * Toggle non-standard debug messages to comments. + * + * 03 06 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Sync BOW Driver to latest person development branch version.. + * + * 03 02 2011 cp.wu + * [WCXRP00000503] [MT6620 Wi-Fi][Driver] Take RCPI brought by association response as initial RSSI right after + * connection is built. + * use RCPI brought by ASSOC-RESP after connection is built as initial RCPI to avoid using a uninitialized MAC-RX RCPI. + * + * 02 24 2011 cp.wu + * [WCXRP00000490] [MT6620 Wi-Fi][Driver][Win32] modify kalMsleep() implementation because NdisMSleep() won't sleep + * long enough for specified interval such as 500ms + * modify cnm_timer and hem_mbox APIs to be thread safe to ease invoking restrictions + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 04 2011 cp.wu + * [WCXRP00000338] [MT6620 Wi-Fi][Driver] Separate kalMemAlloc into kmalloc and vmalloc implementations to ease + * physically continuous memory demands + * separate kalMemAlloc() into virtually-continuous and physically-continuous type to ease slab system pressure + * + * 12 31 2010 cp.wu + * [WCXRP00000335] [MT6620 Wi-Fi][Driver] change to use milliseconds sleep instead of delay to avoid blocking to system + * scheduling + * change to use msleep() and shorten waiting interval to reduce blocking to other task while Wi-Fi driver is being + * loaded + * + * 12 31 2010 jeffrey.chang + * [WCXRP00000332] [MT6620 Wi-Fi][Driver] add kal sleep function for delay which use blocking call + * modify the implementation of kalDelay to msleep + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 11 30 2010 yuche.tsai + * NULL + * Invitation & Provision Discovery Indication. + * + * 11 26 2010 cp.wu + * [WCXRP00000209] [MT6620 Wi-Fi][Driver] Modify NVRAM checking mechanism to warning only with necessary data field + * checking + * 1. NVRAM error is now treated as warning only, thus normal operation is still available but extra scan result used + * to indicate user is attached + * 2. DPD and TX-PWR are needed fields from now on, if these 2 fields are not available then warning message is shown + * + * 11 08 2010 cp.wu + * [WCXRP00000166] [MT6620 Wi-Fi][Driver] use SDIO CMD52 for enabling/disabling interrupt to reduce transaction period + * change to use CMD52 for enabling/disabling interrupt to reduce SDIO transaction time + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * add a kal function for set cipher. + * + * 10 04 2010 wh.su + * [WCXRP00000081] [MT6620][Driver] Fix the compiling error at WinXP while enable P2P + * fixed compiling error while enable p2p. + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 21 2010 cp.wu + * [WCXRP00000053] [MT6620 Wi-Fi][Driver] Reset incomplete and might leads to BSOD when entering RF test with AIS + * associated + * Do a complete reset with STA-REC null checking for RF test re-entry + * + * 09 21 2010 kevin.huang + * [WCXRP00000052] [MT6620 Wi-Fi][Driver] Eliminate Linux Compile Warning + * Eliminate Linux Compile Warning + * + * 09 10 2010 wh.su + * NULL + * fixed the compiling error at win XP. + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct Driver Hook] change event indication API to be consistent with supplicant + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 08 02 2010 jeffrey.chang + * NULL + * modify kalSetEvent declaration + * + * 07 29 2010 cp.wu + * NULL + * simplify post-handling after TX_DONE interrupt is handled. + * + * 07 23 2010 cp.wu + * + * 1) re-enable AIS-FSM beacon timeout handling. + * 2) scan done API revised + * + * 07 23 2010 jeffrey.chang + * + * fix kal header file + * + * 07 22 2010 jeffrey.chang + * + * use different spin lock for security frame + * + * 07 22 2010 jeffrey.chang + * + * add new spinlock + * + * 07 19 2010 jeffrey.chang + * + * add kal api for scanning done + * + * 07 19 2010 jeffrey.chang + * + * modify cmd/data path for new design + * + * 07 19 2010 jeffrey.chang + * + * add new kal api + * + * 07 19 2010 jeffrey.chang + * + * Linux port modification + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 21 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * change MAC address updating logic. + * + * 06 18 2010 cm.chang + * [WPD00003841][LITE Driver] Migrate RLM/CNM to host driver + * Provide cnmMgtPktAlloc() and alloc/free function of msg/buf + * + * 06 11 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * 1) migrate assoc.c. + * 2) add ucTxSeqNum for tracking frames which needs TX-DONE awareness + * 3) add configuration options for CNM_MEM and RSN modules + * 4) add data path for management frames + * 5) eliminate rPacketInfo of MSDU_INFO_T + * + * 06 07 2010 cp.wu + * [WPD00003833][MT6620 and MT5931] Driver migration + * gl_kal merged + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic handling framework for wireless extension ioctls. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * fill network type field while doing frame identification. + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * modify kalMemAlloc method + * + * 04 28 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change prefix for data structure used to communicate with 802.11 PAL + * to avoid ambiguous naming with firmware interface + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 22 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * when acquiring driver-own, wait for up to 8 seconds. + * + * 04 22 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * + * 1) modify rx path code for supporting Wi-Fi direct + * 2) modify config.h since Linux dont need to consider retaining packet + * + * 04 21 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add for private ioctl support + * + * 04 20 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * don't need SPIN_LOCK_PWR_CTRL anymore, it will raise IRQL + * * and cause SdBusSubmitRequest running at DISPATCH_LEVEL as well. + * + * 04 14 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * information buffer for query oid/ioctl is now buffered in prCmdInfo + * * * * * * * * instead of glue-layer variable to improve multiple oid/ioctl capability + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple handler + * * * * * * * * * * * * * * * * * * * capability + * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other purpose + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) add spinlock + * * * 2) add KAPI for handling association info + * + * 04 09 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * adding firmware download KAPI + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * finish non-glue layer access to glue variables + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * accessing to firmware load/start address, and access to OID handling information + * * * * are now handled in glue layer + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * * are done in adapter layer. + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->eParamMediaStateIndicated from non-glue layer + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * add KAL API: kalFlushPendingTxPackets(), and take use of the API + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access to prGlueInfo->rWlanInfo.eLinkAttr.ucMediaStreamMode from non-glue layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) for some OID, never do timeout expiration + * * * * 2) add 2 kal API for later integration + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download KAPI + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\41 2009-09-28 20:19:23 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\40 2009-08-18 22:57:09 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\39 2009-06-23 23:19:15 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\38 2009-02-09 14:03:17 GMT mtk01090 +** Add KAL function kalDevSetPowerState(). It is not implemented yet. Only add an empty macro. +** +** \main\maintrunk.MT5921\37 2009-01-22 13:05:59 GMT mtk01088 +** new defeine to got 1x value at packet reserved field +** \main\maintrunk.MT5921\36 2008-12-08 16:15:02 GMT mtk01461 +** Add kalQueryValidBufferLength() macro +** \main\maintrunk.MT5921\35 2008-11-13 20:33:15 GMT mtk01104 +** Remove lint warning +** \main\maintrunk.MT5921\34 2008-10-22 11:05:52 GMT mtk01461 +** Remove unused macro +** \main\maintrunk.MT5921\33 2008-10-16 15:48:17 GMT mtk01461 +** Update driver to fix lint warning +** \main\maintrunk.MT5921\32 2008-09-02 11:50:51 GMT mtk01461 +** SPIN_LOCK_SDIO_DDK_TX_QUE +** \main\maintrunk.MT5921\31 2008-08-29 15:58:30 GMT mtk01088 +** remove non-used function for code refine +** \main\maintrunk.MT5921\30 2008-08-21 00:33:29 GMT mtk01461 +** Update for Driver Review +** \main\maintrunk.MT5921\29 2008-06-19 13:29:14 GMT mtk01425 +** 1. Add declaration of SPIN_LOCK_SDIO_DDK_TX_QUE and SPIN_LOCK_SDIO_DDK_RX_QUE +** \main\maintrunk.MT5921\28 2008-05-30 20:27:34 GMT mtk01461 +** Rename KAL function +** \main\maintrunk.MT5921\27 2008-05-30 14:42:05 GMT mtk01461 +** Remove WMM Assoc Flag in KAL +** \main\maintrunk.MT5921\26 2008-05-29 14:15:18 GMT mtk01084 +** remove un-used function +** \main\maintrunk.MT5921\25 2008-04-23 14:02:20 GMT mtk01084 +** modify KAL port access function prototype +** \main\maintrunk.MT5921\24 2008-04-17 23:06:41 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\23 2008-04-08 15:38:50 GMT mtk01084 +** add KAL function to setting pattern search function enable/ disable +** \main\maintrunk.MT5921\22 2008-03-26 15:34:48 GMT mtk01461 +** Add update MAC address func +** \main\maintrunk.MT5921\21 2008-03-18 15:56:15 GMT mtk01084 +** update ENUM_NIC_INITIAL_PARAM_E +** \main\maintrunk.MT5921\20 2008-03-18 11:49:28 GMT mtk01084 +** update function for initial value access +** \main\maintrunk.MT5921\19 2008-03-18 10:21:31 GMT mtk01088 +** use kal update associate request at linux +** \main\maintrunk.MT5921\18 2008-03-14 18:03:41 GMT mtk01084 +** refine register and port access function +** \main\maintrunk.MT5921\17 2008-03-11 14:51:02 GMT mtk01461 +** Add copy_to(from)_user macro +** \main\maintrunk.MT5921\16 2008-03-06 23:42:21 GMT mtk01385 +** 1. add Query Registry Mac address function. +** \main\maintrunk.MT5921\15 2008-02-26 09:48:04 GMT mtk01084 +** modify KAL set network address/ checksum offload part +** \main\maintrunk.MT5921\14 2008-01-09 17:54:58 GMT mtk01084 +** Modify the argument of kalQueryPacketInfo +** \main\maintrunk.MT5921\13 2007-11-29 02:05:20 GMT mtk01461 +** Fix Windows RX multiple packet retain problem +** \main\maintrunk.MT5921\12 2007-11-26 19:43:45 GMT mtk01461 +** Add OS_TIMESTAMP macro +** +** \main\maintrunk.MT5921\11 2007-11-09 16:36:15 GMT mtk01425 +** 1. Modify for CSUM offloading with Tx Fragment +** \main\maintrunk.MT5921\10 2007-11-07 18:38:37 GMT mtk01461 +** Add Tx Fragmentation Support +** \main\maintrunk.MT5921\9 2007-11-06 19:36:50 GMT mtk01088 +** add the WPS related code +** \main\maintrunk.MT5921\8 2007-11-02 01:03:57 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** Revision 1.4 2007/07/05 07:25:33 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:50 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:23 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +#ifndef _GL_KAL_H +#define _GL_KAL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "link.h" +#include "nic/mac.h" +#include "nic/wlan_def.h" +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "gl_wext_priv.h" +#include + +#if CFG_ENABLE_BT_OVER_WIFI +#include "nic/bow.h" +#endif + +#if DBG +extern int allocatedMemSize; +#endif + +#if CFG_SUPPORT_MET_PROFILING +#include "linux/kallsyms.h" +#include +#endif + +extern BOOLEAN fgIsUnderSuspend; +extern UINT_32 TaskIsrCnt; +extern BOOLEAN fgIsResetting; +extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); +extern UINT_32 u4MemAllocCnt, u4MemFreeCnt; + + +extern struct delayed_work sched_workq; + +#if defined(MT6620) && CFG_MULTI_ECOVER_SUPPORT +extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* #define USEC_PER_MSEC (1000) */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_SPIN_LOCK_CATEGORY_E { + SPIN_LOCK_FSM = 0, + + /* FIX ME */ + SPIN_LOCK_RX_QUE, + SPIN_LOCK_TX_QUE, + SPIN_LOCK_CMD_QUE, + SPIN_LOCK_TX_RESOURCE, + SPIN_LOCK_CMD_RESOURCE, + SPIN_LOCK_QM_TX_QUEUE, + SPIN_LOCK_CMD_PENDING, + SPIN_LOCK_CMD_SEQ_NUM, + SPIN_LOCK_TX_MSDU_INFO_LIST, + SPIN_LOCK_TXING_MGMT_LIST, + SPIN_LOCK_TX_SEQ_NUM, + SPIN_LOCK_TX_COUNT, + SPIN_LOCK_TXS_COUNT, + /* end */ + SPIN_LOCK_TX, + SPIN_LOCK_IO_REQ, + SPIN_LOCK_INT, + + SPIN_LOCK_MGT_BUF, + SPIN_LOCK_MSG_BUF, + SPIN_LOCK_STA_REC, + + SPIN_LOCK_MAILBOX, + SPIN_LOCK_TIMER, + + SPIN_LOCK_BOW_TABLE, + + SPIN_LOCK_EHPI_BUS, /* only for EHPI */ + SPIN_LOCK_NET_DEV, + SPIN_LOCK_NUM +} ENUM_SPIN_LOCK_CATEGORY_E; + +/* event for assoc information update */ +typedef struct _EVENT_ASSOC_INFO { + UINT_8 ucAssocReq; /* 1 for assoc req, 0 for assoc rsp */ + UINT_8 ucReassoc; /* 0 for assoc, 1 for reassoc */ + UINT_16 u2Length; + PUINT_8 pucIe; +} EVENT_ASSOC_INFO, *P_EVENT_ASSOC_INFO; + +typedef enum _ENUM_KAL_NETWORK_TYPE_INDEX_T { + KAL_NETWORK_TYPE_AIS_INDEX = 0, +#if CFG_ENABLE_WIFI_DIRECT + KAL_NETWORK_TYPE_P2P_INDEX, +#endif +#if CFG_ENABLE_BT_OVER_WIFI + KAL_NETWORK_TYPE_BOW_INDEX, +#endif + KAL_NETWORK_TYPE_INDEX_NUM +} ENUM_KAL_NETWORK_TYPE_INDEX_T; + +typedef enum _ENUM_KAL_MEM_ALLOCATION_TYPE_E { + PHY_MEM_TYPE, /* physically continuous */ + VIR_MEM_TYPE, /* virtually continuous */ + MEM_TYPE_NUM +} ENUM_KAL_MEM_ALLOCATION_TYPE; + +#if CONFIG_ANDROID /* Defined in Android kernel source */ +typedef struct wake_lock KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; +#else +typedef UINT_32 KAL_WAKE_LOCK_T, *P_KAL_WAKE_LOCK_T; +#endif + +#if CFG_SUPPORT_AGPS_ASSIST +typedef enum _ENUM_MTK_AGPS_ATTR { + MTK_ATTR_AGPS_INVALID, + MTK_ATTR_AGPS_CMD, + MTK_ATTR_AGPS_DATA, + MTK_ATTR_AGPS_IFINDEX, + MTK_ATTR_AGPS_IFNAME, + MTK_ATTR_AGPS_MAX +} ENUM_MTK_CCX_ATTR; + +typedef enum _ENUM_AGPS_EVENT { + AGPS_EVENT_WLAN_ON, + AGPS_EVENT_WLAN_OFF, + AGPS_EVENT_WLAN_AP_LIST, + WIFI_EVENT_CHIP_RESET, +} ENUM_CCX_EVENT; +BOOLEAN kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, UINT_8 cmd, PUINT_8 data, UINT_16 dataLen); +#endif + +struct KAL_HALT_CTRL_T { + struct semaphore lock; + struct task_struct *owner; + BOOLEAN fgHalt; + BOOLEAN fgHeldByKalIoctl; + OS_SYSTIME u4HoldStart; +}; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*----------------------------------------------------------------------------*/ +/* Macros of bit operation */ +/*----------------------------------------------------------------------------*/ +#define KAL_SET_BIT(bitOffset, value) set_bit(bitOffset, &value) +#define KAL_CLR_BIT(bitOffset, value) clear_bit(bitOffset, &value) +#define KAL_TEST_AND_CLEAR_BIT(bitOffset, value) test_and_clear_bit(bitOffset, &value) +#define KAL_TEST_BIT(bitOffset, value) test_bit(bitOffset, &value) + +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define KAL_SPIN_LOCK_DECLARATION() unsigned long __u4Flags + +#define KAL_ACQUIRE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalAcquireSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, &__u4Flags) + +#define KAL_RELEASE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalReleaseSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory, __u4Flags) + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ +#define KAL_GET_PKT_QUEUE_ENTRY(_p) GLUE_GET_PKT_QUEUE_ENTRY(_p) +#define KAL_GET_PKT_DESCRIPTOR(_prQueueEntry) GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) +#define KAL_GET_PKT_TID(_p) GLUE_GET_PKT_TID(_p) +#define KAL_GET_PKT_IS1X(_p) GLUE_GET_PKT_IS1X(_p) +#define KAL_GET_PKT_HEADER_LEN(_p) GLUE_GET_PKT_HEADER_LEN(_p) +#define KAL_GET_PKT_PAYLOAD_LEN(_p) GLUE_GET_PKT_PAYLOAD_LEN(_p) +#define KAL_GET_PKT_ARRIVAL_TIME(_p) GLUE_GET_PKT_ARRIVAL_TIME(_p) + +/*----------------------------------------------------------------------------*/ +/* Macros of wake_lock operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#if CONFIG_ANDROID /* Defined in Android kernel source */ +#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) \ + wake_lock_init(_prWakeLock, WAKE_LOCK_SUSPEND, _pcName) + +#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) \ + wake_lock_destroy(_prWakeLock) + +#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) \ + wake_lock(_prWakeLock) + +#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) \ + wake_lock_timeout(_prWakeLock, _u4Timeout) + +#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) \ + wake_unlock(_prWakeLock) + +#else +#define KAL_WAKE_LOCK_INIT(_prAdapter, _prWakeLock, _pcName) +#define KAL_WAKE_LOCK_DESTROY(_prAdapter, _prWakeLock) +#define KAL_WAKE_LOCK(_prAdapter, _prWakeLock) +#define KAL_WAKE_LOCK_TIMEOUT(_prAdapter, _prWakeLock, _u4Timeout) +#define KAL_WAKE_UNLOCK(_prAdapter, _prWakeLock) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Cache memory allocation +* +* \param[in] u4Size Required memory size. +* \param[in] eMemType Memory allocation type +* +* \return Pointer to allocated memory +* or NULL +*/ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemAlloc(u4Size, eMemType) ({ \ + void *pvAddr; \ + if (eMemType == PHY_MEM_TYPE) { \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } \ + else { \ + pvAddr = vmalloc(u4Size); \ + } \ + if (pvAddr) { \ + allocatedMemSize += u4Size; \ + DBGLOG(INIT, INFO, "%p(%u) allocated (%s:%s)\n", \ + pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ + } \ + pvAddr; \ +}) +#else +#define kalMemAlloc(u4Size, eMemType) ({ \ + void *pvAddr; \ + if (eMemType == PHY_MEM_TYPE) { \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } \ + else { \ + pvAddr = vmalloc(u4Size); \ + } \ + pvAddr; \ +}) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Free allocated cache memory +* +* \param[in] pvAddr Required memory size. +* \param[in] eMemType Memory allocation type +* \param[in] u4Size Allocated memory size. +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemFree(pvAddr, eMemType, u4Size) \ +{ \ + if (pvAddr) { \ + allocatedMemSize -= u4Size; \ + DBGLOG(INIT, INFO, "%p(%u) freed (%s:%s)\n", \ + pvAddr, (UINT_32)u4Size, __FILE__, __func__); \ + } \ + if (eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } \ + else { \ + vfree(pvAddr); \ + } \ +} +#else +#define kalMemFree(pvAddr, eMemType, u4Size) \ +{ \ + if (eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } \ + else { \ + vfree(pvAddr); \ + } \ +} +#endif + +#define kalUdelay(u4USec) udelay(u4USec) + +#define kalMdelay(u4MSec) mdelay(u4MSec) +#define kalMsleep(u4MSec) msleep(u4MSec) + +/* Copy memory from user space to kernel space */ +#define kalMemCopyFromUser(_pvTo, _pvFrom, _u4N) copy_from_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory from kernel space to user space */ +#define kalMemCopyToUser(_pvTo, _pvFrom, _u4N) copy_to_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory block with specific size */ +#define kalMemCopy(pvDst, pvSrc, u4Size) memcpy(pvDst, pvSrc, u4Size) + +/* Set memory block with specific pattern */ +#define kalMemSet(pvAddr, ucPattern, u4Size) memset(pvAddr, ucPattern, u4Size) + +/* Compare two memory block with specific length. + * Return zero if they are the same. + */ +#define kalMemCmp(pvAddr1, pvAddr2, u4Size) memcmp(pvAddr1, pvAddr2, u4Size) + +/* Zero specific memory block */ +#define kalMemZero(pvAddr, u4Size) memset(pvAddr, 0, u4Size) + +/* string operation */ +#define kalStrCpy(dest, src) strcpy(dest, src) +#define kalStrnCpy(dest, src, n) strncpy(dest, src, n) +#define kalStrCmp(ct, cs) strcmp(ct, cs) +#define kalStrnCmp(ct, cs, n) strncmp(ct, cs, n) +#define kalStrChr(s, c) strchr(s, c) +#define kalStrrChr(s, c) strrchr(s, c) +#define kalStrnChr(s, n, c) strnchr(s, n, c) +#define kalStrLen(s) strlen(s) +#define kalStrnLen(s, b) strnlen(s, b) +//#define kalStrniCmp(s1, s2, n) strnicmp(s1, s2, n) +#define kalStrniCmp(s1, s2, n) strncasecmp(s1, s2, n) +#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n) +/* #define kalStrtoul(cp, endp, base) simple_strtoul(cp, endp, base) +#define kalStrtol(cp, endp, base) simple_strtol(cp, endp, base) */ +#define kalkStrtou32(cp, base, resp) kstrtou32(cp, base, resp) +#define kalkStrtos32(cp, base, resp) kstrtos32(cp, base, resp) +#define kalSnprintf(buf, size, fmt, ...) snprintf(buf, size, fmt, __VA_ARGS__) +#define kalSprintf(buf, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) +/* remove for AOSP */ +/* #define kalSScanf(buf, fmt, ...) sscanf(buf, fmt, __VA_ARGS__) */ +#define kalStrStr(ct, cs) strstr(ct, cs) +#define kalStrSep(s, ct) strsep(s, ct) +#define kalStrCat(dest, src) strcat(dest, src) + +/* defined for wince sdio driver only */ +#if defined(_HIF_SDIO) +#define kalDevSetPowerState(prGlueInfo, ePowerMode) glSetPowerState(prGlueInfo, ePowerMode) +#else +#define kalDevSetPowerState(prGlueInfo, ePowerMode) +#endif + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Notify OS with SendComplete event of the specific packet. Linux should +* free packets here. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] status Status Code for OS upper layer +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#define kalSendComplete(prGlueInfo, pvPacket, status) \ + kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket) + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to locate the starting address of incoming ethernet +* frame for skb. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* +* \return starting address of ethernet frame buffer. +*/ +/*----------------------------------------------------------------------------*/ +#define kalQueryBufferPointer(prGlueInfo, pvPacket) \ + ((PUINT_8)((struct sk_buff *)pvPacket)->data) + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to query the length of valid buffer which is accessible during +* port read/write. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* +* \return starting address of ethernet frame buffer. +*/ +/*----------------------------------------------------------------------------*/ +#define kalQueryValidBufferLength(prGlueInfo, pvPacket) \ + ((UINT_32)((struct sk_buff *)pvPacket)->end - \ + (UINT_32)((struct sk_buff *)pvPacket)->data) + +/*----------------------------------------------------------------------------*/ +/*! +* \brief This function is used to copy the entire frame from skb to the destination +* address in the input parameter. +* +* \param[in] prGlueInfo Pointer of GLUE Data Structure +* \param[in] pvPacket Pointer of Packet Handle +* \param[in] pucDestBuffer Destination Address +* +* \return - +*/ +/*----------------------------------------------------------------------------*/ +#define kalCopyFrame(prGlueInfo, pvPacket, pucDestBuffer) \ + do {struct sk_buff *skb = (struct sk_buff *)pvPacket; \ + memcpy(pucDestBuffer, skb->data, skb->len); } while (0) + +#define kalGetTimeTick() jiffies_to_msecs(jiffies) + +#define kalPrint pr_debug + +#if !DBG +#define AIS_ERROR_LOGFUNC(_Fmt...) +#define AIS_WARN_LOGFUNC(_Fmt...) +#define AIS_INFO_LOGFUNC(_Fmt...) +#define AIS_STATE_LOGFUNC(_Fmt...) +#define AIS_EVENT_LOGFUNC(_Fmt...) +#define AIS_TRACE_LOGFUNC(_Fmt...) +#define AIS_LOUD_LOGFUNC(_Fmt...) +#define AIS_TEMP_LOGFUNC(_Fmt...) + +#define INTR_ERROR_LOGFUNC(_Fmt...) +#define INTR_WARN_LOGFUNC(_Fmt...) +#define INTR_INFO_LOGFUNC(_Fmt...) +#define INTR_STATE_LOGFUNC(_Fmt...) +#define INTR_EVENT_LOGFUNC(_Fmt...) +#define INTR_TRACE_LOGFUNC(_Fmt...) +#define INTR_LOUD_LOGFUNC(_Fmt...) +#define INTR_TEMP_LOGFUNC(_Fmt...) + +#define INIT_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define INIT_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define INIT_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define INIT_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define INIT_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define INIT_TRACE_LOGFUNC(_Fmt...) +#define INIT_LOUD_LOGFUNC(_Fmt...) +#define INIT_TEMP_LOGFUNC(_Fmt...) + +#define AAA_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_STATE_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_EVENT_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define AAA_LOUD_LOGFUNC(_Fmt...) +#define AAA_TEMP_LOGFUNC(_Fmt...) + +#define ROAMING_ERROR_LOGFUNC(_Fmt...) +#define ROAMING_WARN_LOGFUNC(_Fmt...) +#define ROAMING_INFO_LOGFUNC(_Fmt...) +#define ROAMING_STATE_LOGFUNC(_Fmt...) +#define ROAMING_EVENT_LOGFUNC(_Fmt...) +#define ROAMING_TRACE_LOGFUNC(_Fmt...) +#define ROAMING_LOUD_LOGFUNC(_Fmt...) +#define ROAMING_TEMP_LOGFUNC(_Fmt...) + +#define REQ_ERROR_LOGFUNC(_Fmt...) +#define REQ_WARN_LOGFUNC(_Fmt...) +#define REQ_INFO_LOGFUNC(_Fmt...) +#define REQ_STATE_LOGFUNC(_Fmt...) +#define REQ_EVENT_LOGFUNC(_Fmt...) +#define REQ_TRACE_LOGFUNC(_Fmt...) +#define REQ_LOUD_LOGFUNC(_Fmt...) +#define REQ_TEMP_LOGFUNC(_Fmt...) + +#define TX_ERROR_LOGFUNC(_Fmt...) +#define TX_WARN_LOGFUNC(_Fmt...) +#define TX_INFO_LOGFUNC(_Fmt...) +#define TX_STATE_LOGFUNC(_Fmt...) +#define TX_EVENT_LOGFUNC(_Fmt...) +#define TX_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define TX_LOUD_LOGFUNC(_Fmt...) +#define TX_TEMP_LOGFUNC(_Fmt...) + +#define RX_ERROR_LOGFUNC(_Fmt...) +#define RX_WARN_LOGFUNC(_Fmt...) +#define RX_INFO_LOGFUNC(_Fmt...) +#define RX_STATE_LOGFUNC(_Fmt...) +#define RX_EVENT_LOGFUNC(_Fmt...) +#define RX_TRACE_LOGFUNC(_Fmt...) +#define RX_LOUD_LOGFUNC(_Fmt...) +#define RX_TEMP_LOGFUNC(_Fmt...) + +#define RFTEST_ERROR_LOGFUNC(_Fmt...) +#define RFTEST_WARN_LOGFUNC(_Fmt...) +#define RFTEST_INFO_LOGFUNC(_Fmt...) +#define RFTEST_STATE_LOGFUNC(_Fmt...) +#define RFTEST_EVENT_LOGFUNC(_Fmt...) +#define RFTEST_TRACE_LOGFUNC(_Fmt...) +#define RFTEST_LOUD_LOGFUNC(_Fmt...) +#define RFTEST_TEMP_LOGFUNC(_Fmt...) + +#define EMU_ERROR_LOGFUNC(_Fmt...) +#define EMU_WARN_LOGFUNC(_Fmt...) +#define EMU_INFO_LOGFUNC(_Fmt...) +#define EMU_STATE_LOGFUNC(_Fmt...) +#define EMU_EVENT_LOGFUNC(_Fmt...) +#define EMU_TRACE_LOGFUNC(_Fmt...) +#define EMU_LOUD_LOGFUNC(_Fmt...) +#define EMU_TEMP_LOGFUNC(_Fmt...) + +#define HEM_ERROR_LOGFUNC(_Fmt...) +#define HEM_WARN_LOGFUNC(_Fmt...) +#define HEM_INFO_LOGFUNC(_Fmt...) +#define HEM_STATE_LOGFUNC(_Fmt...) +#define HEM_EVENT_LOGFUNC(_Fmt...) +#define HEM_TRACE_LOGFUNC(_Fmt...) +#define HEM_LOUD_LOGFUNC(_Fmt...) +#define HEM_TEMP_LOGFUNC(_Fmt...) + +#define RLM_ERROR_LOGFUNC(_Fmt...) +#define RLM_WARN_LOGFUNC(_Fmt...) +#define RLM_INFO_LOGFUNC(_Fmt...) +#define RLM_STATE_LOGFUNC(_Fmt...) +#define RLM_EVENT_LOGFUNC(_Fmt...) +#define RLM_TRACE_LOGFUNC(_Fmt...) +#define RLM_LOUD_LOGFUNC(_Fmt...) +#define RLM_TEMP_LOGFUNC(_Fmt...) + +#define MEM_ERROR_LOGFUNC(_Fmt...) +#define MEM_WARN_LOGFUNC(_Fmt...) +#define MEM_INFO_LOGFUNC(_Fmt...) +#define MEM_STATE_LOGFUNC(_Fmt...) +#define MEM_EVENT_LOGFUNC(_Fmt...) +#define MEM_TRACE_LOGFUNC(_Fmt...) +#define MEM_LOUD_LOGFUNC(_Fmt...) +#define MEM_TEMP_LOGFUNC(_Fmt...) + +#define CNM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define CNM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define CNM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define CNM_STATE_LOGFUNC(_Fmt...) +#define CNM_EVENT_LOGFUNC(_Fmt...) +#define CNM_TRACE_LOGFUNC(_Fmt...) +#define CNM_LOUD_LOGFUNC(_Fmt...) +#define CNM_TEMP_LOGFUNC(_Fmt...) + +#define RSN_ERROR_LOGFUNC(_Fmt...) +#define RSN_WARN_LOGFUNC(_Fmt...) +#define RSN_INFO_LOGFUNC(_Fmt...) +#define RSN_STATE_LOGFUNC(_Fmt...) +#define RSN_EVENT_LOGFUNC(_Fmt...) +#define RSN_TRACE_LOGFUNC(_Fmt...) +#define RSN_LOUD_LOGFUNC(_Fmt...) +#define RSN_TEMP_LOGFUNC(_Fmt...) + +#define BSS_ERROR_LOGFUNC(_Fmt...) +#define BSS_WARN_LOGFUNC(_Fmt...) +#define BSS_INFO_LOGFUNC(_Fmt...) +#define BSS_STATE_LOGFUNC(_Fmt...) +#define BSS_EVENT_LOGFUNC(_Fmt...) +#define BSS_TRACE_LOGFUNC(_Fmt...) +#define BSS_LOUD_LOGFUNC(_Fmt...) +#define BSS_TEMP_LOGFUNC(_Fmt...) + +#define SCN_ERROR_LOGFUNC(_Fmt...) +#define SCN_WARN_LOGFUNC(_Fmt...) +#define SCN_INFO_LOGFUNC(_Fmt...) +#define SCN_STATE_LOGFUNC(_Fmt...) +#define SCN_EVENT_LOGFUNC(_Fmt...) +#define SCN_TRACE_LOGFUNC(_Fmt...) +#define SCN_LOUD_LOGFUNC(_Fmt...) +#define SCN_TEMP_LOGFUNC(_Fmt...) + +#define SAA_ERROR_LOGFUNC(_Fmt...) +#define SAA_WARN_LOGFUNC(_Fmt...) +#define SAA_INFO_LOGFUNC(_Fmt...) +#define SAA_STATE_LOGFUNC(_Fmt...) +#define SAA_EVENT_LOGFUNC(_Fmt...) +#define SAA_TRACE_LOGFUNC(_Fmt...) +#define SAA_LOUD_LOGFUNC(_Fmt...) +#define SAA_TEMP_LOGFUNC(_Fmt...) + +#define P2P_ERROR_LOGFUNC(_Fmt...) +#define P2P_WARN_LOGFUNC(_Fmt...) +#define P2P_INFO_LOGFUNC(_Fmt...) +#define P2P_STATE_LOGFUNC(_Fmt...) +#define P2P_EVENT_LOGFUNC(_Fmt...) +#define P2P_TRACE_LOGFUNC(_Fmt...) +#define P2P_LOUD_LOGFUNC(_Fmt...) +#define P2P_TEMP_LOGFUNC(_Fmt...) + +#define QM_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define QM_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define QM_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define QM_STATE_LOGFUNC(_Fmt...) +#define QM_EVENT_LOGFUNC(_Fmt...) +#define QM_TRACE_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define QM_LOUD_LOGFUNC(_Fmt...) +#define QM_TEMP_LOGFUNC(_Fmt...) + +#define SEC_ERROR_LOGFUNC(_Fmt...) +#define SEC_WARN_LOGFUNC(_Fmt...) +#define SEC_INFO_LOGFUNC(_Fmt...) +#define SEC_STATE_LOGFUNC(_Fmt...) +#define SEC_EVENT_LOGFUNC(_Fmt...) +#define SEC_TRACE_LOGFUNC(_Fmt...) +#define SEC_LOUD_LOGFUNC(_Fmt...) +#define SEC_TEMP_LOGFUNC(_Fmt...) + +#define BOW_ERROR_LOGFUNC(_Fmt...) +#define BOW_WARN_LOGFUNC(_Fmt...) +#define BOW_INFO_LOGFUNC(_Fmt...) +#define BOW_STATE_LOGFUNC(_Fmt...) +#define BOW_EVENT_LOGFUNC(_Fmt...) +#define BOW_TRACE_LOGFUNC(_Fmt...) +#define BOW_LOUD_LOGFUNC(_Fmt...) +#define BOW_TEMP_LOGFUNC(_Fmt...) + +#define HAL_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define HAL_WARN_LOGFUNC(_Fmt...) +#define HAL_INFO_LOGFUNC(_Fmt...) +#define HAL_STATE_LOGFUNC(_Fmt...) +#define HAL_EVENT_LOGFUNC(_Fmt...) +#define HAL_TRACE_LOGFUNC(_Fmt...) +#define HAL_LOUD_LOGFUNC(_Fmt...) +#define HAL_TEMP_LOGFUNC(_Fmt...) + +#define WAPI_ERROR_LOGFUNC(_Fmt...) +#define WAPI_WARN_LOGFUNC(_Fmt...) +#define WAPI_INFO_LOGFUNC(_Fmt...) +#define WAPI_STATE_LOGFUNC(_Fmt...) +#define WAPI_EVENT_LOGFUNC(_Fmt...) +#define WAPI_TRACE_LOGFUNC(_Fmt...) +#define WAPI_LOUD_LOGFUNC(_Fmt...) +#define WAPI_TEMP_LOGFUNC(_Fmt...) + +#define TDLS_ERROR_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define TDLS_WARN_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define TDLS_INFO_LOGFUNC(_Fmt...) kalPrint(_Fmt) +#define TDLS_STATE_LOGFUNC(_Fmt...) +#define TDLS_EVENT_LOGFUNC(_Fmt...) +#define TDLS_TRACE_LOGFUNC(_Fmt...) +#define TDLS_LOUD_LOGFUNC(_Fmt...) +#define TDLS_TEMP_LOGFUNC(_Fmt...) + +#define SW1_ERROR_LOGFUNC(_Fmt...) +#define SW1_WARN_LOGFUNC(_Fmt...) +#define SW1_INFO_LOGFUNC(_Fmt...) +#define SW1_STATE_LOGFUNC(_Fmt...) +#define SW1_EVENT_LOGFUNC(_Fmt...) +#define SW1_TRACE_LOGFUNC(_Fmt...) +#define SW1_LOUD_LOGFUNC(_Fmt...) +#define SW1_TEMP_LOGFUNC(_Fmt...) + +#define SW2_ERROR_LOGFUNC(_Fmt...) +#define SW2_WARN_LOGFUNC(_Fmt...) +#define SW2_INFO_LOGFUNC(_Fmt...) +#define SW2_STATE_LOGFUNC(_Fmt...) +#define SW2_EVENT_LOGFUNC(_Fmt...) +#define SW2_TRACE_LOGFUNC(_Fmt...) +#define SW2_LOUD_LOGFUNC(_Fmt...) +#define SW2_TEMP_LOGFUNC(_Fmt...) + +#define SW3_ERROR_LOGFUNC(_Fmt...) +#define SW3_WARN_LOGFUNC(_Fmt...) +#define SW3_INFO_LOGFUNC(_Fmt...) +#define SW3_STATE_LOGFUNC(_Fmt...) +#define SW3_EVENT_LOGFUNC(_Fmt...) +#define SW3_TRACE_LOGFUNC(_Fmt...) +#define SW3_LOUD_LOGFUNC(_Fmt...) +#define SW3_TEMP_LOGFUNC(_Fmt...) + +#define SW4_ERROR_LOGFUNC(_Fmt...) +#define SW4_WARN_LOGFUNC(_Fmt...) +#define SW4_INFO_LOGFUNC(_Fmt...) +#define SW4_STATE_LOGFUNC(_Fmt...) +#define SW4_EVENT_LOGFUNC(_Fmt...) +#define SW4_TRACE_LOGFUNC(_Fmt...) +#define SW4_LOUD_LOGFUNC(_Fmt...) +#define SW4_TEMP_LOGFUNC(_Fmt...) +#endif + +#define kalBreakPoint() \ +do { \ + BUG(); \ + panic("Oops"); \ +} while (0) + +#if CFG_ENABLE_AEE_MSG +#define kalSendAeeException aee_kernel_exception +#define kalSendAeeWarning aee_kernel_warning +#define kalSendAeeReminding aee_kernel_reminding +#else +#define kalSendAeeException(_module, _desc, ...) +#define kalSendAeeWarning(_module, _desc, ...) +#define kalSendAeeReminding(_module, _desc, ...) +#endif + +#define PRINTF_ARG(...) __VA_ARGS__ +#define SPRINTF(buf, arg) {buf += sprintf((char *)(buf), PRINTF_ARG arg); } + +#define USEC_TO_SYSTIME(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_SYSTIME(_msec) (_msec) + +#define MSEC_TO_JIFFIES(_msec) msecs_to_jiffies(_msec) + +#define KAL_HALT_LOCK_TIMEOUT_NORMAL_CASE 3000 /* 3s */ +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Routines in gl_kal.c */ +/*----------------------------------------------------------------------------*/ +VOID +kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT unsigned long *pu4Flags); + +VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN UINT_32 u4Flags); + +VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr); + +VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); + +PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData); + +VOID kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prTimerHandler); + +BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN OS_SYSTIME rInterval); + +WLAN_STATUS +kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, + /* IN PBOOLEAN pfgIsRetain, */ + IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aeCSUM[] +); + +WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum); + +VOID +kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen); + +VOID +kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); + +VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen); + +#if CFG_TX_FRAGMENT +BOOLEAN +kalQueryTxPacketHeader(IN P_GLUE_INFO_T prGlueInfo, + IN PVOID pvPacket, OUT PUINT_16 pu2EtherTypeLen, OUT PUINT_8 pucEthDestAddr); +#endif /* CFG_TX_FRAGMENT */ + +VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag); + +VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T eCSUM[] +); +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr); + +VOID +kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, + IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum, IN UINT_32 u4DurationMs); + +VOID +kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_8 ucChannelNum); + +VOID +kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); + +VOID kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); + +/*----------------------------------------------------------------------------*/ +/* Routines in interface - ehpi/sdio.c */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalDevRegRead(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, OUT PUINT_32 pu4Value); + +BOOLEAN kalDevRegWrite(P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Register, IN UINT_32 u4Value); + +BOOLEAN +kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, IN UINT_32 u2Len, OUT PUINT_8 pucBuf, IN UINT_32 u2ValidOutBufSize); + +BOOLEAN +kalDevPortWrite(P_GLUE_INFO_T prGlueInfo, + IN UINT_16 u2Port, IN UINT_32 u2Len, IN PUINT_8 pucBuf, IN UINT_32 u2ValidInBufSize); + +BOOLEAN kalDevWriteWithSdioCmd52(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Addr, IN UINT_8 ucData); + +void kalDevLoopbkAuto(IN GLUE_INFO_T *GlueInfo); + +#if CFG_SUPPORT_EXT_CONFIG +UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo); +#endif + +BOOLEAN +kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT PUINT_8 pucPriorityParam, + OUT PUINT_32 pu4PacketLen, + OUT PUINT_8 pucEthDestAddr, + OUT PBOOLEAN pfgIs1X, + OUT PBOOLEAN pfgIsPAL, OUT PUINT_8 pucNetworkType, + OUT PVOID prGenUse); + +VOID +kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, + IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus); + +WLAN_STATUS +kalIoctl(IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN PVOID pvInfoBuf, + IN UINT_32 u4InfoBufLen, + IN BOOLEAN fgRead, IN BOOLEAN fgWaitResp, IN BOOLEAN fgCmd, IN BOOLEAN fgIsP2pOid, OUT PUINT_32 pu4QryInfoLen); + +VOID kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN P_EVENT_ASSOC_INFO prAssocInfo); + +#if CFG_ENABLE_FW_DOWNLOAD + +PVOID kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength); + +VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf); +#endif + +/*----------------------------------------------------------------------------*/ +/* Card Removal Check */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* TX */ +/*----------------------------------------------------------------------------*/ +VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* Media State Indication */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate); + +/*----------------------------------------------------------------------------*/ +/* OID handling */ +/*----------------------------------------------------------------------------*/ +VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_ENTRY_T prQueueEntry); + +#if CFG_ENABLE_BT_OVER_WIFI +/*----------------------------------------------------------------------------*/ +/* Bluetooth over Wi-Fi handling */ +/*----------------------------------------------------------------------------*/ +VOID kalIndicateBOWEvent(IN P_GLUE_INFO_T prGlueInfo, IN P_AMPC_EVENT prEvent); + +ENUM_BOW_DEVICE_STATE kalGetBowState(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); + +BOOLEAN kalSetBowState(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BOW_DEVICE_STATE eBowState, PARAM_MAC_ADDRESS rPeerAddr); + +ENUM_BOW_DEVICE_STATE kalGetBowGlobalState(IN P_GLUE_INFO_T prGlueInfo); + +UINT_32 kalGetBowFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); + +UINT_8 kalGetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr); + +VOID kalSetBowRole(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRole, IN PARAM_MAC_ADDRESS rPeerAddr); + +UINT_8 kalGetBowAvailablePhysicalLinkCount(IN P_GLUE_INFO_T prGlueInfo); + +#if CFG_BOW_SEPARATE_DATA_PATH +/*----------------------------------------------------------------------------*/ +/* Bluetooth over Wi-Fi Net Device Init/Uninit */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalInitBowDevice(IN P_GLUE_INFO_T prGlueInfo, IN const char *prDevName); + +BOOLEAN kalUninitBowDevice(IN P_GLUE_INFO_T prGlueInfo); +#endif /* CFG_BOW_SEPARATE_DATA_PATH */ +#endif /* CFG_ENABLE_BT_OVER_WIFI */ + +/*----------------------------------------------------------------------------*/ +/* Firmware Download Handling */ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetFwStartAddress(IN P_GLUE_INFO_T prGlueInfo); + +UINT_32 kalGetFwLoadAddress(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* Security Frame Clearance */ +/*----------------------------------------------------------------------------*/ +VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalClearSecurityFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +VOID kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN WLAN_STATUS rStatus); + +/*----------------------------------------------------------------------------*/ +/* Management Frame Clearance */ +/*----------------------------------------------------------------------------*/ +VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalClearMgmtFramesByNetType(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_NETWORK_TYPE_INDEX_T eNetworkTypeIdx); + +UINT_32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo); + +UINT_32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo); + +BOOLEAN kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Interval); + +BOOLEAN kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalScanDone(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN WLAN_STATUS status); + +UINT_32 kalRandomNumber(VOID); + +VOID kalTimeoutHandler(ULONG arg); + +VOID kalSetEvent(P_GLUE_INFO_T pr); + +/*----------------------------------------------------------------------------*/ +/* NVRAM/Registry Service */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo); + +P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo); + +VOID +kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, + OUT PUINT_16 pu2Part1CfgOwnVersion, + OUT PUINT_16 pu2Part1CfgPeerVersion, + OUT PUINT_16 pu2Part2CfgOwnVersion, OUT PUINT_16 pu2Part2CfgPeerVersion); + +BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data); + +BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, IN UINT_16 u2Data); + +/*----------------------------------------------------------------------------*/ +/* WSC Connection */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* RSSI Updating */ +/*----------------------------------------------------------------------------*/ +VOID +kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, IN INT_8 cRssi, IN INT_8 cLinkQuality); + +/*----------------------------------------------------------------------------*/ +/* I/O Buffer Pre-allocation */ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalInitIOBuffer(VOID); + +VOID kalUninitIOBuffer(VOID); + +PVOID kalAllocateIOBuffer(IN UINT_32 u4AllocSize); + +VOID kalReleaseIOBuffer(IN PVOID pvAddr, IN UINT_32 u4Size); + +VOID +kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); + +BOOLEAN kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo); + +ULONG kalIOPhyAddrGet(IN ULONG VirtAddr); + +VOID kalDmaBufGet(OUT VOID **VirtAddr, OUT VOID **PhyAddr); + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/* 802.11W */ +/*----------------------------------------------------------------------------*/ +UINT_32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo); +#endif + +UINT_32 kalWriteToFile(const PUINT_8 pucPath, BOOLEAN fgDoAppend, PUINT_8 pucData, UINT_32 u4Size); + +/*----------------------------------------------------------------------------*/ +/* NL80211 */ +/*----------------------------------------------------------------------------*/ +VOID +kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBuf, IN UINT_32 u4BufLen, IN UINT_8 ucChannelNum, IN INT_32 i4SignalStrength); + +/*----------------------------------------------------------------------------*/ +/* PNO Support */ +/*----------------------------------------------------------------------------*/ +VOID kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int tx_thread(void *data); + +VOID kalHifAhbKalWakeLockTimeout(IN P_GLUE_INFO_T prGlueInfo); +VOID kalMetProfilingStart(IN P_GLUE_INFO_T prGlueInfo, IN struct sk_buff *prSkb); +VOID kalMetProfilingFinish(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo); +int kalMetRemoveProcfs(void); + +UINT_64 kalGetBootTime(void); + +INT_32 kalReadToFile(const PUINT_8 pucPath, PUINT_8 pucData, UINT_32 u4Size, PUINT_32 pu4ReadSize); +#if CFG_SUPPORT_WAKEUP_REASON_DEBUG +BOOLEAN kalIsWakeupByWlan(P_ADAPTER_T prAdapter); +#endif +INT_32 kalHaltLock(UINT_32 waitMs); +INT_32 kalHaltTryLock(VOID); +VOID kalHaltUnlock(VOID); +VOID kalSetHalted(BOOLEAN fgHalt); +BOOLEAN kalIsHalted(VOID); + +INT32 kalPerMonInit(IN P_GLUE_INFO_T prGlueInfo); +INT32 kalPerMonDisable(IN P_GLUE_INFO_T prGlueInfo); +INT32 kalPerMonEnable(IN P_GLUE_INFO_T prGlueInfo); +INT32 kalPerMonStart(IN P_GLUE_INFO_T prGlueInfo); +INT32 kalPerMonStop(IN P_GLUE_INFO_T prGlueInfo); +INT32 kalPerMonDestroy(IN P_GLUE_INFO_T prGlueInfo); +VOID kalPerMonHandler(IN P_ADAPTER_T prAdapter, ULONG ulParam); +INT32 kalBoostCpu(UINT_32 core_num); + +#endif /* _GL_KAL_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h new file mode 100644 index 0000000000000..a4321e7f9a119 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_os.h @@ -0,0 +1,1270 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_os.h#2 +*/ + +/*! \file gl_os.h + \brief List the external reference to OS for GLUE Layer. + + In this file we define the data structure - GLUE_INFO_T to store those objects + we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the + external reference (header file, extern func() ..) to OS for GLUE Layer should + also list down here. +*/ + +/* +** Log: gl_os.h +** +** 08 20 2012 yuche.tsai +** NULL +** Fix possible KE issue. +** +** 08 20 2012 yuche.tsai +** [ALPS00339327] [Rose][6575JB][BSP Package][Free Test][KE][WIFI]There is no response when you tap the turn off/on +** button,wait a minutes, the device will reboot automatically and "KE" will pop up. +** Fix possible KE when netlink operate mgmt frame register. + * + * 04 12 2012 terry.wu + * NULL + * Add AEE message support + * 1) Show AEE warning(red screen) if SDIO access error occurs + + * + * 03 02 2012 terry.wu + * NULL + * Enable CFG80211 Support. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 12 13 2011 cm.chang + * [WCXRP00001136] [All Wi-Fi][Driver] Add wake lock for pending timer + * Add wake lock if timer timeout value is smaller than 5 seconds + * + * 11 18 2011 yuche.tsai + * NULL + * CONFIG P2P support RSSI query, default turned off. + * + * 11 16 2011 yuche.tsai + * NULL + * Avoid using work thread. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 29 2011 terry.wu + * NULL + * Show DRV_NAME by chip id. + * + * 04 18 2011 terry.wu + * [WCXRP00000660] [MT6620 Wi-Fi][Driver] Remove flag CFG_WIFI_DIRECT_MOVED + * Remove flag CFG_WIFI_DIRECT_MOVED. + * + * 03 29 2011 cp.wu + * [WCXRP00000598] [MT6620 Wi-Fi][Driver] Implementation of interface for communicating with user space process for + * RESET_START and RESET_END events + * implement kernel-to-userspace communication via generic netlink socket for whole-chip resetting mechanism + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * support concurrent network + * + * 03 03 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * modify net device relative functions to support multiple H/W queues + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 02 21 2011 cp.wu + * [WCXRP00000482] [MT6620 Wi-Fi][Driver] Simplify logic for checking NVRAM existence in driver domain + * simplify logic for checking NVRAM existence only once. + * + * 02 16 2011 jeffrey.chang + * NULL + * Add query ipv4 and ipv6 address during early suspend and late resume + * + * 02 10 2011 chinghwa.yu + * [WCXRP00000065] Update BoW design and settings + * Fix kernel API change issue. + * Before ALPS 2.2 (2.2 included), kfifo_alloc() is + * struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); + * After ALPS 2.3, kfifo_alloc() is changed to + * int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask); + * + * 02 09 2011 wh.su + * [WCXRP00000433] [MT6620 Wi-Fi][Driver] Remove WAPI structure define for avoid P2P module with structure miss-align + * pointer issue + * always pre-allio WAPI related structure for align p2p module. + * + * 02 09 2011 terry.wu + * [WCXRP00000383] [MT6620 Wi-Fi][Driver] Separate WiFi and P2P driver into two modules + * Halt p2p module init and exit until TxThread finished p2p register and unregister. + * + * 02 01 2011 cm.chang + * [WCXRP00000415] [MT6620 Wi-Fi][Driver] Check if any memory leakage happens when uninitializing in DGB mode + * . + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 12 2011 cp.wu + * [WCXRP00000357] [MT6620 Wi-Fi][Driver][Bluetooth over Wi-Fi] add another net device interface for BT AMP + * implementation of separate BT_OVER_WIFI data path. + * + * 01 12 2011 cp.wu + * [WCXRP00000356] [MT6620 Wi-Fi][Driver] fill mac header length for security frames 'cause hardware header translation + * needs such information + * fill mac header length information for 802.1x frames. + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. Connection establish + * successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. + * + * 01 10 2011 cp.wu + * [WCXRP00000349] [MT6620 Wi-Fi][Driver] make kalIoctl() of linux port as a thread safe API to avoid potential issues + * due to multiple access + * use mutex to protect kalIoctl() for thread safe. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * ioctl implementations for P2P Service Discovery + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 28 2010 wh.su + * NULL + * [WCXRP00000069][MT6620 Wi-Fi][Driver] Fix some code for phase 1 P2P Demo. + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 09 13 2010 cp.wu + * NULL + * add waitq for poll() and read(). + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 09 06 2010 wh.su + * NULL + * let the p2p can set the privacy bit at beacon and rsn ie at assoc req at key handshake state. + * + * 09 03 2010 kevin.huang + * NULL + * Refine #include sequence and solve recursive/nested #include issue + * + * 09 01 2010 wh.su + * NULL + * adding the wapi support for integration test. + * + * 08 31 2010 kevin.huang + * NULL + * Use LINK LIST operation to process SCAN result + * + * 08 23 2010 cp.wu + * NULL + * revise constant definitions to be matched with implementation (original cmd-event definition is deprecated) + * + * 08 16 2010 cp.wu + * NULL + * P2P packets are now marked when being queued into driver, and identified later without checking MAC address + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 11 2010 cp.wu + * NULL + * 1) do not use in-stack variable for beacon updating. (for MAUI porting) + * 2) extending scanning result to 64 instead of 48 + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 08 02 2010 jeffrey.chang + * NULL + * 1) modify tx service thread to avoid busy looping + * 2) add spin lock declartion for linux build + * + * 07 23 2010 jeffrey.chang + * + * add new KAL api + * + * 07 22 2010 jeffrey.chang + * + * modify tx thread and remove some spinlock + * + * 07 19 2010 jeffrey.chang + * + * add security frame pending count + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * + * 05 10 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement basic wi-fi direct framework + * + * 05 07 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * prevent supplicant accessing driver during resume + * + * 05 07 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add basic framework for implementating P2P driver hook. + * + * 05 05 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * change variable names for multiple physical link to match with coding convention + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * identify BT Over Wi-Fi Security frame and mark it as 802.1X frame + * + * 04 27 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add multiple physical link support + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * 1) fix firmware download bug + * 2) remove query statistics for acelerating firmware download + * + * 04 27 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * follow Linux's firmware framework, and remove unused kal API + * + * 04 23 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * surpress compiler warning + * + * 04 19 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * supporting power management + * + * 04 14 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * pvInformationBuffer and u4InformationBufferLength are no longer in glue + * + * 04 13 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add framework for BT-over-Wi-Fi support. + * * * * * * * * * * * * * * * * * * * * 1) prPendingCmdInfo is replaced by queue for multiple + * * * * * * * * * * * * * * * * * * * * handler capability + * * * * * * * * * * * * * * * * * * * * 2) command sequence number is now increased atomically + * * * * * * * * * * * * * * * * * * * * 3) private data could be hold and taken use for other + * * * * * * * * * * * * * * * * * * * * purpose + * + * 04 07 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * rWlanInfo should be placed at adapter rather than glue due to most operations + * * * * * * * * * * are done in adapter layer. + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * Tag the packet for QoS on Tx path + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * (1)deliver the kalOidComplete status to upper layer + * * (2) fix spin lock + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * add timeout check in the kalOidComplete + * + * 04 06 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * improve none-glue code portability + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * code refine: fgTestMode should be at adapter rather than glue due to the device/fw is also involved + * + * 04 06 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * eliminate direct access for prGlueInfo->fgIsCardRemoved in non-glue layer + * + * 03 30 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * emulate NDIS Pending OID facility + * + * 03 26 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * [WPD00003826] Initial import for Linux port + * adding firmware download related data type + * + * 03 25 2010 cp.wu + * [WPD00001943]Create WiFi test driver framework on WinXP + * 1) correct OID_802_11_CONFIGURATION with frequency setting behavior. + * * * * the frequency is used for adhoc connection only + * * * * 2) update with SD1 v0.9 CMD/EVENT documentation + * + * 03 25 2010 cp.wu + * [WPD00003823][MT6620 Wi-Fi] Add Bluetooth-over-Wi-Fi support + * add Bluetooth-over-Wifi frame header check + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\30 2009-10-20 17:38:31 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, +** and then stop hw. +** \main\maintrunk.MT5921\29 2009-10-08 10:33:33 GMT mtk01090 +** Avoid accessing private data of net_device directly. Replace with netdev_priv(). Add more checking for input +** parameters and pointers. +** \main\maintrunk.MT5921\28 2009-09-28 20:19:26 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\27 2009-08-18 22:57:12 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\26 2009-07-06 21:42:25 GMT mtk01088 +** fixed the compiling error at linux +** \main\maintrunk.MT5921\25 2009-07-06 20:51:46 GMT mtk01088 +** adding the wapi 1x ether type define +** \main\maintrunk.MT5921\24 2009-06-23 23:19:18 GMT mtk01090 +** Add build option BUILD_USE_EEPROM and compile option CFG_SUPPORT_EXT_CONFIG for NVRAM support +** \main\maintrunk.MT5921\23 2009-02-07 15:05:06 GMT mtk01088 +** add the privacy flag to ingo driver the supplicant selected ap's security +** \main\maintrunk.MT5921\22 2009-02-05 15:34:09 GMT mtk01088 +** fixed the compiling error for using bits marco for only one parameter +** \main\maintrunk.MT5921\21 2009-01-22 13:02:13 GMT mtk01088 +** data frame is or not 802.1x value share with tid, using the same reserved byte, provide the function to set and get +** \main\maintrunk.MT5921\20 2008-10-24 12:04:16 GMT mtk01088 +** move the config.h from precomp.h to here for lint check +** \main\maintrunk.MT5921\19 2008-09-22 23:19:02 GMT mtk01461 +** Update driver for code review +** \main\maintrunk.MT5921\18 2008-09-05 17:25:13 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\17 2008-08-01 13:32:47 GMT mtk01084 +** Prevent redundent driver assertion in driver logic when BUS is detached +** \main\maintrunk.MT5921\16 2008-05-30 14:41:43 GMT mtk01461 +** Remove WMM Assoc Flag in KAL +** \main\maintrunk.MT5921\15 2008-05-29 14:16:25 GMT mtk01084 +** remoev un-used variable +** \main\maintrunk.MT5921\14 2008-05-03 15:17:14 GMT mtk01461 +** Add Media Status variable in Glue Layer +** \main\maintrunk.MT5921\13 2008-04-24 11:58:41 GMT mtk01461 +** change threshold to 256 +** \main\maintrunk.MT5921\12 2008-03-11 14:51:05 GMT mtk01461 +** Remove redundant GL_CONN_INFO_T +** \main\maintrunk.MT5921\11 2008-01-07 15:07:41 GMT mtk01461 +** Adjust the netif stop threshold to 150 +** \main\maintrunk.MT5921\10 2007-11-26 19:43:46 GMT mtk01461 +** Add OS_TIMESTAMP macro +** +** \main\maintrunk.MT5921\9 2007-11-07 18:38:38 GMT mtk01461 +** Move definition +** \main\maintrunk.MT5921\8 2007-11-02 01:04:00 GMT mtk01461 +** Unify TX Path for Normal and IBSS Power Save + IBSS neighbor learning +** Revision 1.5 2007/07/12 11:04:28 MTK01084 +** update macro to delay for ms order +** +** Revision 1.4 2007/07/05 07:25:34 MTK01461 +** Add Linux initial code, modify doc, add 11BB, RF init code +** +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +#ifndef _GL_OS_H +#define _GL_OS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +/*------------------------------------------------------------------------------ + * Flags for LINUX(OS) dependent + *------------------------------------------------------------------------------ + */ +#define CFG_MAX_WLAN_DEVICES 1 /* number of wlan card will coexist */ + +#define CFG_MAX_TXQ_NUM 4 /* number of tx queue for support multi-queue h/w */ + +#define CFG_USE_SPIN_LOCK_BOTTOM_HALF 0 /* 1: Enable use of SPIN LOCK Bottom Half for LINUX + 0: Disable - use SPIN LOCK IRQ SAVE instead */ + +#define CFG_TX_PADDING_SMALL_ETH_PACKET 0 /* 1: Enable - Drop ethernet packet if it < 14 bytes. + And pad ethernet packet with dummy 0 if it < 60 bytes. + 0: Disable */ + +#define CFG_TX_STOP_NETIF_QUEUE_THRESHOLD 256 /* packets */ + +#define CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD 256 /* packets */ +#define CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD 128 /* packets */ + +#define ETH_P_1X 0x888E +#define IPTOS_PREC_OFFSET 5 +#define USER_PRIORITY_DEFAULT 0 + +#define ETH_WPI_1X 0x88B4 + +#define ETH_HLEN 14 +#define ETH_TYPE_LEN_OFFSET 12 +#define ETH_P_IP 0x0800 +#define ETH_P_1X 0x888E +#define ETH_P_PRE_1X 0x88C7 +#define ETH_P_ARP 0x0806 + +#define ARP_PRO_REQ 1 +#define ARP_PRO_RSP 2 + +#define IPVERSION 4 +#define IP_HEADER_LEN 20 + +#define IP_PRO_ICMP 0x01 +#define IP_PRO_UDP 0x11 +#define IP_PRO_TCP 0x06 + +#define UDP_PORT_DHCPS 0x43 +#define UDP_PORT_DHCPC 0x44 +#define UDP_PORT_DNS 0x35 + +#define IPVH_VERSION_OFFSET 4 /* For Little-Endian */ +#define IPVH_VERSION_MASK 0xF0 +#define IPTOS_PREC_OFFSET 5 +#define IPTOS_PREC_MASK 0xE0 + +#define SOURCE_PORT_LEN 2 +/* NOTE(Kevin): Without IP Option Length */ +#define LOOK_AHEAD_LEN (ETH_HLEN + IP_HEADER_LEN + SOURCE_PORT_LEN) + +/* 802.2 LLC/SNAP */ +#define ETH_LLC_OFFSET (ETH_HLEN) +#define ETH_LLC_LEN 3 +#define ETH_LLC_DSAP_SNAP 0xAA +#define ETH_LLC_SSAP_SNAP 0xAA +#define ETH_LLC_CONTROL_UNNUMBERED_INFORMATION 0x03 + +/* Bluetooth SNAP */ +#define ETH_SNAP_OFFSET (ETH_HLEN + ETH_LLC_LEN) +#define ETH_SNAP_LEN 5 +#define ETH_SNAP_BT_SIG_OUI_0 0x00 +#define ETH_SNAP_BT_SIG_OUI_1 0x19 +#define ETH_SNAP_BT_SIG_OUI_2 0x58 + +#define BOW_PROTOCOL_ID_SECURITY_FRAME 0x0003 + +#if defined(MT6620) +#define CHIP_NAME "MT6620" +#elif defined(MT6628) +#define CHIP_NAME "MT6582" +#endif + +#define DRV_NAME "["CHIP_NAME"]: " + +#define CONFIG_ANDROID 1 +/* Define if target platform is Android. + * It should already be defined in Android kernel source + */ + +/* for CFG80211 IE buffering mechanism */ +#define CFG_CFG80211_IE_BUF_LEN (512) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include /* constant of kernel version */ + +#include /* bitops.h */ + +#include /* struct timer_list */ +#include /* jiffies */ +#include /* udelay and mdelay macro */ + +#if CONFIG_ANDROID +#include +#endif + +#include /* IRQT_FALLING */ + +#include /* struct net_device, struct net_device_stats */ +#include /* for eth_type_trans() function */ +#include /* struct iw_statistics */ +#include +#include /* struct in_device */ + +#include /* struct iphdr */ + +#include /* for memcpy()/memset() function */ +#include /* for offsetof() macro */ + +#include /* The proc filesystem constants/structures */ + +#include /* for rtnl_lock() and rtnl_unlock() */ +#include /* kthread_should_stop(), kthread_run() */ +#include /* for copy_from_user() */ +#include /* for firmware download */ +#include + +#include /* for kfifo interface */ +#include /* for cdev interface */ + +#include /* for firmware download */ + +#if defined(_HIF_SDIO) +#include +#include +#endif + +#include + +#include +#include + +#include /* readw and writew */ + +#if WIRELESS_EXT > 12 +#include +#endif + +#include "version.h" +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#include +#endif + +#include + +#if CFG_SUPPORT_HOTSPOT_2_0 +#include +#endif + +#include "gl_typedef.h" +#include "typedef.h" +#include "queue.h" +#include "gl_kal.h" +#include "hif.h" +#if CFG_CHIP_RESET_SUPPORT +#include "gl_rst.h" +#endif + +#if (CFG_SUPPORT_TDLS == 1) +#include "tdls_extr.h" +#endif +#include "debug.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" + +#if CFG_ENABLE_AEE_MSG +#include +#endif + +extern BOOLEAN fgIsBusAccessFailed; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define GLUE_FLAG_HALT BIT(0) +#define GLUE_FLAG_INT BIT(1) +#define GLUE_FLAG_OID BIT(2) +#define GLUE_FLAG_TIMEOUT BIT(3) +#define GLUE_FLAG_TXREQ BIT(4) +#define GLUE_FLAG_SUB_MOD_INIT BIT(5) +#define GLUE_FLAG_SUB_MOD_EXIT BIT(6) +#define GLUE_FLAG_SUB_MOD_MULTICAST BIT(7) +#define GLUE_FLAG_FRAME_FILTER BIT(8) +#define GLUE_FLAG_FRAME_FILTER_AIS BIT(9) +#define GLUE_FLAG_HIF_LOOPBK_AUTO BIT(10) +#define GLUE_FLAG_HALT_BIT (0) +#define GLUE_FLAG_INT_BIT (1) +#define GLUE_FLAG_OID_BIT (2) +#define GLUE_FLAG_TIMEOUT_BIT (3) +#define GLUE_FLAG_TXREQ_BIT (4) +#define GLUE_FLAG_SUB_MOD_INIT_BIT (5) +#define GLUE_FLAG_SUB_MOD_EXIT_BIT (6) +#define GLUE_FLAG_SUB_MOD_MULTICAST_BIT (7) +#define GLUE_FLAG_FRAME_FILTER_BIT (8) +#define GLUE_FLAG_FRAME_FILTER_AIS_BIT (9) +#define GLUE_FLAG_HIF_LOOPBK_AUTO_BIT (10) + +#define GLUE_BOW_KFIFO_DEPTH (1024) +/* #define GLUE_BOW_DEVICE_NAME "MT6620 802.11 AMP" */ +#define GLUE_BOW_DEVICE_NAME "ampc0" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _GL_WPA_INFO_T { + UINT_32 u4WpaVersion; + UINT_32 u4KeyMgmt; + UINT_32 u4CipherGroup; + UINT_32 u4CipherPairwise; + UINT_32 u4AuthAlg; + BOOLEAN fgPrivacyInvoke; +#if CFG_SUPPORT_802_11W + UINT_32 u4Mfp; +#endif +} GL_WPA_INFO_T, *P_GL_WPA_INFO_T; + +typedef enum _ENUM_RSSI_TRIGGER_TYPE { + ENUM_RSSI_TRIGGER_NONE, + ENUM_RSSI_TRIGGER_GREATER, + ENUM_RSSI_TRIGGER_LESS, + ENUM_RSSI_TRIGGER_TRIGGERED, + ENUM_RSSI_TRIGGER_NUM +} ENUM_RSSI_TRIGGER_TYPE; + +#if CFG_ENABLE_WIFI_DIRECT +typedef enum _ENUM_SUB_MODULE_IDX_T { + P2P_MODULE = 0, + SUB_MODULE_NUM +} ENUM_SUB_MODULE_IDX_T; + +typedef enum _ENUM_NET_REG_STATE_T { + ENUM_NET_REG_STATE_UNREGISTERED, + ENUM_NET_REG_STATE_REGISTERING, + ENUM_NET_REG_STATE_REGISTERED, + ENUM_NET_REG_STATE_UNREGISTERING, + ENUM_NET_REG_STATE_NUM +} ENUM_NET_REG_STATE_T; + +#endif + +typedef struct _GL_IO_REQ_T { + QUE_ENTRY_T rQueEntry; + /* wait_queue_head_t cmdwait_q; */ + BOOLEAN fgRead; + BOOLEAN fgWaitResp; +#if CFG_ENABLE_WIFI_DIRECT + BOOLEAN fgIsP2pOid; +#endif + P_ADAPTER_T prAdapter; + PFN_OID_HANDLER_FUNC pfnOidHandler; + PVOID pvInfoBuf; + UINT_32 u4InfoBufLen; + PUINT_32 pu4QryInfoLen; + WLAN_STATUS rStatus; + UINT_32 u4Flag; +} GL_IO_REQ_T, *P_GL_IO_REQ_T; + +#if CFG_ENABLE_BT_OVER_WIFI +typedef struct _GL_BOW_INFO { + BOOLEAN fgIsRegistered; + dev_t u4DeviceNumber; /* dynamic device number */ +/* struct kfifo *prKfifo; */ /* for buffering indicated events */ + struct kfifo rKfifo; /* for buffering indicated events */ + spinlock_t rSpinLock; /* spin lock for kfifo */ + struct cdev cdev; + UINT_32 u4FreqInKHz; /* frequency */ + + UINT_8 aucRole[CFG_BOW_PHYSICAL_LINK_NUM]; /* 0: Responder, 1: Initiator */ + ENUM_BOW_DEVICE_STATE aeState[CFG_BOW_PHYSICAL_LINK_NUM]; + PARAM_MAC_ADDRESS arPeerAddr[CFG_BOW_PHYSICAL_LINK_NUM]; + + wait_queue_head_t outq; + +#if CFG_BOW_SEPARATE_DATA_PATH + /* Device handle */ + struct net_device *prDevHandler; + BOOLEAN fgIsNetRegistered; +#endif + +} GL_BOW_INFO, *P_GL_BOW_INFO; +#endif + +#if (CFG_SUPPORT_TDLS == 1) +typedef struct _TDLS_INFO_LINK_T { + /* start time when link is built, end time when link is broken */ + unsigned long jiffies_start, jiffies_end; + + /* the peer MAC */ + UINT8 aucPeerMac[6]; + + /* broken reason */ + UINT8 ucReasonCode; + + /* TRUE: torn down is triggerred by us */ + UINT8 fgIsFromUs; + + /* duplicate count; same reason */ + UINT8 ucDupCount; + + /* HT capability */ +#define TDLS_INFO_LINK_HT_CAP_SUP 0x01 + UINT8 ucHtCap; +#define TDLS_INFO_LINK_HT_BA_SETUP 0x01 +#define TDLS_INFO_LINK_HT_BA_SETUP_OK 0x02 +#define TDLS_INFO_LINK_HT_BA_SETUP_DECLINE 0x04 +#define TDLS_INFO_LINK_HT_BA_PEER 0x10 +#define TDLS_INFO_LINK_HT_BA_RSP_OK 0x20 +#define TDLS_INFO_LINK_HT_BA_RSP_DECLINE 0x40 + UINT8 ucHtBa[8]; /* TID0 ~ TID7 */ +} TDLS_INFO_LINK_T; + +typedef struct _TDLS_INFO_T { + /* link history */ +#define TDLS_LINK_HISTORY_MAX 30 + TDLS_INFO_LINK_T rLinkHistory[TDLS_LINK_HISTORY_MAX]; + UINT32 u4LinkIdx; + + /* TRUE: support 20/40 bandwidth in TDLS link */ + BOOLEAN fgIs2040Sup; + + /* total TDLS link count */ + INT8 cLinkCnt; +} TDLS_INFO_T; +#endif /* CFG_SUPPORT_TDLS */ + +/* +* type definition of pointer to p2p structure +*/ +typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; + +struct _GLUE_INFO_T { + /* Device handle */ + struct net_device *prDevHandler; + + /* Device Index(index of arWlanDevInfo[]) */ + INT_32 i4DevIdx; + + /* Device statistics */ + struct net_device_stats rNetDevStats; + + /* Wireless statistics struct net_device */ + struct iw_statistics rIwStats; + + /* spinlock to sync power save mechanism */ + spinlock_t rSpinLock[SPIN_LOCK_NUM]; + + /* semaphore for ioctl */ + struct semaphore ioctl_sem; + + UINT_64 u8Cookie; + + ULONG ulFlag; /* GLUE_FLAG_XXX */ + UINT_32 u4PendFlag; + /* UINT_32 u4TimeoutFlag; */ + UINT_32 u4OidCompleteFlag; + UINT_32 u4ReadyFlag; /* check if card is ready */ + + UINT_32 u4OsMgmtFrameFilter; + + /* Number of pending frames, also used for debuging if any frame is + * missing during the process of unloading Driver. + * + * NOTE(Kevin): In Linux, we also use this variable as the threshold + * for manipulating the netif_stop(wake)_queue() func. + */ + INT_32 ai4TxPendingFrameNumPerQueue[4][CFG_MAX_TXQ_NUM]; + INT_32 i4TxPendingFrameNum; + INT_32 i4TxPendingSecurityFrameNum; + + /* current IO request for kalIoctl */ + GL_IO_REQ_T OidEntry; + + /* registry info */ + REG_INFO_T rRegInfo; + + /* firmware */ + struct firmware *prFw; + + /* Host interface related information */ + /* defined in related hif header file */ + GL_HIF_INFO_T rHifInfo; + + /*! \brief wext wpa related information */ + GL_WPA_INFO_T rWpaInfo; + + /* Pointer to ADAPTER_T - main data structure of internal protocol stack */ + P_ADAPTER_T prAdapter; + +#ifdef WLAN_INCLUDE_PROC + struct proc_dir_entry *pProcRoot; +#endif /* WLAN_INCLUDE_PROC */ + + /* Indicated media state */ + ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicated; + + /* Device power state D0~D3 */ + PARAM_DEVICE_POWER_STATE ePowerState; + + struct completion rScanComp; /* indicate scan complete */ + struct completion rHaltComp; /* indicate main thread halt complete */ + struct completion rPendComp; /* indicate main thread halt complete */ +#if CFG_ENABLE_WIFI_DIRECT + struct completion rSubModComp; /*indicate sub module init or exit complete */ +#endif + WLAN_STATUS rPendStatus; + + QUE_T rTxQueue; + + /* OID related */ + QUE_T rCmdQueue; + /* PVOID pvInformationBuffer; */ + /* UINT_32 u4InformationBufferLength; */ + /* PVOID pvOidEntry; */ + /* PUINT_8 pucIOReqBuff; */ + /* QUE_T rIOReqQueue; */ + /* QUE_T rFreeIOReqQueue; */ + + wait_queue_head_t waitq; + struct task_struct *main_thread; + + struct timer_list tickfn; + +#if CFG_SUPPORT_EXT_CONFIG + UINT_16 au2ExtCfg[256]; /* NVRAM data buffer */ + UINT_32 u4ExtCfgLength; /* 0 means data is NOT valid */ +#endif + +#if 1 /* CFG_SUPPORT_WAPI */ + /* Should be large than the PARAM_WAPI_ASSOC_INFO_T */ + UINT_8 aucWapiAssocInfoIEs[42]; + UINT_16 u2WapiAssocInfoIESz; +#endif + +#if CFG_ENABLE_BT_OVER_WIFI + GL_BOW_INFO rBowInfo; +#endif + +#if CFG_ENABLE_WIFI_DIRECT + P_GL_P2P_INFO_T prP2PInfo; +#if CFG_SUPPORT_P2P_RSSI_QUERY + /* Wireless statistics struct net_device */ + struct iw_statistics rP2pIwStats; +#endif +#endif + BOOLEAN fgWpsActive; + UINT_8 aucWSCIE[500]; /*for probe req */ + UINT_16 u2WSCIELen; + UINT_8 aucWSCAssocInfoIE[200]; /*for Assoc req */ + UINT_16 u2WSCAssocInfoIELen; + +#if CFG_SUPPORT_HOTSPOT_2_0 + UINT_8 aucHS20AssocInfoIE[200]; /*for Assoc req */ + UINT_16 u2HS20AssocInfoIELen; + UINT_8 ucHotspotConfig; + BOOLEAN fgConnectHS20AP; +#endif + + /* NVRAM availability */ + BOOLEAN fgNvramAvailable; + + BOOLEAN fgMcrAccessAllowed; + + /* MAC Address Overridden by IOCTL */ + BOOLEAN fgIsMacAddrOverride; + PARAM_MAC_ADDRESS rMacAddrOverride; + + SET_TXPWR_CTRL_T rTxPwr; + + /* for cfg80211 scan done indication */ + struct cfg80211_scan_request *prScanRequest; + + /* for cfg80211 scheduled scan */ + struct cfg80211_sched_scan_request *prSchedScanRequest; + + /* to indicate registered or not */ + BOOLEAN fgIsRegistered; + + /* for cfg80211 connected indication */ + UINT_32 u4RspIeLength; + UINT_8 aucRspIe[CFG_CFG80211_IE_BUF_LEN]; + + UINT_32 u4ReqIeLength; + UINT_8 aucReqIe[CFG_CFG80211_IE_BUF_LEN]; + + KAL_WAKE_LOCK_T rAhbIsrWakeLock; + +#if CFG_SUPPORT_HOTSPOT_2_0 + BOOLEAN fgIsDad; + UINT_8 aucDADipv4[4]; + BOOLEAN fgIs6Dad; + UINT_8 aucDADipv6[16]; +#endif +#if (CFG_SUPPORT_MET_PROFILING == 1) + UINT_8 u8MetProfEnable; + INT_16 u16MetUdpPort; +#endif + BOOLEAN fgPoorlinkValid; + UINT_64 u8Statistic[2]; + UINT_64 u8TotalFailCnt; + UINT_32 u4LinkspeedThreshold; + INT_32 i4RssiThreshold; + INT_32 i4RssiCache; + UINT_32 u4LinkSpeedCache; + +#if (CFG_SUPPORT_TDLS == 1) + TDLS_INFO_T rTdlsLink; + + UINT8 aucTdlsHtPeerMac[6]; + IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ + + /* + [0~7]: jiffies + [8~13]: Peer MAC + [14]: Reason Code + [15]: From us or peer + [16]: Duplicate Count + */ +/* UINT8 aucTdlsDisconHistory[TDLS_DISCON_HISTORY_MAX][20]; */ +/* UINT32 u4TdlsDisconIdx; */ +#endif /* CFG_SUPPORT_TDLS */ + UINT_32 IsrCnt; + UINT_32 IsrPassCnt; + UINT_32 TaskIsrCnt; + + UINT_32 IsrPreCnt; + UINT_32 IsrPrePassCnt; + UINT_32 TaskPreIsrCnt; + + UINT_32 IsrAbnormalCnt; + UINT_32 IsrSoftWareCnt; + UINT_32 IsrTxCnt; + UINT_32 IsrRxCnt; + UINT_64 u8SkbToDriver; + UINT_64 u8SkbFreed; +}; + +typedef irqreturn_t(*PFN_WLANISR) (int irq, void *dev_id, struct pt_regs *regs); + +typedef void (*PFN_LINUX_TIMER_FUNC) (unsigned long); + +/* generic sub module init/exit handler +* now, we only have one sub module, p2p +*/ +#if CFG_ENABLE_WIFI_DIRECT +typedef BOOLEAN(*SUB_MODULE_INIT) (P_GLUE_INFO_T prGlueInfo); +typedef BOOLEAN(*SUB_MODULE_EXIT) (P_GLUE_INFO_T prGlueInfo); + +typedef struct _SUB_MODULE_HANDLER { + SUB_MODULE_INIT subModInit; + SUB_MODULE_EXIT subModExit; + BOOLEAN fgIsInited; +} SUB_MODULE_HANDLER, *P_SUB_MODULE_HANDLER; + +#endif + + +#ifdef CONFIG_NL80211_TESTMODE +enum TestModeCmdType { + /* old test mode command id, compatible with exist testmode command */ + TESTMODE_CMD_ID_SW_CMD = 1, + TESTMODE_CMD_ID_WAPI = 2, + TESTMODE_CMD_ID_HS20 = 3, + TESTMODE_CMD_ID_POORLINK = 4, + TESTMODE_CMD_ID_STATISTICS = 0x10, + TESTMODE_CMD_ID_LINK_DETECT = 0x20, + /* old test mode command id, compatible with exist testmode command */ + + /* all new added test mode command should great than TESTMODE_CMD_ID_NEW_BEGIN */ + TESTMODE_CMD_ID_NEW_BEGIN = 100, + TESTMODE_CMD_ID_SUSPEND = 101, +}; +#if CFG_SUPPORT_HOTSPOT_2_0 +enum Hs20CmdType { + HS20_CMD_ID_SET_BSSID_POOL = 0, + NUM_OF_HS20_CMD_ID +}; +#endif + +typedef struct _NL80211_DRIVER_TEST_MODE_PARAMS { + UINT_32 index; + UINT_32 buflen; +} NL80211_DRIVER_TEST_MODE_PARAMS, *P_NL80211_DRIVER_TEST_MODE_PARAMS; + +/*SW CMD */ +typedef struct _NL80211_DRIVER_SW_CMD_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_8 set; + UINT_32 adr; + UINT_32 data; +} NL80211_DRIVER_SW_CMD_PARAMS, *P_NL80211_DRIVER_SW_CMD_PARAMS; + +typedef struct _NL80211_DRIVER_SUSPEND_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_8 suspend; +} NL80211_DRIVER_SUSPEND_PARAMS, *P_NL80211_DRIVER_SUSPEND_PARAMS; +struct iw_encode_exts { + __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 addr[MAC_ADDR_LEN]; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + __u16 alg; /*!< IW_ENCODE_ALG_* */ + __u16 key_len; + __u8 key[32]; +}; + +/*SET KEY EXT */ +typedef struct _NL80211_DRIVER_SET_KEY_EXTS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + UINT_8 key_index; + UINT_8 key_len; + struct iw_encode_exts ext; +} NL80211_DRIVER_SET_KEY_EXTS, *P_NL80211_DRIVER_SET_KEY_EXTS; + +#if CFG_SUPPORT_HOTSPOT_2_0 + +struct param_hs20_set_bssid_pool { + u8 fgBssidPoolIsEnable; + u8 ucNumBssidPool; + u8 arBssidPool[8][ETH_ALEN]; +}; + +struct wpa_driver_hs20_data_s { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + enum Hs20CmdType CmdType; + struct param_hs20_set_bssid_pool hs20_set_bssid_pool; +}; + +#endif /* CFG_SUPPORT_HOTSPOT_2_0 */ + +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Glue Layer */ +/*----------------------------------------------------------------------------*/ +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF +#define GLUE_SPIN_LOCK_DECLARATION() +#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ + } +#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ + } +#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ + spin_lock_bh(prLock) +#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ + spin_unlock_bh(prLock) + +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ +#define GLUE_SPIN_LOCK_DECLARATION() unsigned long __u4Flags = 0 +#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_irqsave(&(prGlueInfo)->rSpinLock[rLockCategory], __u4Flags); \ + } +#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_irqrestore(&(prGlueInfo->rSpinLock[rLockCategory]), __u4Flags); \ + } +#define GLUE_ACQUIRE_THE_SPIN_LOCK(prLock) \ + spin_lock_irqsave(prLock, __u4Flags) +#define GLUE_RELEASE_THE_SPIN_LOCK(prLock) \ + spin_unlock_irqrestore(prLock, __u4Flags) +#endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ +#define GLUE_CB_OFFSET 4 /* For 64-bit platform, avoiding that the cb + isoverwrited by "(prQueueEntry)->prNext = + (P_QUE_ENTRY_T)NULL;" in QUEUE_INSERT_TAIL */ +#define GLUE_GET_PKT_QUEUE_ENTRY(_p) \ + (&(((struct sk_buff *)(_p))->cb[0])) + +#define GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) \ + ((P_NATIVE_PACKET) ((ULONG)_prQueueEntry - offsetof(struct sk_buff, cb[0]))) + +#define GLUE_SET_PKT_FLAG_802_11(_p) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(7)) + +#define GLUE_SET_PKT_FLAG_1X(_p) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(6)) + +#define GLUE_SET_PKT_FLAG_PAL(_p) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(5)) + +#define GLUE_SET_PKT_FLAG_P2P(_p) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= BIT(4)) + +#define GLUE_SET_PKT_TID(_p, _tid) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4])) |= (((UINT_8)((_tid) & (BITS(0, 3)))))) + +#define GLUE_SET_PKT_FRAME_LEN(_p, _u2PayloadLen) \ + (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6])) = (UINT_16)(_u2PayloadLen)) + +#define GLUE_GET_PKT_FRAME_LEN(_p) \ + (*((PUINT_16)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+6]))) + +#define GLUE_GET_PKT_IS_802_11(_p) \ + ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(7))) + +#define GLUE_GET_PKT_IS_1X(_p) \ + ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(6))) + +#define GLUE_GET_PKT_TID(_p) \ + ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BITS(0, 3))) + +#define GLUE_GET_PKT_IS_PAL(_p) \ + ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(5))) + +#define GLUE_GET_PKT_IS_P2P(_p) \ + ((*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+4]))) & (BIT(4))) + +#define GLUE_SET_PKT_HEADER_LEN(_p, _ucMacHeaderLen) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5])) = (UINT_8)(_ucMacHeaderLen)) + +#define GLUE_GET_PKT_HEADER_LEN(_p) \ + (*((PUINT_8)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+5]))) + +#define GLUE_SET_PKT_ARRIVAL_TIME(_p, _rSysTime) \ + (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8])) = (OS_SYSTIME)(_rSysTime)) + +#define GLUE_GET_PKT_ARRIVAL_TIME(_p) \ + (*((POS_SYSTIME)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+8]))) + +#define GLUE_SET_PKT_XTIME(_p, _rSysTime) \ + (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16])) = (UINT_64)(_rSysTime)) + +#define GLUE_GET_PKT_XTIME(_p) \ + (*((UINT_64 *)&(((struct sk_buff *)(_p))->cb[GLUE_CB_OFFSET+16]))) + +/* Check validity of prDev, private data, and pointers */ +#define GLUE_CHK_DEV(prDev) \ + ((prDev && *((P_GLUE_INFO_T *) netdev_priv(prDev))) ? TRUE : FALSE) + +#define GLUE_CHK_PR2(prDev, pr2) \ + ((GLUE_CHK_DEV(prDev) && pr2) ? TRUE : FALSE) + +#define GLUE_CHK_PR3(prDev, pr2, pr3) \ + ((GLUE_CHK_PR2(prDev, pr2) && pr3) ? TRUE : FALSE) + +#define GLUE_CHK_PR4(prDev, pr2, pr3, pr4) \ + ((GLUE_CHK_PR3(prDev, pr2, pr3) && pr4) ? TRUE : FALSE) + +#define GLUE_SET_EVENT(pr) \ + kalSetEvent(pr) + +#define GLUE_INC_REF_CNT(_refCount) atomic_inc((atomic_t *)&(_refCount)) +#define GLUE_DEC_REF_CNT(_refCount) atomic_dec((atomic_t *)&(_refCount)) + +#define DbgPrint(...) +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#ifdef WLAN_INCLUDE_PROC +INT_32 procRemoveProcfs(VOID); + +INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo); +INT_32 procInitFs(VOID); +INT_32 procUninitProcFs(VOID); + +#endif /* WLAN_INCLUDE_PROC */ + +#if CFG_ENABLE_BT_OVER_WIFI +BOOLEAN glRegisterAmpc(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN glUnregisterAmpc(P_GLUE_INFO_T prGlueInfo); +#endif + +#if CFG_ENABLE_WIFI_DIRECT + +VOID wlanSubModRunInit(P_GLUE_INFO_T prGlueInfo); + +VOID wlanSubModRunExit(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN wlanSubModInit(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN wlanSubModExit(P_GLUE_INFO_T prGlueInfo); + +VOID +wlanSubModRegisterInitExit(SUB_MODULE_INIT rSubModInit, SUB_MODULE_EXIT rSubModExit, ENUM_SUB_MODULE_IDX_T eSubModIdx); + +BOOLEAN wlanExportGlueInfo(P_GLUE_INFO_T *prGlueInfoExpAddr); + +BOOLEAN wlanIsLaunched(VOID); + +VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo); + +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_OS_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h new file mode 100644 index 0000000000000..a27294e335003 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_ioctl.h @@ -0,0 +1,743 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_ioctl.h#9 +*/ + +/*! \file gl_p2p_ioctl.h + \brief This file is for custom ioctls for Wi-Fi Direct only +*/ + +/* +** Log: gl_p2p_ioctl.h +** +** 07 26 2012 yuche.tsai +** [ALPS00324337] [ALPS.JB][Hot-Spot] Driver update for Hot-Spot +** Update driver code of ALPS.JB for hot-spot. +** +** 07 19 2012 yuche.tsai +** NULL +** Code update for JB. + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 06 07 2011 yuche.tsai + * [WCXRP00000763] [Volunteer Patch][MT6620][Driver] RX Service Discovery Frame under AP mode Issue + * Fix RX SD request under AP mode issue. + * + * 03 25 2011 wh.su + * NULL + * Fix P2P IOCTL of multicast address bug, add low power driver stop control. + * + * 11 22 2011 yuche.tsai + * NULL + * Update RSSI link quality of P2P Network query method. (Bug fix) + * + * 11 19 2011 yuche.tsai + * NULL + * Add RSSI support for P2P network. + * + * 11 11 2011 yuche.tsai + * NULL + * Fix work thread cancel issue. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service + * discovery version check. + * Add support for driver version query & p2p supplicant verseion set. + * For new service discovery mechanism sync. + * + * 10 25 2011 cm.chang + * [WCXRP00001058] [All Wi-Fi][Driver] Fix sta_rec's phyTypeSet and OBSS scan in AP mode + * . + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 16 2011 chinglan.wang + * NULL + * Add the group id information in the invitation indication. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 05 04 2011 chinglan.wang + * [WCXRP00000698] [MT6620 Wi-Fi][P2P][Driver] Add p2p invitation command for the p2p driver + * . + * + * 03 29 2011 wh.su + * [WCXRP00000095] [MT6620 Wi-Fi] [FW] Refine the P2P GO send broadcast protected code + * add the set power and get power function sample. + * + * 03 22 2011 george.huang + * [WCXRP00000504] [MT6620 Wi-Fi][FW] Support Sigma CAPI for power saving related command + * link with supplicant commands + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 03 01 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * fixed the ioctl sumcmd to meet the p2p_supplicant setting. + * + * 02 23 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int define for p2p parameter. + * + * 02 22 2011 wh.su + * [WCXRP00000488] [MT6620 Wi-Fi][Driver] Support the SIGMA set p2p parameter to driver + * adding the ioctl set int from supplicant, and can used to set the p2p parameters + * + * 02 17 2011 wh.su + * [WCXRP00000448] [MT6620 Wi-Fi][Driver] Fixed WSC IE not send out at probe request + * adjust the set wsc ie structure. + * + * 01 05 2011 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * ioctl implementations for P2P Service Discovery + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * + * 12 15 2010 cp.wu + * NULL + * invoke nicEnableInterrupt() before leaving from wlanAdapterStart() + * + * 12 07 2010 cp.wu + * [WCXRP00000237] [MT6620 Wi-Fi][Wi-Fi Direct][Driver] Add interface for supporting service discovery + * define a pair of i/o control for multiplexing layer + * + * 11 04 2010 wh.su + * [WCXRP00000164] [MT6620 Wi-Fi][Driver] Support the p2p random SSID + * adding the p2p random ssid support. + * + * 10 20 2010 wh.su + * [WCXRP00000124] [MT6620 Wi-Fi] [Driver] Support the dissolve P2P Group + * Add the code to support disconnect p2p group + * + * 09 21 2010 kevin.huang + * [WCXRP00000054] [MT6620 Wi-Fi][Driver] Restructure driver for second Interface + * Isolate P2P related function for Hardware Software Bundle + * + * 09 10 2010 george.huang + * NULL + * update iwpriv LP related + * + * 09 07 2010 wh.su + * NULL + * adding the code for beacon/probe req/ probe rsp wsc ie at p2p. + * + * 08 25 2010 cp.wu + * NULL + * add netdev_ops(NDO) for linux kernel 2.6.31 or greater + * + * 08 20 2010 yuche.tsai + * NULL + * Refine a function parameter name. + * + * 08 19 2010 cp.wu + * NULL + * add set mac address interface for further possibilities of wpa_supplicant overriding interface address. + * + * 08 16 2010 george.huang + * NULL + * add wext handlers to link P2P set PS profile/ network address function (TBD) + * + * 08 16 2010 cp.wu + * NULL + * revised implementation of Wi-Fi Direct io controls. + * + * 08 12 2010 cp.wu + * NULL + * follow-up with ioctl interface update for Wi-Fi Direct application + * + * 08 06 2010 cp.wu + * NULL + * driver hook modifications corresponding to ioctl interface change. + * + * 08 03 2010 cp.wu + * NULL + * [Wi-Fi Direct] add framework for driver hooks + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 06 01 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl to configure scan mode for p2p connection + * + * 05 31 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add cfg80211 interface, which is to replace WE, for further extension + * + * 05 17 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement get scan result. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * implement wireless extension ioctls in iw_handler form. + * + * 05 14 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl framework for Wi-Fi Direct by reusing wireless extension ioctls as well + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * p2p ioctls revised. + * + * 05 11 2010 cp.wu + * [WPD00003831][MT6620 Wi-Fi] Add framework for Wi-Fi Direct support + * add ioctl for controlling p2p scan phase parameters + * +*/ + +#ifndef _GL_P2P_IOCTL_H +#define _GL_P2P_IOCTL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#include +#endif + +#include "wlan_oid.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Device private ioctl calls */ +/* #define SIOCDEVPRIVATE 0x89F0*/ +#define IOC_GET_PRIVATE_IOCTL_CMD (SIOCDEVPRIVATE+1) + +/* (WirelessExtension) Private I/O Controls */ +#define IOC_P2P_CFG_DEVICE (SIOCIWFIRSTPRIV+0) +#define IOC_P2P_PROVISION_COMPLETE (SIOCIWFIRSTPRIV+2) +#define IOC_P2P_START_STOP_DISCOVERY (SIOCIWFIRSTPRIV+4) +#define IOC_P2P_DISCOVERY_RESULTS (SIOCIWFIRSTPRIV+5) +#define IOC_P2P_WSC_BEACON_PROBE_RSP_IE (SIOCIWFIRSTPRIV+6) +#define IOC_P2P_GO_WSC_IE IOC_P2P_WSC_BEACON_PROBE_RSP_IE +#define IOC_P2P_CONNECT_DISCONNECT (SIOCIWFIRSTPRIV+8) +#define IOC_P2P_PASSWORD_READY (SIOCIWFIRSTPRIV+10) +/* #define IOC_P2P_SET_PWR_MGMT_PARAM (SIOCIWFIRSTPRIV+12) */ +#define IOC_P2P_SET_INT (SIOCIWFIRSTPRIV+12) +#define IOC_P2P_GET_STRUCT (SIOCIWFIRSTPRIV+13) +#define IOC_P2P_SET_STRUCT (SIOCIWFIRSTPRIV+14) +#define IOC_P2P_GET_REQ_DEVICE_INFO (SIOCIWFIRSTPRIV+15) + +#define PRIV_CMD_INT_P2P_SET 0 + +/* IOC_P2P_PROVISION_COMPLETE (iw_point . flags) */ +#define P2P_PROVISIONING_SUCCESS 0 +#define P2P_PROVISIONING_FAIL 1 + +/* IOC_P2P_START_STOP_DISCOVERY (iw_point . flags) */ +#define P2P_STOP_DISCOVERY 0 +#define P2P_START_DISCOVERY 1 + +/* IOC_P2P_CONNECT_DISCONNECT (iw_point . flags) */ +#define P2P_CONNECT 0 +#define P2P_DISCONNECT 1 + +/* IOC_P2P_START_STOP_DISCOVERY (scan_type) */ +#define P2P_SCAN_FULL_AND_FIND 0 +#define P2P_SCAN_FULL 1 +#define P2P_SCAN_SEARCH_AND_LISTEN 2 +#define P2P_LISTEN 3 + +/* IOC_P2P_GET_STRUCT/IOC_P2P_SET_STRUCT */ +#define P2P_SEND_SD_RESPONSE 0 +#define P2P_GET_SD_REQUEST 1 +#define P2P_SEND_SD_REQUEST 2 +#define P2P_GET_SD_RESPONSE 3 +#define P2P_TERMINATE_SD_PHASE 4 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/*----------------------------------------------------------------------------*/ +/* Wireless Extension: Private I/O Control */ +/*----------------------------------------------------------------------------*/ +typedef struct iw_p2p_cfg_device_type { + void __user *ssid; + UINT_8 ssid_len; + UINT_8 pri_device_type[8]; + UINT_8 snd_device_type[8]; + void __user *device_name; + UINT_8 device_name_len; + UINT_8 intend; + UINT_8 persistence; + UINT_8 sec_mode; + UINT_8 ch; + UINT_8 ch_width; /* 0: 20 Mhz 1:20/40 Mhz auto */ + UINT_8 max_scb; +} IW_P2P_CFG_DEVICE_TYPE, *P_IW_P2P_CFG_DEVICE_TYPE; + +typedef struct iw_p2p_hostapd_param { + UINT_8 cmd; + UINT_8 rsv[3]; + UINT_8 sta_addr[6]; + void __user *data; + UINT_16 len; +} IW_P2P_HOSTAPD_PARAM, *P_IW_P2P_HOSTAPD_PARAM; + +typedef struct iw_p2p_req_device_type { + UINT_8 scan_type; /* 0: Full scan + Find + * 1: Full scan + * 2: Scan (Search +Listen) + * 3: Listen + * other : reserved + */ + UINT_8 pri_device_type[8]; + void __user *probe_req_ie; + UINT_16 probe_req_len; + void __user *probe_rsp_ie; + UINT_16 probe_rsp_len; +} IW_P2P_REQ_DEVICE_TYPE, *P_IW_P2P_REQ_DEVICE_TYPE; + +typedef struct iw_p2p_connect_device { + UINT_8 sta_addr[6]; + UINT_8 p2pRole; /* 0: P2P Device, 1:GC, 2: GO */ + UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ + UINT_8 authPeer; /* 1: auth peer invitation request */ + UINT_8 intend_config_method; /* Request Peer Device used config method */ +} IW_P2P_CONNECT_DEVICE, *P_IW_P2P_CONNECT_DEVICE; + +typedef struct iw_p2p_password_ready { + UINT_8 active_config_method; + void __user *probe_req_ie; + UINT_16 probe_req_len; + void __user *probe_rsp_ie; + UINT_16 probe_rsp_len; +} IW_P2P_PASSWORD_READY, *P_IW_P2P_PASSWORD_READY; + +typedef struct iw_p2p_device_req { + UINT_8 name[33]; + UINT_32 name_len; + UINT_8 device_addr[6]; + UINT_8 device_type; + INT_32 config_method; + INT_32 active_config_method; +} IW_P2P_DEVICE_REQ, *P_IW_P2P_DEVICE_REQ; + +typedef struct iw_p2p_transport_struct { + UINT_32 u4CmdId; + UINT_32 inBufferLength; + UINT_32 outBufferLength; + UINT_8 aucBuffer[16]; +} IW_P2P_TRANSPORT_STRUCT, *P_IW_P2P_TRANSPORT_STRUCT; + +/* For Invitation */ +typedef struct iw_p2p_ioctl_invitation_struct { + UINT_8 aucDeviceID[6]; + UINT_8 aucGroupID[6]; /* BSSID */ + UINT_8 aucSsid[32]; + UINT_32 u4SsidLen; + UINT_8 ucReinvoke; +} IW_P2P_IOCTL_INVITATION_STRUCT, *P_IW_P2P_IOCTL_INVITATION_STRUCT; + +typedef struct iw_p2p_ioctl_abort_invitation { + UINT_8 dev_addr[6]; +} IW_P2P_IOCTL_ABORT_INVITATION, *P_IW_P2P_IOCTL_ABORT_INVITATION; + +typedef struct iw_p2p_ioctl_invitation_indicate { + UINT_8 dev_addr[6]; + UINT_8 group_bssid[6]; + INT_32 config_method; /* peer device supported config method */ + UINT_8 dev_name[32]; /* for reinvoke */ + UINT_32 name_len; + UINT_8 operating_channel; /* for re-invoke, target operating channel */ + UINT_8 invitation_type; /* invitation or re-invoke */ +} IW_P2P_IOCTL_INVITATION_INDICATE, *P_IW_P2P_IOCTL_INVITATION_INDICATE; + +typedef struct iw_p2p_ioctl_invitation_status { + UINT_32 status_code; +} IW_P2P_IOCTL_INVITATION_STATUS, *P_IW_P2P_IOCTL_INVITATION_STATUS; + +/* For Formation */ +typedef struct iw_p2p_ioctl_start_formation { + UINT_8 dev_addr[6]; /* bssid */ + UINT_8 role; /* 0: P2P Device, 1:GC, 2: GO */ + UINT_8 needProvision; /* 0: Don't needed provision, 1: doing the wsc provision first */ + UINT_8 auth; /* 1: auth peer invitation request */ + UINT_8 config_method; /* Request Peer Device used config method */ +} IW_P2P_IOCTL_START_FORMATION, *P_IW_P2P_IOCTL_START_FORMATION; + +/* SET_STRUCT / GET_STRUCT */ +typedef enum _ENUM_P2P_CMD_ID_T { + P2P_CMD_ID_SEND_SD_RESPONSE = 0, /* 0x00 (Set) */ + P2P_CMD_ID_GET_SD_REQUEST, /* 0x01 (Get) */ + P2P_CMD_ID_SEND_SD_REQUEST, /* 0x02 (Set) */ + P2P_CMD_ID_GET_SD_RESPONSE, /* 0x03 (Get) */ + P2P_CMD_ID_TERMINATE_SD_PHASE, /* 0x04 (Set) */ +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + P2P_CMD_ID_SEC_CHECK, /* 0x05(Set) */ +#endif + P2P_CMD_ID_INVITATION, /* 0x06 (Set) */ + P2P_CMD_ID_INVITATION_INDICATE, /* 0x07 (Get) */ + P2P_CMD_ID_INVITATION_STATUS, /* 0x08 (Get) */ + P2P_CMD_ID_INVITATION_ABORT, /* 0x09 (Set) */ + P2P_CMD_ID_START_FORMATION, /* 0x0A (Set) */ + P2P_CMD_ID_P2P_VERSION, /* 0x0B (Set/Get) */ + P2P_CMD_ID_GET_CH_LIST = 12, /* 0x0C (Get) */ + P2P_CMD_ID_GET_OP_CH = 14 /* 0x0E (Get) */ +} ENUM_P2P_CMD_ID_T, *P_ENUM_P2P_CMD_ID_T; + +/* Service Discovery */ +typedef struct iw_p2p_cmd_send_sd_response { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucSeqNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_SEND_SD_RESPONSE, *P_IW_P2P_CMD_SEND_SD_RESPONSE; + +typedef struct iw_p2p_cmd_get_sd_request { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_GET_SD_REQUEST, *P_IW_P2P_CMD_GET_SD_REQUEST; + +typedef struct iw_p2p_cmd_send_service_discovery_request { + PARAM_MAC_ADDRESS rReceiverAddr; + UINT_8 fgNeedTxDoneIndication; + UINT_8 ucSeqNum; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_SEND_SD_REQUEST, *P_IW_P2P_CMD_SEND_SD_REQUEST; + +typedef struct iw_p2p_cmd_get_sd_response { + PARAM_MAC_ADDRESS rTransmitterAddr; + UINT_16 u2PacketLength; + UINT_8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_GET_SD_RESPONSE, *P_IW_P2P_CMD_GET_SD_RESPONSE; + +typedef struct iw_p2p_cmd_terminate_sd_phase { + PARAM_MAC_ADDRESS rPeerAddr; +} IW_P2P_CMD_TERMINATE_SD_PHASE, *P_IW_P2P_CMD_TERMINATE_SD_PHASE; + +typedef struct iw_p2p_version { + UINT_32 u4Version; +} IW_P2P_VERSION, *P_IW_P2P_VERSION; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +extern struct ieee80211_supported_band mtk_band_2ghz; +extern struct ieee80211_supported_band mtk_band_5ghz; +extern UINT_32 mtk_cipher_suites[5]; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +int mtk_p2p_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type,/* u32 *flags,*/ struct vif_params *params); + +int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); + +int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback) (void *cookie, struct key_params *) +); + +int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr); + +int +mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, u8 key_index, bool unicast, bool multicast); + +int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo); + +int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); + +int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); + +int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code); + +int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); + +int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev); + +int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); + +int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params); + +int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, unsigned int duration, u64 *cookie); + +int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); + +int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie); + +int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm); + +int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); + +int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req); + +int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req); + +int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings); + +int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); + +int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); + +int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev); + +int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params); +//int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac); + +int mtk_p2p_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef); + +void mtk_p2p_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg); + +int +mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, + IN struct net_device *dev, + IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask); + +#ifdef CONFIG_NL80211_TESTMODE +int mtk_p2p_cfg80211_testmode_cmd(IN struct wiphy *wiphy, IN struct wireless_dev *wdev, IN void *data, IN int len); +int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); + +#if CFG_SUPPORT_WFD +int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +#endif + +int mtk_p2p_cfg80211_testmode_hotspot_block_cmd(IN struct wiphy *wiphy, IN void *data, IN int len); +#else +#error "Please ENABLE kernel config (CONFIG_NL80211_TESTMODE) to support Wi-Fi Direct" +#endif + +#endif + +/* I/O control handlers */ + +int +mtk_p2p_wext_get_priv(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_reconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_auth(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_key(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_powermode(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_get_powermode(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +/* Private Wireless I/O Controls takes use of iw_handler */ +int +mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_discovery_results(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_password_ready(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_invitation_status(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_network_address(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_int(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +/* Private Wireless I/O Controls for IOC_SET_STRUCT/IOC_GET_STRUCT */ +int +mtk_p2p_wext_set_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_get_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +/* IOC_SET_STRUCT/IOC_GET_STRUCT: Service Discovery */ +int +mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +#if CFG_SUPPORT_ANTI_PIRACY +int +mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); +#endif + +int +mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +int +mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +void mtk_p2p_wext_set_Multicastlist(IN P_GLUE_INFO_T prGlueInfo); + +#if CFG_SUPPORT_P2P_RSSI_QUERY +int +mtk_p2p_wext_get_rssi(IN struct net_device *prDev, + IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra); + +struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev); + +#endif + +int +mtk_p2p_wext_set_txpow(IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, IN OUT union iwreq_data *prTxPow, IN char *pcExtra); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_P2P_IOCTL_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h new file mode 100644 index 0000000000000..bf9d8871ef48a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_kal.h @@ -0,0 +1,243 @@ +/* +** Id: //Department/DaVinci/TRUNK/WiFi_P2P_Driver/os/linux/include/gl_p2p_kal.h#2 +*/ + +/*! \file gl_p2p_kal.h + \brief Declaration of KAL functions for Wi-Fi Direct support + - kal*() which is provided by GLUE Layer. + + Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/* +** Log: gl_p2p_kal.h +** +** 08 30 2012 chinglan.wang +** [ALPS00349664] [6577JB][WIFI] Phone can not connect to AP secured with AES via WPS in 802.11n Only +** . + * + * 07 17 2012 yuche.tsai + * NULL + * Compile no error before trial run. + * + * 10 18 2011 yuche.tsai + * [WCXRP00001045] [WiFi Direct][Driver] Check 2.1 branch. + * New 2.1 branch + + * + * 08 15 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Add group BSSID in invitation request indication. + * The BSSID is used for APP to decide the configure method. + * + * 08 09 2011 yuche.tsai + * [WCXRP00000919] [Volunteer Patch][WiFi Direct][Driver] Invitation New Feature. + * Invitation Feature add on. + * + * 03 19 2011 terry.wu + * [WCXRP00000577] [MT6620 Wi-Fi][Driver][FW] Create V2.0 branch for firmware and driver + * create V2.0 p2p driver release based on label "MT6620_WIFI_P2P_DRIVER_V2_0_2100_0319_2011" from main trunk. + * + * 03 07 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * rename the define to anti_pviracy. + * + * 03 05 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * add the code to get the check rsponse and indicate to app. + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add Security check related code. + * + * 12 22 2010 cp.wu + * [WCXRP00000283] [MT6620 Wi-Fi][Driver][Wi-Fi Direct] Implementation of interface for supporting Wi-Fi Direct Service + * Discovery + * 1. header file restructure for more clear module isolation + * 2. add function interface definition for implementing Service Discovery callbacks + * +*/ + +#ifndef _GL_P2P_KAL_H +#define _GL_P2P_KAL_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_p2p.h" +#include "gl_kal.h" +#include "gl_wext_priv.h" +#include "nic/p2p.h" + +#if DBG +extern int allocatedMemSize; +#endif + +extern BOOLEAN +wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); + +#if CFG_SUPPORT_WPS +extern BOOLEAN +wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT unsigned char **ppucDesiredIE); +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type); +struct ieee80211_channel *kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, IN P_RF_CHANNEL_INFO_T prChannelInfo); + +/* Service Discovery */ +VOID kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); + +void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucSeqNum); + +VOID kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucSeqNum, IN UINT_8 ucStatus); + +/*----------------------------------------------------------------------------*/ +/* Wi-Fi Direct handling */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo); + +VOID +kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucRole); + +VOID +kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest); + +UINT_32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo); + +UINT_8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo); + +VOID +kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_8 ucResult, IN PUINT_8 pucSSID, IN UINT_8 ucSSIDLen, IN UINT_8 ucRole); + +VOID kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Cipher); + +BOOLEAN kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo); + +BOOLEAN kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo); + +BOOLEAN kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucWscMode); + +UINT_8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo); + +UINT_16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType); + +VOID kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer); + +VOID kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucType, IN PUINT_8 pucBuffer, IN UINT_16 u2BufferLength); + +BOOLEAN kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo); + +VOID kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucDevName, IN INT_32 u4NameLength, + IN PARAM_MAC_ADDRESS rPeerAddr, IN UINT_8 ucDevType, /* 0: P2P Device / 1: GC / 2: GO */ + IN INT_32 i4ConfigMethod, IN INT_32 i4ActiveConfigMethod); + +VOID kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4InvStatus); + +VOID +kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_DEVICE_DESC_T prP2pDevDesc, + IN PUINT_8 pucSsid, + IN UINT_8 ucSsidLen, + IN UINT_8 ucOperatingChnl, IN UINT_8 ucInvitationType, IN PUINT_8 pucGroupBssid); + +struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo); + +VOID +kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN UINT_8 ucMaxChannelNum, IN PUINT_8 pucNumOfChannel, IN P_RF_CHANNEL_INFO_T paucChannelList); + +#if CFG_SUPPORT_ANTI_PIRACY +VOID kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucRsp, IN UINT_16 u2RspLen); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID +kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8SeqNum, + IN UINT_32 u4ChannelNum, + IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, IN UINT_32 u4Duration); + +VOID kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN BOOLEAN fgIsAbort); + +VOID +kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN PUINT_8 pucFrameBuf, + IN UINT_32 u4BufLen, IN P_RF_CHANNEL_INFO_T prChannelInfo, IN INT_32 i4SignalStrength); + +VOID kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); + +VOID +kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN UINT_64 u8Cookie, IN BOOLEAN fgIsAck, IN PUINT_8 pucFrameBuf, IN UINT_32 u4FrameLen); + +VOID kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +VOID +kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, + IN PUINT_8 pucRxIEBuf, IN UINT_16 u2RxIELen, IN UINT_16 u2StatusReason, + IN WLAN_STATUS eStatus); + +VOID kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew); + +INT_32 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock); + +BOOLEAN kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid); + +VOID kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4MaxClient); + +BOOLEAN kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4NumClient); + +#endif /* _GL_P2P_KAL_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h new file mode 100644 index 0000000000000..e5026e7e6eec5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_p2p_os.h @@ -0,0 +1,242 @@ +/* +** Id: +//Department/DaVinci/TRUNK/MT6620_5931_WiFi_Driver/os/linux/include/gl_p2p_os.h#28 +*/ + +/*! \file gl_p2p_os.h + \brief List the external reference to OS for p2p GLUE Layer. + + In this file we define the data structure - GLUE_INFO_T to store those objects + we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all the + external reference (header file, extern func() ..) to OS for GLUE Layer should + also list down here. +*/ + +#ifndef _GL_P2P_OS_H +#define _GL_P2P_OS_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include +#endif + +#include "wlan_oid.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +struct _GL_P2P_INFO_T { + + /* Device handle */ + struct net_device *prDevHandler; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* cfg80211 */ + struct wireless_dev *prWdev; + + struct cfg80211_scan_request *prScanRequest; + + UINT_64 u8Cookie; + + /* Generation for station list update. */ + INT_32 i4Generation; + + UINT_32 u4OsMgmtFrameFilter; + +#endif + + /* Device statistics */ + struct net_device_stats rNetDevStats; + + /* glue layer variables */ + UINT_32 u4FreqInKHz; /* frequency */ + UINT_8 ucRole; /* 0: P2P Device, 1: Group Client, 2: Group Owner */ + UINT_8 ucIntent; /* range: 0-15 */ + UINT_8 ucScanMode; /* 0: Search & Listen, 1: Scan without probe response */ + + ENUM_PARAM_MEDIA_STATE_T eState; + UINT_32 u4PacketFilter; + PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR]; + + /* connection-requested peer information */ + UINT_8 aucConnReqDevName[32]; + INT_32 u4ConnReqNameLength; + PARAM_MAC_ADDRESS rConnReqPeerAddr; + PARAM_MAC_ADDRESS rConnReqGroupAddr; /* For invitation group. */ + UINT_8 ucConnReqDevType; + INT_32 i4ConnReqConfigMethod; + INT_32 i4ConnReqActiveConfigMethod; + + UINT_32 u4CipherPairwise; + UINT_8 ucWSCRunning; + + UINT_8 aucWSCIE[3][400]; /* 0 for beacon, 1 for probe req, 2 for probe response */ + UINT_16 u2WSCIELen[3]; + +#if CFG_SUPPORT_WFD + UINT_8 aucVenderIE[1024]; /* Save the other IE for prove resp */ + UINT_16 u2VenderIELen; +#endif + + UINT_8 ucOperatingChnl; + UINT_8 ucInvitationType; + + UINT_32 u4InvStatus; + + /* For SET_STRUCT/GET_STRUCT */ + UINT_8 aucOidBuf[4096]; + +#if 1 /* CFG_SUPPORT_ANTI_PIRACY */ + UINT_8 aucSecCheck[256]; + UINT_8 aucSecCheckRsp[256]; +#endif + + /* Hotspot Client Management */ + PARAM_MAC_ADDRESS aucblackMACList[8]; + UINT_8 ucMaxClients; + +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + UINT_32 u4PsLevel; +#endif +}; + +#ifdef CONFIG_NL80211_TESTMODE +typedef struct _NL80211_DRIVER_TEST_PRE_PARAMS { + UINT_16 idx_mode; + UINT_16 idx; + UINT_32 value; +} NL80211_DRIVER_TEST_PRE_PARAMS, *P_NL80211_DRIVER_TEST_PRE_PARAMS; + +typedef struct _NL80211_DRIVER_TEST_PARAMS { + UINT_32 index; + UINT_32 buflen; +} NL80211_DRIVER_TEST_PARAMS, *P_NL80211_DRIVER_TEST_PARAMS; + +/* P2P Sigma*/ +typedef struct _NL80211_DRIVER_P2P_SIGMA_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + UINT_32 idx; + UINT_32 value; +} NL80211_DRIVER_P2P_SIGMA_PARAMS, *P_NL80211_DRIVER_P2P_SIGMA_PARAMS; + +/* Hotspot Client Management */ +typedef struct _NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + UINT_8 ucblocked; + UINT_8 aucBssid[MAC_ADDR_LEN]; +} NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS, *P_NL80211_DRIVER_HOTSPOT_BLOCK_PARAMS; + +#if CFG_SUPPORT_WFD +typedef struct _NL80211_DRIVER_WFD_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + UINT_32 WfdCmdType; + UINT_8 WfdEnable; + UINT_8 WfdCoupleSinkStatus; + UINT_8 WfdSessionAvailable; + UINT_8 WfdSigmaMode; + UINT_16 WfdDevInfo; + UINT_16 WfdControlPort; + UINT_16 WfdMaximumTp; + UINT_16 WfdExtendCap; + UINT_8 WfdCoupleSinkAddress[MAC_ADDR_LEN]; + UINT_8 WfdAssociatedBssid[MAC_ADDR_LEN]; + UINT_8 WfdVideoIp[4]; + UINT_8 WfdAudioIp[4]; + UINT_16 WfdVideoPort; + UINT_16 WfdAudioPort; + UINT_32 WfdFlag; + UINT_32 WfdPolicy; + UINT_32 WfdState; + UINT_8 WfdSessionInformationIE[24 * 8]; /* Include Subelement ID, length */ + UINT_16 WfdSessionInformationIELen; + UINT_8 aucReserved1[2]; + UINT_8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; + UINT_8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; + UINT_32 WfdAdvanceFlag; + /* Group 1 64 bytes */ + UINT_8 aucWfdLocalIp[4]; + UINT_16 WfdLifetimeAc2; /* Unit is 2 TU */ + UINT_16 WfdLifetimeAc3; /* Unit is 2 TU */ + UINT_16 WfdCounterThreshold; /* Unit is ms */ + UINT_8 aucReserved2[54]; + /* Group 3 64 bytes */ + UINT_8 aucReserved3[64]; + /* Group 3 64 bytes */ + UINT_8 aucReserved4[64]; +} NL80211_DRIVER_WFD_PARAMS, *P_NL80211_DRIVER_WFD_PARAMS; +#endif +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +BOOLEAN p2pLaunch(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN p2pRemove(P_GLUE_INFO_T prGlueInfo); + +VOID p2pSetMode(IN BOOLEAN fgIsAPMOde); + +BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, BOOLEAN fgIsApMode); + +VOID p2pEalySuspendReg(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsEnable); + +BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); + +BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired); + +BOOLEAN p2pStopImmediate(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo); + +BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo); + +VOID glP2pDestroyWirelessDevice(VOID); + +VOID p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h new file mode 100644 index 0000000000000..f24ceee9e921a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_rst.h @@ -0,0 +1,133 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_rst.h#1 +*/ + +/*! \file gl_rst.h + \brief Declaration of functions and finite state machine for + MT6620 Whole-Chip Reset Mechanism +*/ + +#ifndef _GL_RST_H +#define _GL_RST_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "gl_typedef.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if 1 +typedef INT_32(*wmt_wlan_probe_cb) (VOID); +typedef INT_32(*wmt_wlan_remove_cb) (VOID); +typedef INT_32(*wmt_wlan_bus_cnt_get_cb) (VOID); +typedef INT_32(*wmt_wlan_bus_cnt_clr_cb) (VOID); + +typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { + wmt_wlan_probe_cb wlan_probe_cb; + wmt_wlan_remove_cb wlan_remove_cb; + wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; + wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; +} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; + +extern INT_32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); +extern INT_32 mtk_wcn_wmt_wlan_unreg(VOID); +#endif + +typedef enum _ENUM_RESET_STATUS_T { + RESET_FAIL, + RESET_SUCCESS +} ENUM_RESET_STATUS_T; + +typedef struct _RESET_STRUCT_T { + ENUM_RESET_STATUS_T rst_data; + struct work_struct rst_work; +} RESET_STRUCT_T; + +typedef enum _ENUM_WMTRSTMSG_TYPE_T { + WMTRSTMSG_RESET_START = 0x0, + WMTRSTMSG_RESET_END = 0x1, + WMTRSTMSG_RESET_END_FAIL = 0x2, + WMTRSTMSG_RESET_MAX, + WMTRSTMSG_RESET_INVALID = 0xff +} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; + +typedef void (*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + void *, /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. Client + can't touch this buffer after this function return. */ + unsigned int /* Buffer size in unit of byte */ +); + +/******************************************************************************* +* E X T E R N A L F U N C T I O N S +******************************************************************************** +*/ +#define glDoChipReset() \ + do { \ + if (!kalStrnCmp(current->comm, "mtk_wmtd", 8)) { \ + g_IsNeedDoChipReset = 1; \ + DBGLOG(INIT, ERROR, "forbid core dump in mtk_wmtd %s line %d\n", __func__, __LINE__); \ + break; \ + } \ + DBGLOG(INIT, ERROR, "Do core dump and chip reset in %s line %d\n", __func__, __LINE__); \ + mtk_wcn_wmt_assert(WMTDRV_TYPE_WIFI, 0x40); \ + } while (0) + +#if CFG_CHIP_RESET_SUPPORT +extern int mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); +extern int mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); +extern int wifi_reset_start(void); +extern int wifi_reset_end(ENUM_RESET_STATUS_T); +#endif +extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); +extern BOOLEAN mtk_wcn_set_connsys_power_off_flag(BOOLEAN value); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern UINT_32 g_IsNeedDoChipReset; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +VOID glResetInit(VOID); + +VOID glResetUninit(VOID); + +VOID glSendResetRequest(VOID); + +BOOLEAN kalIsResetting(VOID); + +#endif /* _GL_RST_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h new file mode 100644 index 0000000000000..3cc57780f2010 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_sec.h @@ -0,0 +1,21 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_sec.h#1 +*/ + +/*! \file p2p_fsm.h + \brief Declaration of functions and finite state machine for P2P Module. + + Declaration of functions and finite state machine for P2P Module. +*/ + +#ifndef _GL_SEC_H +#define _GL_SEC_H + +extern void handle_sec_msg_1(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_2(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_3(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_4(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_5(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); +extern void handle_sec_msg_final(unsigned char *msg_in, int msg_in_len, unsigned char *msg_out, int *msg_out_len); + +#endif /* _GL_SEC_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h new file mode 100644 index 0000000000000..e9aa3e849eb2e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_typedef.h @@ -0,0 +1,298 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_typedef.h#1 +*/ + +/*! \file gl_typedef.h + \brief Definition of basic data type(os dependent). + + In this file we define the basic data type. +*/ + +/* +** Log: gl_typedef.h + * + * 06 22 2012 cp.wu + * [WCXRP00001257] [MT6620][MT5931][MT6628][Driver][Linux] Modify KAL_HZ to align ms accuracy + * modify KAL_HZ to (1000) for correct definition. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * portability improvement + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\6 2009-08-18 22:57:14 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\5 2008-09-22 23:19:30 GMT mtk01461 +** Update comment for code review +** \main\maintrunk.MT5921\4 2008-09-05 17:25:16 GMT mtk01461 +** Update Driver for Code Review +** \main\maintrunk.MT5921\3 2007-11-09 11:00:50 GMT mtk01425 +** 1. Use macro to unify network-to-host and host-to-network related functions +** Revision 1.3 2007/06/27 02:18:51 MTK01461 +** Update SCAN_FSM, Initial(Can Load Module), Proc(Can do Reg R/W), TX API +** +** Revision 1.2 2007/06/25 06:16:24 MTK01461 +** Update illustrations, gl_init.c, gl_kal.c, gl_kal.h, gl_os.h and RX API +** +*/ + +#ifndef _GL_TYPEDEF_H +#define _GL_TYPEDEF_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Define HZ of timer tick for function kalGetTimeTick() */ +#define KAL_HZ (1000) + +/* Miscellaneous Equates */ +#ifndef FALSE +#define FALSE ((BOOLEAN) 0) +#define TRUE ((BOOLEAN) 1) +#endif /* FALSE */ + +#ifndef NULL +#if defined(__cplusplus) +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* Type definition for void */ +/*mach/mt_typedefs.h define _TYPEDEFS_H, to avoid compile error*/ +#ifndef _TYPEDEFS_H +typedef void VOID; +#endif +typedef void *PVOID, **PPVOID; + +/* Type definition for Boolean */ +typedef unsigned char BOOLEAN, *PBOOLEAN; + +/* Type definition for signed integers */ +typedef signed char CHAR, *PCHAR, **PPCHAR; +typedef signed char INT_8, *PINT_8, **PPINT_8; +typedef signed short INT_16, *PINT_16, **PPINT_16; +typedef signed int INT_32, *PINT_32, **PPINT_32; +typedef long LONG, *PLONG, **PPLONG; +typedef signed long long INT_64, *PINT_64, **PPINT_64; + +/* Type definition for unsigned integers */ +typedef unsigned char UCHAR, *PUCHAR, **PPUCHAR; +typedef unsigned char UINT_8, *PUINT_8, **PPUINT_8, *P_UINT_8; +typedef unsigned short UINT_16, *PUINT_16, **PPUINT_16; +typedef unsigned int UINT32, *PUINT32; +typedef unsigned int UINT_32, *PUINT_32, **PPUINT_32; +typedef unsigned long ULONG, *PULONG, **PPULONG; +typedef unsigned long long UINT_64, *PUINT_64, **PPUINT_64; + +typedef unsigned int OS_SYSTIME, *POS_SYSTIME, **PPOS_SYSTIME; + +#ifndef _TYPEDEFS_H +typedef signed char INT8, *PINT8; +typedef signed short INT16, *PINT16; +typedef signed int INT32, *PINT32; +typedef unsigned char UINT8, *PUINT8; +typedef unsigned short UINT16, *PUINT16; +typedef unsigned int UINT32, *PUINT32; +#endif + +/* Type definition of large integer (64bits) union to be comptaible with + * Windows definition, so we won't apply our own coding style to these data types. + * NOTE: LARGE_INTEGER must NOT be floating variable. + * : Check for big-endian compatibility. + */ +typedef union _LARGE_INTEGER { + struct { + UINT_32 LowPart; + INT_32 HighPart; + } u; + INT_64 QuadPart; +} LARGE_INTEGER, *PLARGE_INTEGER; + +typedef union _ULARGE_INTEGER { + struct { + UINT_32 LowPart; + UINT_32 HighPart; + } u; + UINT_64 QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; + +typedef INT_32(*probe_card) (PVOID pvData); +typedef VOID(*remove_card) (VOID); + +/* duplicated from wmt_exp.h for better driver isolation */ +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_STP = 5, + WMTDRV_TYPE_SDIO1 = 6, + WMTDRV_TYPE_SDIO2 = 7, + WMTDRV_TYPE_LPBK = 8, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY = 3, + WMTMSG_TYPE_HW_FUNC_ON = 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define IN /* volatile */ +#define OUT /* volatile */ + +#define __KAL_ATTRIB_PACKED__ __attribute__((__packed__)) +#define __KAL_ATTRIB_ALIGN_4__ __aligned(4) + +#ifndef BIT +#define BIT(n) ((UINT_32) 1U << (n)) +#endif /* BIT */ + +#ifndef BITS +/* bits range: for example BITS(16,23) = 0xFF0000 + * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 + * ==> (BIT(n+1)-1) = 0x00FFFFFF + */ +#define BITS(m, n) (~(BIT(m)-1) & ((BIT(n) - 1) | BIT(n))) +#endif /* BIT */ + +/* This macro returns the byte offset of a named field in a known structure + type. + _type - structure name, + _field - field name of the structure */ +#ifndef OFFSET_OF +#define OFFSET_OF(_type, _field) ((ULONG)&(((_type *)0)->_field)) +#endif /* OFFSET_OF */ + +/* This macro returns the base address of an instance of a structure + * given the type of the structure and the address of a field within the + * containing structure. + * _addrOfField - address of current field of the structure, + * _type - structure name, + * _field - field name of the structure + */ +#ifndef ENTRY_OF +#define ENTRY_OF(_addrOfField, _type, _field) \ + ((_type *)((PINT_8)(_addrOfField) - (PINT_8)OFFSET_OF(_type, _field))) +#endif /* ENTRY_OF */ + +/* This macro align the input value to the DW boundary. + * _value - value need to check + */ +#ifndef ALIGN_4 +#define ALIGN_4(_value) (((_value) + 3) & ~3u) +#endif /* ALIGN_4 */ + +/* This macro check the DW alignment of the input value. + * _value - value of address need to check + */ +#ifndef IS_ALIGN_4 +#define IS_ALIGN_4(_value) (((_value) & 0x3) ? FALSE : TRUE) +#endif /* IS_ALIGN_4 */ + +#ifndef IS_NOT_ALIGN_4 +#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? TRUE : FALSE) +#endif /* IS_NOT_ALIGN_4 */ + +/* This macro evaluate the input length in unit of Double Word(4 Bytes). + * _value - value in unit of Byte, output will round up to DW boundary. + */ +#ifndef BYTE_TO_DWORD +#define BYTE_TO_DWORD(_value) ((_value + 3) >> 2) +#endif /* BYTE_TO_DWORD */ + +/* This macro evaluate the input length in unit of Byte. + * _value - value in unit of DW, output is in unit of Byte. + */ +#ifndef DWORD_TO_BYTE +#define DWORD_TO_BYTE(_value) ((_value) << 2) +#endif /* DWORD_TO_BYTE */ + +#if 1 /* Little-Endian */ +#define CONST_NTOHS(_x) ntohs(_x) + +#define CONST_HTONS(_x) htons(_x) + +#define NTOHS(_x) ntohs(_x) + +#define HTONS(_x) htons(_x) + +#define NTOHL(_x) ntohl(_x) + +#define HTONL(_x) htonl(_x) + +#else /* Big-Endian */ + +#define CONST_NTOHS(_x) + +#define CONST_HTONS(_x) + +#define NTOHS(_x) + +#define HTONS(_x) + +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_TYPEDEF_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h new file mode 100644 index 0000000000000..d8d5b0fb67402 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_vendor.h @@ -0,0 +1,619 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_vendor.h#1 +*/ + +/*! \file gl_vendor.h + \brief This file is for Portable Driver linux gl_vendor support. +*/ + +/* +** Log: gl_vendor.h +** +** 10 14 2014 +** add vendor declaration +** + * +*/ + +#ifndef _GL_VENDOR_H +#define _GL_VENDOR_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "gl_os.h" + +#include "wlan_lib.h" +#include "gl_wext.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define GOOGLE_OUI 0x001A11 + +typedef enum { + /* Don't use 0 as a valid subcommand */ + ANDROID_NL80211_SUBCMD_UNSPECIFIED, + + /* Define all vendor startup commands between 0x0 and 0x0FFF */ + ANDROID_NL80211_SUBCMD_WIFI_RANGE_START = 0x0001, + ANDROID_NL80211_SUBCMD_WIFI_RANGE_END = 0x0FFF, + + /* Define all GScan related commands between 0x1000 and 0x10FF */ + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, + ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, + + /* Define all RTT related commands between 0x1100 and 0x11FF */ + ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, + ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, + + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, + ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, + + /* Define all Logger related commands between 0x1400 and 0x14FF */ + ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400, + ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF, + + /* Define all wifi offload related commands between 0x1600 and 0x16FF */ + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, + ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, + + /* This is reserved for future usage */ + +} ANDROID_VENDOR_SUB_COMMAND; + +typedef enum { + WIFI_SUBCMD_GET_CHANNEL_LIST = ANDROID_NL80211_SUBCMD_WIFI_RANGE_START, + + WIFI_SUBCMD_GET_FEATURE_SET, /* 0x0001 */ + WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x0002 */ + WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x0003 */ + WIFI_SUBCMD_NODFS_SET, /* 0x0004 */ + WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x0005 */ + /* Add more sub commands here */ + +} WIFI_SUB_COMMAND; + +typedef enum { + GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START, + + GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */ + GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */ + GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */ + GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */ + GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */ + + GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */ + + GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */ + GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */ + /* Add more sub commands here */ + +} GSCAN_SUB_COMMAND; + +typedef enum { + RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, + RTT_SUBCMD_CANCEL_CONFIG, + RTT_SUBCMD_GETCAPABILITY, +} RTT_SUB_COMMAND; + +typedef enum { + LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START, +} LSTATS_SUB_COMMAND; + +typedef enum { + GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, + GSCAN_EVENT_HOTLIST_RESULTS_FOUND, + GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, + GSCAN_EVENT_FULL_SCAN_RESULTS, + RTT_EVENT_COMPLETE, + GSCAN_EVENT_COMPLETE_SCAN, + GSCAN_EVENT_HOTLIST_RESULTS_LOST +} WIFI_VENDOR_EVENT; + +typedef enum { + WIFI_ATTRIBUTE_BAND, + WIFI_ATTRIBUTE_NUM_CHANNELS, + WIFI_ATTRIBUTE_CHANNEL_LIST, + + WIFI_ATTRIBUTE_NUM_FEATURE_SET, + WIFI_ATTRIBUTE_FEATURE_SET, + WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, + WIFI_ATTRIBUTE_NODFS_VALUE, + WIFI_ATTRIBUTE_COUNTRY_CODE + +} WIFI_ATTRIBUTE; + +typedef enum { + GSCAN_ATTRIBUTE_CAPABILITIES = 1, + + GSCAN_ATTRIBUTE_NUM_BUCKETS = 10, + GSCAN_ATTRIBUTE_BASE_PERIOD, + GSCAN_ATTRIBUTE_BUCKETS_BAND, + GSCAN_ATTRIBUTE_BUCKET_ID, + GSCAN_ATTRIBUTE_BUCKET_PERIOD, + GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS, + GSCAN_ATTRIBUTE_BUCKET_CHANNELS, + GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, + GSCAN_ATTRIBUTE_REPORT_THRESHOLD, + GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, + + GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20, + GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */ + GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */ + GSCAN_ENABLE_FULL_SCAN_RESULTS, + GSCAN_ATTRIBUTE_REPORT_EVENTS, + + GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30, + GSCAN_ATTRIBUTE_FLUSH_RESULTS, + GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */ + GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */ + GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */ + GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */ + + GSCAN_ATTRIBUTE_SSID = 40, + GSCAN_ATTRIBUTE_BSSID, + GSCAN_ATTRIBUTE_CHANNEL, + GSCAN_ATTRIBUTE_RSSI, + GSCAN_ATTRIBUTE_TIMESTAMP, + GSCAN_ATTRIBUTE_RTT, + GSCAN_ATTRIBUTE_RTTSD, + + GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50, + GSCAN_ATTRIBUTE_RSSI_LOW, + GSCAN_ATTRIBUTE_RSSI_HIGH, + GSCAN_ATTRIBUTE_HOTLIST_ELEM, + GSCAN_ATTRIBUTE_HOTLIST_FLUSH, + + GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60, + GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, + GSCAN_ATTRIBUTE_MIN_BREACHING, + GSCAN_ATTRIBUTE_NUM_AP, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS, + GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + +} GSCAN_ATTRIBUTE; + +typedef enum { + RTT_ATTRIBUTE_CAPABILITIES = 1, + + RTT_ATTRIBUTE_TARGET_CNT = 10, + RTT_ATTRIBUTE_TARGET_INFO, + RTT_ATTRIBUTE_TARGET_MAC, + RTT_ATTRIBUTE_TARGET_TYPE, + RTT_ATTRIBUTE_TARGET_PEER, + RTT_ATTRIBUTE_TARGET_CHAN, + RTT_ATTRIBUTE_TARGET_PERIOD, + RTT_ATTRIBUTE_TARGET_NUM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM, + RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR, + RTT_ATTRIBUTE_TARGET_LCI, + RTT_ATTRIBUTE_TARGET_LCR, + RTT_ATTRIBUTE_TARGET_BURST_DURATION, + RTT_ATTRIBUTE_TARGET_PREAMBLE, + RTT_ATTRIBUTE_TARGET_BW, + RTT_ATTRIBUTE_RESULTS_COMPLETE = 30, + RTT_ATTRIBUTE_RESULTS_PER_TARGET, + RTT_ATTRIBUTE_RESULT_CNT, + RTT_ATTRIBUTE_RESULT +} RTT_ATTRIBUTE; + +typedef enum { + LSTATS_ATTRIBUTE_STATS = 2, +} LSTATS_ATTRIBUTE; + +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ +} WIFI_BAND; + +typedef enum { + WIFI_SCAN_BUFFER_FULL, + WIFI_SCAN_COMPLETE, +} WIFI_SCAN_EVENT; + +#define GSCAN_MAX_REPORT_THRESHOLD 1024000 +#define GSCAN_MAX_CHANNELS 8 +#define GSCAN_MAX_BUCKETS 8 +#define MAX_HOTLIST_APS 16 +#define MAX_SIGNIFICANT_CHANGE_APS 16 +#define PSCAN_MAX_SCAN_CACHE_SIZE 16 +#define PSCAN_MAX_AP_CACHE_PER_SCAN 16 +#define PSCAN_VERSION 1 + +#define MAX_BUFFERED_GSCN_RESULTS 5 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef UINT_64 wifi_timestamp; /* In microseconds (us) */ +typedef UINT_64 wifi_timespan; /* In nanoseconds (ns) */ + +typedef UINT_8 mac_addr[6]; +typedef UINT_32 wifi_channel; /* Indicates channel frequency in MHz */ +typedef INT_32 wifi_rssi; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +typedef struct _PARAM_WIFI_GSCAN_GET_RESULT_PARAMS { + UINT_32 get_num; + UINT_8 flush; +} PARAM_WIFI_GSCAN_GET_RESULT_PARAMS, *P_PARAM_WIFI_GSCAN_GET_RESULT_PARAMS; + +typedef struct _PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS { + UINT_8 ucPscanAct; + UINT_8 aucReserved[3]; +} PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS; + +typedef struct _PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T { + UINT_32 max_scan_cache_size; /* total space allocated for scan (in bytes) */ + UINT_32 max_scan_buckets; /* maximum number of channel buckets */ + UINT_32 max_ap_cache_per_scan; /* maximum number of APs that can be stored per scan */ + UINT_32 max_rssi_sample_size; /* number of RSSI samples used for averaging RSSI */ + UINT_32 max_scan_reporting_threshold; /* max possible report_threshold as described */ + /* in wifi_scan_cmd_params */ + UINT_32 max_hotlist_aps; /* maximum number of entries for hotlist APs */ + UINT_32 max_significant_wifi_change_aps; /* maximum number of entries for */ + /* significant wifi change APs */ + UINT_32 max_bssid_history_entries; /* number of BSSID/RSSI entries that device can hold */ +} PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T, *P_PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T; + +typedef struct _PARAM_WIFI_GSCAN_CHANNEL_SPEC { + UINT_32 channel; /* frequency */ + UINT_32 dwellTimeMs; /* dwell time hint */ + UINT_32 passive; /* 0 => active, 1 => passive scan; ignored for DFS */ + /* Add channel class */ +} PARAM_WIFI_GSCAN_CHANNEL_SPEC, *P_PARAM_WIFI_GSCAN_CHANNEL_SPEC; + +typedef struct _PARAM_WIFI_GSCAN_BUCKET_SPEC { + UINT_32 bucket; /* bucket index, 0 based */ + WIFI_BAND band; /* when UNSPECIFIED, use channel list */ + UINT_32 period; /* desired period, in millisecond; if this is too */ + /* low, the firmware should choose to generate results as */ + /* fast as it can instead of failing the command */ + /* report_events semantics - + * 0 => report only when scan history is % full + * 1 => same as 0 + report a scan completion event after scanning this bucket + * 2 => same as 1 + forward scan results (beacons/probe responses + IEs) in real time to HAL + * 3 => same as 2 + forward scan results (beacons/probe responses + IEs) in real time to + supplicant as well (optional) . */ + UINT_8 report_events; + + UINT_32 num_channels; + PARAM_WIFI_GSCAN_CHANNEL_SPEC channels[GSCAN_MAX_CHANNELS]; /* channels to scan; + these may include DFS channels */ +} PARAM_WIFI_GSCAN_BUCKET_SPEC, *P_PARAM_WIFI_GSCAN_BUCKET_SPEC; + +typedef struct _PARAM_WIFI_GSCAN_CMD_PARAMS { + UINT_32 base_period; /* base timer period in ms */ + UINT_32 max_ap_per_scan; /* number of APs to store in each scan in the */ + /* BSSID/RSSI history buffer (keep the highest RSSI APs) */ + UINT_32 report_threshold; /* in %, when scan buffer is this much full, wake up AP */ + UINT_32 num_scans; + UINT_32 num_buckets; + PARAM_WIFI_GSCAN_BUCKET_SPEC buckets[GSCAN_MAX_BUCKETS]; +} PARAM_WIFI_GSCAN_CMD_PARAMS, *P_PARAM_WIFI_GSCAN_CMD_PARAMS; + +typedef struct _PARAM_WIFI_GSCAN_RESULT { + wifi_timestamp ts; /* time since boot (in microsecond) when the result was */ + /* retrieved */ + UINT_8 ssid[32 + 1]; /* null terminated */ + mac_addr bssid; + wifi_channel channel; /* channel frequency in MHz */ + wifi_rssi rssi; /* in db */ + wifi_timespan rtt; /* in nanoseconds */ + wifi_timespan rtt_sd; /* standard deviation in rtt */ + UINT_16 beacon_period; /* period advertised in the beacon */ + UINT_16 capability; /* capabilities advertised in the beacon */ + UINT_32 ie_length; /* size of the ie_data blob */ + UINT_8 ie_data[1]; /* blob of all the information elements found in the */ + /* beacon; this data should be a packed list of */ + /* wifi_information_element objects, one after the other. */ + /* other fields */ +} PARAM_WIFI_GSCAN_RESULT, *P_PARAM_WIFI_GSCAN_RESULT; + +/* Significant wifi change*/ +/*typedef struct _PARAM_WIFI_CHANGE_RESULT{ + mac_addr bssid; // BSSID + wifi_channel channel; // channel frequency in MHz + UINT_32 num_rssi; // number of rssi samples + wifi_rssi rssi[8]; // RSSI history in db +} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT;*/ + +typedef struct _PARAM_WIFI_CHANGE_RESULT { + UINT_16 flags; + UINT_16 channel; + mac_addr bssid; /* BSSID */ + INT_8 rssi[8]; /* RSSI history in db */ +} PARAM_WIFI_CHANGE_RESULT, *P_PARAM_WIFI_CHANGE_RESULT; + +typedef struct _PARAM_AP_THRESHOLD { + mac_addr bssid; /* AP BSSID */ + wifi_rssi low; /* low threshold */ + wifi_rssi high; /* high threshold */ + wifi_channel channel; /* channel hint */ +} PARAM_AP_THRESHOLD, *P_PARAM_AP_THRESHOLD; + +typedef struct _PARAM_WIFI_BSSID_HOTLIST { + UINT_32 lost_ap_sample_size; + UINT_32 num_ap; /* number of hotlist APs */ + PARAM_AP_THRESHOLD ap[MAX_HOTLIST_APS]; /* hotlist APs */ +} PARAM_WIFI_BSSID_HOTLIST, *P_PARAM_WIFI_BSSID_HOTLIST; + +typedef struct _PARAM_WIFI_SIGNIFICANT_CHANGE { + UINT_16 rssi_sample_size; /* number of samples for averaging RSSI */ + UINT_16 lost_ap_sample_size; /* number of samples to confirm AP loss */ + UINT_16 min_breaching; /* number of APs breaching threshold */ + UINT_16 num_ap; /* max 64 */ + PARAM_AP_THRESHOLD ap[MAX_SIGNIFICANT_CHANGE_APS]; +} PARAM_WIFI_SIGNIFICANT_CHANGE, *P_PARAM_WIFI_SIGNIFICANT_CHANGE; + +/* RTT Capabilities */ +typedef struct _PARAM_WIFI_RTT_CAPABILITIES { + UINT_8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ + UINT_8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ + UINT_8 lci_support; /* if initiator supports LCI request. Applies to 2-sided RTT */ + UINT_8 lcr_support; /* if initiator supports LCR request. Applies to 2-sided RTT */ + UINT_8 preamble_support; /* bit mask indicates what preamble is supported by initiator */ + UINT_8 bw_support; /* bit mask indicates what BW is supported by initiator */ +} PARAM_WIFI_RTT_CAPABILITIES, *P_PARAM_WIFI_RTT_CAPABILITIES; + +/* channel operating width */ +typedef enum { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, + WIFI_CHAN_WIDTH_INVALID = -1 +} WIFI_CHANNEL_WIDTH; + +/* channel information */ +typedef struct { + WIFI_CHANNEL_WIDTH width; /* channel width (20, 40, 80, 80+80, 160) */ + UINT_32 center_freq; /* primary 20 MHz channel */ + UINT_32 center_freq0; /* center frequency (MHz) first segment */ + UINT_32 center_freq1; /* center frequency (MHz) second segment */ +} WIFI_CHANNEL_INFO; + +/* channel statistics */ +typedef struct { + WIFI_CHANNEL_INFO channel; /* channel */ + UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ + UINT_32 cca_busy_time; /* msecs the CCA register is busy (32 bits number accruing over time) */ +} WIFI_CHANNEL_STAT; + +/* radio statistics */ +typedef struct { + UINT_32 radio; /* wifi radio (if multiple radio supported) */ + UINT_32 on_time; /* msecs the radio is awake (32 bits number accruing over time) */ + UINT_32 tx_time; /* msecs the radio is transmitting (32 bits number accruing over time) */ + UINT_32 rx_time; /* msecs the radio is in active receive (32 bits number accruing over time) */ + UINT_32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits number accruing over time) */ + UINT_32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits number accruing over time) */ + UINT_32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits number accruing over time) */ + UINT_32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan + (32 bits number accruing over time) */ + UINT_32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan + (32 bits number accruing over time) */ + UINT_32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and GAS exchange + 32 bits number accruing over time) */ + UINT_32 num_channels; /* number of channels */ + WIFI_CHANNEL_STAT channels[]; /* channel statistics */ +} WIFI_RADIO_STAT; + +/* wifi rate */ +typedef struct { + UINT_32 preamble:3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + UINT_32 nss:2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + UINT_32 bw:3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + UINT_32 rateMcsIdx:8; /* OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps */ + /* HT/VHT it would be mcs index */ + UINT_32 reserved:16; /* reserved */ + UINT_32 bitrate; /* units of 100 Kbps */ +} WIFI_RATE; + +/* per rate statistics */ +typedef struct { + WIFI_RATE rate; /* rate information */ + UINT_32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ + UINT_32 rx_mpdu; /* number of received data pkts */ + UINT_32 mpdu_lost; /* number of data packet losses (no ACK) */ + UINT_32 retries; /* total number of data pkt retries */ + UINT_32 retries_short; /* number of short data pkt retries */ + UINT_32 retries_long; /* number of long data pkt retries */ +} WIFI_RATE_STAT; + +/*wifi_interface_link_layer_info*/ +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} WIFI_CONNECTION_STATE; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1, +} WIFI_ROAM_STATE; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6, + WIFI_INTERFACE_UNKNOWN = -1 +} WIFI_INTERFACE_MODE; + +typedef struct { + WIFI_INTERFACE_MODE mode; /* interface mode */ + u8 mac_addr[6]; /* interface mac address (self) */ + WIFI_CONNECTION_STATE state; /* connection state (valid for STA, CLI only) */ + WIFI_ROAM_STATE roaming; /* roaming state */ + u32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ + u8 ssid[33]; /* null terminated SSID */ + u8 bssid[6]; /* bssid */ + u8 ap_country_str[3]; /* country string advertised by AP */ + u8 country_str[3]; /* country string for this association */ +} WIFI_INTERFACE_LINK_LAYER_INFO; + +/* access categories */ +typedef enum { + WIFI_AC_VO = 0, + WIFI_AC_VI = 1, + WIFI_AC_BE = 2, + WIFI_AC_BK = 3, + WIFI_AC_MAX = 4, +} WIFI_TRAFFIC_AC; + +/* wifi peer type */ +typedef enum { + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID, +} WIFI_PEER_TYPE; + +/* per peer statistics */ +typedef struct { + WIFI_PEER_TYPE type; /* peer type (AP, TDLS, GO etc.) */ + UINT_8 peer_mac_address[6]; /* mac address */ + UINT_32 capabilities; /* peer WIFI_CAPABILITY_XXX */ + UINT_32 num_rate; /* number of rates */ + WIFI_RATE_STAT rate_stats[]; /* per rate statistics, number of entries = num_rate */ +} WIFI_PEER_INFO; + +/* per access category statistics */ +typedef struct { + WIFI_TRAFFIC_AC ac; /* access category (VI, VO, BE, BK) */ + UINT_32 tx_mpdu; /* number of successfully transmitted unicast data pkts (ACK rcvd) */ + UINT_32 rx_mpdu; /* number of received unicast mpdus */ + UINT_32 tx_mcast; /* number of successfully transmitted multicast data packets */ + /* STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent */ + UINT_32 rx_mcast; /* number of received multicast data packets */ + UINT_32 rx_ampdu; /* number of received unicast a-mpdus */ + UINT_32 tx_ampdu; /* number of transmitted unicast a-mpdus */ + UINT_32 mpdu_lost; /* number of data pkt losses (no ACK) */ + UINT_32 retries; /* total number of data pkt retries */ + UINT_32 retries_short; /* number of short data pkt retries */ + UINT_32 retries_long; /* number of long data pkt retries */ + UINT_32 contention_time_min; /* data pkt min contention time (usecs) */ + UINT_32 contention_time_max; /* data pkt max contention time (usecs) */ + UINT_32 contention_time_avg; /* data pkt avg contention time (usecs) */ + UINT_32 contention_num_samples; /* num of data pkts used for contention statistics */ +} WIFI_WMM_AC_STAT; + +/* interface statistics */ +typedef struct { + /* wifi_interface_handle iface; // wifi interface */ + WIFI_INTERFACE_LINK_LAYER_INFO info; /* current state of the interface */ + UINT_32 beacon_rx; /* access point beacon received count from connected AP */ + UINT_32 mgmt_rx; /* access point mgmt frames received count from connected AP (including Beacon) */ + UINT_32 mgmt_action_rx; /* action frames received count */ + UINT_32 mgmt_action_tx; /* action frames transmit count */ + wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI (averaged) */ + wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from connected AP */ + wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from connected AP */ + WIFI_WMM_AC_STAT ac[WIFI_AC_MAX]; /* per ac data packet statistics */ + UINT_32 num_peers; /* number of peers */ + WIFI_PEER_INFO peer_info[]; /* per peer statistics */ +} WIFI_IFACE_STAT; + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_get_gscan_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + +int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + +int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + +int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + +int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_get_rtt_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete); + +int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num); + +int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); + +int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len); + +int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); + +int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, + P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len); + +#endif /* _GL_VENDOR_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h new file mode 100644 index 0000000000000..827ff92b1581f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext.h @@ -0,0 +1,357 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext.h#1 +*/ + +/*! \file gl_wext.h + \brief This file is for Portable Driver linux wireless extension support. +*/ + +/* +** Log: gl_wext.h + * + * 10 12 2011 wh.su + * [WCXRP00001036] [MT6620 Wi-Fi][Driver][FW] Adding the 802.11w code for MFP + * adding the 802.11w related function and define . + * + * 09 20 2011 chinglan.wang + * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. + * . + * + * 09 20 2011 chinglan.wang + * [WCXRP00000989] [WiFi Direct] [Driver] Add a new io control API to start the formation for the sigma test. + * . + * + * 01 11 2011 chinglan.wang + * NULL + * Modify to reslove the CR :[ALPS00028994] Use WEP security to connect Marvell 11N AP. + * Connection establish successfully. + * Use the WPS function to connect AP, the privacy bit always is set to 1. . + * + * 09 27 2010 wh.su + * NULL + * [WCXRP00000067][MT6620 Wi-Fi][Driver] Support the android+ WAPI function. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\12 2009-10-20 17:38:33 GMT mtk01090 +** Refine driver unloading and clean up procedure. Block requests, stop main thread and clean up queued requests, +** and then stop hw. +** \main\maintrunk.MT5921\11 2009-09-28 20:19:28 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\10 2009-09-03 12:12:35 GMT mtk01088 +** adding the function declaration +** \main\maintrunk.MT5921\9 2009-08-18 22:57:17 GMT mtk01090 +** Add Linux SDIO (with mmc core) support. +** Add Linux 2.6.21, 2.6.25, 2.6.26. +** Fix compile warning in Linux. +** \main\maintrunk.MT5921\8 2008-08-29 16:59:07 GMT mtk01088 +** fixed compiling error +** \main\maintrunk.MT5921\7 2008-08-29 14:13:28 GMT mtk01088 +** adjust the header file for code refine +** \main\maintrunk.MT5921\6 2008-03-28 10:40:31 GMT mtk01461 +** Add set desired rate in Linux STD IOCTL +** \main\maintrunk.MT5921\5 2008-03-11 14:51:08 GMT mtk01461 +** Refine private IOCTL functions +** \main\maintrunk.MT5921\4 2008-02-12 23:45:45 GMT mtk01461 +** Add Set Frequency & Channel oid support for Linux +** \main\maintrunk.MT5921\3 2007-11-06 19:36:19 GMT mtk01088 +** add the WPS related code +*/ + +#ifndef _GL_WEXT_H +#define _GL_WEXT_H + +#ifdef WIRELESS_EXT +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define KILO 1000 +#define RATE_5_5M 11 /* 5.5M */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef struct _PARAM_FIXED_IEs { + UINT_8 aucTimestamp[8]; + UINT_16 u2BeaconInterval; + UINT_16 u2Capabilities; +} PARAM_FIXED_IEs; + +typedef struct _PARAM_VARIABLE_IE_T { + UINT_8 ucElementID; + UINT_8 ucLength; + UINT_8 aucData[1]; +} PARAM_VARIABLE_IE_T, *P_PARAM_VARIABLE_IE_T; + +#if WIRELESS_EXT < 18 + +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses struct iw_mlme */ +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ +#define IW_MLME_DEAUTH 0 +#define IW_MLME_DISASSOC 1 + +/*! \brief SIOCSIWMLME data */ +struct iw_mlme { + __u16 cmd; /*!< IW_MLME_* */ + __u16 reason_code; + struct sockaddr addr; +}; + +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ +#define IW_AUTH_INDEX 0x0FFF +#define IW_AUTH_FLAGS 0xF000 +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the + * parameter that is being set/get to; value will be read/written to + * struct iw_param value field) */ +#define IW_AUTH_WPA_VERSION 0 +#define IW_AUTH_CIPHER_PAIRWISE 1 +#define IW_AUTH_CIPHER_GROUP 2 +#define IW_AUTH_KEY_MGMT 3 +#define IW_AUTH_TKIP_COUNTERMEASURES 4 +#define IW_AUTH_DROP_UNENCRYPTED 5 +#define IW_AUTH_80211_AUTH_ALG 6 +#define IW_AUTH_WPA_ENABLED 7 +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 +#define IW_AUTH_ROAMING_CONTROL 9 +#define IW_AUTH_PRIVACY_INVOKED 10 +#if CFG_SUPPORT_802_11W +#define IW_AUTH_MFP 12 + +#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +/* IW_AUTH_WPA_VERSION values (bit field) */ +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 + +/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ +#define IW_AUTH_CIPHER_NONE 0x00000001 +#define IW_AUTH_CIPHER_WEP40 0x00000002 +#define IW_AUTH_CIPHER_TKIP 0x00000004 +#define IW_AUTH_CIPHER_CCMP 0x00000008 +#define IW_AUTH_CIPHER_WEP104 0x00000010 + +/* IW_AUTH_KEY_MGMT values (bit field) */ +#define IW_AUTH_KEY_MGMT_802_1X 1 +#define IW_AUTH_KEY_MGMT_PSK 2 +#define IW_AUTH_KEY_MGMT_WPA_NONE 4 + +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 +#define IW_AUTH_ALG_LEAP 0x00000004 + +/* IW_AUTH_ROAMING_CONTROL values */ +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ +#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming + * control */ + +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ +/* SIOCSIWENCODEEXT definitions */ +#define IW_ENCODE_SEQ_MAX_SIZE 8 +/* struct iw_encode_ext ->alg */ +#define IW_ENCODE_ALG_NONE 0 +#define IW_ENCODE_ALG_WEP 1 +#define IW_ENCODE_ALG_TKIP 2 +#define IW_ENCODE_ALG_CCMP 3 +#if CFG_SUPPORT_802_11W +#define IW_ENCODE_ALG_AES_CMAC 5 +#endif + +/* struct iw_encode_ext ->ext_flags */ +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 + +struct iw_encode_ext { + __u32 ext_flags; /*!< IW_ENCODE_EXT_* */ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + struct sockaddr addr; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + __u16 alg; /*!< IW_ENCODE_ALG_* */ + __u16 key_len; + __u8 key[0]; +}; + +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ +#define IW_PMKSA_ADD 1 +#define IW_PMKSA_REMOVE 2 +#define IW_PMKSA_FLUSH 3 + +#define IW_PMKID_LEN 16 + +struct iw_pmksa { + __u32 cmd; /*!< IW_PMKSA_* */ + struct sockaddr bssid; + __u8 pmkid[IW_PMKID_LEN]; +}; + +#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) + * (scan results); This includes id and + * length fields. One IWEVGENIE may + * contain more than one IE. Scan + * results may contain one or more + * IWEVGENIE events. */ +#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure + * (struct iw_michaelmicfailure) + */ +#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. + * The data includes id and length + * fields and may contain more than one + * IE. This event is required in + * Managed mode if the driver + * generates its own WPA/RSN IE. This + * should be sent just before + * IWEVREGISTERED event for the + * association. */ +#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association + * Response. The data includes id and + * length fields and may contain more + * than one IE. This may be sent + * between IWEVASSOCREQIE and + * IWEVREGISTERED events for the + * association. */ +#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN + * pre-authentication + * (struct iw_pmkid_cand) */ + +#endif /* WIRELESS_EXT < 18 */ + +#if WIRELESS_EXT < 17 +/* Statistics flags (bitmask in updated) */ +#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */ +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#endif + +enum { + IEEE80211_FILTER_TYPE_BEACON = 1 << 0, + IEEE80211_FILTER_TYPE_PROBE_REQ = 1 << 1, + IEEE80211_FILTER_TYPE_PROBE_RESP = 1 << 2, + IEEE80211_FILTER_TYPE_ASSOC_REQ = 1 << 3, + IEEE80211_FILTER_TYPE_ASSOC_RESP = 1 << 4, + IEEE80211_FILTER_TYPE_AUTH = 1 << 5, + IEEE80211_FILTER_TYPE_DEAUTH = 1 << 6, + IEEE80211_FILTER_TYPE_DISASSOC = 1 << 7, + IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */ +}; + +#if CFG_SUPPORT_WAPI +#define IW_AUTH_WAPI_ENABLED 0x20 +#define IW_ENCODE_ALG_SMS4 0x20 +#endif + +#if CFG_SUPPORT_WAPI /* Android+ */ +#define IW_AUTH_KEY_MGMT_WAPI_PSK 3 +#define IW_AUTH_KEY_MGMT_WAPI_CERT 4 +#endif +#define IW_AUTH_KEY_MGMT_WPS 5 + +#if CFG_SUPPORT_802_11W +#define IW_AUTH_KEY_MGMT_802_1X_SHA256 7 +#define IW_AUTH_KEY_MGMT_PSK_SHA256 8 +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern const struct iw_handler_def wext_handler_def; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* wireless extensions' ioctls */ +int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, IN int i4Cmd); + +int +wext_set_rate(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN struct iw_param *prRate, IN char *pcExtra); + +void +wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, IN unsigned char *pucData, IN unsigned int u4DataLen); + +struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev); + +BOOLEAN +wextSrchDesiredWPAIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); + +#if CFG_SUPPORT_WPS +BOOLEAN +wextSrchDesiredWPSIE(IN PUINT_8 pucIEStart, + IN INT_32 i4TotalIeLen, IN UINT_8 ucDesiredElemId, OUT PUINT_8 *ppucDesiredIE); +#endif + +#if CFG_SUPPORT_HOTSPOT_2_0 +BOOLEAN wextSrchDesiredHS20IE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); + +BOOLEAN wextSrchDesiredInterworkingIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); + +BOOLEAN wextSrchDesiredAdvProtocolIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); + +BOOLEAN wextSrchDesiredRoamingConsortiumIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); +#endif + +#if CFG_SUPPORT_WAPI +BOOLEAN wextSrchDesiredWAPIIE(IN PUINT_8 pucIEStart, IN INT_32 i4TotalIeLen, OUT PUINT_8 *ppucDesiredIE); +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* WIRELESS_EXT */ + +#endif /* _GL_WEXT_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h new file mode 100644 index 0000000000000..31933fc6a461e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/include/gl_wext_priv.h @@ -0,0 +1,402 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/include/gl_wext_priv.h#3 +*/ + +/*! \file gl_wext_priv.h + \brief This file includes private ioctl support. +*/ + +/* +** Log: gl_wext_priv.h + * + * 01 16 2012 wh.su + * [WCXRP00001170] [MT6620 Wi-Fi][Driver] Adding the related code for set/get band ioctl + * Adding the template code for set / get band IOCTL (with ICS supplicant_6).. + * + * 01 05 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the related ioctl / wlan oid function to set the Tx power cfg. + * + * 01 02 2012 wh.su + * [WCXRP00001153] [MT6620 Wi-Fi][Driver] Adding the get_ch_list and set_tx_power proto type function + * Adding the proto type function for set_int set_tx_power and get int get_ch_list. + * + * 11 08 2011 yuche.tsai + * [WCXRP00001094] [Volunteer Patch][Driver] Driver version & supplicant version query & set support for service + * discovery version check. + * Add a CMD ID for P2P driver version query. + * + * 03 17 2011 chinglan.wang + * [WCXRP00000570] [MT6620 Wi-Fi][Driver] Add Wi-Fi Protected Setup v2.0 feature + * . + * + * 03 02 2011 wh.su + * [WCXRP00000506] [MT6620 Wi-Fi][Driver][FW] Add Security check related code + * Add security check code. + * + * 01 27 2011 cm.chang + * [WCXRP00000402] [MT6620 Wi-Fi][Driver] Enable MCR read/write by iwpriv by default + * . + * + * 01 20 2011 eddie.chen + * [WCXRP00000374] [MT6620 Wi-Fi][DRV] SW debug control + * Add Oid for sw control debug command + * + * 01 07 2011 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add a new compiling option to control if MCR read/write is permitted + * + * 12 31 2010 cm.chang + * [WCXRP00000336] [MT6620 Wi-Fi][Driver] Add test mode commands in normal phone operation + * Add some iwpriv commands to support test mode operation + * + * 11 08 2010 wh.su + * [WCXRP00000171] [MT6620 Wi-Fi][Driver] Add message check code same behavior as mt5921 + * add the message check code from mt5921. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 09 23 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * add skeleton for NVRAM integration + * + * 08 04 2010 cp.wu + * NULL + * revert changelist #15371, efuse read/write access will be done by RF test approach + * + * 08 04 2010 cp.wu + * NULL + * add OID definitions for EFUSE read/write access. + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base + * + * 03 31 2010 wh.su + * [WPD00003816][MT6620 Wi-Fi] Adding the security support + * modify the wapi related code for new driver's design. + * + * 03 24 2010 jeffrey.chang + * [WPD00003826]Initial import for Linux port + * initial import for Linux port +** \main\maintrunk.MT5921\16 2009-09-29 16:47:23 GMT mtk01090 +** Remove unused functions +** \main\maintrunk.MT5921\15 2009-09-28 20:19:31 GMT mtk01090 +** Add private ioctl to carry OID structures. Restructure public/private ioctl interfaces to Linux kernel. +** \main\maintrunk.MT5921\14 2009-05-07 22:26:06 GMT mtk01089 +** add private IO control for Linux BWCS +** \main\maintrunk.MT5921\13 2008-08-29 14:55:20 GMT mtk01088 +** adjust the code to meet coding style +** \main\maintrunk.MT5921\12 2008-07-16 15:23:45 GMT mtk01104 +** Support GPIO2 mode +** \main\maintrunk.MT5921\11 2008-07-14 13:55:58 GMT mtk01104 +** Support PRIV_CMD_BT_COEXIST +** \main\maintrunk.MT5921\10 2008-07-09 00:20:24 GMT mtk01461 +** Add priv oid to support WMM_PS_TEST +** \main\maintrunk.MT5921\9 2008-05-30 20:27:24 GMT mtk01461 +** Add POWER_MODE Private IOCTL cmd +** \main\maintrunk.MT5921\8 2008-04-17 23:06:44 GMT mtk01461 +** Add iwpriv support for AdHocMode setting +** \main\maintrunk.MT5921\7 2008-03-31 21:01:24 GMT mtk01461 +** Add priv IOCTL for VOIP settings +** \main\maintrunk.MT5921\6 2008-03-31 13:49:47 GMT mtk01461 +** add priv ioctl arg definition for turning on / off roaming +** \main\maintrunk.MT5921\5 2008-03-26 15:35:09 GMT mtk01461 +** Add CSUM offload priv ioctl for Linux +** \main\maintrunk.MT5921\4 2008-03-11 14:51:11 GMT mtk01461 +** Refine private IOCTL functions +** \main\maintrunk.MT5921\3 2007-11-06 19:36:25 GMT mtk01088 +** add the WPS related code +*/ + +#ifndef _GL_WEXT_PRIV_H +#define _GL_WEXT_PRIV_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +/* If it is set to 1, iwpriv will support register read/write */ +#define CFG_SUPPORT_PRIV_MCR_RW 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#if CFG_ENABLE_WIFI_DIRECT +extern int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); +#if 0 +extern BOOLEAN fgIsResetting; +extern BOOLEAN g_u4HaltFlag; +extern spinlock_t g_p2p_lock; +extern int g_u4P2PEnding; +extern int g_u4P2POnOffing; +#endif +#endif + + +#if (CFG_SUPPORT_TXR_ENC == 1) +extern VOID rlmCmd(P_GLUE_INFO_T prGlueInfo, UINT_8 *prInBuf, UINT_32 u4InBufLen); +#endif /* CFG_SUPPORT_TXR_ENC */ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* New wireless extensions API - SET/GET convention (even ioctl numbers are + * root only) + */ +#define IOCTL_SET_INT (SIOCIWFIRSTPRIV + 0) +#define IOCTL_GET_INT (SIOCIWFIRSTPRIV + 1) + +#define IOCTL_SET_ADDRESS (SIOCIWFIRSTPRIV + 2) +#define IOCTL_GET_ADDRESS (SIOCIWFIRSTPRIV + 3) +#define IOCTL_SET_STR (SIOCIWFIRSTPRIV + 4) +#define IOCTL_GET_STR (SIOCIWFIRSTPRIV + 5) +#define IOCTL_SET_KEY (SIOCIWFIRSTPRIV + 6) +#define IOCTL_GET_KEY (SIOCIWFIRSTPRIV + 7) +#define IOCTL_SET_STRUCT (SIOCIWFIRSTPRIV + 8) +#define IOCTL_GET_STRUCT (SIOCIWFIRSTPRIV + 9) +#define IOCTL_SET_STRUCT_FOR_EM (SIOCIWFIRSTPRIV + 11) +#define IOCTL_SET_INTS (SIOCIWFIRSTPRIV + 12) +#define IOCTL_GET_INTS (SIOCIWFIRSTPRIV + 13) +#define IOCTL_SET_STRING (SIOCIWFIRSTPRIV + 14) + +#define PRIV_CMD_REG_DOMAIN 0 +#define PRIV_CMD_BEACON_PERIOD 1 +#define PRIV_CMD_ADHOC_MODE 2 + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +#define PRIV_CMD_CSUM_OFFLOAD 3 +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + +#define PRIV_CMD_ROAMING 4 +#define PRIV_CMD_VOIP_DELAY 5 +#define PRIV_CMD_POWER_MODE 6 + +#define PRIV_CMD_WMM_PS 7 +#define PRIV_CMD_BT_COEXIST 8 +#define PRIV_GPIO2_MODE 9 + +#define PRIV_CUSTOM_SET_PTA 10 +#define PRIV_CUSTOM_CONTINUOUS_POLL 11 +#define PRIV_CUSTOM_SINGLE_ANTENNA 12 +#define PRIV_CUSTOM_BWCS_CMD 13 +#define PRIV_CUSTOM_DISABLE_BEACON_DETECTION 14 /* later */ +#define PRIV_CMD_OID 15 +#define PRIV_SEC_MSG_OID 16 + +#define PRIV_CMD_TEST_MODE 17 +#define PRIV_CMD_TEST_CMD 18 +#define PRIV_CMD_ACCESS_MCR 19 +#define PRIV_CMD_SW_CTRL 20 + +#if 1 /* ANTI_PRIVCY */ +#define PRIV_SEC_CHECK_OID 21 +#endif + +#define PRIV_CMD_WSC_PROBE_REQ 22 + +#define PRIV_CMD_P2P_VERSION 23 + +#define PRIV_CMD_GET_CH_LIST 24 + +#define PRIV_CMD_SET_TX_POWER 25 + +#define PRIV_CMD_BAND_CONFIG 26 + +#define PRIV_CMD_DUMP_MEM 27 + +#define PRIV_CMD_P2P_MODE 28 + +#define PRIV_CMD_GET_BUILD_DATE_CODE 29 + +#define PRIV_CMD_GET_DEBUG_CODE 30 + +#define PRIV_CMD_OTHER 31 + +#define PRIV_CMD_WFD_DEBUG_CODE 32 + +#define PRIV_CMD_MET_PROFILING 33 + +/* other string command ID */ +#define PRIV_CMD_OTHER_TDLS 0x00 +#define PRIV_CMD_OTHER_TAR 0x01 /* TX auto rate */ + +/* 802.3 Objects (Ethernet) */ +#define OID_802_3_CURRENT_ADDRESS 0x01010102 + +/* IEEE 802.11 OIDs */ +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_CONFIGURATION 0x0D010211 + +/* PnP and PM OIDs, NDIS default OIDS */ +#define OID_PNP_SET_POWER 0xFD010101 + +#define OID_CUSTOM_OID_INTERFACE_VERSION 0xFFA0C000 + +/* MT5921 specific OIDs */ +#define OID_CUSTOM_BT_COEXIST_CTRL 0xFFA0C580 +#define OID_CUSTOM_POWER_MANAGEMENT_PROFILE 0xFFA0C581 +#define OID_CUSTOM_PATTERN_CONFIG 0xFFA0C582 +#define OID_CUSTOM_BG_SSID_SEARCH_CONFIG 0xFFA0C583 +#define OID_CUSTOM_VOIP_SETUP 0xFFA0C584 +#define OID_CUSTOM_ADD_TS 0xFFA0C585 +#define OID_CUSTOM_DEL_TS 0xFFA0C586 +#define OID_CUSTOM_SLT 0xFFA0C587 +#define OID_CUSTOM_ROAMING_EN 0xFFA0C588 +#define OID_CUSTOM_WMM_PS_TEST 0xFFA0C589 +#define OID_CUSTOM_COUNTRY_STRING 0xFFA0C58A +#define OID_CUSTOM_MULTI_DOMAIN_CAPABILITY 0xFFA0C58B +#define OID_CUSTOM_GPIO2_MODE 0xFFA0C58C +#define OID_CUSTOM_CONTINUOUS_POLL 0xFFA0C58D +#define OID_CUSTOM_DISABLE_BEACON_DETECTION 0xFFA0C58E + +/* CR1460, WPS privacy bit check disable */ +#define OID_CUSTOM_DISABLE_PRIVACY_CHECK 0xFFA0C600 + +/* Precedent OIDs */ +#define OID_CUSTOM_MCR_RW 0xFFA0C801 +#define OID_CUSTOM_EEPROM_RW 0xFFA0C803 +#define OID_CUSTOM_SW_CTRL 0xFFA0C805 +#define OID_CUSTOM_MEM_DUMP 0xFFA0C807 + +/* RF Test specific OIDs */ +#define OID_CUSTOM_TEST_MODE 0xFFA0C901 +#define OID_CUSTOM_TEST_RX_STATUS 0xFFA0C903 +#define OID_CUSTOM_TEST_TX_STATUS 0xFFA0C905 +#define OID_CUSTOM_ABORT_TEST_MODE 0xFFA0C906 +#define OID_CUSTOM_MTK_WIFI_TEST 0xFFA0C911 + +/* BWCS */ +#define OID_CUSTOM_BWCS_CMD 0xFFA0C931 +#define OID_CUSTOM_SINGLE_ANTENNA 0xFFA0C932 +#define OID_CUSTOM_SET_PTA 0xFFA0C933 + +/* NVRAM */ +#define OID_CUSTOM_MTK_NVRAM_RW 0xFFA0C941 +#define OID_CUSTOM_CFG_SRC_TYPE 0xFFA0C942 +#define OID_CUSTOM_EEPROM_TYPE 0xFFA0C943 + +#if CFG_SUPPORT_WAPI +#define OID_802_11_WAPI_MODE 0xFFA0CA00 +#define OID_802_11_WAPI_ASSOC_INFO 0xFFA0CA01 +#define OID_802_11_SET_WAPI_KEY 0xFFA0CA02 +#endif + +#if CFG_SUPPORT_WPS2 +#define OID_802_11_WSC_ASSOC_INFO 0xFFA0CB00 +#endif + +/* Define magic key of test mode (Don't change it for future compatibity) */ +#define PRIV_CMD_TEST_MAGIC_KEY 2011 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +/* NIC BBCR configuration entry structure */ +typedef struct _PRIV_CONFIG_ENTRY { + UINT_8 ucOffset; + UINT_8 ucValue; +} PRIV_CONFIG_ENTRY, *PPRIV_CONFIG_ENTRY; + +typedef WLAN_STATUS(*PFN_OID_HANDLER_FUNC_REQ) (IN PVOID prAdapter, + IN OUT PVOID pvBuf, IN UINT_32 u4BufLen, OUT PUINT_32 pu4OutInfoLen); + +typedef enum _ENUM_OID_METHOD_T { + ENUM_OID_GLUE_ONLY, + ENUM_OID_GLUE_EXTENSION, + ENUM_OID_DRIVER_CORE +} ENUM_OID_METHOD_T, *P_ENUM_OID_METHOD_T; + +/* OID set/query processing entry */ +typedef struct _WLAN_REQ_ENTRY { + UINT_32 rOid; /* OID */ + PUINT_8 pucOidName; /* OID name text */ + BOOLEAN fgQryBufLenChecking; + BOOLEAN fgSetBufLenChecking; + ENUM_OID_METHOD_T eOidMethod; + UINT_32 u4InfoBufLen; + PFN_OID_HANDLER_FUNC_REQ pfOidQueryHandler; /* PFN_OID_HANDLER_FUNC */ + PFN_OID_HANDLER_FUNC_REQ pfOidSetHandler; /* PFN_OID_HANDLER_FUNC */ +} WLAN_REQ_ENTRY, *P_WLAN_REQ_ENTRY; + +typedef struct _NDIS_TRANSPORT_STRUCT { + UINT_32 ndisOidCmd; + UINT_32 inNdisOidlength; + UINT_32 outNdisOidLength; + UINT_8 ndisOidContent[16]; +} NDIS_TRANSPORT_STRUCT, *P_NDIS_TRANSPORT_STRUCT; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int +priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); + +int +priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); + +int +priv_set_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); + +int +priv_get_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); + +int +priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); + +int +priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN OUT char *pcExtra); + +UINT_32 CmdStringDecParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen); + +UINT_32 CmdStringMacParse(IN UINT_8 *InStr, OUT UINT_8 **OutStr, OUT UINT_32 *OutLen, OUT UINT_8 *OutMac); + +int +priv_set_string(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, IN union iwreq_data *prIwReqData, IN char *pcExtra); + +int priv_support_ioctl(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); + +int priv_support_driver_cmd(IN struct net_device *prDev, IN OUT struct ifreq *prReq, IN int i4Cmd); + +INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _GL_WEXT_PRIV_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c new file mode 100644 index 0000000000000..fba854cfd68e1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/linux/platform.c @@ -0,0 +1,542 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/platform.c#1 +*/ + +/*! \file "platform.c" + \brief This file including the protocol layer privacy function. + + This file provided the macros and functions library support for the + protocol layer security setting from wlan_oid.c and for parse.c and + rsn.c and nic_privacy.c + +*/ + +/* +** Log: platform.c + * + * 11 14 2011 cm.chang + * NULL + * Fix compiling warning + * + * 11 10 2011 cp.wu + * [WCXRP00001098] [MT6620 Wi-Fi][Driver] Replace printk by DBG LOG macros in linux porting layer + * 1. eliminaite direct calls to printk in porting layer. + * 2. replaced by DBGLOG, which would be XLOG on ALPS platforms. + * + * 09 13 2011 jeffrey.chang + * [WCXRP00000983] [MT6620][Wi-Fi Driver] invalid pointer casting causes kernel panic during p2p connection + * fix the pointer casting + * + * 06 29 2011 george.huang + * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 + * . + * + * 06 28 2011 george.huang + * [WCXRP00000818] [MT6620 Wi-Fi][Driver] Remove unused code segment regarding CONFIG_IPV6 + * remove un-used code + * + * 05 11 2011 jeffrey.chang + * NULL + * fix build error + * + * 05 09 2011 jeffrey.chang + * [WCXRP00000710] [MT6620 Wi-Fi] Support pattern filter update function on IP address change + * support ARP filter through kernel notifier + * + * 04 08 2011 pat.lu + * [WCXRP00000623] [MT6620 Wi-Fi][Driver] use ARCH define to distinguish PC Linux driver + * Use CONFIG_X86 instead of PC_LINUX_DRIVER_USE option to have proper compile setting for PC Linux driver + * + * 03 22 2011 pat.lu + * [WCXRP00000592] [MT6620 Wi-Fi][Driver] Support PC Linux Environment Driver Build + * Add a compiler option "PC_LINUX_DRIVER_USE" for building driver in PC Linux environment. + * + * 03 21 2011 cp.wu + * [WCXRP00000540] [MT5931][Driver] Add eHPI8/eHPI16 support to Linux Glue Layer + * improve portability for awareness of early version of linux kernel and wireless extension. + * + * 03 18 2011 jeffrey.chang + * [WCXRP00000512] [MT6620 Wi-Fi][Driver] modify the net device relative functions to support the H/W multiple queue + * remove early suspend functions + * + * 03 03 2011 jeffrey.chang + * NULL + * add the ARP filter callback + * + * 02 15 2011 jeffrey.chang + * NULL + * to support early suspend in android + * + * 02 01 2011 cp.wu + * [WCXRP00000413] [MT6620 Wi-Fi][Driver] Merge 1103 changes on NVRAM file path change to DaVinci main trunk and V1.1 + * branch + * upon Jason Zhang(NVRAM owner)'s change, ALPS has modified its NVRAM storage from /nvram/... to /data/nvram/... + * + * 11 01 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000150] [MT6620 Wi-Fi][Driver] + * Add implementation for querying current TX rate from firmware auto rate module + * 1) Query link speed (TX rate) from firmware directly with buffering mechanism to reduce overhead + * 2) Remove CNM CH-RECOVER event handling + * 3) cfg read/write API renamed with kal prefix for unified naming rules. + * + * 10 18 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check[WCXRP00000086] [MT6620 Wi-Fi][Driver] + * The mac address is all zero at android + * complete implementation of Android NVRAM access + * + * 10 05 2010 cp.wu + * [WCXRP00000056] [MT6620 Wi-Fi][Driver] NVRAM implementation with Version Check + * 1) add NVRAM access API + * 2) fake scanning result when NVRAM doesn't exist and/or version mismatch. (off by compiler option) + * 3) add OID implementation for NVRAM read/write service + * +** +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include + +#include + +#include "gl_os.h" + +#ifndef CONFIG_X86 +#if defined(CONFIG_HAS_EARLY_SUSPEND) +#include +#endif +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define WIFI_NVRAM_FILE_NAME "/etc/firmware/nvram/WIFI" +#define WIFI_NVRAM_CUSTOM_NAME "/etc/firmware/nvram/WIFI_CUSTOM" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static int netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + UINT_8 ip[4] = { 0 }; + UINT_32 u4NumIPv4 = 0; +/* #ifdef CONFIG_IPV6 */ +#if 0 + UINT_8 ip6[16] = { 0 }; /* FIX ME: avoid to allocate large memory in stack */ + UINT_32 u4NumIPv6 = 0; +#endif + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct net_device *prDev = ifa->ifa_dev->dev; + UINT_32 i; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (prDev == NULL) { + DBGLOG(REQ, ERROR, "netdev_event: device is empty.\n"); + return NOTIFY_DONE; + } + DBGLOG(REQ, INFO, "netdev_event, addr=%x, notification=%lx, dev_name=%s\n", + ifa->ifa_address, notification, prDev->name); + if (!fgIsUnderSuspend) + return NOTIFY_DONE; + if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { + DBGLOG(REQ, WARN, "netdev_event: not our device\n"); + return NOTIFY_DONE; + } +#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ + { + /* printk(KERN_INFO "[netdev_event] IPV4_DAD is unlock now!!\n"); */ + prGlueInfo->fgIsDad = FALSE; + } +#endif + + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + + if (prGlueInfo == NULL) { + DBGLOG(REQ, ERROR, "netdev_event: prGlueInfo is empty.\n"); + return NOTIFY_DONE; + } + ASSERT(prGlueInfo); + + /* <3> get the IPv4 address */ + if (!prDev || !(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local))) { + DBGLOG(REQ, INFO, "ip is not available.\n"); + return NOTIFY_DONE; + } + + kalMemCopy(ip, &(((struct in_device *)(prDev->ip_ptr))->ifa_list->ifa_local), sizeof(ip)); + DBGLOG(REQ, INFO, "ip is %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + + /* todo: traverse between list to find whole sets of IPv4 addresses */ + if (!((ip[0] == 0) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 0))) + u4NumIPv4++; +/* #ifdef CONFIG_IPV6 */ +#if 0 + if (!prDev || !(prDev->ip6_ptr) || + !((struct in_device *)(prDev->ip6_ptr))->ifa_list || + !(&(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local))) { + DBGLOG(REQ, INFO, "ipv6 is not available.\n"); + return NOTIFY_DONE; + } + + kalMemCopy(ip6, &(((struct in_device *)(prDev->ip6_ptr))->ifa_list->ifa_local), sizeof(ip6)); + DBGLOG(REQ, INFO, "ipv6 is %d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d.%d\n", + ip6[0], ip6[1], ip6[2], ip6[3], + ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); + + /* todo: traverse between list to find whole sets of IPv6 addresses */ + if (!((ip6[0] == 0) && (ip6[1] == 0) && (ip6[2] == 0) && (ip6[3] == 0) && (ip6[4] == 0) && (ip6[5] == 0))) + /* u4NumIPv6++; */ +#endif + + /* here we can compare the dev with other network's netdev to */ + /* set the proper arp filter */ + /* */ + /* IMPORTANT: please make sure if the context can sleep, if the context can't sleep */ + /* we should schedule a kernel thread to do this for us */ + + /* <7> set up the ARP filter */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + UINT_32 u4SetInfoLen = 0; + UINT_8 aucBuf[32] = { 0 }; + UINT_32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = (P_PARAM_NETWORK_ADDRESS_LIST) aucBuf; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = prParamNetAddrList->arAddress; + +/* #ifdef CONFIG_IPV6 */ +#if 0 + prParamNetAddrList->u4AddressCount = u4NumIPv4 + u4NumIPv6; +#else + prParamNetAddrList->u4AddressCount = u4NumIPv4; +#endif + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = sizeof(PARAM_NETWORK_ADDRESS_IP); /* 4;; */ + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; +#if 0 + kalMemCopy(prParamNetAddr->aucAddress, ip, sizeof(ip)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip); +#else + prParamIpAddr = (P_PARAM_NETWORK_ADDRESS_IP) prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, ip, sizeof(ip)); + prParamNetAddr = + (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(PARAM_NETWORK_ADDRESS)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(PARAM_NETWORK_ADDRESS); +#endif + } +/* #ifdef CONFIG_IPV6 */ +#if 0 + for (i = 0; i < u4NumIPv6; i++) { + prParamNetAddr->u2AddressLength = 6; + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + kalMemCopy(prParamNetAddr->aucAddress, ip6, sizeof(ip6)); + prParamNetAddr = (P_PARAM_NETWORK_ADDRESS) ((PUINT_8) prParamNetAddr + sizeof(ip6)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + sizeof(ip6); + } +#endif + ASSERT(u4Len <= sizeof(aucBuf)); + + DBGLOG(REQ, INFO, "kalIoctl (0x%p, 0x%p)\n", prGlueInfo, prParamNetAddrList); + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetNetworkAddress, + (PVOID) prParamNetAddrList, u4Len, FALSE, FALSE, TRUE, FALSE, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) + DBGLOG(REQ, ERROR, "set HW pattern filter fail 0x%x\n", rStatus); + } + + return NOTIFY_DONE; + +} + +/* #if CFG_SUPPORT_HOTSPOT_2_0 */ +#if 0 +static int net6dev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; + struct net_device *prDev = ifa->idev->dev; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (prDev == NULL) { + DBGLOG(REQ, INFO, "net6dev_event: device is empty.\n"); + return NOTIFY_DONE; + } + + if ((strncmp(prDev->name, "p2p", 3) != 0) && (strncmp(prDev->name, "wlan", 4) != 0)) { + DBGLOG(REQ, INFO, "net6dev_event: xxx\n"); + return NOTIFY_DONE; + } + + if (strncmp(prDev->name, "p2p", 3) == 0) { + /* because we store the address of prGlueInfo in p2p's private date of net device */ + /* *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; */ + prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev)); + } else { /* wlan0 */ + prGlueInfo = (P_GLUE_INFO_T) netdev_priv(prDev); + } + + if (prGlueInfo == NULL) { + DBGLOG(REQ, INFO, "netdev_event: prGlueInfo is empty.\n"); + return NOTIFY_DONE; + } + /* printk(KERN_INFO "[net6dev_event] IPV6_DAD is unlock now!!\n"); */ + prGlueInfo->fgIs6Dad = FALSE; + + return NOTIFY_DONE; +} +#endif + +static struct notifier_block inetaddr_notifier = { + .notifier_call = netdev_event, +}; + +#if 0 /* CFG_SUPPORT_HOTSPOT_2_0 */ +static struct notifier_block inet6addr_notifier = { + .notifier_call = net6dev_event, +}; +#endif + +void wlanRegisterNotifier(void) +{ + register_inetaddr_notifier(&inetaddr_notifier); + +#if CFG_SUPPORT_HOTSPOT_2_0 + /* register_inet6addr_notifier(&inet6addr_notifier); */ +#endif +} + +/* EXPORT_SYMBOL(wlanRegisterNotifier); */ + +void wlanUnregisterNotifier(void) +{ + unregister_inetaddr_notifier(&inetaddr_notifier); + +#if CFG_SUPPORT_HOTSPOT_2_0 + /* unregister_inetaddr_notifier(&inet6addr_notifier); */ +#endif +} + +/* EXPORT_SYMBOL(wlanUnregisterNotifier); */ + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Utility function for reading data from files on NVRAM-FS +* +* \param[in] +* filename +* len +* offset +* \param[out] +* buf +* \return +* actual length of data being read +*/ +/*----------------------------------------------------------------------------*/ +static int nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_RDONLY, 0644); + + if (IS_ERR(fd)) { + DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to open!!\n"); + return -1; + } + + do { + //if ((fd->f_op == NULL) || (fd->f_op->read == NULL)) { + if ( fd->f_op == NULL ) { + DBGLOG(INIT, INFO, "[MT6620][nvram_read] : file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, INFO, "[MT6620][nvram_read] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = vfs_read(fd, buf, len, &fd->f_pos); + + } while (FALSE); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; + +#else /* !CFG_SUPPORT_NVRAM */ + + return -EIO; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief Utility function for writing data to files on NVRAM-FS +* +* \param[in] +* filename +* buf +* len +* offset +* \return +* actual length of data being written +*/ +/*----------------------------------------------------------------------------*/ +static int nvram_write(char *filename, char *buf, ssize_t len, int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY | O_CREAT, 0644); + + if (IS_ERR(fd)) { + DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to open!!\n"); + return -1; + } + + do { + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) { + DBGLOG(INIT, INFO, "[MT6620][nvram_write] : file can not be write!!\n"); + break; + } + /* End of if */ + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, INFO, "[MT6620][nvram_write] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = vfs_write(fd, buf, len, &fd->f_pos); + + } while (FALSE); + + filp_close(fd, NULL); + + set_fs(old_fs); + + return retLen; + +#else /* !CFG_SUPPORT_NVRAMS */ + + return -EIO; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief API for reading data on NVRAM +* +* \param[in] +* prGlueInfo +* u4Offset +* \param[out] +* pu2Data +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Offset, OUT PUINT_16 pu2Data) +{ + if (pu2Data == NULL) + return FALSE; + + if (nvram_read(WIFI_NVRAM_FILE_NAME, + (char *)pu2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { + return FALSE; + } else { + return TRUE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! +* \brief API for writing data on NVRAM +* +* \param[in] +* prGlueInfo +* u4Offset +* u2Data +* \return +* TRUE +* FALSE +*/ +/*----------------------------------------------------------------------------*/ +BOOLEAN kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, UINT_32 u4Offset, UINT_16 u2Data) +{ + if (nvram_write(WIFI_NVRAM_FILE_NAME, + (char *)&u2Data, sizeof(unsigned short), u4Offset) != sizeof(unsigned short)) { + return FALSE; + } else { + return TRUE; + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h new file mode 100644 index 0000000000000..9444d415c60e8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/gen2/os/version.h @@ -0,0 +1,190 @@ +/* +** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/version.h#1 +*/ + +/*! \file "version.h" + \brief Driver's version definition + +*/ + +/* +** Log: version.h + * + * 11 01 2011 chinglan.wang + * NULL + * Change the version number to v2.0.1.1. + * + * 08 26 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.9.. + * + * 08 23 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.8. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * correct typo. + * + * 08 15 2011 cp.wu + * [WCXRP00000851] [MT6628 Wi-Fi][Driver] Add HIFSYS related definition to driver source tree + * for building MT6628 Win32 driver environment + * + * 08 03 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.7. + * + * 07 24 2011 puff.wen + * NULL + * [MT5931][Beta 5]Change the version number to v0.2.2.0 + * + * 06 01 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.6.. + * + * 05 09 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.5.. + * + * 04 19 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.4. + * + * 04 18 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.3. + * + * 03 25 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.2. + * + * 03 21 2011 chinglan.wang + * NULL + * Change the version number to 2.0.0.1. + * + * 03 18 2011 chinglan.wang + * NULL + * Change the version number to v2.0.0.0. + * + * 02 11 2011 chinglan.wang + * NULL + * Change to the version 1.2.0.2. + * + * 02 10 2011 chinglan.wang + * NULL + * Change the version to 1.2.0.1. + * + * 02 08 2011 cp.wu + * [WCXRP00000427] [MT6620 Wi-Fi][Driver] Modify veresion information to match with release revision number + * change version number to v1.2.0.0 for preparing v1.2 software package release. + * + * 12 10 2010 kevin.huang + * [WCXRP00000128] [MT6620 Wi-Fi][Driver] Add proc support to Android Driver for debug and driver status check + * Add Linux Proc Support + * + * 10 07 2010 cp.wu + * [WCXRP00000083] [MT5931][Driver][FW] Add necessary logic for MT5931 first connection + * [WINDDK] build system changes for MT5931 + * + * 07 08 2010 cp.wu + * + * [WPD00003833] [MT6620 and MT5931] Driver migration - move to new repository. + * + * 06 06 2010 kevin.huang + * [WPD00003832][MT6620 5931] Create driver base + * [MT6620 5931] Create driver base +** \main\maintrunk.MT6620WiFiDriver_Prj\5 2009-12-14 14:10:55 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\4 2009-11-17 22:41:00 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\3 2009-11-13 16:20:33 GMT mtk01084 +** \main\maintrunk.MT6620WiFiDriver_Prj\2 2009-03-10 20:27:13 GMT mtk01426 +** Init for develop +** +*/ + +#ifndef _VERSION_H +#define _VERSION_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#ifndef NIC_AUTHOR +#define NIC_AUTHOR "NIC_AUTHOR" +#endif +#ifndef NIC_DESC +#define NIC_DESC "NIC_DESC" +#endif + +#ifndef NIC_NAME +#if defined(MT6620) +#define NIC_NAME "MT6620" +#define NIC_DEVICE_ID "MT6620" +#define NIC_DEVICE_ID_LOW "mt6620" +#elif defined(MT6628) +#define NIC_NAME "MT6582" +#define NIC_DEVICE_ID "MT6582" +#define NIC_DEVICE_ID_LOW "mt6582" +#endif +#endif + +/* NIC driver information */ +#define NIC_VENDOR "MediaTek Inc." +#define NIC_VENDOR_OUI {0x00, 0x0C, 0xE7} + +#if defined(MT6620) +#define NIC_PRODUCT_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter" +#define NIC_DRIVER_NAME "MediaTek Inc. MT6620 Wireless LAN Adapter Driver" +#elif defined(MT6628) +/* #define NIC_PRODUCT_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter" */ +/* #define NIC_DRIVER_NAME "MediaTek Inc. MT6628 Wireless LAN Adapter Driver" */ +#define NIC_PRODUCT_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter" +#define NIC_DRIVER_NAME "MediaTek Inc. MT6582 Wireless LAN Adapter Driver" +#endif + +/* Define our driver version */ +#define NIC_DRIVER_MAJOR_VERSION 2 +#define NIC_DRIVER_MINOR_VERSION 0 +#define NIC_DRIVER_VERSION (2, 0, 1, 1) +#define NIC_DRIVER_VERSION_STRING "2.0.1.1" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _VERSION_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/aee.h b/drivers/misc/mediatek/include/mt-plat/aee.h new file mode 100644 index 0000000000000..d1cf448dafb21 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/aee.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#if !defined(__AEE_H__) +#define __AEE_H__ + +#include +#include + +#define AEE_MODULE_NAME_LENGTH 64 +#define AEE_PROCESS_NAME_LENGTH 256 +#define AEE_BACKTRACE_LENGTH 3072 + +typedef enum { + AE_DEFECT_FATAL, + AE_DEFECT_EXCEPTION, + AE_DEFECT_WARNING, + AE_DEFECT_REMINDING, + AE_DEFECT_ATTR_END +} AE_DEFECT_ATTR; + +typedef enum { + AE_KE = 0, /* Fatal Exception */ + AE_HWT, + AE_REBOOT, + AE_NE, + AE_JE, + AE_SWT, + AE_EE, + AE_EXP_ERR_END, + AE_ANR, /* Error or Warning or Defect */ + AE_RESMON, + AE_MODEM_WARNING, + AE_WTF, + AE_WRN_ERR_END, + AE_MANUAL, /* Manual Raise */ + AE_EXP_CLASS_END, + + AE_KERNEL_PROBLEM_REPORT = 1000, + AE_SYSTEM_JAVA_DEFECT, + AE_SYSTEM_NATIVE_DEFECT, + AE_MANUAL_MRDUMP_KEY, +} AE_EXP_CLASS; /* General Program Exception Class */ + +typedef enum { + AEE_REBOOT_MODE_NORMAL = 0, + AEE_REBOOT_MODE_KERNEL_OOPS, + AEE_REBOOT_MODE_KERNEL_PANIC, + AEE_REBOOT_MODE_NESTED_EXCEPTION, + AEE_REBOOT_MODE_WDT, + AEE_REBOOT_MODE_MANUAL_KDUMP, +} AEE_REBOOT_MODE; + +#define AEE_SZ_SYMBOL_L 140 +#define AEE_SZ_SYMBOL_S 80 +struct aee_bt_frame { + __u64 pc; + __u64 lr; + __u32 pad[5]; + char pc_symbol[AEE_SZ_SYMBOL_S]; /* Now we use different symbol length for PC &LR */ + char lr_symbol[AEE_SZ_SYMBOL_L]; +}; + +/* aee_process_info struct should strictly small than ipanic_buffer, now 4KB */ +struct aee_process_info { + char process_path[AEE_PROCESS_NAME_LENGTH]; + char backtrace[AEE_BACKTRACE_LENGTH]; + struct aee_bt_frame ke_frame; +}; + +struct aee_process_bt { + __u32 pid; + __u32 nr_entries; + struct aee_bt_frame *entries; +}; + + +struct aee_thread_reg { + pid_t tid; + struct pt_regs regs; +}; + +struct aee_user_thread_stack { + pid_t tid; + int StackLength; + unsigned char *Userthread_Stack; /*8k stack ,define to char only for match 64bit/32bit*/ +}; + +struct aee_user_thread_maps { + pid_t tid; + int Userthread_mapsLength; + unsigned char *Userthread_maps; /*8k stack ,define to char only for match 64bit/32bit*/ +}; + + + +struct aee_oops { + struct list_head list; + AE_DEFECT_ATTR attr; + AE_EXP_CLASS clazz; + + char module[AEE_MODULE_NAME_LENGTH]; + /* consist with struct aee_process_info */ + char process_path[AEE_PROCESS_NAME_LENGTH]; + char backtrace[AEE_BACKTRACE_LENGTH]; + struct aee_bt_frame ke_frame; + + char *detail; + int detail_len; + + char *console; + int console_len; + + char *android_main; + int android_main_len; + char *android_radio; + int android_radio_len; + char *android_system; + int android_system_len; + + char *userspace_info; + int userspace_info_len; + + char *mmprofile; + int mmprofile_len; + + char *mini_rdump; + int mini_rdump_len; + + + struct aee_user_thread_stack userthread_stack; + struct aee_thread_reg userthread_reg; + struct aee_user_thread_maps userthread_maps; + + int dump_option; +}; + +struct aee_kernel_api { + void (*kernel_reportAPI)(const AE_DEFECT_ATTR attr, const int db_opt, const char *module, + const char *msg); + void (*md_exception)(const char *assert_type, const int *log, int log_size, const int *phy, + int phy_size, const char *detail, const int db_opt); + void (*md32_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); + void (*combo_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); + void (*scp_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); +}; + +void aee_sram_printk(const char *fmt, ...); +int aee_nested_printf(const char *fmt, ...); +void aee_wdt_irq_info(void); +void aee_wdt_fiq_info(void *arg, void *regs, void *svc_sp); +void aee_trigger_kdb(void); +struct aee_oops *aee_oops_create(AE_DEFECT_ATTR attr, AE_EXP_CLASS clazz, const char *module); +void aee_oops_set_backtrace(struct aee_oops *oops, const char *backtrace); +void aee_oops_set_process_path(struct aee_oops *oops, const char *process_path); +void aee_oops_free(struct aee_oops *oops); +/* powerkey press,modules use bits */ +#define AE_WDT_Powerkey_DEVICE_PATH "/dev/kick_powerkey" +#define WDT_SETBY_DEFAULT (0) +#define WDT_SETBY_Backlight (1<<0) +#define WDT_SETBY_Display (1<<1) +#define WDT_SETBY_SF (1<<2) +#define WDT_SETBY_PM (1<<3) +#define WDT_SETBY_WMS_DISABLE_PWK_MONITOR (0xAEEAEE00) +#define WDT_SETBY_WMS_ENABLE_PWK_MONITOR (0xAEEAEE01) +#define WDT_PWK_HANG_FORCE_HWT (0xAEE0FFFF) + +/* QHQ RT Monitor */ +#define AEEIOCTL_RT_MON_Kick _IOR('p', 0x0A, int) +#define AE_WDT_DEVICE_PATH "/dev/RT_Monitor" +/* QHQ RT Monitor end */ + +/* DB dump option bits, set relative bit to 1 to include related file in db */ +#define DB_OPT_DEFAULT (0) +#define DB_OPT_FTRACE (1<<0) +#define DB_OPT_PRINTK_TOO_MUCH (1<<1) +#define DB_OPT_NE_JBT_TRACES (1<<2) +#define DB_OPT_SWT_JBT_TRACES (1<<3) +#define DB_OPT_VM_TRACES (1<<4) +#define DB_OPT_DUMPSYS_ACTIVITY (1<<5) +#define DB_OPT_DUMPSYS_WINDOW (1<<6) +#define DB_OPT_DUMPSYS_GFXINFO (1<<7) +#define DB_OPT_DUMPSYS_SURFACEFLINGER (1<<8) +#define DB_OPT_DISPLAY_HANG_DUMP (1<<9) +#define DB_OPT_LOW_MEMORY_KILLER (1<<10) +#define DB_OPT_PROC_MEM (1<<11) +#define DB_OPT_FS_IO_LOG (1<<12) +#define DB_OPT_PROCESS_COREDUMP (1<<13) +#define DB_OPT_VM_HPROF (1<<14) +#define DB_OPT_PROCMEM (1<<15) +#define DB_OPT_DUMPSYS_INPUT (1<<16) +#define DB_OPT_MMPROFILE_BUFFER (1<<17) +#define DB_OPT_BINDER_INFO (1<<18) +#define DB_OPT_WCN_ISSUE_INFO (1<<19) +#define DB_OPT_DUMMY_DUMP (1<<20) +#define DB_OPT_PID_MEMORY_INFO (1<<21) +#define DB_OPT_VM_OOME_HPROF (1<<22) +#define DB_OPT_PID_SMAPS (1<<23) +#define DB_OPT_PROC_CMDQ_INFO (1<<24) +#define DB_OPT_PROC_USKTRK (1<<25) +#define DB_OPT_SF_RTT_DUMP (1<<26) +#define DB_OPT_PAGETYPE_INFO (1<<27) +#define DB_OPT_DUMPSYS_PROCSTATS (1<<28) +#define DB_OPT_DUMP_DISPLAY (1<<29) +#define DB_OPT_NATIVE_BACKTRACE (1<<30) +#define DB_OPT_AARCH64 (1<<31) + +#define aee_kernel_exception(module, msg...) \ + aee_kernel_exception_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_warning(module, msg...) \ + aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_reminding(module, msg...) \ + aee_kernel_reminding_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_dal_show(msg) \ + aee_kernel_dal_api(__FILE__, __LINE__, msg) + +#define aed_md_exception(log, log_size, phy, phy_size, detail) \ + aed_md_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_md32_exception(log, log_size, phy, phy_size, detail) \ + aed_md32_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_scp_exception(log, log_size, phy, phy_size, detail) \ + aed_scp_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_combo_exception(log, log_size, phy, phy_size, detail) \ + aed_combo_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) + +void aee_kernel_exception_api(const char *file, const int line, const int db_opt, + const char *module, const char *msg, ...); +void aee_kernel_warning_api(const char *file, const int line, const int db_opt, const char *module, + const char *msg, ...); +void aee_kernel_reminding_api(const char *file, const int line, const int db_opt, + const char *module, const char *msg, ...); +void aee_kernel_dal_api(const char *file, const int line, const char *msg); + +void aed_md_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_md32_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_scp_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_combo_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); + +void aee_kernel_wdt_kick_Powkey_api(const char *module, int msg); +int aee_kernel_wdt_kick_api(int kinterval); +void aee_powerkey_notify_press(unsigned long pressed); +int aee_kernel_Powerkey_is_press(void); + +void ipanic_recursive_ke(struct pt_regs *regs, struct pt_regs *excp_regs, int cpu); + +/* QHQ RT Monitor */ +void aee_kernel_RT_Monitor_api(int lParam); +/* QHQ RT Monitor end */ +void mt_fiq_printf(const char *fmt, ...); +void aee_register_api(struct aee_kernel_api *aee_api); +int aee_in_nested_panic(void); +void aee_stop_nested_panic(struct pt_regs *regs); +void aee_wdt_dump_info(void); +void aee_wdt_printf(const char *fmt, ...); + +void aee_fiq_ipi_cpu_stop(void *arg, void *regs, void *svc_sp); + +#if defined(CONFIG_MTK_AEE_DRAM_CONSOLE) +void aee_dram_console_reserve_memory(void); +#else +static inline void aee_dram_console_reserve_memory(void) +{ +} +#endif + +extern void *aee_excp_regs; /* To store latest exception, in case of stack corruption */ +#endif /* __AEE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mrdump.h b/drivers/misc/mediatek/include/mt-plat/mrdump.h new file mode 100644 index 0000000000000..b6bdfa2f7617c --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mrdump.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#if !defined(__MRDUMP_H__) +#define __MRDUMP_H__ + +#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#define reg_pc pc +#define reg_lr regs[30] +#define reg_sp sp +#define reg_fp regs[29] +#else +#define reg_pc ARM_pc +#define reg_lr ARM_lr +#define reg_sp ARM_sp +#define reg_ip ARM_ip +#define reg_fp ARM_fp +#endif + +#define MRDUMP_CPU_MAX 16 + +#define MRDUMP_DEV_NULL 0 +#define MRDUMP_DEV_SDCARD 1 +#define MRDUMP_DEV_EMMC 2 + +#define MRDUMP_FS_NULL 0 +#define MRDUMP_FS_VFAT 1 +#define MRDUMP_FS_EXT4 2 + +#define MRDUMP_GO_DUMP "MRDUMP04" + +typedef uint32_t arm32_gregset_t[18]; +typedef uint64_t aarch64_gregset_t[34]; + +struct mrdump_crash_record { + int reboot_mode; + + char msg[128]; + char backtrace[512]; + + uint32_t fault_cpu; + + union { + arm32_gregset_t arm32_regs; + aarch64_gregset_t aarch64_regs; + } cpu_regs[MRDUMP_CPU_MAX]; +}; + +struct mrdump_machdesc { + uint32_t crc; + + uint32_t output_device; + + uint32_t nr_cpus; + + uint64_t page_offset; + uint64_t high_memory; + + uint64_t vmalloc_start; + uint64_t vmalloc_end; + + uint64_t modules_start; + uint64_t modules_end; + + uint64_t phys_offset; + uint64_t master_page_table; + + uint32_t output_fstype; + uint32_t output_lbaooo; +}; + +struct mrdump_control_block { + char sig[8]; + + struct mrdump_machdesc machdesc; + struct mrdump_crash_record crash_record; +}; + +/* NOTE!! any change to this struct should be compatible in aed */ +struct mrdump_mini_reg_desc { + unsigned long reg; /* register value */ + unsigned long kstart; /* start kernel addr of memory dump */ + unsigned long kend; /* end kernel addr of memory dump */ + unsigned long pos; /* next pos to dump */ + int valid; /* 1: valid regiser, 0: invalid regiser */ + int pad; /* reserved */ + loff_t offset; /* offset in buffer */ +}; + +/* it should always be smaller than MRDUMP_MINI_HEADER_SIZE */ +struct mrdump_mini_header { + struct mrdump_mini_reg_desc reg_desc[ELF_NGREG]; +}; + +#define MRDUMP_MINI_NR_SECTION 60 +#define MRDUMP_MINI_SECTION_SIZE (32 * 1024) +#define NT_IPANIC_MISC 4095 +#define MRDUMP_MINI_NR_MISC 20 + +struct mrdump_mini_elf_misc { + unsigned long vaddr; + unsigned long paddr; + unsigned long start; + unsigned long size; +}; + +#define NOTE_NAME_SHORT 12 +#define NOTE_NAME_LONG 20 + +struct mrdump_mini_elf_psinfo { + struct elf_note note; + char name[NOTE_NAME_SHORT]; + struct elf_prpsinfo data; +}; + +struct mrdump_mini_elf_prstatus { + struct elf_note note; + char name[NOTE_NAME_SHORT]; + struct elf_prstatus data; +}; + +struct mrdump_mini_elf_note { + struct elf_note note; + char name[NOTE_NAME_LONG]; + struct mrdump_mini_elf_misc data; +}; + +struct mrdump_mini_elf_header { + struct elfhdr ehdr; + struct elf_phdr phdrs[MRDUMP_MINI_NR_SECTION]; + struct mrdump_mini_elf_psinfo psinfo; + struct mrdump_mini_elf_prstatus prstatus[NR_CPUS + 1]; + struct mrdump_mini_elf_note misc[MRDUMP_MINI_NR_MISC]; +}; + +typedef struct mrdump_rsvmem_block { + phys_addr_t start_addr; + phys_addr_t size; +} mrdump_rsvmem_block_t; + + +#define MRDUMP_MINI_HEADER_SIZE ALIGN(sizeof(struct mrdump_mini_elf_header), PAGE_SIZE) +#define MRDUMP_MINI_DATA_SIZE (MRDUMP_MINI_NR_SECTION * MRDUMP_MINI_SECTION_SIZE) +#define MRDUMP_MINI_BUF_SIZE (MRDUMP_MINI_HEADER_SIZE + MRDUMP_MINI_DATA_SIZE) + +#ifdef CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR +#define MRDUMP_MINI_BUF_PADDR (CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR + 0xf0000) +#else +#define MRDUMP_MINI_BUF_PADDR 0 +#endif + +int mrdump_init(void); +void __mrdump_create_oops_dump(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, + ...); +#if defined(CONFIG_MTK_AEE_IPANIC) +void mrdump_rsvmem(void); +#else +static inline void mrdump_rsvmem(void) +{ +} +#endif + +#if defined(CONFIG_MTK_AEE_MRDUMP) +void aee_kdump_reboot(AEE_REBOOT_MODE, const char *msg, ...); +#else +static inline void aee_kdump_reboot(AEE_REBOOT_MODE reboot_mode, const char *msg, ...) +{ +} +#endif + +typedef int (*mrdump_write)(void *buf, int off, int len, int encrypt); +#if defined(CONFIG_MTK_AEE_IPANIC) +int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, + loff_t sd_offset, const char *msg, va_list ap); +void mrdump_mini_reserve_memory(void); +#else +static inline int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, + loff_t sd_offset, const char *msg, va_list ap) +{ + return 0; +} + +static inline void mrdump_mini_reserve_memory(void) +{ +} +#endif + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h new file mode 100644 index 0000000000000..1b60f007d0fdf --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef _MT8167_THERMAL_H +#define _MT8167_THERMAL_H + +#include +#include +#include +#include + +#include +#include + +#include "sync_write.h" + +extern void __iomem *thermal_base; +extern void __iomem *auxadc_ts_base; +extern void __iomem *apmixed_base; +extern void __iomem *pericfg_base; +extern int auxadc_ts_phy_base; +extern int apmixed_phy_base; + +#define THERM_CTRL_BASE_2 thermal_base +#define AUXADC_BASE_2 auxadc_ts_base +#define PERICFG_BASE pericfg_base +#define APMIXED_BASE_2 apmixed_base + +#define MT6752_EVB_BUILD_PASS /*Jerry fix build error FIX_ME*/ + +/******************************************************************************* +* AUXADC Register Definition +******************************************************************************/ +/*AUXADC_BASE: 0xF1001000 from Vincent Liang 2014.5.8*/ + +#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /*yes, 0x11003000*/ +#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) +#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) +#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) +#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) +/*#define AUXADC_CON3_V (AUXADC_BASE_2 + 0x014)*/ +#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) +#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) +#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) +#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) +#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) +#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) +#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) +#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) +#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) +#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) +#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) +#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) +#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) + +#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) +#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) +#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) +#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) +#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) +/*#define AUXADC_CON3_P (auxadc_ts_phy_base + 0x014)*/ +#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) +#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) +#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) +#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) +#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) +#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) +#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) +#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) +#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) +#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) +#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) +#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) + +#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) + +/******************************************************************************* +* Peripheral Configuration Register Definition +******************************************************************************/ +/*#define PERICFG_BASE (0x10002000)*/ +#define PERI_GLOBALCON_RST0 (pericfg_base + 0x000) /*yes, 0x10002000*/ +/******************************************************************************* + * APMixedSys Configuration Register Definition + ******************************************************************************/ +#define TS_CON0 (APMIXED_BASE_2 + 0x600) /*yes 0x10209000*/ +#define TS_CON1 (APMIXED_BASE_2 + 0x604) +#define TS_CON0_TM (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ +#define TS_CON1_TM (APMIXED_BASE_2 + 0x604) +#define TS_CON0_P (apmixed_phy_base + 0x600) +#define TS_CON1_P (apmixed_phy_base + 0x604) + +/******************************************************************************* + * Thermal Controller Register Definition + ******************************************************************************/ +#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /*yes 0x1100B000*/ +#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) +#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) +#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) +#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) +#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) +#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) +#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) +#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) +#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) +#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) +#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) +#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) +#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) +#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) +#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) +#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) +#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) +#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) +#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) +#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) + +#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) +#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) +#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) +#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) +#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) +#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) +#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) +#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) +#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) +#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) +#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) +#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) +#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) +#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) +#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) +#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) +#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) +#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) +#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) + +#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) +#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) +#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) +#define TEMPIMMD3 (THERM_CTRL_BASE_2 + 0x0BC) + + +#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) +#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) +#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) +#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) + +#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) +#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) +#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) +#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) + +#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) +#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) +#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) +#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) +#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) +#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) +#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) +#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /*Only for DE debug*/ +#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) +#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) +#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) +#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) +#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) + + +#define PTPSPARE0_P (thermal_phy_base + 0x420) +#define PTPSPARE1_P (thermal_phy_base + 0x424) +#define PTPSPARE2_P (thermal_phy_base + 0x428) +#define PTPSPARE3_P (thermal_phy_base + 0x42C) + +/******************************************************************************* + * Thermal Controller Register Mask Definition + ******************************************************************************/ +#define THERMAL_ENABLE_SEN0 0x1 +#define THERMAL_ENABLE_SEN1 0x2 +#define THERMAL_ENABLE_SEN2 0x4 +#define THERMAL_MONCTL0_MASK 0x00000007 + +#define THERMAL_PUNT_MASK 0x00000FFF +#define THERMAL_FSINTVL_MASK 0x03FF0000 +#define THERMAL_SPINTVL_MASK 0x000003FF +#define THERMAL_MON_INT_MASK 0x0007FFFF + +#define THERMAL_MON_CINTSTS0 0x000001 +#define THERMAL_MON_HINTSTS0 0x000002 +#define THERMAL_MON_LOINTSTS0 0x000004 +#define THERMAL_MON_HOINTSTS0 0x000008 +#define THERMAL_MON_NHINTSTS0 0x000010 +#define THERMAL_MON_CINTSTS1 0x000020 +#define THERMAL_MON_HINTSTS1 0x000040 +#define THERMAL_MON_LOINTSTS1 0x000080 +#define THERMAL_MON_HOINTSTS1 0x000100 +#define THERMAL_MON_NHINTSTS1 0x000200 +#define THERMAL_MON_CINTSTS2 0x000400 +#define THERMAL_MON_HINTSTS2 0x000800 +#define THERMAL_MON_LOINTSTS2 0x001000 +#define THERMAL_MON_HOINTSTS2 0x002000 +#define THERMAL_MON_NHINTSTS2 0x004000 +#define THERMAL_MON_TOINTSTS 0x008000 +#define THERMAL_MON_IMMDINTSTS0 0x010000 +#define THERMAL_MON_IMMDINTSTS1 0x020000 +#define THERMAL_MON_IMMDINTSTS2 0x040000 +#define THERMAL_MON_FILTINTSTS0 0x080000 +#define THERMAL_MON_FILTINTSTS1 0x100000 +#define THERMAL_MON_FILTINTSTS2 0x200000 + + +#define THERMAL_tri_SPM_State0 0x20000000 +#define THERMAL_tri_SPM_State1 0x40000000 +#define THERMAL_tri_SPM_State2 0x80000000 + + +#define THERMAL_MSRCTL0_MASK 0x00000007 +#define THERMAL_MSRCTL1_MASK 0x00000038 +#define THERMAL_MSRCTL2_MASK 0x000001C0 + +enum thermal_sensor_name { + THERMAL_SENSOR1 = 0,/*TS_MCU1*/ + THERMAL_SENSOR_NUM +}; + +enum thermal_bank_name { + THERMAL_BANK0 = 0, /*CPU (TS_MCU1) (TS1)*/ + THERMAL_BANK_NUM +}; + +struct TS_SVS { + unsigned int ts_MTS; + unsigned int ts_BTS; +}; + +struct mtk_gpu_power_info { + unsigned int gpufreq_khz; + unsigned int gpufreq_power; +}; + +/* svs driver need this function */ +extern void get_thermal_slope_intercept(struct TS_SVS *ts_info, enum thermal_bank_name ts_bank); + +/* mtk_thermal_platform.c need this */ +extern void set_taklking_flag(bool flag); + +#define THERMAL_WRAP_WR32(val, addr) mt_reg_sync_writel((val), ((void *)addr)) + +enum MTK_THERMAL_SENSOR_CPU_ID_MET { + MTK_THERMAL_SENSOR_TS1 = 0, + MTK_THERMAL_SENSOR_TS2, + MTK_THERMAL_SENSOR_TS3, + MTK_THERMAL_SENSOR_TS4, + MTK_THERMAL_SENSOR_TSABB, + + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + + MTK_THERMAL_SENSOR_CPU_COUNT +}; + +extern int tscpu_get_cpu_temp_met(enum MTK_THERMAL_SENSOR_CPU_ID_MET id); +extern int mtk_gpufreq_register(struct mtk_gpu_power_info *freqs, int num); + +typedef void (*met_thermalsampler_funcMET)(void); +void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); + +void tscpu_start_thermal(void); +void tscpu_stop_thermal(void); +void tscpu_cancel_thermal_timer(void); +void tscpu_start_thermal_timer(void); +int mtkts_bts_get_hw_temp(void); + +extern int get_immediate_ts1_wrap(void); +extern int get_immediate_ts2_wrap(void); +extern int get_immediate_ts3_wrap(void); + +extern int is_cpu_power_unlimit(void); /* in mtk_ts_cpu.c */ +extern int is_cpu_power_min(void); /* in mtk_ts_cpu.c */ +extern int get_cpu_target_tj(void); +extern int get_cpu_target_offset(void); + +extern int mtktscpu_debug_log; + +#endif + diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h new file mode 100644 index 0000000000000..142a007805b95 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 MediaTek, Inc. + * + * Author: Holmes Chiou + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MT_FREQHOPPING_H__ +#define __MT_FREQHOPPING_H__ + +#define MT_FHPLL_MAX 6 +#define MT_SSC_NR_PREDEFINE_SETTING 10 /* TODO: is 10 a good number ? */ + +#define MEMPLL_SSC 0 +#define MAINPLL_SSC 1 + +#define FHTAG "[FH]" + +#define VERBOSE_DEBUG 0 + +#if VERBOSE_DEBUG +#define FH_MSG(fmt, args...) \ + pr_debug(FHTAG""fmt" <- %s(): L<%d> PID<%s><%d>\n", ##args, __func__, __LINE__, current->comm, current->pid) +#else + +#if 1 /* log level is 6 xlog */ +#define FH_MSG(fmt, args...) pr_debug(fmt, ##args) +#else /* log level is 4 (printk) */ +#define FH_MSG(fmt, args...) printk(FHTAG""fmt"\n", ##args) +#endif + +#endif + +/* not support at mt2701 yet */ +/* DRAMC */ +#define FULLY_VERSION_FHCTL 0 + +enum FH_FH_STATUS { + FH_FH_DISABLE = 0, + FH_FH_ENABLE_SSC, + FH_FH_ENABLE_DFH, + FH_FH_ENABLE_DVFS, +}; + +enum FH_PLL_STATUS { + FH_PLL_DISABLE = 0, + FH_PLL_ENABLE = 1 +}; + +/* TODO: FREQ_MODIFIED should not be here */ +/* FH_PLL_STATUS_FREQ_MODIFIED = 3 */ + + +enum FH_CMD { + FH_CMD_ENABLE = 1, + FH_CMD_DISABLE, + FH_CMD_ENABLE_USR_DEFINED, + FH_CMD_DISABLE_USR_DEFINED, + FH_CMD_INTERNAL_MAX_CMD, +/* TODO: do we need these cmds ? + * FH_CMD_PLL_ENABLE, + * FH_CMD_PLL_DISABLE, + * FH_CMD_EXT_ALL_FULL_RANGE_CMD, + * FH_CMD_EXT_ALL_HALF_RANGE_CMD, + * FH_CMD_EXT_DISABLE_ALL_CMD, + * FH_CMD_EXT_DESIGNATED_PLL_FULL_RANGE_CMD, + * FH_CMD_EXT_DESIGNATED_PLL_AND_SETTING_CMD +*/ +}; + +/* + * enum FH_OPCODE{ + * FH_OPCODE_ENABLE_WITH_ID = 1, + * FH_OPCODE_ENABLE_WITHOUT_ID, + * FH_OPCODE_DISABLE, + * }; +*/ + +enum FH_PLL_ID { + MT658X_FH_MINIMUMM_PLL = 0, + MT658X_FH_ARM_PLL = MT658X_FH_MINIMUMM_PLL, + MT658X_FH_MAIN_PLL = 1, + MT658X_FH_MEM_PLL = 2, + MT658X_FH_MSDC_PLL = 3, + MT658X_FH_MM_PLL = 4, /* MT658X_FH_TVD_PLL = 4, */ + MT658X_FH_VENC_PLL = 5, /* MT658X_FH_LVDS_PLL = 5, */ + /* 8127 FHCTL MB */ + MT658X_FH_TVD_PLL = 6, /* MT658X_FH_TVD_PLL = 6, */ + MT658X_FH_MAXIMUMM_PLL = MT658X_FH_TVD_PLL, + /* 8127 FHCTL ME */ + MT658X_FH_PLL_TOTAL_NUM +}; + +/* keep track the status of each PLL */ +/* TODO: do we need another "uint mode" for Dynamic FH */ +typedef struct { + unsigned int fh_status; + unsigned int pll_status; + unsigned int setting_id; + unsigned int curr_freq; + unsigned int user_defined; +} fh_pll_t; + + +/* Record the owner of enable freq hopping <==TBD */ +struct freqhopping_pll { + union { + int mt_pll[MT_FHPLL_MAX]; + struct { + int mt_arm_fhpll; + int mt_main_fhpll; + int mt_mem_fhpll; + int mt_msdc_fhpll; + int mt_mm_fhpll; + int mt_venc_fhpll; + }; + }; +}; + +struct freqhopping_ssc { + unsigned int freq; + unsigned int dt; + unsigned int df; + unsigned int upbnd; + unsigned int lowbnd; + unsigned int dds; +}; + +struct freqhopping_ioctl { + unsigned int pll_id; + struct freqhopping_ssc ssc_setting; /* used only when user-define */ + int result; +}; + +int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable); +void mt_freqhopping_init(void); +void mt_freqhopping_pll_init(void); +int mt_h2l_mempll(void); +int mt_l2h_mempll(void); +int mt_h2l_dvfs_mempll(void); +int mt_l2h_dvfs_mempll(void); +int mt_dfs_armpll(unsigned int current_freq, unsigned int target_freq); +int mt_is_support_DFS_mode(void); +void mt_fh_popod_save(void); +void mt_fh_popod_restore(void); +int mt_fh_dram_overclock(int clk); +int mt_fh_get_dramc(void); +unsigned int mt_get_emi_freq(void); + +#endif /* !__MT_FREQHOPPING_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h new file mode 100644 index 0000000000000..0c049db9aa977 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#define STA_POWER_DOWN 0 +#define STA_POWER_ON 1 + +/* + * 1. for CPU MTCMOS: CPU0, CPU1, CPU2, CPU3, DBG0, CPU4, CPU5, CPU6, CPU7, DBG1, CPUSYS1 + * 2. call spm_mtcmos_cpu_lock/unlock() before/after any operations + */ +extern int spm_mtcmos_cpu_init(void); +extern void spm_mtcmos_cpu_lock(unsigned long *flags); +extern void spm_mtcmos_cpu_unlock(unsigned long *flags); +extern int spm_mtcmos_ctrl_cpu(unsigned int cpu, int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu0(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu1(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu2(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu3(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu4(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu5(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu6(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu7(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpusys0(int state, int chkWfiBeforePdn); +extern bool spm_cpusys0_can_power_down(void); diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h new file mode 100644 index 0000000000000..28176b3cd9af1 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BOOT_SHARE_PAGE_H__ +#define __MTK_BOOT_SHARE_PAGE_H__ + +#define BOOT_SHARE_BASE (0xC0002000) /* address in linux kernel */ +#define BOOT_SHARE_SIZE (0x1000) /* page size 4K bytes */ + +#define BOOT_SHARE_MAGIC (0x4545544D) /* MTEE */ + +/* Memory map & defines for boot share page */ +/* + * Note: + * 1. BOOT_SHARE_XXXXX_OFST is the address offset related to BOOT_SHARE_BASE + */ +#define BOOT_SHARE_MAGIC1_OFST (0) +#define BOOT_SHARE_MAGIC1_SIZE (4) + +#define BOOT_SHARE_DEV_INFO_OFST (BOOT_SHARE_MAGIC1_OFST+BOOT_SHARE_MAGIC1_SIZE) +#define BOOT_SHARE_DEV_INFO_SIZE (16) + +#define BOOT_SHARE_HOTPLUG_OFST (1008) /* 16 bytes for hotplug/jump-reg */ +#define BOOT_SHARE_HOTPLUG_SIZE (32) + +#define BOOT_SHARE_MAGIC2_OFST (4092) +#define BOOT_SHARE_MAGIC2_SIZE (4) + +#endif /* __MTK_BOOT_SHARE_PAGE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h new file mode 100644 index 0000000000000..eefdaad4aaa5d --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _MT8127_THERMAL_H +#define _MT8127_THERMAL_H + +#include +#include +#include +#include + +#include +#include + +#include "mt-plat/sync_write.h" +#include + +/* #include */ +/* #include "../../../../../thermal/mt8127/inc/mt_gpufreq.h" */ + +#if 1 +extern void __iomem *thermal_base; +extern void __iomem *auxadc_ts_base; +extern void __iomem *pericfg_base; +extern void __iomem *apmixed_ts_base; + +extern int mtktscpu_limited_dmips; + +void __attribute__ ((weak)) mt_gpufreq_thermal_protect(unsigned int limited_power) { +} + +unsigned int __attribute__ ((weak)) mt_gpufreq_get_cur_freq(void) { + return 0; +} + +u32 __attribute__ ((weak)) get_devinfo_with_index(u32 index) { + return 0; +} + +extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); +extern int IMM_IsAdcInitReady(void); +extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); +extern int thermal_phy_base; +extern int auxadc_ts_phy_base; +extern int apmixed_phy_base; +extern int pericfg_phy_base; + +/* extern int last_abb_t; */ +/* extern int last_CPU2_t; */ +extern int get_immediate_temp2_wrap(void); +extern void mtkts_dump_cali_info(void); +extern u32 get_devinfo_with_index(u32 index); +extern int bts_cur_temp; + +#define THERM_CTRL_BASE_2 thermal_base +#define AUXADC_BASE_2 auxadc_ts_base +#define PERICFG_BASE_2 pericfg_base +#define APMIXED_BASE_2 apmixed_ts_base +#endif + +/******************************************************************************* + * AUXADC Register Definition + ******************************************************************************/ +#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /* yes, 0x11001000 */ +#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) +#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) +#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) +#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) +#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) +#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) +#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) +#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) +#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) +#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) +#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) +#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) +#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) +#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) +#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) +#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) +#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) +#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) +#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) +#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) +#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) +#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) +#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) +#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) +#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) +#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) +#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) +#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) +#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) +#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) +#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) +#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) +#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) +#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) +#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) + +/******************************************************************************* + * Peripheral Configuration Register Definition + ******************************************************************************/ +#define PERI_GLOBALCON_RST0 (PERICFG_BASE_2 + 0x000) /* yes, 0x10003000 */ + +/******************************************************************************* + * APMixedSys Configuration Register Definition + ******************************************************************************/ +#define TS_CON0 (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ +#define TS_CON1 (APMIXED_BASE_2 + 0x604) +/******************************************************************************* + * Thermal Controller Register Definition + ******************************************************************************/ +#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /* yes 0x1100B000 */ +#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) +#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) +#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) +#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) +#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) +#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) +#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) +#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) +#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) +#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) +#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) +#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) +#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) +#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) +#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) +#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) +#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) +#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) +#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) +#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) + +#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) +#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) +#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) +#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) +#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) +#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) +#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) +#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) +#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) +#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) +#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) +#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) +#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) +#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) +#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) +#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) +#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) +#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) +#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) + +#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) +#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) +#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) + +#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) +#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) +#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) +#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) + +#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) +#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) +#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) +#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) + +#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) +#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) +#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) +#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) +#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) +#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) +#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) +#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /* Only for DE debug */ +#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) +#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) +#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) +#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) +#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) + +/******************************************************************************* + * Thermal Controller Register Mask Definition + ******************************************************************************/ +#define THERMAL_ENABLE_SEN0 0x1 +#define THERMAL_ENABLE_SEN1 0x2 +#define THERMAL_ENABLE_SEN2 0x4 +#define THERMAL_MONCTL0_MASK 0x00000007 + +#define THERMAL_PUNT_MASK 0x00000FFF +#define THERMAL_FSINTVL_MASK 0x03FF0000 +#define THERMAL_SPINTVL_MASK 0x000003FF +#define THERMAL_MON_INT_MASK 0x0007FFFF + +#define THERMAL_MON_CINTSTS0 0x000001 +#define THERMAL_MON_HINTSTS0 0x000002 +#define THERMAL_MON_LOINTSTS0 0x000004 +#define THERMAL_MON_HOINTSTS0 0x000008 +#define THERMAL_MON_NHINTSTS0 0x000010 +#define THERMAL_MON_CINTSTS1 0x000020 +#define THERMAL_MON_HINTSTS1 0x000040 +#define THERMAL_MON_LOINTSTS1 0x000080 +#define THERMAL_MON_HOINTSTS1 0x000100 +#define THERMAL_MON_NHINTSTS1 0x000200 +#define THERMAL_MON_CINTSTS2 0x000400 +#define THERMAL_MON_HINTSTS2 0x000800 +#define THERMAL_MON_LOINTSTS2 0x001000 +#define THERMAL_MON_HOINTSTS2 0x002000 +#define THERMAL_MON_NHINTSTS2 0x004000 +#define THERMAL_MON_TOINTSTS 0x008000 +#define THERMAL_MON_IMMDINTSTS0 0x010000 +#define THERMAL_MON_IMMDINTSTS1 0x020000 +#define THERMAL_MON_IMMDINTSTS2 0x040000 +#define THERMAL_MON_FILTINTSTS0 0x080000 +#define THERMAL_MON_FILTINTSTS1 0x100000 +#define THERMAL_MON_FILTINTSTS2 0x200000 + + +#define THERMAL_tri_SPM_State0 0x20000000 +#define THERMAL_tri_SPM_State1 0x40000000 +#define THERMAL_tri_SPM_State2 0x80000000 + + +#define THERMAL_MSRCTL0_MASK 0x00000007 +#define THERMAL_MSRCTL1_MASK 0x00000038 +#define THERMAL_MSRCTL2_MASK 0x000001C0 + +/* extern int thermal_one_shot_handler(int times); */ + +typedef enum { + THERMAL_SENSOR1 = 0, /* TS1 */ + THERMAL_SENSOR_NUM +} thermal_sensor_name; + +struct TS_PTPOD { + unsigned int ts_MTS; + unsigned int ts_BTS; +}; + +extern void get_thermal_slope_intercept(struct TS_PTPOD *ts_info); +extern void set_taklking_flag(bool flag); +extern int tscpu_get_cpu_temp(void); + +/*5 thermal sensors*/ +typedef enum { + MTK_THERMAL_SENSOR_TS1 = 0, + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + MTK_THERMAL_SENSOR_CPU_COUNT +} MTK_THERMAL_SENSOR_CPU_ID_MET; + +struct mtk_cpu_power_info { + unsigned int cpufreq_khz; + unsigned int cpufreq_ncpu; + unsigned int cpufreq_power; +}; +extern int mtk_cpufreq_register(struct mtk_cpu_power_info *freqs, int num); + +extern int tscpu_get_cpu_temp_met(MTK_THERMAL_SENSOR_CPU_ID_MET id); + + +typedef void (*met_thermalsampler_funcMET) (void); +void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); + +void tscpu_start_thermal(void); +void tscpu_stop_thermal(void); +void tscpu_cancel_thermal_timer(void); +void tscpu_start_thermal_timer(void); +int mtkts_AP_get_hw_temp(void); + +extern int amddulthro_backoff(int level); +/* extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); */ +/* extern int IMM_IsAdcInitReady(void); */ +extern int get_immediate_temp2_wrap(void); +extern void mtkts_dump_cali_info(void); +extern unsigned int read_dram_temperature(void); +extern int mtk_thermal_get_cpu_load_sum(void); + +/********************************** + * Power table struct for thermal + **********************************/ +struct mt_gpufreq_power_table_info { + unsigned int gpufreq_khz; + unsigned int gpufreq_volt; + unsigned int gpufreq_power; +}; + +extern int mtk_gpufreq_register(struct mt_gpufreq_power_table_info *freqs, int num); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mt_sched.h b/drivers/misc/mediatek/include/mt-plat/mt_sched.h new file mode 100644 index 0000000000000..71206f0805482 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt_sched.h @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#ifdef CONFIG_MTK_SCHED_RQAVG_US +/* + * @cpu: cpu id + * @reset: reset the statistic start time after this time query + * @use_maxfreq: caculate cpu loading with max cpu max frequency + * return: cpu loading as percentage (0~100) + */ +extern unsigned int sched_get_percpu_load(int cpu, bool reset, bool use_maxfreq); + +/* + * return: heavy task(loading>90%) number in the system + */ +extern unsigned int sched_get_nr_heavy_task(void); + +/* + * @threshold: heavy task loading threshold (0~1023) + * return: heavy task(loading>threshold) number in the system + */ +extern unsigned int sched_get_nr_heavy_task_by_threshold(unsigned int threshold); +#endif /* CONFIG_MTK_SCHED_RQAVG_US */ + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_io.h b/drivers/misc/mediatek/include/mt-plat/mtk_io.h new file mode 100644 index 0000000000000..de17db505d3e5 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_io.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT_IO_H__ +#define __MT_IO_H__ + +/* only for arm64 */ +#ifdef CONFIG_ARM64 +#define IOMEM(a) ((void __force __iomem *)((a))) +#endif + +#endif /* !__MT_IO_H__ */ + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h new file mode 100644 index 0000000000000..d679c5a1ce738 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_LPAE_H__ +#define __MTK_LPAE_H__ +#ifdef CONFIG_MTK_LM_MODE + +#include + +#define INTERAL_MAPPING_OFFSET (0x40000000) +#define INTERAL_MAPPING_LIMIT (INTERAL_MAPPING_OFFSET + 0x80000000) + +#define MT_OVERFLOW_ADDR_START 0x100000000ULL + +unsigned int __attribute__((weak)) enable_4G(void) +{ + return 0; +} + +/* For HW modules which support 33-bit address setting */ +#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) \ + do { \ + ret = 0; \ + if (enable_4G()) {\ + if (((phys_addr_t)phy_addr < MT_OVERFLOW_ADDR_START)\ + && (((phys_addr_t)phy_addr + size) >= MT_OVERFLOW_ADDR_START)) \ + ret = MT_OVERFLOW_ADDR_START - phy_addr; \ + } \ + } while (0) \ + +/* For SPM and MD32 only in ROME */ +#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) \ + do { \ + if (enable_4G()) {\ + if (phy_addr >= INTERAL_MAPPING_OFFSET && phy_addr < INTERAL_MAPPING_LIMIT) \ + phy_addr += INTERAL_MAPPING_OFFSET; \ + } \ + } while (0)\ + +#else /* !CONFIG_ARM_LPAE */ + +#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) +#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) +#define MT_OVERFLOW_ADDR_START 0 + +static inline unsigned int enable_4G(void) +{ + return 0; +} + +#endif +#endif /*!__MTK_LPAE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h new file mode 100644 index 0000000000000..7baafc4329bfc --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_MDM_MONITOR_H +#define _MTK_MDM_MONITOR_H + +struct md_info { + char *attribute; + int value; + char *unit; + int invalid_value; + int index; +}; + +extern +int mtk_mdm_get_md_info(struct md_info **p_inf, int *size); + +extern +int mtk_mdm_start_query(void); + +extern +int mtk_mdm_stop_query(void); + +extern +int mtk_mdm_set_signal_period(int second); + +extern +int mtk_mdm_set_md1_signal_period(int second); + +extern +int mtk_mdm_set_md2_signal_period(int second); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h new file mode 100644 index 0000000000000..8f20f38b75d6c --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_PLATFORM_DEBUG_H__ +#define __MTK_PLATFORM_DEBUG_H__ + +#ifdef CONFIG_MTK_PLAT_SRAM_FLAG +/* plat_sram_flag */ +extern int set_sram_flag_lastpc_valid(void); +extern int set_sram_flag_dfd_valid(void); +extern int set_sram_flag_etb_user(unsigned int etb_id, unsigned int user_id); +#endif + +#ifdef CONFIG_MTK_DFD_INTERNAL_DUMP +extern int dfd_setup(void); +#endif + +#endif /* __MTK_PLATFORM_DEBUG_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h new file mode 100644 index 0000000000000..3a94a1bbcd241 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_RAM_CONSOLE_H__ +#define __MTK_RAM_CONSOLE_H__ + +#include +#include + +typedef enum { + AEE_FIQ_STEP_FIQ_ISR_BASE = 1, + AEE_FIQ_STEP_WDT_FIQ_INFO = 4, + AEE_FIQ_STEP_WDT_FIQ_STACK, + AEE_FIQ_STEP_WDT_FIQ_LOOP, + AEE_FIQ_STEP_WDT_FIQ_DONE, + AEE_FIQ_STEP_WDT_IRQ_INFO = 8, + AEE_FIQ_STEP_WDT_IRQ_KICK, + AEE_FIQ_STEP_WDT_IRQ_SMP_STOP, + AEE_FIQ_STEP_WDT_IRQ_TIME, + AEE_FIQ_STEP_WDT_IRQ_STACK, + AEE_FIQ_STEP_WDT_IRQ_GIC, + AEE_FIQ_STEP_WDT_IRQ_LOCALTIMER, + AEE_FIQ_STEP_WDT_IRQ_IDLE, + AEE_FIQ_STEP_WDT_IRQ_SCHED, + AEE_FIQ_STEP_WDT_IRQ_DONE, + AEE_FIQ_STEP_KE_WDT_INFO = 20, + AEE_FIQ_STEP_KE_WDT_PERCPU, + AEE_FIQ_STEP_KE_WDT_LOG, + AEE_FIQ_STEP_KE_SCHED_DEBUG, + AEE_FIQ_STEP_KE_EINT_DEBUG, + AEE_FIQ_STEP_KE_WDT_DONE, + AEE_FIQ_STEP_KE_IPANIC_DIE = 32, + AEE_FIQ_STEP_KE_IPANIC_START, + AEE_FIQ_STEP_KE_IPANIC_OOP_HEADER, + AEE_FIQ_STEP_KE_IPANIC_DETAIL, + AEE_FIQ_STEP_KE_IPANIC_CONSOLE, + AEE_FIQ_STEP_KE_IPANIC_USERSPACE, + AEE_FIQ_STEP_KE_IPANIC_ANDROID, + AEE_FIQ_STEP_KE_IPANIC_MMPROFILE, + AEE_FIQ_STEP_KE_IPANIC_HEADER, + AEE_FIQ_STEP_KE_IPANIC_DONE, + AEE_FIQ_STEP_KE_NESTED_PANIC = 64, +} AEE_FIQ_STEP_NUM; + +#ifdef CONFIG_MTK_RAM_CONSOLE +extern int aee_rr_curr_fiq_step(void); +extern void aee_rr_rec_fiq_step(u8 i); +extern void aee_rr_rec_reboot_mode(u8 mode); +extern void aee_rr_rec_kdump_params(void *params); +extern void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j); +extern void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j); +extern void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm); +extern void aee_sram_fiq_log(const char *msg); +extern void ram_console_write(struct console *console, const char *s, unsigned int count); +extern void aee_sram_fiq_save_bin(const char *buffer, size_t len); +extern void aee_rr_rec_hotplug_footprint(int cpu, u8 fp); +extern void aee_rr_rec_hotplug_cpu_event(u8 val); +extern void aee_rr_rec_hotplug_cb_index(u8 val); +extern void aee_rr_rec_hotplug_cb_fp(unsigned long val); +#ifdef CONFIG_MTK_EMMC_SUPPORT +extern void last_kmsg_store_to_emmc(void); +#endif + +#else +static inline void aee_rr_rec_hotplug_footprint(int cpu, u8 fp) +{ +} +static inline void aee_rr_rec_hotplug_cpu_event(u8 val) +{ +} +static inline void aee_rr_rec_hotplug_cb_index(u8 val) +{ +} +static inline void aee_rr_rec_hotplug_cb_fp(unsigned long val) +{ +} +static inline int aee_rr_curr_fiq_step(void) +{ + return 0; +} + +static inline void aee_rr_rec_fiq_step(u8 i) +{ +} + +static inline unsigned int aee_rr_curr_exp_type(void) +{ + return 0; +} + +static inline void aee_rr_rec_exp_type(unsigned int type) +{ +} + +static inline void aee_rr_rec_reboot_mode(u8 mode) +{ +} + +static inline void aee_rr_rec_kdump_params(void *params) +{ +} + +static inline void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j) +{ +} + +static inline void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j) +{ +} + +static inline void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm) +{ +} + +static inline void aee_sram_fiq_log(const char *msg) +{ +} + +static inline void ram_console_write(struct console *console, const char *s, unsigned int count) +{ +} + +static inline void aee_sram_fiq_save_bin(unsigned char *buffer, size_t len) +{ +} + +#ifdef CONFIG_MTK_EMMC_SUPPORT +static inline void last_kmsg_store_to_emmc(void) +{ +} +#endif + +#endif /* CONFIG_MTK_RAM_CONSOLE */ + +#ifdef CONFIG_MTK_AEE_IPANIC +extern int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size); +extern int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, + char **buf, struct pstore_info *psi); +#else +static inline int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size) +{ + return 0; +} + +static inline int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, + char **buf, struct pstore_info *psi) +{ + return 0; +} +#endif /* CONFIG_MTK_AEE_IPANIC */ + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h new file mode 100644 index 0000000000000..2181e99895934 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MTK_RTC_H +#define MTK_RTC_H + +#include +#include +#include + +typedef enum { + RTC_GPIO_USER_WIFI = 8, + RTC_GPIO_USER_GPS = 9, + RTC_GPIO_USER_BT = 10, + RTC_GPIO_USER_FM = 11, + RTC_GPIO_USER_PMIC = 12, +} rtc_gpio_user_t; + +#ifdef CONFIG_MTK_RTC + +/* + * NOTE: + * 1. RTC_GPIO always exports 32K enabled by some user even if the phone is powered off + */ + +extern unsigned long rtc_read_hw_time(void); +extern void rtc_gpio_enable_32k(rtc_gpio_user_t user); +extern void rtc_gpio_disable_32k(rtc_gpio_user_t user); +extern bool rtc_gpio_32k_status(void); + +/* for AUDIOPLL (deprecated) */ +extern void rtc_enable_abb_32k(void); +extern void rtc_disable_abb_32k(void); + +/* NOTE: used in Sleep driver to workaround Vrtc-Vore level shifter issue */ +extern void rtc_enable_writeif(void); +extern void rtc_disable_writeif(void); + +extern void rtc_mark_recovery(void); +#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) +extern void rtc_mark_kpoc(void); +#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ +extern void rtc_mark_fast(void); +extern u16 rtc_rdwr_uart_bits(u16 *val); +extern void rtc_bbpu_power_down(void); +extern void rtc_read_pwron_alarm(struct rtc_wkalrm *alm); +extern int get_rtc_spare_fg_value(void); +extern int set_rtc_spare_fg_value(int val); +extern void rtc_irq_handler(void); +extern bool crystal_exist_status(void); +extern void mt_power_off(void); +#else/*ifdef CONFIG_MTK_RTC*/ +#define rtc_read_hw_time() ({ 0; }) +#define rtc_gpio_enable_32k(user) do {} while (0) +#define rtc_gpio_disable_32k(user) do {} while (0) +#define rtc_gpio_32k_status() do {} while (0) +#define rtc_enable_abb_32k() do {} while (0) +#define rtc_disable_abb_32k() do {} while (0) +#define rtc_enable_writeif() do {} while (0) +#define rtc_disable_writeif() do {} while (0) +#define rtc_mark_recovery() do {} while (0) +#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) +#define rtc_mark_kpoc() do {} while (0) +#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ +#define rtc_mark_fast() do {} while (0) +#define rtc_rdwr_uart_bits(val) ({ 0; }) +#define rtc_bbpu_power_down() do {} while (0) +#define rtc_read_pwron_alarm(alm) do {} while (0) +#define get_rtc_spare_fg_value() ({ 0; }) +#define set_rtc_spare_fg_value(val) ({ 0; }) +#define rtc_irq_handler() do {} while (0) +#define crystal_exist_status() do {} while (0) +__weak void mt_power_off(void); +#endif/*ifdef CONFIG_MTK_RTC*/ +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h new file mode 100644 index 0000000000000..eac6bc713c985 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _MTK_THERMAL_EXT_CONTROL_H +#define _MTK_THERMAL_EXT_CONTROL_H + +#define THERMAL_MD32_IPI_MSG_BASE 0x1F00 +#define THERMAL_AP_IPI_MSG_BASE 0x2F00 + +typedef enum { + THERMAL_AP_IPI_MSG_SET_TZ_THRESHOLD = THERMAL_AP_IPI_MSG_BASE, + THERMAL_AP_IPI_MSG_MD32_START, + + THERMAL_MD32_IPI_MSG_READY = THERMAL_MD32_IPI_MSG_BASE, + THERMAL_MD32_IPI_MSG_MD32_START_ACK, + THERMAL_MD32_IPI_MSG_REACH_THRESHOLD, +} thermal_ipi_msg_id; + +typedef enum { +/* MTK_THERMAL_EXT_SENSOR_CPU = 0, */ + MTK_THERMAL_EXT_SENSOR_ABB = 0, + MTK_THERMAL_EXT_SENSOR_PMIC, + MTK_THERMAL_EXT_SENSOR_BATTERY, + MTK_THERMAL_EXT_SENSOR_COUNT +} MTK_THERMAL_EXT_SENSOR_ID; + +typedef struct { + int id; /* id of this tz */ + int polling_delay; /* polling delay of this tz */ + long high_trip_point; /* high threshold of this tz */ + long low_trip_point; /* low threshold of this tz */ +} thermal_zone_data; + +typedef struct { + int id; /* id of this tz */ + long high_trip_point; /* high threshold of this tz */ + long low_trip_point; /* low threshold of this tz */ + long temperature; /* Current temperature gotten from TS */ +} thermal_zone_status; + +typedef struct { + short id; + union { + thermal_zone_data tz; + thermal_zone_status tz_status; + } data; +} thermal_ipi_msg; + +#endif /* _MTK_THERMAL_EXT_CONTROL_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h new file mode 100644 index 0000000000000..7903b49dc419c --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_THERMAL_MONITOR_H +#define _MTK_THERMAL_MONITOR_H + +#include + +/* + * MTK_THERMAL_WRAPPER_BYPASS = 1 (use original Linux Thermal API) + * MTK_THERMAL_WRAPPER_BYPASS = 0 (use MTK Thermal API Monitor) + */ +#define MTK_THERMAL_WRAPPER_BYPASS 0 + +#if MTK_THERMAL_WRAPPER_BYPASS +/* Original LTF API */ +#define mtk_thermal_zone_device_register thermal_zone_device_register +#define mtk_thermal_zone_device_unregister thermal_zone_device_unregister +#define mtk_thermal_cooling_device_unregister thermal_cooling_device_unregister +#define mtk_thermal_cooling_device_register thermal_cooling_device_register +#define mtk_thermal_zone_bind_cooling_device thermal_zone_bind_cooling_device + +#else + +struct thermal_cooling_device_ops_extra { + int (*set_cur_temp)(struct thermal_cooling_device *, unsigned long); +}; + +extern +struct thermal_zone_device *mtk_thermal_zone_device_register_wrapper +(char *type, int trips, void *devdata, const struct thermal_zone_device_ops *ops, +int tc1, int tc2, int passive_delay, int polling_delay); + +extern +void mtk_thermal_zone_device_unregister_wrapper(struct thermal_zone_device *tz); + +extern +struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper +(char *type, void *devdata, const struct thermal_cooling_device_ops *ops); + +extern +struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper_extra +(char *type, void *devdata, const struct thermal_cooling_device_ops *ops, +const struct thermal_cooling_device_ops_extra *ops_ext); + +extern +int mtk_thermal_cooling_device_add_exit_point +(struct thermal_cooling_device *cdev, int exit_point); + +extern +void mtk_thermal_cooling_device_unregister_wrapper(struct thermal_cooling_device *cdev); + +extern int mtk_thermal_zone_bind_cooling_device_wrapper +(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev); + +extern int mtk_thermal_zone_bind_trigger_trip(struct thermal_zone_device *tz, int trip, int mode); +#define mtk_thermal_zone_device_register mtk_thermal_zone_device_register_wrapper +#define mtk_thermal_zone_device_unregister mtk_thermal_zone_device_unregister_wrapper +#define mtk_thermal_cooling_device_unregister mtk_thermal_cooling_device_unregister_wrapper +#define mtk_thermal_cooling_device_register mtk_thermal_cooling_device_register_wrapper +#define mtk_thermal_zone_bind_cooling_device mtk_thermal_zone_bind_cooling_device_wrapper + +#endif + +typedef enum { + MTK_THERMAL_SENSOR_CPU = 0, + MTK_THERMAL_SENSOR_ABB, + MTK_THERMAL_SENSOR_PMIC, + MTK_THERMAL_SENSOR_BATTERY, + MTK_THERMAL_SENSOR_MD1, + MTK_THERMAL_SENSOR_MD2, + MTK_THERMAL_SENSOR_WIFI, + MTK_THERMAL_SENSOR_BATTERY2, + MTK_THERMAL_SENSOR_BUCK, + MTK_THERMAL_SENSOR_AP, + MTK_THERMAL_SENSOR_PCB1, + MTK_THERMAL_SENSOR_PCB2, + MTK_THERMAL_SENSOR_SKIN, + MTK_THERMAL_SENSOR_XTAL, + MTK_THERMAL_SENSOR_MD_PA, + + MTK_THERMAL_SENSOR_COUNT +} MTK_THERMAL_SENSOR_ID; + +extern int mtk_thermal_get_temp(MTK_THERMAL_SENSOR_ID id); +extern struct proc_dir_entry *mtk_thermal_get_proc_drv_therm_dir_entry(void); + +/* This API function is implemented in mediatek/kernel/drivers/leds/leds.c */ +extern int setMaxbrightness(int max_level, int enable); + +extern void machine_power_off(void); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h new file mode 100644 index 0000000000000..305574031196a --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_THERMAL_PLATFORM_H +#define _MTK_THERMAL_PLATFORM_H + +#include +#include + +extern +int mtk_thermal_get_cpu_info(int *nocores, int **cpufreq, int **cpuloading); + +extern +int mtk_thermal_get_gpu_info(int *nocores, int **gpufreq, int **gpuloading); + +extern +int mtk_thermal_get_batt_info(int *batt_voltage, int *batt_current, int *batt_temp); + +extern +int mtk_thermal_get_extra_info(int *no_extra_attr, + char ***attr_names, int **attr_values, char ***attr_unit); + +extern +int mtk_thermal_force_get_batt_temp(void); + + +enum { + MTK_THERMAL_SCEN_CALL = 0x1 +}; + +extern +unsigned int mtk_thermal_set_user_scenarios(unsigned int mask); + +extern +unsigned int mtk_thermal_clear_user_scenarios(unsigned int mask); + + +#if defined(CONFIG_MTK_SMART_BATTERY) +/* global variable from battery driver... */ +extern kal_bool gFG_Is_Charging; +#endif + +extern int force_get_tbat(void); +#endif /* _MTK_THERMAL_PLATFORM_H */ + + +typedef enum { + TA_DAEMON_CMD_GET_INIT_FLAG = 0, + TA_DAEMON_CMD_SET_DAEMON_PID, + TA_DAEMON_CMD_NOTIFY_DAEMON, + TA_DAEMON_CMD_NOTIFY_DAEMON_CATMINIT, + TA_DAEMON_CMD_SET_TTJ, + TA_DAEMON_CMD_GET_TPCB, + + TA_DAEMON_CMD_TO_KERNEL_NUMBER +} TA_DAEMON_CTRL_CMD_TO_KERNEL; /*must sync userspace/kernel: TA_DAEMON_CTRL_CMD_FROM_USER*/ + +#define TAD_NL_MSG_T_HDR_LEN 12 +#define TAD_NL_MSG_MAX_LEN 2048 + +struct tad_nl_msg_t { + unsigned int tad_cmd; + unsigned int tad_data_len; + unsigned int tad_ret_data_len; + char tad_data[TAD_NL_MSG_MAX_LEN]; +}; + +enum { + TA_CATMPLUS = 1, + TA_CONTINUOUS = 2, + TA_CATMPLUS_TTJ = 3 +}; + + +struct cATM_params_t { + int CATM_ON; + int K_TT; + int K_SUM_TT_LOW; + int K_SUM_TT_HIGH; + int MIN_SUM_TT; + int MAX_SUM_TT; + int MIN_TTJ; + int CATMP_STEADY_TTJ_DELTA; +}; +struct continuetm_params_t { + int STEADY_TARGET_TJ; + int MAX_TARGET_TJ; + int TRIP_TPCB; + int STEADY_TARGET_TPCB; +}; + + +struct CATM_T { + struct cATM_params_t t_catm_par; + struct continuetm_params_t t_continuetm_par; +}; +extern struct CATM_T thermal_atm_t; +int wakeup_ta_algo(int flow_state); +int ta_get_ttj(void); + +extern int mtk_thermal_get_tpcb_target(void); +extern int tsatm_thermal_get_catm_type(void); + + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h new file mode 100644 index 0000000000000..1c23a9f4a862e --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM thermal + +#if !defined(_MTK_THERMAL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _MTK_THERMAL_TRACE_H + +#include + +TRACE_EVENT(cooling_device_state, + TP_PROTO(int device, unsigned long state), + TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) + __field(unsigned long, state) + ), + TP_fast_assign(__entry->device = device; + __entry->state = state;), + TP_printk("cooling_device=%d, state=%lu\n", __entry->device, __entry->state) +); + +TRACE_EVENT(thermal_zone_state, + TP_PROTO(int device, int state), + TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) + __field(int, state) + ), + TP_fast_assign(__entry->device = device; + __entry->state = state;), + TP_printk("thermal_zone=%d, state=%d\n", __entry->device, __entry->state) +); +#endif /* _MTK_THERMAL_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE mach/mtk_thermal_trace +#include diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h new file mode 100644 index 0000000000000..dfcef3d952fc7 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _TYPEDEFS_H +#define _TYPEDEFS_H + +#include + +/* --------------------------------------------------------------------------- */ +/* Basic Type Definitions */ +/* --------------------------------------------------------------------------- */ + +typedef volatile unsigned char *P_kal_uint8; +typedef volatile unsigned short *P_kal_uint16; +typedef volatile unsigned int *P_kal_uint32; + +typedef long LONG; +typedef unsigned char UBYTE; +typedef short SHORT; + +typedef signed char kal_int8; +typedef signed short kal_int16; +typedef signed int kal_int32; +typedef long long kal_int64; +typedef unsigned char kal_uint8; +typedef unsigned short kal_uint16; +typedef unsigned int kal_uint32; +typedef unsigned long long kal_uint64; +typedef char kal_char; + +typedef unsigned int *UINT32P; +typedef volatile unsigned short *UINT16P; +typedef volatile unsigned char *UINT8P; +typedef unsigned char *U8P; + +typedef volatile unsigned char *P_U8; +typedef volatile signed char *P_S8; +typedef volatile unsigned short *P_U16; +typedef volatile signed short *P_S16; +typedef volatile unsigned int *P_U32; +typedef volatile signed int *P_S32; +typedef unsigned long long *P_U64; +typedef signed long long *P_S64; + +typedef unsigned char U8; +typedef signed char S8; +typedef unsigned short U16; +typedef signed short S16; +typedef unsigned int U32; +typedef signed int S32; +typedef unsigned long long U64; +typedef signed long long S64; +/* typedef unsigned char bool; */ + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned short USHORT; +typedef signed char INT8; +typedef signed short INT16; +typedef signed int INT32; +typedef unsigned int DWORD; +typedef void VOID; +typedef unsigned char BYTE; +typedef float FLOAT; + +typedef char *LPCSTR; +typedef short *LPWSTR; + + +/* --------------------------------------------------------------------------- */ +/* Constants */ +/* --------------------------------------------------------------------------- */ + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef NULL +#define NULL (0) +#endif + +/* enum boolean {false, true}; */ +enum { RX, TX, NONE }; + +#ifndef BOOL +typedef unsigned char BOOL; +#endif + +#ifndef BATTERY_BOOL +#define BATTERY_BOOL +typedef enum { + KAL_FALSE = 0, + KAL_TRUE = 1, +} kal_bool; +#endif + +/* --------------------------------------------------------------------------- */ +/* Type Casting */ +/* --------------------------------------------------------------------------- */ + +#define AS_INT32(x) (*(INT32 *)((void *)x)) +#define AS_INT16(x) (*(INT16 *)((void *)x)) +#define AS_INT8(x) (*(INT8 *)((void *)x)) + +#define AS_UINT32(x) (*(UINT32 *)((void *)x)) +#define AS_UINT16(x) (*(UINT16 *)((void *)x)) +#define AS_UINT8(x) (*(UINT8 *)((void *)x)) + + +/* --------------------------------------------------------------------------- */ +/* Register Manipulations */ +/* --------------------------------------------------------------------------- */ + +#define READ_REGISTER_UINT32(reg) \ + (*(volatile UINT32 * const)(reg)) + +#define WRITE_REGISTER_UINT32(reg, val) \ + ((*(volatile UINT32 * const)(reg)) = (val)) + +#define READ_REGISTER_UINT16(reg) \ + ((*(volatile UINT16 * const)(reg))) + +#define WRITE_REGISTER_UINT16(reg, val) \ + ((*(volatile UINT16 * const)(reg)) = (val)) + +#define READ_REGISTER_UINT8(reg) \ + ((*(volatile UINT8 * const)(reg))) + +#define WRITE_REGISTER_UINT8(reg, val) \ + ((*(volatile UINT8 * const)(reg)) = (val)) + +#define INREG8(x) READ_REGISTER_UINT8((UINT8 *)((void *)(x))) +#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8 *)((void *)(x)), (UINT8)(y)) +#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) +#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) +#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) + +#define INREG16(x) READ_REGISTER_UINT16((UINT16 *)((void *)(x))) +#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16 *)((void *)(x)), (UINT16)(y)) +#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) +#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) +#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) + +#define INREG32(x) READ_REGISTER_UINT32((UINT32 *)((void *)(x))) +#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32 *)((void *)(x)), (UINT32)(y)) +#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) +#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) +#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) + + +#define DRV_Reg8(addr) INREG8(addr) +#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) +#define DRV_SetReg8(addr, data) SETREG8(addr, data) +#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) + +#define DRV_Reg16(addr) INREG16(addr) +#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) +#define DRV_SetReg16(addr, data) SETREG16(addr, data) +#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) + +#define DRV_Reg32(addr) INREG32(addr) +#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) +#define DRV_SetReg32(addr, data) SETREG32(addr, data) +#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) + +/* !!! DEPRECATED, WILL BE REMOVED LATER !!! */ +#define DRV_Reg(addr) DRV_Reg16(addr) +#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) +#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) +#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) + + +/* --------------------------------------------------------------------------- */ +/* Compiler Time Deduction Macros */ +/* --------------------------------------------------------------------------- */ + + + +/* --------------------------------------------------------------------------- */ +/* Assertions */ +/* --------------------------------------------------------------------------- */ + +/* +*#ifndef ASSERT +*#define ASSERT(expr) BUG_ON(!(expr)) +*#endif +* +*#ifndef NOT_IMPLEMENTED +*#define NOT_IMPLEMENTED() BUG_ON(1) +*#endif +*/ +#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) +#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) +#define STATIC_ASSERT_XX(pred, line) \ +extern char assertion_failed_at_##line[(pred) ? 1 : -1] + +/* --------------------------------------------------------------------------- */ +/* Resolve Compiler Warnings */ +/* --------------------------------------------------------------------------- */ + +#define NOT_REFERENCED(x) { (x) = (x); } + + +/* --------------------------------------------------------------------------- */ +/* Utilities */ +/* --------------------------------------------------------------------------- */ + +#define MAXIMUM(A, B) (((A) > (B))?(A):(B)) +#define MINIMUM(A, B) (((A) < (B))?(A):(B)) + +#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) +#define DVT_DELAYMACRO(u4Num) \ +{ \ + UINT32 u4Count = 0; \ + for (u4Count = 0; u4Count < u4Num; u4Count++) \ + ; \ +} \ + +#define A68351B 0 +#define B68351B 1 +#define B68351D 2 +#define B68351E 3 +#define UNKNOWN_IC_VERSION 0xFF + + +#endif /* _TYPEDEFS_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h new file mode 100644 index 0000000000000..0a4fda1916540 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_WCN_CMB_STUB_H_ +#define _MTK_WCN_CMB_STUB_H_ + +#include + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Audio GPIO naming style for 73/75/77 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_0 1 */ +/* Audio GPIO naming style for 89/8135 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_1 1 */ +/* Audio GPIO naming style for 6592 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_2 1 */ +/* Audio GPIO naming style for 6595 */ +#define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_3 1 +#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + CMB_STUB_AIF_4 = 4, /* 0100: BT_I2S & FM disable in special projects, e.g. protea*/ + CMB_STUB_AIF_MAX = 5, +} CMB_STUB_AIF_X; + +/*COMBO_CHIP_AUDIO_PIN_CTRL*/ +typedef enum { + CMB_STUB_AIF_CTRL_DIS = 0, + CMB_STUB_AIF_CTRL_EN = 1, + CMB_STUB_AIF_CTRL_MAX = 2, +} CMB_STUB_AIF_CTRL; + +typedef enum { + COMBO_FUNC_TYPE_BT = 0, + COMBO_FUNC_TYPE_FM = 1, + COMBO_FUNC_TYPE_GPS = 2, + COMBO_FUNC_TYPE_WIFI = 3, + COMBO_FUNC_TYPE_WMT = 4, + COMBO_FUNC_TYPE_STP = 5, + COMBO_FUNC_TYPE_NUM = 6 +} COMBO_FUNC_TYPE; + +typedef enum { + COMBO_IF_UART = 0, + COMBO_IF_MSDC = 1, + COMBO_IF_BTIF = 2, + COMBO_IF_MAX, +} COMBO_IF; + +typedef void (*wmt_bgf_eirq_cb) (void); +typedef int (*wmt_aif_ctrl_cb) (CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); +typedef void (*wmt_func_ctrl_cb) (unsigned int, unsigned int); +typedef signed long (*wmt_thermal_query_cb) (void); +typedef int (*wmt_deep_idle_ctrl_cb) (unsigned int); +typedef int (*wmt_func_do_reset) (unsigned int); + +/* for DVFS driver do 1v autok */ +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +typedef unsigned int (*wmt_get_drv_status)(unsigned int); +#endif + +typedef void (*msdc_sdio_irq_handler_t) (void *); /* external irq handler */ +typedef void (*pm_callback_t) (pm_message_t state, void *data); + +struct sdio_ops { + void (*sdio_request_eirq)(msdc_sdio_irq_handler_t irq_handler, void *data); + void (*sdio_enable_eirq)(void); + void (*sdio_disable_eirq)(void); + void (*sdio_register_pm)(pm_callback_t pm_cb, void *data); +}; + +typedef struct _CMB_STUB_CB_ { + unsigned int size; /* structure size */ + /*wmt_bgf_eirq_cb bgf_eirq_cb; *//* remove bgf_eirq_cb from stub. handle it in platform */ + wmt_aif_ctrl_cb aif_ctrl_cb; + wmt_func_ctrl_cb func_ctrl_cb; + wmt_thermal_query_cb thermal_query_cb; + wmt_deep_idle_ctrl_cb deep_idle_ctrl_cb; + wmt_func_do_reset wmt_do_reset_cb; +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + wmt_get_drv_status get_drv_status_cb; +#endif +} CMB_STUB_CB, *P_CMB_STUB_CB; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern struct sdio_ops mt_sdio_ops[4]; + +extern int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb); +extern int mtk_wcn_cmb_stub_unreg(void); + +extern int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +static inline int mtk_wcn_cmb_stub_audio_ctrl(CMB_STUB_AIF_X state) +{ +/* return mtk_wcn_cmb_stub_aif_ctrl(state, 1); */ + return 0; +} + +extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); +extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); + +/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control + * function on/off. + */ +extern void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on); +extern int mtk_wcn_cmb_stub_query_ctrl(void); +extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); +extern int mtk_wcn_sdio_irq_flag_set(int falg); + +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +extern int mtk_wcn_cmb_stub_1vautok_for_dvfs(void); +#endif + +extern int mtk_wcn_wmt_chipid_query(void); +extern void mtk_wcn_wmt_set_chipid(int chipid); + +/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver + * + * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" + * @ enable - "1", enable deep idle; "0", disable deep idle + * + * Return 0 if success, else -1 + */ +extern unsigned int mtk_uart_pdn_enable(char *port, int enable); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_WCN_CMB_STUB_H_ */ diff --git a/drivers/misc/mediatek/include/mt-plat/rt-regmap.h b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h new file mode 100644 index 0000000000000..9a45e23005cad --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h @@ -0,0 +1,291 @@ +/* drivers/misc/mediatek/include/mt-plat/rt-regmap.h + * Header of Richtek regmap with debugfs Driver + * + * Copyright (C) 2014 Richtek Technology Corp. + * Jeff Chang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MISC_MEDIATEK_RT_REGMAP_H +#define MISC_MEDIATEK_RT_REGMAP_H + +#include +#include + +/* #define RT_REGMAP_VERSION "1.1.11_G" */ + +enum rt_access_mode { + RT_1BYTE_MODE = 1, + RT_2BYTE_MODE = 2, + RT_4BYTE_MODE = 4, +}; + +/* start : the start address of group + * end : the end address of group + * mode : access mode (1,2,4 bytes) + */ +struct rt_access_group { + u32 start; + u32 end; + enum rt_access_mode mode; +}; + +/* rt_reg_type + * RT_NORMAL : Write data without mask + * Read from cache + * RT_WBITS : Write data with mask + * Read from cache + * RT_VOLATILE : Write data to chip directly + * Read data from chip + * RT_RESERVE : Reserve registers (Write/Read as RT_NORMAL) + */ + +#define RT_REG_TYPE_MASK (0x03) +#define RT_NORMAL (0x00) +#define RT_WBITS (0x01) +#define RT_VOLATILE (0x02) +#define RT_RESERVE (0x03) + +/* RT_WR_ONCE : write once will check write data and cache data, + * if write data = cache data, data will not be writen. + */ +#define RT_WR_ONCE (0x08) +#define RT_NORMAL_WR_ONCE (RT_NORMAL|RT_WR_ONCE) +#define RT_WBITS_WR_ONCE (RT_WBITS|RT_WR_ONCE) + +enum rt_data_format { + RT_LITTLE_ENDIAN, + RT_BIG_ENDIAN, +}; + +/* rt_regmap_mode + * 0 0 0 0 0 0 0 0 + * | | | | | | + * | | | |__| byte_mode + * | |__| || + * | || Cache_mode + * | Block_mode + * Debug_mode + */ + +#define RT_BYTE_MODE_MASK (0x01) +/* 1 byte for each register*/ +#define RT_SINGLE_BYTE (0 << 0) +/* multi bytes for each regiseter*/ +#define RT_MULTI_BYTE (1 << 0) + +#define RT_CACHE_MODE_MASK (0x06) +/* write to cache and chip synchronously */ +#define RT_CACHE_WR_THROUGH (0 << 1) +/* write to cache and chip asynchronously */ +#define RT_CACHE_WR_BACK (1 << 1) +/* disable cache */ +#define RT_CACHE_DISABLE (2 << 1) + +#define RT_IO_BLK_MODE_MASK (0x18) +/* pass through all write function */ +#define RT_IO_PASS_THROUGH (0 << 3) +/* block all write function */ +#define RT_IO_BLK_ALL (1 << 3) +/* block cache write function */ +#define RT_IO_BLK_CACHE (2 << 3) +/* block chip write function */ +#define RT_IO_BLK_CHIP (3 << 3) + +#define DBG_MODE_MASK (0x20) +/* create general debugfs for register map */ +#define RT_DBG_GENERAL (0 << 5) +/* create node for each regisetr map by register address*/ +#define RT_DBG_SPECIAL (1 << 5) + + +/* struct rt_register + * + * Ricktek register map structure for store mapping data + * @addr: register address. + * @name: register name. + * @size: register byte size. + * @reg_type: register R/W type ( RT_NORMAL, RT_WBITS, RT_VOLATILE, RT_RESERVE) + * @wbit_mask: register writeable bits mask; + * @cache_data: cache data for store cache value. + */ +struct rt_register { + u32 addr; + const char *name; + unsigned int size; + unsigned char reg_type; + unsigned char *wbit_mask; + unsigned char *cache_data; +}; + +/* Declare a rt_register by RT_REG_DECL + * @_addr: regisetr address. + * @_reg_length: register data length. + * @_reg_type: register type (rt_reg_type). + * @_mask: register writealbe mask. + */ +#define RT_REG_DECL(_addr, _reg_length, _reg_type, _mask_...) \ + static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ + static struct rt_register rt_register_##_addr = { \ + .addr = _addr, \ + .size = _reg_length,\ + .reg_type = _reg_type,\ + .wbit_mask = rt_writable_mask_##_addr,\ + } + +/* Declare a rt_register by RT_NAMED_REG_DECL + * @_name: a name for a rt_register. + */ +#define RT_NAMED_REG_DECL(_addr, _name, _reg_length, _reg_type, _mask_...) \ + static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ + static struct rt_register rt_register_##_addr = { \ + .addr = _addr, \ + .name = _name, \ + .size = _reg_length,\ + .reg_type = _reg_type,\ + .wbit_mask = rt_writable_mask_##_addr,\ + } + +#define RT_REG(_addr) (&rt_register_##_addr) + +/* rt_regmap_properties + * @name: the name of debug node. + * @aliases: alisis name of rt_regmap_device. + * @register_num: the number of rt_register_map registers. + * @rm: rt_regiseter_map pointer array. + * @group: register map access group. + * @rt_format: default is little endian. + * @rt_regmap_mode: rt_regmap_device mode. + * @io_log_en: enable/disable io log + */ +struct rt_regmap_properties { + const char *name; + const char *aliases; + int register_num; + struct rt_register **rm; + struct rt_access_group *group; + enum rt_data_format rt_format; + unsigned char rt_regmap_mode; + unsigned char io_log_en:1; +}; + +/* A passing struct for rt_regmap_reg_read and rt_regmap_reg_write function + * reg: regmap addr. + * mask: mask for update bits. + * rt_data: register value. + */ +struct rt_reg_data { + u32 reg; + u32 mask; + union { + u32 data_u32; + u16 data_u16; + u8 data_u8; + u8 data[4]; + } rt_data; +}; + +struct rt_regmap_device; + +struct rt_debug_st { + void *info; + int id; +}; + +/* basic chip read/write function */ +struct rt_regmap_fops { + int (*read_device)(void *client, u32 addr, int leng, void *dst); + int (*write_device)(void *client, u32 addr, int leng, const void *src); +}; + +/* with slave address */ +extern struct rt_regmap_device* + rt_regmap_device_register_ex(struct rt_regmap_properties *props, + struct rt_regmap_fops *rops, + struct device *parent, + void *client, int slv_addr, void *drvdata); + +static inline struct rt_regmap_device* + rt_regmap_device_register(struct rt_regmap_properties *props, + struct rt_regmap_fops *rops, + struct device *parent, + struct i2c_client *client, void *drvdata) +{ + return rt_regmap_device_register_ex(props, rops, parent, + client, client->addr, drvdata); +} + +extern void rt_regmap_device_unregister(struct rt_regmap_device *rd); + +extern int rt_regmap_cache_init(struct rt_regmap_device *rd); + +extern int rt_regmap_cache_reload(struct rt_regmap_device *rd); + +extern int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg, + int bytes, const void *rc); +extern int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg, + int bytes, const void *rc); +extern int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg, + int bytes, void *dst); + +extern int _rt_regmap_reg_read(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_regmap_update_bits(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); + +static inline int rt_regmap_reg_read(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg) +{ + rrd->reg = reg; + return _rt_regmap_reg_read(rd, rrd); +}; + +static inline int rt_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, const u32 data) +{ + rrd->reg = reg; + rrd->rt_data.data_u32 = data; + return _rt_regmap_reg_write(rd, rrd); +}; + +static inline int rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, const u32 data) +{ + rrd->reg = reg; + rrd->rt_data.data_u32 = data; + return _rt_asyn_regmap_reg_write(rd, rrd); +}; + +static inline int rt_regmap_update_bits(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, u32 mask, u32 data) +{ + rrd->reg = reg; + rrd->mask = mask; + rrd->rt_data.data_u32 = data; + return _rt_regmap_update_bits(rd, rrd); +} + +extern void rt_regmap_cache_backup(struct rt_regmap_device *rd); + +extern void rt_regmap_cache_sync(struct rt_regmap_device *rd); +extern void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg); + +extern int rt_is_reg_readable(struct rt_regmap_device *rd, u32 reg); +extern int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg); +extern int rt_get_regsize(struct rt_regmap_device *rd, u32 reg); +extern void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf); +extern void rt_cache_clrlasterror(struct rt_regmap_device *rd); + +extern int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name, + umode_t mode, void *data, const struct file_operations *fops); + +#define to_rt_regmap_device(obj) container_of(obj, struct rt_regmap_device, dev) + +#endif /*MISC_MEDIATEK_RT_REGMAP_H*/ diff --git a/drivers/misc/mediatek/include/mt-plat/sync_write.h b/drivers/misc/mediatek/include/mt-plat/sync_write.h new file mode 100644 index 0000000000000..f9e5fe4c23e17 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/sync_write.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT_SYNC_WRITE_H +#define _MT_SYNC_WRITE_H + +#if defined(__KERNEL__) + +#include +#include + +/* + * Define macros. + */ +#define mt_reg_sync_writel(v, a) \ + do { \ + __raw_writel((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#define mt_reg_sync_writew(v, a) \ + do { \ + __raw_writew((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#define mt_reg_sync_writeb(v, a) \ + do { \ + __raw_writeb((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#ifdef CONFIG_64BIT +#define mt_reg_sync_writeq(v, a) \ + do { \ + __raw_writeq((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) +#endif + +#else /* __KERNEL__ */ + +#include +#include +#include +#include +#include + +#define mt_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) +#define mt_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) +#define mt_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) + +#define mb() \ + { \ + __asm__ __volatile__ ("dsb" : : : "memory"); \ + } + +#define mt65xx_reg_sync_writel(v, a) \ + do { \ + *(volatile unsigned int *)(a) = (v); \ + mb(); \ + } while (0) + +#define mt65xx_reg_sync_writew(v, a) \ + do { \ + *(volatile unsigned short *)(a) = (v); \ + mb(); \ + } while (0) + +#define mt65xx_reg_sync_writeb(v, a) \ + do { \ + *(volatile unsigned char *)(a) = (v); \ + mb(); \ + } while (0) + +#endif /* __KERNEL__ */ + +#endif /* !_MT_SYNC_WRITE_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/wakelock.h b/drivers/misc/mediatek/include/mt-plat/wakelock.h new file mode 100644 index 0000000000000..f4a698a228803 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/wakelock.h @@ -0,0 +1,67 @@ +/* include/linux/wakelock.h + * + * Copyright (C) 2007-2012 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_WAKELOCK_H +#define _LINUX_WAKELOCK_H + +#include +#include + +/* A wake_lock prevents the system from entering suspend or other low power + * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock + * prevents a full system suspend. + */ + +enum { + WAKE_LOCK_SUSPEND, /* Prevent suspend */ + WAKE_LOCK_TYPE_COUNT +}; + +struct wake_lock { + struct wakeup_source ws; +}; + +static inline void wake_lock_init(struct wake_lock *lock, int type, + const char *name) +{ + wakeup_source_init(&lock->ws, name); +} + +static inline void wake_lock_destroy(struct wake_lock *lock) +{ + wakeup_source_trash(&lock->ws); +} + +static inline void wake_lock(struct wake_lock *lock) +{ + __pm_stay_awake(&lock->ws); +} + +static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) +{ + __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); +} + +static inline void wake_unlock(struct wake_lock *lock) +{ + __pm_relax(&lock->ws); +} + +static inline int wake_lock_active(struct wake_lock *lock) +{ + return lock->ws.active; +} + +#endif diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index deb2030264965..e089bb6dde3a8 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -533,6 +533,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, test->base = test->bar[test_reg_bar]; if (!test->base) { + err = -ENOMEM; dev_err(dev, "Cannot perform PCI test without BAR%d\n", test_reg_bar); goto err_iounmap; @@ -542,6 +543,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL); if (id < 0) { + err = id; dev_err(dev, "unable to get id\n"); goto err_iounmap; } @@ -588,6 +590,8 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev) if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) return; + if (id < 0) + return; misc_deregister(&test->miscdev); ida_simple_remove(&pci_endpoint_test_ida, id); diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index eda38cbe85307..41f2a9f6851d9 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 1e688bfec5672..9047c0a529b28 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -1271,7 +1271,7 @@ static int __init vmballoon_init(void) * Check if we are running on VMware's hypervisor and bail out * if we are not. */ - if (x86_hyper != &x86_hyper_vmware) + if (x86_hyper_type != X86_HYPER_VMWARE) return -ENODEV; for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES; diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2ad7b5c691569..ccb516f18d72e 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -119,6 +119,10 @@ struct mmc_blk_data { struct device_attribute force_ro; struct device_attribute power_ro_lock; int area_type; + + /* debugfs files (only in main mmc_blk_data) */ + struct dentry *status_dentry; + struct dentry *ext_csd_dentry; }; static DEFINE_MUTEX(open_lock); @@ -204,9 +208,14 @@ static ssize_t power_ro_lock_store(struct device *dev, /* Dispatch locking to the block layer */ req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM); + if (IS_ERR(req)) { + count = PTR_ERR(req); + goto out_put; + } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP; blk_execute_rq(mq->queue, NULL, req, 0); ret = req_to_mmc_queue_req(req)->drv_op_result; + blk_put_request(req); if (!ret) { pr_info("%s: Locking boot partition ro until next power on\n", @@ -219,7 +228,7 @@ static ssize_t power_ro_lock_store(struct device *dev, set_disk_ro(part_md->disk, 1); } } - +out_put: mmc_blk_put(md); return count; } @@ -580,6 +589,10 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, req = blk_get_request(mq->queue, idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto cmd_done; + } idatas[0] = idata; req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idatas; @@ -643,6 +656,10 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, req = blk_get_request(mq->queue, idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto cmd_err; + } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; @@ -2314,6 +2331,8 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) /* Ask the block layer about the card status */ req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) + return PTR_ERR(req); req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS; blk_execute_rq(mq->queue, NULL, req, 0); ret = req_to_mmc_queue_req(req)->drv_op_result; @@ -2321,6 +2340,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) *val = ret; ret = 0; } + blk_put_request(req); return ret; } @@ -2347,10 +2367,15 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) /* Ask the block layer for the EXT CSD */ req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto out_free; + } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD; req_to_mmc_queue_req(req)->drv_op_data = &ext_csd; blk_execute_rq(mq->queue, NULL, req, 0); err = req_to_mmc_queue_req(req)->drv_op_result; + blk_put_request(req); if (err) { pr_err("FAILED %d\n", err); goto out_free; @@ -2396,7 +2421,7 @@ static const struct file_operations mmc_dbg_ext_csd_fops = { .llseek = default_llseek, }; -static int mmc_blk_add_debugfs(struct mmc_card *card) +static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) { struct dentry *root; @@ -2406,28 +2431,53 @@ static int mmc_blk_add_debugfs(struct mmc_card *card) root = card->debugfs_root; if (mmc_card_mmc(card) || mmc_card_sd(card)) { - if (!debugfs_create_file("status", S_IRUSR, root, card, - &mmc_dbg_card_status_fops)) + md->status_dentry = + debugfs_create_file("status", S_IRUSR, root, card, + &mmc_dbg_card_status_fops); + if (!md->status_dentry) return -EIO; } if (mmc_card_mmc(card)) { - if (!debugfs_create_file("ext_csd", S_IRUSR, root, card, - &mmc_dbg_ext_csd_fops)) + md->ext_csd_dentry = + debugfs_create_file("ext_csd", S_IRUSR, root, card, + &mmc_dbg_ext_csd_fops); + if (!md->ext_csd_dentry) return -EIO; } return 0; } +static void mmc_blk_remove_debugfs(struct mmc_card *card, + struct mmc_blk_data *md) +{ + if (!card->debugfs_root) + return; + + if (!IS_ERR_OR_NULL(md->status_dentry)) { + debugfs_remove(md->status_dentry); + md->status_dentry = NULL; + } + + if (!IS_ERR_OR_NULL(md->ext_csd_dentry)) { + debugfs_remove(md->ext_csd_dentry); + md->ext_csd_dentry = NULL; + } +} #else -static int mmc_blk_add_debugfs(struct mmc_card *card) +static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) { return 0; } +static void mmc_blk_remove_debugfs(struct mmc_card *card, + struct mmc_blk_data *md) +{ +} + #endif /* CONFIG_DEBUG_FS */ static int mmc_blk_probe(struct mmc_card *card) @@ -2467,7 +2517,7 @@ static int mmc_blk_probe(struct mmc_card *card) } /* Add two debugfs entries */ - mmc_blk_add_debugfs(card); + mmc_blk_add_debugfs(card, md); pm_runtime_set_autosuspend_delay(&card->dev, 3000); pm_runtime_use_autosuspend(&card->dev); @@ -2493,6 +2543,7 @@ static void mmc_blk_remove(struct mmc_card *card) { struct mmc_blk_data *md = dev_get_drvdata(&card->dev); + mmc_blk_remove_debugfs(card, md); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); mmc_claim_host(card->host); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 301246513a370..7f428e387de3f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -157,6 +157,9 @@ static int mmc_bus_suspend(struct device *dev) return ret; ret = host->bus_ops->suspend(host); + if (ret) + pm_generic_resume(dev); + return ret; } diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index f06cd91964ce9..79a5b985ccf5e 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -75,9 +75,11 @@ struct mmc_fixup { #define EXT_CSD_REV_ANY (-1u) #define CID_MANFID_SANDISK 0x2 +#define CID_MANFID_ATP 0x9 #define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_MICRON 0x13 #define CID_MANFID_SAMSUNG 0x15 +#define CID_MANFID_APACER 0x27 #define CID_MANFID_KINGSTON 0x70 #define CID_MANFID_HYNIX 0x90 diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 01e459a34f332..0f4a7d7b26261 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -314,4 +314,5 @@ void mmc_add_card_debugfs(struct mmc_card *card) void mmc_remove_card_debugfs(struct mmc_card *card) { debugfs_remove_recursive(card->debugfs_root); + card->debugfs_root = NULL; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 36217ad5e9b1f..bad5c1bf4ed9f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -780,7 +780,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); -MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info); +MMC_DEV_ATTR(pre_eol_info, "0x%02x\n", card->ext_csd.pre_eol_info); MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n", card->ext_csd.device_life_time_est_typ_a, card->ext_csd.device_life_time_est_typ_b); @@ -790,7 +790,7 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); -MMC_DEV_ATTR(ocr, "%08x\n", card->ocr); +MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en); static ssize_t mmc_fwrev_show(struct device *dev, diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index f664e9cbc9f8b..75d317623852d 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -52,6 +52,14 @@ static const struct mmc_fixup mmc_blk_fixups[] = { MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), + /* + * Some SD cards lockup while using CMD23 multiblock transfers. + */ + MMC_FIXUP("AF SD", CID_MANFID_ATP, CID_OEMID_ANY, add_quirk_sd, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("APUSD", CID_MANFID_APACER, 0x5048, add_quirk_sd, + MMC_QUIRK_BLK_NO_CMD23), + /* * Some MMC cards need longer data read timeout than indicated in CSD. */ diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 4fd1620b732d0..eb9de21349679 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -675,7 +675,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); -MMC_DEV_ATTR(ocr, "%08x\n", card->ocr); +MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); static ssize_t mmc_dsr_show(struct device *dev, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 267f7ab08420e..643c795f1bdda 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -95,6 +95,9 @@ #define MSDC_CFG_CKDIV (0xff << 8) /* RW */ #define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ #define MSDC_CFG_HS400_CK_MODE (0x1 << 18) /* RW */ +#define MSDC_CFG_HS400_CK_MODE_EXTRA (0x1 << 22) /* RW */ +#define MSDC_CFG_CKDIV_EXTRA (0xfff << 8) /* RW */ +#define MSDC_CFG_CKMOD_EXTRA (0x3 << 20) /* RW */ /* MSDC_IOCON mask */ #define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ @@ -295,6 +298,10 @@ struct msdc_save_para { u32 emmc50_cfg0; }; +struct mtk_mmc_compatible { + u8 clk_div_bits; +}; + struct msdc_tune_para { u32 iocon; u32 pad_tune; @@ -309,6 +316,7 @@ struct msdc_delay_phase { struct msdc_host { struct device *dev; + const struct mtk_mmc_compatible *dev_comp; struct mmc_host *mmc; /* mmc structure */ int cmd_rsp; @@ -350,6 +358,31 @@ struct msdc_host { struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ }; +static const struct mtk_mmc_compatible mt8135_compat = { + .clk_div_bits = 8, +}; + +static const struct mtk_mmc_compatible mt8173_compat = { + .clk_div_bits = 8, +}; + +static const struct mtk_mmc_compatible mt2701_compat = { + .clk_div_bits = 12, +}; + +static const struct mtk_mmc_compatible mt2712_compat = { + .clk_div_bits = 12, +}; + +static const struct of_device_id msdc_of_ids[] = { + { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, + { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, + { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, + { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, + {} +}; +MODULE_DEVICE_TABLE(of, msdc_of_ids); + static void sdr_set_bits(void __iomem *reg, u32 bs) { u32 val = readl(reg); @@ -509,7 +542,12 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) timeout = (ns + clk_ns - 1) / clk_ns + clks; /* in 1048576 sclk cycle unit */ timeout = (timeout + (0x1 << 20) - 1) >> 20; - sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &mode); + if (host->dev_comp->clk_div_bits == 8) + sdr_get_field(host->base + MSDC_CFG, + MSDC_CFG_CKMOD, &mode); + else + sdr_get_field(host->base + MSDC_CFG, + MSDC_CFG_CKMOD_EXTRA, &mode); /*DDR mode will double the clk cycles for data timeout */ timeout = mode >= 2 ? timeout * 2 : timeout; timeout = timeout > 1 ? timeout - 1 : 0; @@ -548,7 +586,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) flags = readl(host->base + MSDC_INTEN); sdr_clr_bits(host->base + MSDC_INTEN, flags); - sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE); + if (host->dev_comp->clk_div_bits == 8) + sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE); + else + sdr_clr_bits(host->base + MSDC_CFG, + MSDC_CFG_HS400_CK_MODE_EXTRA); if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52 || timing == MMC_TIMING_MMC_HS400) { @@ -568,8 +610,12 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) if (timing == MMC_TIMING_MMC_HS400 && hz >= (host->src_clk_freq >> 1)) { - sdr_set_bits(host->base + MSDC_CFG, - MSDC_CFG_HS400_CK_MODE); + if (host->dev_comp->clk_div_bits == 8) + sdr_set_bits(host->base + MSDC_CFG, + MSDC_CFG_HS400_CK_MODE); + else + sdr_set_bits(host->base + MSDC_CFG, + MSDC_CFG_HS400_CK_MODE_EXTRA); sclk = host->src_clk_freq >> 1; div = 0; /* div is ignore when bit18 is set */ } @@ -587,8 +633,15 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) sclk = (host->src_clk_freq >> 2) / div; } } - sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD | MSDC_CFG_CKDIV, - (mode << 8) | div); + if (host->dev_comp->clk_div_bits == 8) + sdr_set_field(host->base + MSDC_CFG, + MSDC_CFG_CKMOD | MSDC_CFG_CKDIV, + (mode << 8) | div); + else + sdr_set_field(host->base + MSDC_CFG, + MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA, + (mode << 12) | div); + sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) cpu_relax(); @@ -1617,12 +1670,17 @@ static int msdc_drv_probe(struct platform_device *pdev) struct mmc_host *mmc; struct msdc_host *host; struct resource *res; + const struct of_device_id *of_id; int ret; if (!pdev->dev.of_node) { dev_err(&pdev->dev, "No DT found\n"); return -EINVAL; } + + of_id = of_match_node(msdc_of_ids, pdev->dev.of_node); + if (!of_id) + return -EINVAL; /* Allocate MMC host for this device */ mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); if (!mmc) @@ -1686,11 +1744,15 @@ static int msdc_drv_probe(struct platform_device *pdev) msdc_of_property_parse(pdev, host); host->dev = &pdev->dev; + host->dev_comp = of_id->data; host->mmc = mmc; host->src_clk_freq = clk_get_rate(host->src_clk); /* Set host parameters to mmc */ mmc->ops = &mt_msdc_ops; - mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255); + if (host->dev_comp->clk_div_bits == 8) + mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255); + else + mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23; /* MMC core transfer sizes tunable parameters */ @@ -1839,12 +1901,6 @@ static const struct dev_pm_ops msdc_dev_pm_ops = { SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL) }; -static const struct of_device_id msdc_of_ids[] = { - { .compatible = "mediatek,mt8135-mmc", }, - {} -}; -MODULE_DEVICE_TABLE(of, msdc_of_ids); - static struct platform_driver mt_msdc_driver = { .probe = msdc_drv_probe, .remove = msdc_drv_remove, diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index fcf7235d5742a..157e1d9e7725a 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -667,3 +668,5 @@ int renesas_sdhi_remove(struct platform_device *pdev) return 0; } EXPORT_SYMBOL_GPL(renesas_sdhi_remove); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 85140c9af5812..8b941f814472f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -687,6 +687,20 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, return; } + /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ + if (is_imx53_esdhc(imx_data)) { + /* + * According to the i.MX53 reference manual, if DLLCTRL[10] can + * be set, then the controller is eSDHCv3, else it is eSDHCv2. + */ + val = readl(host->ioaddr + ESDHC_DLL_CTRL); + writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL); + temp = readl(host->ioaddr + ESDHC_DLL_CTRL); + writel(val, host->ioaddr + ESDHC_DLL_CTRL); + if (temp & BIT(10)) + pre_div = 2; + } + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index fc73e56eb1e2e..92c483ec6cb2e 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1251,6 +1251,21 @@ static int sdhci_msm_probe(struct platform_device *pdev) CORE_VENDOR_SPEC_CAPABILITIES0); } + /* + * Power on reset state may trigger power irq if previous status of + * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq + * interrupt in GIC, any pending power irq interrupt should be + * acknowledged. Otherwise power irq interrupt handler would be + * fired prematurely. + */ + sdhci_msm_voltage_switch(host); + + /* + * Ensure that above writes are propogated before interrupt enablement + * in GIC. + */ + mb(); + /* Setup IRQ for handling power/voltage tasks with PMIC */ msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); if (msm_host->pwr_irq < 0) { @@ -1260,6 +1275,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) goto clk_disable; } + /* Enable pwr irq interrupts */ + writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK); + ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, sdhci_msm_pwr_irq, IRQF_ONESHOT, dev_name(&pdev->dev), host); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0d5fcca18c9ec..6152e83ff9352 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -3650,23 +3651,30 @@ int sdhci_setup_host(struct sdhci_host *host) spin_lock_init(&host->lock); + /* + * Maximum number of sectors in one transfer. Limited by SDMA boundary + * size (512KiB). Note some tuning modes impose a 4MiB limit, but this + * is less anyway. + */ + mmc->max_req_size = 524288; + /* * Maximum number of segments. Depends on if the hardware * can do scatter/gather or not. */ - if (host->flags & SDHCI_USE_ADMA) + if (host->flags & SDHCI_USE_ADMA) { mmc->max_segs = SDHCI_MAX_SEGS; - else if (host->flags & SDHCI_USE_SDMA) + } else if (host->flags & SDHCI_USE_SDMA) { mmc->max_segs = 1; - else /* PIO */ + if (swiotlb_max_segment()) { + unsigned int max_req_size = (1 << IO_TLB_SHIFT) * + IO_TLB_SEGSIZE; + mmc->max_req_size = min(mmc->max_req_size, + max_req_size); + } + } else { /* PIO */ mmc->max_segs = SDHCI_MAX_SEGS; - - /* - * Maximum number of sectors in one transfer. Limited by SDMA boundary - * size (512KiB). Note some tuning modes impose a 4MiB limit, but this - * is less anyway. - */ - mmc->max_req_size = 524288; + } /* * Maximum segment size. Could be one segment with the maximum number diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 9c4e6199b854d..3a6d49f07e22d 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1113,8 +1113,11 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) { struct tmio_mmc_data *pdata = host->pdata; struct mmc_host *mmc = host->mmc; + int err; - mmc_regulator_get_supply(mmc); + err = mmc_regulator_get_supply(mmc); + if (err) + return err; /* use ocr_mask if no regulator */ if (!mmc->ocr_avail) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 84b16133554be..0806f72102c09 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1814,8 +1814,13 @@ static void __init doc_dbg_register(struct mtd_info *floor) struct dentry *root = floor->dbg.dfs_dir; struct docg3 *docg3 = floor->priv; - if (IS_ERR_OR_NULL(root)) + if (IS_ERR_OR_NULL(root)) { + if (IS_ENABLED(CONFIG_DEBUG_FS) && + !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + dev_warn(floor->dev.parent, + "CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n"); return; + } debugfs_create_file("docg3_flashcontrol", S_IRUSR, root, docg3, &flashcontrol_fops); diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index f25eca79f4e56..68c9d98a3347c 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -2547,6 +2547,7 @@ static struct platform_driver atmel_nand_controller_driver = { .driver = { .name = "atmel-nand-controller", .of_match_table = of_match_ptr(atmel_nand_controller_of_ids), + .pm = &atmel_nand_controller_pm_ops, }, .probe = atmel_nand_controller_probe, .remove = atmel_nand_controller_remove, diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c index 7f3b065b6b8fe..c51d214d169ea 100644 --- a/drivers/mtd/nand/mtk_ecc.c +++ b/drivers/mtd/nand/mtk_ecc.c @@ -115,6 +115,11 @@ static irqreturn_t mtk_ecc_irq(int irq, void *id) op = ECC_DECODE; dec = readw(ecc->regs + ECC_DECDONE); if (dec & ecc->sectors) { + /* + * Clear decode IRQ status once again to ensure that + * there will be no extra IRQ. + */ + readw(ecc->regs + ECC_DECIRQ_STA); ecc->sectors = 0; complete(&ecc->done); } else { @@ -130,8 +135,6 @@ static irqreturn_t mtk_ecc_irq(int irq, void *id) } } - writel(0, ecc->regs + ECC_IRQ_REG(op)); - return IRQ_HANDLED; } @@ -307,6 +310,12 @@ void mtk_ecc_disable(struct mtk_ecc *ecc) /* disable it */ mtk_ecc_wait_idle(ecc, op); + if (op == ECC_DECODE) + /* + * Clear decode IRQ status in case there is a timeout to wait + * decode IRQ. + */ + readw(ecc->regs + ECC_DECIRQ_STA); writew(0, ecc->regs + ECC_IRQ_REG(op)); writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op)); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 12edaae17d81f..3f1d806e590a1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1246,6 +1246,7 @@ int nand_reset(struct nand_chip *chip, int chipnr) return 0; } +EXPORT_SYMBOL_GPL(nand_reset); /** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data @@ -2799,15 +2800,18 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd_to_nand(mtd); + int chipnr = (int)(to >> chip->chip_shift); struct mtd_oob_ops ops; int ret; - /* Wait for the device to get ready */ - panic_nand_wait(mtd, chip, 400); - /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); + chip->select_chip(mtd, chipnr); + + /* Wait for the device to get ready */ + panic_nand_wait(mtd, chip, 400); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = (uint8_t *)buf; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 246b4393118e4..44322a363ba54 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -520,11 +520,16 @@ static int nandsim_debugfs_create(struct nandsim *dev) struct dentry *root = nsmtd->dbg.dfs_dir; struct dentry *dent; - if (!IS_ENABLED(CONFIG_DEBUG_FS)) + /* + * Just skip debugfs initialization when the debugfs directory is + * missing. + */ + if (IS_ERR_OR_NULL(root)) { + if (IS_ENABLED(CONFIG_DEBUG_FS) && + !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + NS_WARN("CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n"); return 0; - - if (IS_ERR_OR_NULL(root)) - return -1; + } dent = debugfs_create_file("nandsim_wear_report", S_IRUSR, root, dev, &dfs_fops); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 54540c8fa1a28..9f98f74ff221a 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1133,129 +1133,172 @@ static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, 0x97, 0x79, 0xe5, 0x24, 0xb5}; /** - * omap_calculate_ecc_bch - Generate bytes of ECC bytes + * _omap_calculate_ecc_bch - Generate ECC bytes for one sector * @mtd: MTD device structure * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer + * @i: The sector number (for a multi sector page) * - * Support calculating of BCH4/8 ecc vectors for the page + * Support calculating of BCH4/8/16 ECC vectors for one sector + * within a page. Sector number is in @i. */ -static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_calc) +static int _omap_calculate_ecc_bch(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_calc, int i) { struct omap_nand_info *info = mtd_to_omap(mtd); int eccbytes = info->nand.ecc.bytes; struct gpmc_nand_regs *gpmc_regs = &info->reg; u8 *ecc_code; - unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; + unsigned long bch_val1, bch_val2, bch_val3, bch_val4; u32 val; - int i, j; + int j; + + ecc_code = ecc_calc; + switch (info->ecc_opt) { + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW: + bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); + bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); + bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]); + bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]); + *ecc_code++ = (bch_val4 & 0xFF); + *ecc_code++ = ((bch_val3 >> 24) & 0xFF); + *ecc_code++ = ((bch_val3 >> 16) & 0xFF); + *ecc_code++ = ((bch_val3 >> 8) & 0xFF); + *ecc_code++ = (bch_val3 & 0xFF); + *ecc_code++ = ((bch_val2 >> 24) & 0xFF); + *ecc_code++ = ((bch_val2 >> 16) & 0xFF); + *ecc_code++ = ((bch_val2 >> 8) & 0xFF); + *ecc_code++ = (bch_val2 & 0xFF); + *ecc_code++ = ((bch_val1 >> 24) & 0xFF); + *ecc_code++ = ((bch_val1 >> 16) & 0xFF); + *ecc_code++ = ((bch_val1 >> 8) & 0xFF); + *ecc_code++ = (bch_val1 & 0xFF); + break; + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH4_CODE_HW: + bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); + bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); + *ecc_code++ = ((bch_val2 >> 12) & 0xFF); + *ecc_code++ = ((bch_val2 >> 4) & 0xFF); + *ecc_code++ = ((bch_val2 & 0xF) << 4) | + ((bch_val1 >> 28) & 0xF); + *ecc_code++ = ((bch_val1 >> 20) & 0xFF); + *ecc_code++ = ((bch_val1 >> 12) & 0xFF); + *ecc_code++ = ((bch_val1 >> 4) & 0xFF); + *ecc_code++ = ((bch_val1 & 0xF) << 4); + break; + case OMAP_ECC_BCH16_CODE_HW: + val = readl(gpmc_regs->gpmc_bch_result6[i]); + ecc_code[0] = ((val >> 8) & 0xFF); + ecc_code[1] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result5[i]); + ecc_code[2] = ((val >> 24) & 0xFF); + ecc_code[3] = ((val >> 16) & 0xFF); + ecc_code[4] = ((val >> 8) & 0xFF); + ecc_code[5] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result4[i]); + ecc_code[6] = ((val >> 24) & 0xFF); + ecc_code[7] = ((val >> 16) & 0xFF); + ecc_code[8] = ((val >> 8) & 0xFF); + ecc_code[9] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result3[i]); + ecc_code[10] = ((val >> 24) & 0xFF); + ecc_code[11] = ((val >> 16) & 0xFF); + ecc_code[12] = ((val >> 8) & 0xFF); + ecc_code[13] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result2[i]); + ecc_code[14] = ((val >> 24) & 0xFF); + ecc_code[15] = ((val >> 16) & 0xFF); + ecc_code[16] = ((val >> 8) & 0xFF); + ecc_code[17] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result1[i]); + ecc_code[18] = ((val >> 24) & 0xFF); + ecc_code[19] = ((val >> 16) & 0xFF); + ecc_code[20] = ((val >> 8) & 0xFF); + ecc_code[21] = ((val >> 0) & 0xFF); + val = readl(gpmc_regs->gpmc_bch_result0[i]); + ecc_code[22] = ((val >> 24) & 0xFF); + ecc_code[23] = ((val >> 16) & 0xFF); + ecc_code[24] = ((val >> 8) & 0xFF); + ecc_code[25] = ((val >> 0) & 0xFF); + break; + default: + return -EINVAL; + } + + /* ECC scheme specific syndrome customizations */ + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + /* Add constant polynomial to remainder, so that + * ECC of blank pages results in 0x0 on reading back + */ + for (j = 0; j < eccbytes; j++) + ecc_calc[j] ^= bch4_polynomial[j]; + break; + case OMAP_ECC_BCH4_CODE_HW: + /* Set 8th ECC byte as 0x0 for ROM compatibility */ + ecc_calc[eccbytes - 1] = 0x0; + break; + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + /* Add constant polynomial to remainder, so that + * ECC of blank pages results in 0x0 on reading back + */ + for (j = 0; j < eccbytes; j++) + ecc_calc[j] ^= bch8_polynomial[j]; + break; + case OMAP_ECC_BCH8_CODE_HW: + /* Set 14th ECC byte as 0x0 for ROM compatibility */ + ecc_calc[eccbytes - 1] = 0x0; + break; + case OMAP_ECC_BCH16_CODE_HW: + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction + * @mtd: MTD device structure + * @dat: The pointer to data on which ecc is computed + * @ecc_code: The ecc_code buffer + * + * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used + * when SW based correction is required as ECC is required for one sector + * at a time. + */ +static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_calc) +{ + return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0); +} + +/** + * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors + * @mtd: MTD device structure + * @dat: The pointer to data on which ecc is computed + * @ecc_code: The ecc_code buffer + * + * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go. + */ +static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_calc) +{ + struct omap_nand_info *info = mtd_to_omap(mtd); + int eccbytes = info->nand.ecc.bytes; + unsigned long nsectors; + int i, ret; nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; for (i = 0; i < nsectors; i++) { - ecc_code = ecc_calc; - switch (info->ecc_opt) { - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - case OMAP_ECC_BCH8_CODE_HW: - bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); - bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); - bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]); - bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]); - *ecc_code++ = (bch_val4 & 0xFF); - *ecc_code++ = ((bch_val3 >> 24) & 0xFF); - *ecc_code++ = ((bch_val3 >> 16) & 0xFF); - *ecc_code++ = ((bch_val3 >> 8) & 0xFF); - *ecc_code++ = (bch_val3 & 0xFF); - *ecc_code++ = ((bch_val2 >> 24) & 0xFF); - *ecc_code++ = ((bch_val2 >> 16) & 0xFF); - *ecc_code++ = ((bch_val2 >> 8) & 0xFF); - *ecc_code++ = (bch_val2 & 0xFF); - *ecc_code++ = ((bch_val1 >> 24) & 0xFF); - *ecc_code++ = ((bch_val1 >> 16) & 0xFF); - *ecc_code++ = ((bch_val1 >> 8) & 0xFF); - *ecc_code++ = (bch_val1 & 0xFF); - break; - case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: - case OMAP_ECC_BCH4_CODE_HW: - bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); - bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); - *ecc_code++ = ((bch_val2 >> 12) & 0xFF); - *ecc_code++ = ((bch_val2 >> 4) & 0xFF); - *ecc_code++ = ((bch_val2 & 0xF) << 4) | - ((bch_val1 >> 28) & 0xF); - *ecc_code++ = ((bch_val1 >> 20) & 0xFF); - *ecc_code++ = ((bch_val1 >> 12) & 0xFF); - *ecc_code++ = ((bch_val1 >> 4) & 0xFF); - *ecc_code++ = ((bch_val1 & 0xF) << 4); - break; - case OMAP_ECC_BCH16_CODE_HW: - val = readl(gpmc_regs->gpmc_bch_result6[i]); - ecc_code[0] = ((val >> 8) & 0xFF); - ecc_code[1] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result5[i]); - ecc_code[2] = ((val >> 24) & 0xFF); - ecc_code[3] = ((val >> 16) & 0xFF); - ecc_code[4] = ((val >> 8) & 0xFF); - ecc_code[5] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result4[i]); - ecc_code[6] = ((val >> 24) & 0xFF); - ecc_code[7] = ((val >> 16) & 0xFF); - ecc_code[8] = ((val >> 8) & 0xFF); - ecc_code[9] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result3[i]); - ecc_code[10] = ((val >> 24) & 0xFF); - ecc_code[11] = ((val >> 16) & 0xFF); - ecc_code[12] = ((val >> 8) & 0xFF); - ecc_code[13] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result2[i]); - ecc_code[14] = ((val >> 24) & 0xFF); - ecc_code[15] = ((val >> 16) & 0xFF); - ecc_code[16] = ((val >> 8) & 0xFF); - ecc_code[17] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result1[i]); - ecc_code[18] = ((val >> 24) & 0xFF); - ecc_code[19] = ((val >> 16) & 0xFF); - ecc_code[20] = ((val >> 8) & 0xFF); - ecc_code[21] = ((val >> 0) & 0xFF); - val = readl(gpmc_regs->gpmc_bch_result0[i]); - ecc_code[22] = ((val >> 24) & 0xFF); - ecc_code[23] = ((val >> 16) & 0xFF); - ecc_code[24] = ((val >> 8) & 0xFF); - ecc_code[25] = ((val >> 0) & 0xFF); - break; - default: - return -EINVAL; - } - - /* ECC scheme specific syndrome customizations */ - switch (info->ecc_opt) { - case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: - /* Add constant polynomial to remainder, so that - * ECC of blank pages results in 0x0 on reading back */ - for (j = 0; j < eccbytes; j++) - ecc_calc[j] ^= bch4_polynomial[j]; - break; - case OMAP_ECC_BCH4_CODE_HW: - /* Set 8th ECC byte as 0x0 for ROM compatibility */ - ecc_calc[eccbytes - 1] = 0x0; - break; - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - /* Add constant polynomial to remainder, so that - * ECC of blank pages results in 0x0 on reading back */ - for (j = 0; j < eccbytes; j++) - ecc_calc[j] ^= bch8_polynomial[j]; - break; - case OMAP_ECC_BCH8_CODE_HW: - /* Set 14th ECC byte as 0x0 for ROM compatibility */ - ecc_calc[eccbytes - 1] = 0x0; - break; - case OMAP_ECC_BCH16_CODE_HW: - break; - default: - return -EINVAL; - } + ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i); + if (ret) + return ret; - ecc_calc += eccbytes; + ecc_calc += eccbytes; } return 0; @@ -1496,7 +1539,7 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, chip->write_buf(mtd, buf, mtd->writesize); /* Update ecc vector from GPMC result registers */ - chip->ecc.calculate(mtd, buf, &ecc_calc[0]); + omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); @@ -1508,6 +1551,72 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, return 0; } +/** + * omap_write_subpage_bch - BCH hardware ECC based subpage write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @offset: column address of subpage within the page + * @data_len: data length + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * + * OMAP optimized subpage write method. + */ +static int omap_write_subpage_bch(struct mtd_info *mtd, + struct nand_chip *chip, u32 offset, + u32 data_len, const u8 *buf, + int oob_required, int page) +{ + u8 *ecc_calc = chip->buffers->ecccalc; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int ecc_steps = chip->ecc.steps; + u32 start_step = offset / ecc_size; + u32 end_step = (offset + data_len - 1) / ecc_size; + int step, ret = 0; + + /* + * Write entire page at one go as it would be optimal + * as ECC is calculated by hardware. + * ECC is calculated for all subpages but we choose + * only what we want. + */ + + /* Enable GPMC ECC engine */ + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + + /* Write data */ + chip->write_buf(mtd, buf, mtd->writesize); + + for (step = 0; step < ecc_steps; step++) { + /* mask ECC of un-touched subpages by padding 0xFF */ + if (step < start_step || step > end_step) + memset(ecc_calc, 0xff, ecc_bytes); + else + ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step); + + if (ret) + return ret; + + buf += ecc_size; + ecc_calc += ecc_bytes; + } + + /* copy calculated ECC for whole page to chip->buffer->oob */ + /* this include masked-value(0xFF) for unwritten subpages */ + ecc_calc = chip->buffers->ecccalc; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; + + /* write OOB buffer to NAND device */ + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + /** * omap_read_page_bch - BCH ecc based page read function for entire page * @mtd: mtd info structure @@ -1544,7 +1653,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, chip->ecc.total); /* Calculate ecc bytes */ - chip->ecc.calculate(mtd, buf, ecc_calc); + omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc); ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, chip->ecc.total); @@ -2044,7 +2153,7 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.strength = 4; nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap_calculate_ecc_bch; + nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw; mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops); /* Reserve one byte for the OMAP marker */ oobbytes_per_step = nand_chip->ecc.bytes + 1; @@ -2066,9 +2175,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.strength = 4; nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; + nand_chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = nand_chip->ecc.bytes; @@ -2087,7 +2196,7 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.strength = 8; nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap_calculate_ecc_bch; + nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw; mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops); /* Reserve one byte for the OMAP marker */ oobbytes_per_step = nand_chip->ecc.bytes + 1; @@ -2109,9 +2218,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.strength = 8; nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; + nand_chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = nand_chip->ecc.bytes; @@ -2131,9 +2240,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.strength = 16; nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; + nand_chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = nand_chip->ecc.bytes; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 85cff68643e0b..125b744c9c285 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -950,6 +950,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) switch (command) { case NAND_CMD_READ0: + case NAND_CMD_READOOB: case NAND_CMD_PAGEPROG: info->use_ecc = 1; break; diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index 8a596bfeddff6..7802ac3ba9348 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -422,7 +422,7 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf, if (ret < 0) return ret; - val = (len << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; + val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; val |= ret << SSFSTS_CTL_COP_SHIFT; val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; val |= SSFSTS_CTL_SCGO; @@ -432,7 +432,7 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf, if (ret) return ret; - status = readl(ispi->base + SSFSTS_CTL); + status = readl(ispi->sregs + SSFSTS_CTL); if (status & SSFSTS_CTL_FCERR) return -EIO; else if (status & SSFSTS_CTL_AEL) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 86c0931543c53..ad6a3e1844cbe 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -240,12 +240,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, STM32_QSPI_FIFO_TIMEOUT_US); if (ret) { dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); - break; + return ret; } tx_fifo(buf++, qspi->io_base + QUADSPI_DR); } - return ret; + return 0; } static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, diff --git a/drivers/mux/core.c b/drivers/mux/core.c index 2260063b0ea83..6e5cf9d9cd992 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -413,6 +413,7 @@ static int of_dev_node_match(struct device *dev, const void *data) return dev->of_node == data; } +/* Note this function returns a reference to the mux_chip dev. */ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) { struct device *dev; @@ -466,6 +467,7 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) (!args.args_count && (mux_chip->controllers > 1))) { dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n", np, args.np); + put_device(&mux_chip->dev); return ERR_PTR(-EINVAL); } @@ -476,10 +478,10 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) if (controller >= mux_chip->controllers) { dev_err(dev, "%pOF: bad mux controller %u specified in %pOF\n", np, controller, args.np); + put_device(&mux_chip->dev); return ERR_PTR(-EINVAL); } - get_device(&mux_chip->dev); return &mux_chip->mux[controller]; } EXPORT_SYMBOL_GPL(mux_control_get); diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index a13a4896a8bdd..c4d1140116ea2 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -189,7 +189,7 @@ * MX35 FlexCAN2 03.00.00.00 no no ? no no * MX53 FlexCAN2 03.00.00.00 yes no no no no * MX6s FlexCAN3 10.00.12.00 yes yes no no yes - * VF610 FlexCAN3 ? no yes ? yes yes? + * VF610 FlexCAN3 ? no yes no yes yes? * * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. */ @@ -297,7 +297,8 @@ static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { static const struct flexcan_devtype_data fsl_vf610_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | + FLEXCAN_QUIRK_BROKEN_PERR_STATE, }; static const struct can_bittiming_const flexcan_bittiming_const = { diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 85268be0c913d..55513411a82e6 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -258,21 +258,18 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv, /* if this frame is an echo, */ if ((rx_msg_flags & PUCAN_MSG_LOOPED_BACK) && !(rx_msg_flags & PUCAN_MSG_SELF_RECEIVE)) { - int n; unsigned long flags; spin_lock_irqsave(&priv->echo_lock, flags); - n = can_get_echo_skb(priv->ndev, msg->client); + can_get_echo_skb(priv->ndev, msg->client); spin_unlock_irqrestore(&priv->echo_lock, flags); /* count bytes of the echo instead of skb */ stats->tx_bytes += cf_len; stats->tx_packets++; - if (n) { - /* restart tx queue only if a slot is free */ - netif_wake_queue(priv->ndev); - } + /* restart tx queue (a slot is free) */ + netif_wake_queue(priv->ndev); return 0; } diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index b4efd711f824c..788c3464a3b0e 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -825,7 +825,10 @@ static int peak_pciefd_probe(struct pci_dev *pdev, err_disable_pci: pci_disable_device(pdev); - return err; + /* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while + * the probe() function must return a negative errno in case of failure + * (err is unchanged if negative) */ + return pcibios_err_to_errno(err); } /* free the board structure object, as well as its resources: */ diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index 131026fbc2d77..5adc95c922eef 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -717,7 +717,10 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) failure_disable_pci: pci_disable_device(pdev); - return err; + /* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while + * the probe() function must return a negative errno in case of failure + * (err is unchanged if negative) */ + return pcibios_err_to_errno(err); } static void peak_pci_remove(struct pci_dev *pdev) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 4d4941469cfc0..db6ea936dc3fc 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -637,6 +637,9 @@ static int ti_hecc_rx_poll(struct napi_struct *napi, int quota) mbx_mask = hecc_read(priv, HECC_CANMIM); mbx_mask |= HECC_TX_MBOX_MASK; hecc_write(priv, HECC_CANMIM, mbx_mask); + } else { + /* repoll is done only if whole budget is used */ + num_pkts = quota; } return num_pkts; diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index b3d02759c226b..b003582974246 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -288,6 +288,8 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) case -ECONNRESET: /* unlink */ case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 9fdb0f0bfa06a..c6dcf93675c00 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -393,6 +393,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb) break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 68ac3e88a8cec..8bf80ad9dc44c 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -449,7 +449,7 @@ static int gs_usb_set_bittiming(struct net_device *netdev) dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)", rc); - return rc; + return (rc > 0) ? 0 : rc; } static void gs_usb_xmit_callback(struct urb *urb) diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 9b18d96ef5263..63587b8e6825a 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -609,8 +609,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, } if (pos + tmp->len > actual_len) { - dev_err(dev->udev->dev.parent, - "Format error\n"); + dev_err_ratelimited(dev->udev->dev.parent, + "Format error\n"); break; } @@ -813,6 +813,7 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv, if (err) { netdev_err(netdev, "Error transmitting URB\n"); usb_unanchor_urb(urb); + kfree(buf); usb_free_urb(urb); return err; } @@ -1325,6 +1326,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) case 0: break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; default: @@ -1333,7 +1336,7 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) goto resubmit_urb; } - while (pos <= urb->actual_length - MSG_HEADER_LEN) { + while (pos <= (int)(urb->actual_length - MSG_HEADER_LEN)) { msg = urb->transfer_buffer + pos; /* The Kvaser firmware can only read and write messages that @@ -1352,7 +1355,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) } if (pos + msg->len > urb->actual_length) { - dev_err(dev->udev->dev.parent, "Format error\n"); + dev_err_ratelimited(dev->udev->dev.parent, + "Format error\n"); break; } @@ -1768,6 +1772,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&priv->tx_contexts_lock, flags); usb_unanchor_urb(urb); + kfree(buf); stats->tx_dropped++; diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 7f0272558befe..e0c24abce16ce 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -592,6 +592,8 @@ static void mcba_usb_read_bulk_callback(struct urb *urb) break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 7ccdc3e30c98c..53d6bb045e9e9 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -184,7 +184,7 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) void *cmd_head = pcan_usb_fd_cmd_buffer(dev); int err = 0; u8 *packet_ptr; - int i, n = 1, packet_len; + int packet_len; ptrdiff_t cmd_len; /* usb device unregistered? */ @@ -201,17 +201,13 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) } packet_ptr = cmd_head; + packet_len = cmd_len; /* firmware is not able to re-assemble 512 bytes buffer in full-speed */ - if ((dev->udev->speed != USB_SPEED_HIGH) && - (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) { - packet_len = PCAN_UFD_LOSPD_PKT_SIZE; - n += cmd_len / packet_len; - } else { - packet_len = cmd_len; - } + if (unlikely(dev->udev->speed != USB_SPEED_HIGH)) + packet_len = min(packet_len, PCAN_UFD_LOSPD_PKT_SIZE); - for (i = 0; i < n; i++) { + do { err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT), @@ -224,7 +220,12 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) } packet_ptr += packet_len; - } + cmd_len -= packet_len; + + if (cmd_len < PCAN_UFD_LOSPD_PKT_SIZE) + packet_len = cmd_len; + + } while (packet_len > 0); return err; } diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index d000cb62d6ae8..27861c417c940 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -524,6 +524,8 @@ static void usb_8dev_read_bulk_callback(struct urb *urb) break; case -ENOENT: + case -EPIPE: + case -EPROTO: case -ESHUTDOWN: return; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 8404e8852a0f9..b4c4a2c764378 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -194,7 +194,7 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, tbp = peer_tb; } - if (tbp[IFLA_IFNAME]) { + if (ifmp && tbp[IFLA_IFNAME]) { nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); name_assign_type = NET_NAME_USER; } else { diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index d7b53d53c116e..72d6ffbfd6387 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -167,7 +167,7 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable) reg = reg_readl(priv, REG_SPHY_CNTRL); if (enable) { reg |= PHY_RESET; - reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS); + reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | IDDQ_GLOBAL_PWR | CK25_DIS); reg_writel(priv, reg, REG_SPHY_CNTRL); udelay(21); reg = reg_readl(priv, REG_SPHY_CNTRL); diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index b471413d3df98..1e5a69b9d90a3 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -569,7 +569,7 @@ static int lan9303_disable_processing(struct lan9303 *chip) { int p; - for (p = 0; p < LAN9303_NUM_PORTS; p++) { + for (p = 1; p < LAN9303_NUM_PORTS; p++) { int ret = lan9303_disable_processing_port(chip, p); if (ret) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index dc5de275352a7..aa764c5e3c6b9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1875,7 +1875,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) * here forever if we consistently cannot allocate * buffers. */ - else if (rc == -ENOMEM) + else if (rc == -ENOMEM && budget) rx_pkts++; else if (rc == -EBUSY) /* partial completion */ break; @@ -1961,7 +1961,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR); rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event); - if (likely(rc == -EIO)) + if (likely(rc == -EIO) && budget) rx_pkts++; else if (rc == -EBUSY) /* partial completion */ break; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 656e6af70f0a0..aef3fcf2f5b99 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14227,7 +14227,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) /* Reset PHY, otherwise the read DMA engine will be in a mode that * breaks all requests to 256 bytes. */ - if (tg3_asic_rev(tp) == ASIC_REV_57766) + if (tg3_asic_rev(tp) == ASIC_REV_57766 || + tg3_asic_rev(tp) == ASIC_REV_5717 || + tg3_asic_rev(tp) == ASIC_REV_5719) reset_phy = true; err = tg3_restart_hw(tp, reset_phy); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 2e993ce43b661..4d2db22e011b3 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -1289,6 +1289,9 @@ static int liquidio_stop(struct net_device *netdev) struct octeon_device *oct = lio->oct_dev; struct napi_struct *napi, *n; + /* tell Octeon to stop forwarding packets to host */ + send_rx_ctrl_cmd(lio, 0); + if (oct->props[lio->ifidx].napi_enabled) { list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) napi_disable(napi); @@ -1306,9 +1309,6 @@ static int liquidio_stop(struct net_device *netdev) netif_carrier_off(netdev); lio->link_changes++; - /* tell Octeon to stop forwarding packets to host */ - send_rx_ctrl_cmd(lio, 0); - ifstate_reset(lio, LIO_IFSTATE_RUNNING); txqs_stop(netdev); diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index d4496e9afcdf3..a3d12dbde95b6 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -1355,7 +1355,8 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry, /* Offload checksum calculation to HW */ if (skb->ip_summed == CHECKSUM_PARTIAL) { - hdr->csum_l3 = 1; /* Enable IP csum calculation */ + if (ip.v4->version == 4) + hdr->csum_l3 = 1; /* Enable IP csum calculation */ hdr->l3_offset = skb_network_offset(skb); hdr->l4_offset = skb_transport_offset(skb); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 0e3d9f39a8075..1b03c32afc1f0 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4634,6 +4634,15 @@ int be_update_queues(struct be_adapter *adapter) be_schedule_worker(adapter); + /* + * The IF was destroyed and re-created. We need to clear + * all promiscuous flags valid for the destroyed IF. + * Without this promisc mode is not restored during + * be_open() because the driver thinks that it is + * already enabled in HW. + */ + adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS; + if (netif_running(netdev)) status = be_open(netdev); diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index e92859dab7aed..e191c4ebeaf41 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -257,8 +257,8 @@ enum rx_desc_status_bits { RXFSD = 0x00000800, /* first descriptor */ RXLSD = 0x00000400, /* last descriptor */ ErrorSummary = 0x80, /* error summary */ - RUNT = 0x40, /* runt packet received */ - LONG = 0x20, /* long packet received */ + RUNTPKT = 0x40, /* runt packet received */ + LONGPKT = 0x20, /* long packet received */ FAE = 0x10, /* frame align error */ CRC = 0x08, /* crc error */ RXER = 0x04, /* receive error */ @@ -1632,7 +1632,7 @@ static int netdev_rx(struct net_device *dev) dev->name, rx_status); dev->stats.rx_errors++; /* end of a packet. */ - if (rx_status & (LONG | RUNT)) + if (rx_status & (LONGPKT | RUNTPKT)) dev->stats.rx_length_errors++; if (rx_status & RXER) dev->stats.rx_frame_errors++; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 3dc2d771a2221..311539c6625f4 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -818,6 +818,12 @@ static void fec_enet_bd_init(struct net_device *dev) for (i = 0; i < txq->bd.ring_size; i++) { /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = cpu_to_fec16(0); + if (bdp->cbd_bufaddr && + !IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr))) + dma_unmap_single(&fep->pdev->dev, + fec32_to_cpu(bdp->cbd_bufaddr), + fec16_to_cpu(bdp->cbd_datlen), + DMA_TO_DEVICE); if (txq->tx_skbuff[i]) { dev_kfree_skb_any(txq->tx_skbuff[i]); txq->tx_skbuff[i] = NULL; @@ -3452,6 +3458,10 @@ fec_probe(struct platform_device *pdev) goto failed_regulator; } } else { + if (PTR_ERR(fep->reg_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto failed_regulator; + } fep->reg_phy = NULL; } @@ -3533,8 +3543,9 @@ fec_probe(struct platform_device *pdev) failed_clk: if (of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); -failed_phy: of_node_put(phy_node); +failed_phy: + dev_id--; failed_ioremap: free_netdev(ndev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c1cdbfd83bdba..a0ef97e7f3c93 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3981,7 +3981,7 @@ static int hclge_init_client_instance(struct hnae3_client *client, vport->roce.client = client; } - if (hdev->roce_client) { + if (hdev->roce_client && hdev->nic_client) { ret = hclge_init_roce_base_info(vport); if (ret) goto err; @@ -4007,13 +4007,19 @@ static void hclge_uninit_client_instance(struct hnae3_client *client, for (i = 0; i < hdev->num_vmdq_vport + 1; i++) { vport = &hdev->vport[i]; - if (hdev->roce_client) + if (hdev->roce_client) { hdev->roce_client->ops->uninit_instance(&vport->roce, 0); + hdev->roce_client = NULL; + vport->roce.client = NULL; + } if (client->type == HNAE3_CLIENT_ROCE) return; - if (client->ops->uninit_instance) + if (client->ops->uninit_instance) { client->ops->uninit_instance(&vport->nic, 0); + hdev->nic_client = NULL; + vport->nic.client = NULL; + } } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index 35369e1c8036f..186772493711e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -721,7 +721,7 @@ static void hns3_set_txbd_baseinfo(u16 *bdtp_fe_sc_vld_ra_ri, int frag_end) HNS3_TXD_BDTYPE_M, 0); hnae_set_bit(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, !!frag_end); hnae_set_bit(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1); - hnae_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_SC_M, HNS3_TXD_SC_S, 1); + hnae_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_SC_M, HNS3_TXD_SC_S, 0); } static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, @@ -1546,7 +1546,7 @@ static int hns3_reserve_buffer_map(struct hns3_enet_ring *ring, return 0; out_with_buf: - hns3_free_buffers(ring); + hns3_free_buffer(ring, cb); out: return ret; } @@ -1586,7 +1586,7 @@ static int hns3_alloc_ring_buffers(struct hns3_enet_ring *ring) static void hns3_replace_buffer(struct hns3_enet_ring *ring, int i, struct hns3_desc_cb *res_cb) { - hns3_map_buffer(ring, &ring->desc_cb[i]); + hns3_unmap_buffer(ring, &ring->desc_cb[i]); ring->desc_cb[i] = *res_cb; ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma); } @@ -2460,9 +2460,8 @@ static int hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv) (void)irq_set_affinity_hint( priv->tqp_vector[i].vector_irq, NULL); - devm_free_irq(&pdev->dev, - priv->tqp_vector[i].vector_irq, - &priv->tqp_vector[i]); + free_irq(priv->tqp_vector[i].vector_irq, + &priv->tqp_vector[i]); } priv->ring_data[i].ring->irq_init_flag = HNS3_VECTOR_NOT_INITED; @@ -2489,16 +2488,16 @@ static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, if (ring_type == HNAE3_RING_TYPE_TX) { ring_data[q->tqp_index].ring = ring; + ring_data[q->tqp_index].queue_index = q->tqp_index; ring->io_base = (u8 __iomem *)q->io_base + HNS3_TX_REG_OFFSET; } else { ring_data[q->tqp_index + queue_num].ring = ring; + ring_data[q->tqp_index + queue_num].queue_index = q->tqp_index; ring->io_base = q->io_base; } hnae_set_bit(ring->flag, HNAE3_RING_TYPE_B, ring_type); - ring_data[q->tqp_index].queue_index = q->tqp_index; - ring->tqp = q; ring->desc = NULL; ring->desc_cb = NULL; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c index d636399232fb1..e590d96e434a1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c @@ -375,6 +375,9 @@ static int hns3_get_link_ksettings(struct net_device *netdev, break; } + if (!cmd->base.autoneg) + advertised_caps &= ~HNS3_LM_AUTONEG_BIT; + /* now, map driver link modes to ethtool link modes */ hns3_driv_to_eth_caps(supported_caps, cmd, false); hns3_driv_to_eth_caps(advertised_caps, cmd, true); diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index c66abd476023a..3b0db01ead1f4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -927,6 +927,7 @@ static int ibmvnic_open(struct net_device *netdev) } rc = __ibmvnic_open(netdev); + netif_carrier_on(netdev); mutex_unlock(&adapter->reset_lock); return rc; @@ -3899,6 +3900,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) if (rc) goto ibmvnic_init_fail; + netif_carrier_off(netdev); rc = register_netdev(netdev); if (rc) { dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc); diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 0641c00987380..afb7ebe20b243 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -398,6 +398,7 @@ #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ #define E1000_ICR_RXSEQ 0x00000008 /* Rx sequence error */ #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* Receiver Overrun */ #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ #define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */ /* If this bit asserted, the driver should claim the interrupt */ diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index d6d4ed7acf031..31277d3bb7dc1 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1367,6 +1367,9 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. + * + * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link + * up). **/ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) { @@ -1382,7 +1385,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 0; + return 1; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -1613,10 +1616,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) + if (ret_val) { e_dbg("Error configuring flow control\n"); + return ret_val; + } - return ret_val; + return 1; } static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 67163ca898ba2..00a36df02a3fd 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -113,7 +113,8 @@ #define NVM_SIZE_MULTIPLIER 4096 /*multiplier for NVMS field */ #define E1000_FLASH_BASE_ADDR 0xE000 /*offset of NVM access regs */ #define E1000_CTRL_EXT_NVMVS 0x3 /*NVM valid sector */ -#define E1000_TARC0_CB_MULTIQ_3_REQ (1 << 28 | 1 << 29) +#define E1000_TARC0_CB_MULTIQ_3_REQ 0x30000000 +#define E1000_TARC0_CB_MULTIQ_2_REQ 0x20000000 #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index b322011ec2828..f457c5703d0c4 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -410,6 +410,9 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. + * + * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link + * up). **/ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) { @@ -423,7 +426,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 0; + return 1; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -461,10 +464,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) + if (ret_val) { e_dbg("Error configuring flow control\n"); + return ret_val; + } - return ret_val; + return 1; } /** diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 327dfe5bedc00..991c2a0dd67e0 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1910,14 +1910,30 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u32 icr; + bool enable = true; + + icr = er32(ICR); + if (icr & E1000_ICR_RXO) { + ew32(ICR, E1000_ICR_RXO); + enable = false; + /* napi poll will re-enable Other, make sure it runs */ + if (napi_schedule_prep(&adapter->napi)) { + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __napi_schedule(&adapter->napi); + } + } + if (icr & E1000_ICR_LSC) { + ew32(ICR, E1000_ICR_LSC); + hw->mac.get_link_status = true; + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } - hw->mac.get_link_status = true; - - /* guard against interrupt when we're going down */ - if (!test_bit(__E1000_DOWN, &adapter->state)) { - mod_timer(&adapter->watchdog_timer, jiffies + 1); + if (enable && !test_bit(__E1000_DOWN, &adapter->state)) ew32(IMS, E1000_IMS_OTHER); - } return IRQ_HANDLED; } @@ -2687,7 +2703,8 @@ static int e1000e_poll(struct napi_struct *napi, int weight) napi_complete_done(napi, work_done); if (!test_bit(__E1000_DOWN, &adapter->state)) { if (adapter->msix_entries) - ew32(IMS, adapter->rx_ring->ims_val); + ew32(IMS, adapter->rx_ring->ims_val | + E1000_IMS_OTHER); else e1000_irq_enable(adapter); } @@ -3004,8 +3021,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) hw->mac.ops.config_collision_dist(hw); - /* SPT and CNP Si errata workaround to avoid data corruption */ - if (hw->mac.type >= e1000_pch_spt) { + /* SPT and KBL Si errata workaround to avoid data corruption */ + if (hw->mac.type == e1000_pch_spt) { u32 reg_val; reg_val = er32(IOSFPC); @@ -3013,7 +3030,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(IOSFPC, reg_val); reg_val = er32(TARC(0)); - reg_val |= E1000_TARC0_CB_MULTIQ_3_REQ; + /* SPT and KBL Si errata workaround to avoid Tx hang. + * Dropping the number of outstanding requests from + * 3 to 2 in order to avoid a buffer overrun. + */ + reg_val &= ~E1000_TARC0_CB_MULTIQ_3_REQ; + reg_val |= E1000_TARC0_CB_MULTIQ_2_REQ; ew32(TARC(0), reg_val); } } @@ -4204,7 +4226,7 @@ static void e1000e_trigger_lsc(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) - ew32(ICS, E1000_ICS_OTHER); + ew32(ICS, E1000_ICS_LSC | E1000_ICS_OTHER); else ew32(ICS, E1000_ICS_LSC); } @@ -5081,7 +5103,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) case e1000_media_type_copper: if (hw->mac.get_link_status) { ret_val = hw->mac.ops.check_for_link(hw); - link_active = !hw->mac.get_link_status; + link_active = ret_val > 0; } else { link_active = true; } @@ -5099,7 +5121,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) break; } - if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && + if ((ret_val == -E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) { /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ e_info("Gigabit has been disabled, downgrading speed\n"); diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index d78d47b41a716..86ff0969efb6e 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -1744,6 +1744,7 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, s32 ret_val = 0; u16 i, phy_status; + *success = false; for (i = 0; i < iterations; i++) { /* Some PHYs require the MII_BMSR register to be read * twice due to the link bit being sticky. No harm doing @@ -1763,16 +1764,16 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, ret_val = e1e_rphy(hw, MII_BMSR, &phy_status); if (ret_val) break; - if (phy_status & BMSR_LSTATUS) + if (phy_status & BMSR_LSTATUS) { + *success = true; break; + } if (usec_interval >= 1000) msleep(usec_interval / 1000); else udelay(usec_interval); } - *success = (i < iterations); - return ret_val; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index 689c413b7782f..d2f9a2dd76a22 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h @@ -526,8 +526,8 @@ s32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid); int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac); int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, u8 qos, __be16 vlan_proto); -int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int rate, - int unused); +int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, + int __always_unused min_rate, int max_rate); int fm10k_ndo_get_vf_config(struct net_device *netdev, int vf_idx, struct ifla_vf_info *ivi); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c index 5f4dac0d36ef1..e72fd52bacfe0 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c @@ -126,6 +126,9 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface) struct fm10k_mbx_info *mbx = &vf_info->mbx; u16 glort = vf_info->glort; + /* process the SM mailbox first to drain outgoing messages */ + hw->mbx.ops.process(hw, &hw->mbx); + /* verify port mapping is valid, if not reset port */ if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) hw->iov.ops.reset_lport(hw, vf_info); @@ -482,7 +485,7 @@ int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, } int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, - int __always_unused unused, int rate) + int __always_unused min_rate, int max_rate) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_iov_data *iov_data = interface->iov_data; @@ -493,14 +496,15 @@ int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, return -EINVAL; /* rate limit cannot be less than 10Mbs or greater than link speed */ - if (rate && ((rate < FM10K_VF_TC_MIN) || rate > FM10K_VF_TC_MAX)) + if (max_rate && + (max_rate < FM10K_VF_TC_MIN || max_rate > FM10K_VF_TC_MAX)) return -EINVAL; /* store values */ - iov_data->vf_info[vf_idx].rate = rate; + iov_data->vf_info[vf_idx].rate = max_rate; /* update hardware configuration */ - hw->iov.ops.configure_tc(hw, vf_idx, rate); + hw->iov.ops.configure_tc(hw, vf_idx, max_rate); return 0; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 9dffaba85ae6b..103c0a742d039 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -1229,7 +1229,7 @@ static bool fm10k_clean_tx_irq(struct fm10k_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->flags & FM10K_TXD_FLAG_DONE)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6498da8806cbf..b2cde9b16d824 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2874,14 +2874,15 @@ static void i40e_vsi_free_rx_resources(struct i40e_vsi *vsi) static void i40e_config_xps_tx_ring(struct i40e_ring *ring) { struct i40e_vsi *vsi = ring->vsi; + int cpu; if (!ring->q_vector || !ring->netdev) return; if ((vsi->tc_config.numtc <= 1) && !test_and_set_bit(__I40E_TX_XPS_INIT_DONE, &ring->state)) { - netif_set_xps_queue(ring->netdev, - get_cpu_mask(ring->q_vector->v_idx), + cpu = cpumask_local_spread(ring->q_vector->v_idx, -1); + netif_set_xps_queue(ring->netdev, get_cpu_mask(cpu), ring->queue_index); } @@ -3471,6 +3472,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename) int tx_int_idx = 0; int vector, err; int irq_num; + int cpu; for (vector = 0; vector < q_vectors; vector++) { struct i40e_q_vector *q_vector = vsi->q_vectors[vector]; @@ -3506,10 +3508,14 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename) q_vector->affinity_notify.notify = i40e_irq_affinity_notify; q_vector->affinity_notify.release = i40e_irq_affinity_release; irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify); - /* get_cpu_mask returns a static constant mask with - * a permanent lifetime so it's ok to use here. + /* Spread affinity hints out across online CPUs. + * + * get_cpu_mask returns a static constant mask with + * a permanent lifetime so it's ok to pass to + * irq_set_affinity_hint without making a copy. */ - irq_set_affinity_hint(irq_num, get_cpu_mask(q_vector->v_idx)); + cpu = cpumask_local_spread(q_vector->v_idx, -1); + irq_set_affinity_hint(irq_num, get_cpu_mask(cpu)); } vsi->irqs_ready = true; @@ -3760,7 +3766,7 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if the descriptor isn't done, no work yet to do */ if (!(eop_desc->cmd_type_offset_bsz & diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 120c68f78951d..3c07ff171ddcc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -759,7 +759,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); /* we have caught up to head, no work left to do */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 4d1e670f490ed..e368b0237a1b6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1008,8 +1008,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states); clear_bit(I40E_VF_STATE_DISABLED, &vf->vf_states); /* Do not notify the client during VF init */ - if (test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE, - &vf->vf_states)) + if (!test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE, + &vf->vf_states)) i40e_notify_client_of_vf_reset(pf, abs_vf_id); vf->num_vlan = 0; } @@ -2779,6 +2779,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) struct i40e_mac_filter *f; struct i40e_vf *vf; int ret = 0; + struct hlist_node *h; int bkt; /* validate the request */ @@ -2817,7 +2818,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) /* Delete all the filters for this VSI - we're going to kill it * anyway. */ - hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) + hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) __i40e_del_filter(vsi, f); spin_unlock_bh(&vsi->mac_filter_hash_lock); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index c32c62462c844..07a4e6e13925f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -179,7 +179,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); /* if the descriptor isn't done, no work yet to do */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1825d956bb005..1ccad6f30ebf4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -546,6 +546,7 @@ i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) unsigned int vector, q_vectors; unsigned int rx_int_idx = 0, tx_int_idx = 0; int irq_num, err; + int cpu; i40evf_irq_disable(adapter); /* Decrement for Other and TCP Timer vectors */ @@ -584,10 +585,12 @@ i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) q_vector->affinity_notify.release = i40evf_irq_affinity_release; irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify); - /* get_cpu_mask returns a static constant mask with - * a permanent lifetime so it's ok to use here. + /* Spread the IRQ affinity hints across online CPUs. Note that + * get_cpu_mask returns a mask with a permanent lifetime so + * it's safe to use as a hint for irq_set_affinity_hint. */ - irq_set_affinity_hint(irq_num, get_cpu_mask(q_vector->v_idx)); + cpu = cpumask_local_spread(q_vector->v_idx, -1); + irq_set_affinity_hint(irq_num, get_cpu_mask(cpu)); } return 0; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ea69af267d635..667dbc7d4a4ec 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3162,6 +3162,8 @@ static int igb_sw_init(struct igb_adapter *adapter) /* Setup and initialize a copy of the hw vlan table array */ adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32), GFP_ATOMIC); + if (!adapter->shadow_vfta) + return -ENOMEM; /* This call may decrease the number of queues */ if (igb_init_interrupt_scheme(adapter, true)) { @@ -6970,7 +6972,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector, int napi_budget) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 1ed556911b147..6f5888bd91944 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -810,7 +810,7 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring) break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 6e6ab6f6875eb..64429a14c630f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3781,10 +3781,10 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, fw_cmd.ver_build = build; fw_cmd.ver_sub = sub; fw_cmd.hdr.checksum = 0; - fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, - (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); fw_cmd.pad = 0; fw_cmd.pad2 = 0; + fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, + (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { ret_val = ixgbe_host_interface_command(hw, &fw_cmd, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6d5f31e943583..879a9c4cef598 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1192,7 +1192,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 19fbb2f28ea45..8a85217845ae4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -900,6 +900,8 @@ static s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, /* convert offset from words to bytes */ buffer.address = cpu_to_be32((offset + current_word) * 2); buffer.length = cpu_to_be16(words_to_read * 2); + buffer.pad2 = 0; + buffer.pad3 = 0; status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer), IXGBE_HI_COMMAND_TIMEOUT); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 032f8ac06357a..90ecc4b064621 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -326,7 +326,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, break; /* prevent any other reads prior to eop_desc */ - read_barrier_depends(); + smp_rmb(); /* if DD is not set pending work has not been completed */ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index c9798210fa0f6..0495487f7b42e 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -344,7 +344,8 @@ static int orion_mdio_probe(struct platform_device *pdev) dev->regs + MVMDIO_ERR_INT_MASK); } else if (dev->err_interrupt == -EPROBE_DEFER) { - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto out_mdio; } if (pdev->dev.of_node) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 64a04975bcf89..a539263cd79ce 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -816,11 +816,14 @@ static void mvneta_txq_pend_desc_add(struct mvneta_port *pp, { u32 val; - /* Only 255 descriptors can be added at once ; Assume caller - * process TX desriptors in quanta less than 256 - */ - val = pend_desc + txq->pending; - mvreg_write(pp, MVNETA_TXQ_UPDATE_REG(txq->id), val); + pend_desc += txq->pending; + + /* Only 255 Tx descriptors can be added at once */ + do { + val = min(pend_desc, 255); + mvreg_write(pp, MVNETA_TXQ_UPDATE_REG(txq->id), val); + pend_desc -= val; + } while (pend_desc > 0); txq->pending = 0; } @@ -1211,6 +1214,10 @@ static void mvneta_port_disable(struct mvneta_port *pp) val &= ~MVNETA_GMAC0_PORT_ENABLE; mvreg_write(pp, MVNETA_GMAC_CTRL_0, val); + pp->link = 0; + pp->duplex = -1; + pp->speed = 0; + udelay(200); } @@ -1955,9 +1962,9 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo, if (!mvneta_rxq_desc_is_first_last(rx_status) || (rx_status & MVNETA_RXD_ERR_SUMMARY)) { + mvneta_rx_error(pp, rx_desc); err_drop_frame: dev->stats.rx_errors++; - mvneta_rx_error(pp, rx_desc); /* leave the descriptor untouched */ continue; } @@ -3008,7 +3015,7 @@ static void mvneta_cleanup_rxqs(struct mvneta_port *pp) { int queue; - for (queue = 0; queue < txq_number; queue++) + for (queue = 0; queue < rxq_number; queue++) mvneta_rxq_deinit(pp, &pp->rxqs[queue]); } diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index fcf9ba5eb8d1d..d147dc7d0f777 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4552,11 +4552,6 @@ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port) MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE; val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL; writel(val, port->base + MVPP22_GMAC_CTRL_4_REG); - - val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); - val |= MVPP2_GMAC_DISABLE_PADDING; - val &= ~MVPP2_GMAC_FLOW_CTRL_MASK; - writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); } else if (phy_interface_mode_is_rgmii(port->phy_interface)) { val = readl(port->base + MVPP22_GMAC_CTRL_4_REG); val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL | @@ -4564,10 +4559,6 @@ static void mvpp2_port_mii_gmac_configure_mode(struct mvpp2_port *port) MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE; val &= ~MVPP22_CTRL4_DP_CLK_SEL; writel(val, port->base + MVPP22_GMAC_CTRL_4_REG); - - val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); - val &= ~MVPP2_GMAC_DISABLE_PADDING; - writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); } /* The port is connected to a copper PHY */ diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 5e81a72636543..c8e5d4643351f 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2445,6 +2445,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) eth->netdev[id]->vlan_features = MTK_HW_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); eth->netdev[id]->features |= MTK_HW_FEATURES; + eth->netdev[id]->features &= ~NETIF_F_GSO; + eth->netdev[id]->hw_features = eth->netdev[id]->features; eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; eth->netdev[id]->irq = eth->irq[0]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 1fffdebbc9e89..e9a1fbcc4adfa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -362,7 +362,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_QUERY_VPORT_COUNTER: case MLX5_CMD_OP_ALLOC_Q_COUNTER: case MLX5_CMD_OP_QUERY_Q_COUNTER: - case MLX5_CMD_OP_SET_RATE_LIMIT: + case MLX5_CMD_OP_SET_PP_RATE_LIMIT: case MLX5_CMD_OP_QUERY_RATE_LIMIT: case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT: case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT: @@ -505,7 +505,7 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(ALLOC_Q_COUNTER); MLX5_COMMAND_STR_CASE(DEALLOC_Q_COUNTER); MLX5_COMMAND_STR_CASE(QUERY_Q_COUNTER); - MLX5_COMMAND_STR_CASE(SET_RATE_LIMIT); + MLX5_COMMAND_STR_CASE(SET_PP_RATE_LIMIT); MLX5_COMMAND_STR_CASE(QUERY_RATE_LIMIT); MLX5_COMMAND_STR_CASE(CREATE_SCHEDULING_ELEMENT); MLX5_COMMAND_STR_CASE(DESTROY_SCHEDULING_ELEMENT); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 13b5ef9d8703f..5fa0716201049 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -590,6 +590,7 @@ struct mlx5e_channel { struct mlx5_core_dev *mdev; struct mlx5e_tstamp *tstamp; int ix; + int cpu; }; struct mlx5e_channels { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index cc11bbbd0309d..3cdb932cae76e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -71,11 +71,6 @@ struct mlx5e_channel_param { struct mlx5e_cq_param icosq_cq; }; -static int mlx5e_get_node(struct mlx5e_priv *priv, int ix) -{ - return pci_irq_get_node(priv->mdev->pdev, MLX5_EQ_VEC_COMP_BASE + ix); -} - static bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev) { return MLX5_CAP_GEN(mdev, striding_rq) && @@ -452,17 +447,16 @@ static int mlx5e_rq_alloc_mpwqe_info(struct mlx5e_rq *rq, int wq_sz = mlx5_wq_ll_get_size(&rq->wq); int mtt_sz = mlx5e_get_wqe_mtt_sz(); int mtt_alloc = mtt_sz + MLX5_UMR_ALIGN - 1; - int node = mlx5e_get_node(c->priv, c->ix); int i; rq->mpwqe.info = kzalloc_node(wq_sz * sizeof(*rq->mpwqe.info), - GFP_KERNEL, node); + GFP_KERNEL, cpu_to_node(c->cpu)); if (!rq->mpwqe.info) goto err_out; /* We allocate more than mtt_sz as we will align the pointer */ - rq->mpwqe.mtt_no_align = kzalloc_node(mtt_alloc * wq_sz, - GFP_KERNEL, node); + rq->mpwqe.mtt_no_align = kzalloc_node(mtt_alloc * wq_sz, GFP_KERNEL, + cpu_to_node(c->cpu)); if (unlikely(!rq->mpwqe.mtt_no_align)) goto err_free_wqe_info; @@ -570,7 +564,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, int err; int i; - rqp->wq.db_numa_node = mlx5e_get_node(c->priv, c->ix); + rqp->wq.db_numa_node = cpu_to_node(c->cpu); err = mlx5_wq_ll_create(mdev, &rqp->wq, rqc_wq, &rq->wq, &rq->wq_ctrl); @@ -636,8 +630,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, default: /* MLX5_WQ_TYPE_LINKED_LIST */ rq->wqe.frag_info = kzalloc_node(wq_sz * sizeof(*rq->wqe.frag_info), - GFP_KERNEL, - mlx5e_get_node(c->priv, c->ix)); + GFP_KERNEL, cpu_to_node(c->cpu)); if (!rq->wqe.frag_info) { err = -ENOMEM; goto err_rq_wq_destroy; @@ -1007,13 +1000,13 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c, sq->uar_map = mdev->mlx5e_res.bfreg.map; sq->min_inline_mode = params->tx_min_inline_mode; - param->wq.db_numa_node = mlx5e_get_node(c->priv, c->ix); + param->wq.db_numa_node = cpu_to_node(c->cpu); err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); if (err) return err; sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; - err = mlx5e_alloc_xdpsq_db(sq, mlx5e_get_node(c->priv, c->ix)); + err = mlx5e_alloc_xdpsq_db(sq, cpu_to_node(c->cpu)); if (err) goto err_sq_wq_destroy; @@ -1060,13 +1053,13 @@ static int mlx5e_alloc_icosq(struct mlx5e_channel *c, sq->channel = c; sq->uar_map = mdev->mlx5e_res.bfreg.map; - param->wq.db_numa_node = mlx5e_get_node(c->priv, c->ix); + param->wq.db_numa_node = cpu_to_node(c->cpu); err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); if (err) return err; sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; - err = mlx5e_alloc_icosq_db(sq, mlx5e_get_node(c->priv, c->ix)); + err = mlx5e_alloc_icosq_db(sq, cpu_to_node(c->cpu)); if (err) goto err_sq_wq_destroy; @@ -1132,13 +1125,13 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c, if (MLX5_IPSEC_DEV(c->priv->mdev)) set_bit(MLX5E_SQ_STATE_IPSEC, &sq->state); - param->wq.db_numa_node = mlx5e_get_node(c->priv, c->ix); + param->wq.db_numa_node = cpu_to_node(c->cpu); err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); if (err) return err; sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; - err = mlx5e_alloc_txqsq_db(sq, mlx5e_get_node(c->priv, c->ix)); + err = mlx5e_alloc_txqsq_db(sq, cpu_to_node(c->cpu)); if (err) goto err_sq_wq_destroy; @@ -1510,8 +1503,8 @@ static int mlx5e_alloc_cq(struct mlx5e_channel *c, struct mlx5_core_dev *mdev = c->priv->mdev; int err; - param->wq.buf_numa_node = mlx5e_get_node(c->priv, c->ix); - param->wq.db_numa_node = mlx5e_get_node(c->priv, c->ix); + param->wq.buf_numa_node = cpu_to_node(c->cpu); + param->wq.db_numa_node = cpu_to_node(c->cpu); param->eq_ix = c->ix; err = mlx5e_alloc_cq_common(mdev, param, cq); @@ -1610,6 +1603,11 @@ static void mlx5e_close_cq(struct mlx5e_cq *cq) mlx5e_free_cq(cq); } +static int mlx5e_get_cpu(struct mlx5e_priv *priv, int ix) +{ + return cpumask_first(priv->mdev->priv.irq_info[ix].mask); +} + static int mlx5e_open_tx_cqs(struct mlx5e_channel *c, struct mlx5e_params *params, struct mlx5e_channel_param *cparam) @@ -1758,12 +1756,13 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, { struct mlx5e_cq_moder icocq_moder = {0, 0}; struct net_device *netdev = priv->netdev; + int cpu = mlx5e_get_cpu(priv, ix); struct mlx5e_channel *c; unsigned int irq; int err; int eqn; - c = kzalloc_node(sizeof(*c), GFP_KERNEL, mlx5e_get_node(priv, ix)); + c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu)); if (!c) return -ENOMEM; @@ -1771,6 +1770,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->mdev = priv->mdev; c->tstamp = &priv->tstamp; c->ix = ix; + c->cpu = cpu; c->pdev = &priv->mdev->pdev->dev; c->netdev = priv->netdev; c->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key); @@ -1859,8 +1859,7 @@ static void mlx5e_activate_channel(struct mlx5e_channel *c) for (tc = 0; tc < c->num_tc; tc++) mlx5e_activate_txqsq(&c->sq[tc]); mlx5e_activate_rq(&c->rq); - netif_set_xps_queue(c->netdev, - mlx5_get_vector_affinity(c->priv->mdev, c->ix), c->ix); + netif_set_xps_queue(c->netdev, get_cpu_mask(c->cpu), c->ix); } static void mlx5e_deactivate_channel(struct mlx5e_channel *c) @@ -3554,6 +3553,7 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv, struct sk_buff *skb, netdev_features_t features) { + unsigned int offset = 0; struct udphdr *udph; u8 proto; u16 port; @@ -3563,7 +3563,7 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv, proto = ip_hdr(skb)->protocol; break; case htons(ETH_P_IPV6): - proto = ipv6_hdr(skb)->nexthdr; + proto = ipv6_find_hdr(skb, &offset, -1, NULL, NULL); break; default: goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c index acf32fe952cde..3d3b1f97dc273 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c @@ -197,9 +197,15 @@ static int mlx5e_am_stats_compare(struct mlx5e_rx_am_stats *curr, return (curr->bpms > prev->bpms) ? MLX5E_AM_STATS_BETTER : MLX5E_AM_STATS_WORSE; + if (!prev->ppms) + return curr->ppms ? MLX5E_AM_STATS_BETTER : + MLX5E_AM_STATS_SAME; + if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms)) return (curr->ppms > prev->ppms) ? MLX5E_AM_STATS_BETTER : MLX5E_AM_STATS_WORSE; + if (!prev->epms) + return MLX5E_AM_STATS_SAME; if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms)) return (curr->epms < prev->epms) ? MLX5E_AM_STATS_BETTER : diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index 1f1f8af87d4df..5a4608281f38d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -238,15 +238,19 @@ static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv, int err = 0; /* Temporarily enable local_lb */ - if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { - mlx5_nic_vport_query_local_lb(priv->mdev, &lbtp->local_lb); - if (!lbtp->local_lb) - mlx5_nic_vport_update_local_lb(priv->mdev, true); + err = mlx5_nic_vport_query_local_lb(priv->mdev, &lbtp->local_lb); + if (err) + return err; + + if (!lbtp->local_lb) { + err = mlx5_nic_vport_update_local_lb(priv->mdev, true); + if (err) + return err; } err = mlx5e_refresh_tirs(priv, true); if (err) - return err; + goto out; lbtp->loopback_ok = false; init_completion(&lbtp->comp); @@ -256,16 +260,21 @@ static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv, lbtp->pt.dev = priv->netdev; lbtp->pt.af_packet_priv = lbtp; dev_add_pack(&lbtp->pt); + + return 0; + +out: + if (!lbtp->local_lb) + mlx5_nic_vport_update_local_lb(priv->mdev, false); + return err; } static void mlx5e_test_loopback_cleanup(struct mlx5e_priv *priv, struct mlx5e_lbt_priv *lbtp) { - if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { - if (!lbtp->local_lb) - mlx5_nic_vport_update_local_lb(priv->mdev, false); - } + if (!lbtp->local_lb) + mlx5_nic_vport_update_local_lb(priv->mdev, false); dev_remove_pack(&lbtp->pt); mlx5e_refresh_tirs(priv, false); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c index 3c11d6e2160ab..14962969c5ba8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c @@ -66,6 +66,9 @@ static int mlx5_fpga_mem_read_i2c(struct mlx5_fpga_device *fdev, size_t size, u8 actual_size; int err; + if (!size) + return -EINVAL; + if (!fdev->mdev) return -ENOTCONN; @@ -95,6 +98,9 @@ static int mlx5_fpga_mem_write_i2c(struct mlx5_fpga_device *fdev, size_t size, u8 actual_size; int err; + if (!size) + return -EINVAL; + if (!fdev->mdev) return -ENOTCONN; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 06562c9a6b9cb..4ddd632d10f99 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -316,9 +316,6 @@ static int mlx5_alloc_irq_vectors(struct mlx5_core_dev *dev) { struct mlx5_priv *priv = &dev->priv; struct mlx5_eq_table *table = &priv->eq_table; - struct irq_affinity irqdesc = { - .pre_vectors = MLX5_EQ_VEC_COMP_BASE, - }; int num_eqs = 1 << MLX5_CAP_GEN(dev, log_max_eq); int nvec; @@ -332,10 +329,9 @@ static int mlx5_alloc_irq_vectors(struct mlx5_core_dev *dev) if (!priv->irq_info) goto err_free_msix; - nvec = pci_alloc_irq_vectors_affinity(dev->pdev, + nvec = pci_alloc_irq_vectors(dev->pdev, MLX5_EQ_VEC_COMP_BASE + 1, nvec, - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, - &irqdesc); + PCI_IRQ_MSIX); if (nvec < 0) return nvec; @@ -581,8 +577,7 @@ static int mlx5_core_set_hca_defaults(struct mlx5_core_dev *dev) int ret = 0; /* Disable local_lb by default */ - if ((MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH) && - MLX5_CAP_GEN(dev, disable_local_lb)) + if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH) ret = mlx5_nic_vport_update_local_lb(dev, false); return ret; @@ -621,6 +616,63 @@ u64 mlx5_read_internal_timer(struct mlx5_core_dev *dev) return (u64)timer_l | (u64)timer_h1 << 32; } +static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) +{ + struct mlx5_priv *priv = &mdev->priv; + int irq = pci_irq_vector(mdev->pdev, MLX5_EQ_VEC_COMP_BASE + i); + + if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { + mlx5_core_warn(mdev, "zalloc_cpumask_var failed"); + return -ENOMEM; + } + + cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node), + priv->irq_info[i].mask); + + if (IS_ENABLED(CONFIG_SMP) && + irq_set_affinity_hint(irq, priv->irq_info[i].mask)) + mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq); + + return 0; +} + +static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i) +{ + struct mlx5_priv *priv = &mdev->priv; + int irq = pci_irq_vector(mdev->pdev, MLX5_EQ_VEC_COMP_BASE + i); + + irq_set_affinity_hint(irq, NULL); + free_cpumask_var(priv->irq_info[i].mask); +} + +static int mlx5_irq_set_affinity_hints(struct mlx5_core_dev *mdev) +{ + int err; + int i; + + for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++) { + err = mlx5_irq_set_affinity_hint(mdev, i); + if (err) + goto err_out; + } + + return 0; + +err_out: + for (i--; i >= 0; i--) + mlx5_irq_clear_affinity_hint(mdev, i); + + return err; +} + +static void mlx5_irq_clear_affinity_hints(struct mlx5_core_dev *mdev) +{ + int i; + + for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++) + mlx5_irq_clear_affinity_hint(mdev, i); +} + int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, unsigned int *irqn) { @@ -1093,6 +1145,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_stop_eqs; } + err = mlx5_irq_set_affinity_hints(dev); + if (err) { + dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n"); + goto err_affinity_hints; + } + err = mlx5_init_fs(dev); if (err) { dev_err(&pdev->dev, "Failed to init flow steering\n"); @@ -1150,6 +1208,9 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_cleanup_fs(dev); err_fs: + mlx5_irq_clear_affinity_hints(dev); + +err_affinity_hints: free_comp_eqs(dev); err_stop_eqs: @@ -1218,6 +1279,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_sriov_detach(dev); mlx5_cleanup_fs(dev); + mlx5_irq_clear_affinity_hints(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); mlx5_put_uars_page(dev, priv->uar); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index db9e665ab1047..889130edb7152 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -213,8 +213,8 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev, err_cmd: memset(din, 0, sizeof(din)); memset(dout, 0, sizeof(dout)); - MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); - MLX5_SET(destroy_qp_in, in, qpn, qp->qpn); + MLX5_SET(destroy_qp_in, din, opcode, MLX5_CMD_OP_DESTROY_QP); + MLX5_SET(destroy_qp_in, din, qpn, qp->qpn); mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout)); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rl.c b/drivers/net/ethernet/mellanox/mlx5/core/rl.c index e651e4c028677..d3c33e9eea729 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/rl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/rl.c @@ -125,16 +125,16 @@ static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table, return ret_entry; } -static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev, +static int mlx5_set_pp_rate_limit_cmd(struct mlx5_core_dev *dev, u32 rate, u16 index) { - u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)] = {0}; - u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(set_pp_rate_limit_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(set_pp_rate_limit_out)] = {0}; - MLX5_SET(set_rate_limit_in, in, opcode, - MLX5_CMD_OP_SET_RATE_LIMIT); - MLX5_SET(set_rate_limit_in, in, rate_limit_index, index); - MLX5_SET(set_rate_limit_in, in, rate_limit, rate); + MLX5_SET(set_pp_rate_limit_in, in, opcode, + MLX5_CMD_OP_SET_PP_RATE_LIMIT); + MLX5_SET(set_pp_rate_limit_in, in, rate_limit_index, index); + MLX5_SET(set_pp_rate_limit_in, in, rate_limit, rate); return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } @@ -173,7 +173,7 @@ int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u16 *index) entry->refcount++; } else { /* new rate limit */ - err = mlx5_set_rate_limit_cmd(dev, rate, entry->index); + err = mlx5_set_pp_rate_limit_cmd(dev, rate, entry->index); if (err) { mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n", rate, err); @@ -209,7 +209,7 @@ void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate) entry->refcount--; if (!entry->refcount) { /* need to remove rate */ - mlx5_set_rate_limit_cmd(dev, 0, entry->index); + mlx5_set_pp_rate_limit_cmd(dev, 0, entry->index); entry->rate = 0; } @@ -262,8 +262,8 @@ void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev) /* Clear all configured rates */ for (i = 0; i < table->max_size; i++) if (table->rl_entry[i].rate) - mlx5_set_rate_limit_cmd(dev, 0, - table->rl_entry[i].index); + mlx5_set_pp_rate_limit_cmd(dev, 0, + table->rl_entry[i].index); kfree(dev->priv.rl_table.rl_entry); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index d653b0025b13e..a1296a62497da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -908,23 +908,33 @@ int mlx5_nic_vport_update_local_lb(struct mlx5_core_dev *mdev, bool enable) void *in; int err; - mlx5_core_dbg(mdev, "%s local_lb\n", enable ? "enable" : "disable"); + if (!MLX5_CAP_GEN(mdev, disable_local_lb_mc) && + !MLX5_CAP_GEN(mdev, disable_local_lb_uc)) + return 0; + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; - MLX5_SET(modify_nic_vport_context_in, in, - field_select.disable_mc_local_lb, 1); MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.disable_mc_local_lb, !enable); - - MLX5_SET(modify_nic_vport_context_in, in, - field_select.disable_uc_local_lb, 1); MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.disable_uc_local_lb, !enable); + if (MLX5_CAP_GEN(mdev, disable_local_lb_mc)) + MLX5_SET(modify_nic_vport_context_in, in, + field_select.disable_mc_local_lb, 1); + + if (MLX5_CAP_GEN(mdev, disable_local_lb_uc)) + MLX5_SET(modify_nic_vport_context_in, in, + field_select.disable_uc_local_lb, 1); + err = mlx5_modify_nic_vport_context(mdev, in, inlen); + if (!err) + mlx5_core_dbg(mdev, "%s local_lb\n", + enable ? "enable" : "disable"); + kvfree(in); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c index 07a9ba6cfc70a..2f74953e45615 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c @@ -71,9 +71,9 @@ struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port) struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; struct mlx5e_vxlan *vxlan; - spin_lock(&vxlan_db->lock); + spin_lock_bh(&vxlan_db->lock); vxlan = radix_tree_lookup(&vxlan_db->tree, port); - spin_unlock(&vxlan_db->lock); + spin_unlock_bh(&vxlan_db->lock); return vxlan; } @@ -88,8 +88,12 @@ static void mlx5e_vxlan_add_port(struct work_struct *work) struct mlx5e_vxlan *vxlan; int err; - if (mlx5e_vxlan_lookup_port(priv, port)) + mutex_lock(&priv->state_lock); + vxlan = mlx5e_vxlan_lookup_port(priv, port); + if (vxlan) { + atomic_inc(&vxlan->refcount); goto free_work; + } if (mlx5e_vxlan_core_add_port_cmd(priv->mdev, port)) goto free_work; @@ -99,10 +103,11 @@ static void mlx5e_vxlan_add_port(struct work_struct *work) goto err_delete_port; vxlan->udp_port = port; + atomic_set(&vxlan->refcount, 1); - spin_lock_irq(&vxlan_db->lock); + spin_lock_bh(&vxlan_db->lock); err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan); - spin_unlock_irq(&vxlan_db->lock); + spin_unlock_bh(&vxlan_db->lock); if (err) goto err_free; @@ -113,35 +118,39 @@ static void mlx5e_vxlan_add_port(struct work_struct *work) err_delete_port: mlx5e_vxlan_core_del_port_cmd(priv->mdev, port); free_work: + mutex_unlock(&priv->state_lock); kfree(vxlan_work); } -static void __mlx5e_vxlan_core_del_port(struct mlx5e_priv *priv, u16 port) +static void mlx5e_vxlan_del_port(struct work_struct *work) { + struct mlx5e_vxlan_work *vxlan_work = + container_of(work, struct mlx5e_vxlan_work, work); + struct mlx5e_priv *priv = vxlan_work->priv; struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; + u16 port = vxlan_work->port; struct mlx5e_vxlan *vxlan; + bool remove = false; - spin_lock_irq(&vxlan_db->lock); - vxlan = radix_tree_delete(&vxlan_db->tree, port); - spin_unlock_irq(&vxlan_db->lock); - + mutex_lock(&priv->state_lock); + spin_lock_bh(&vxlan_db->lock); + vxlan = radix_tree_lookup(&vxlan_db->tree, port); if (!vxlan) - return; - - mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port); - - kfree(vxlan); -} + goto out_unlock; -static void mlx5e_vxlan_del_port(struct work_struct *work) -{ - struct mlx5e_vxlan_work *vxlan_work = - container_of(work, struct mlx5e_vxlan_work, work); - struct mlx5e_priv *priv = vxlan_work->priv; - u16 port = vxlan_work->port; + if (atomic_dec_and_test(&vxlan->refcount)) { + radix_tree_delete(&vxlan_db->tree, port); + remove = true; + } - __mlx5e_vxlan_core_del_port(priv, port); +out_unlock: + spin_unlock_bh(&vxlan_db->lock); + if (remove) { + mlx5e_vxlan_core_del_port_cmd(priv->mdev, port); + kfree(vxlan); + } + mutex_unlock(&priv->state_lock); kfree(vxlan_work); } @@ -171,12 +180,11 @@ void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv) struct mlx5e_vxlan *vxlan; unsigned int port = 0; - spin_lock_irq(&vxlan_db->lock); + /* Lockless since we are the only radix-tree consumers, wq is disabled */ while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) { port = vxlan->udp_port; - spin_unlock_irq(&vxlan_db->lock); - __mlx5e_vxlan_core_del_port(priv, (u16)port); - spin_lock_irq(&vxlan_db->lock); + radix_tree_delete(&vxlan_db->tree, port); + mlx5e_vxlan_core_del_port_cmd(priv->mdev, port); + kfree(vxlan); } - spin_unlock_irq(&vxlan_db->lock); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h index 5def12c048e38..5ef6ae7d568ab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h @@ -36,6 +36,7 @@ #include "en.h" struct mlx5e_vxlan { + atomic_t refcount; u16 udp_port; }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 696b99e65a5a6..99bd6e88ebc7e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2974,6 +2974,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, if (IS_ERR(mlxsw_sp_port_vlan)) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", mlxsw_sp_port->local_port); + err = PTR_ERR(mlxsw_sp_port_vlan); goto err_port_vlan_get; } @@ -4163,6 +4164,7 @@ static int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) { + u16 vid = 1; int err; err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); @@ -4175,8 +4177,19 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) true, false); if (err) goto err_port_vlan_set; + + for (; vid <= VLAN_N_VID - 1; vid++) { + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, + vid, false); + if (err) + goto err_vid_learning_set; + } + return 0; +err_vid_learning_set: + for (vid--; vid >= 1; vid--) + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); err_port_vlan_set: mlxsw_sp_port_stp_set(mlxsw_sp_port, false); err_port_stp_set: @@ -4186,6 +4199,12 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) { + u16 vid; + + for (vid = VLAN_N_VID - 1; vid >= 1; vid--) + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, + vid, true); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, false, false); mlxsw_sp_port_stp_set(mlxsw_sp_port, false); @@ -4216,7 +4235,10 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, return -EINVAL; if (!info->linking) break; - if (netdev_has_any_upper_dev(upper_dev)) + if (netdev_has_any_upper_dev(upper_dev) && + (!netif_is_bridge_master(upper_dev) || + !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, + upper_dev))) return -EINVAL; if (netif_is_lag_master(upper_dev) && !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev, @@ -4328,6 +4350,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct netdev_notifier_changeupper_info *info = ptr; struct net_device *upper_dev; int err = 0; @@ -4339,7 +4362,10 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, return -EINVAL; if (!info->linking) break; - if (netdev_has_any_upper_dev(upper_dev)) + if (netdev_has_any_upper_dev(upper_dev) && + (!netif_is_bridge_master(upper_dev) || + !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, + upper_dev))) return -EINVAL; break; case NETDEV_CHANGEUPPER: diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 84ce83acdc199..88892d47acaeb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -326,6 +326,8 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *brport_dev, struct net_device *br_dev); +bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev); /* spectrum.c */ int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 5189022a1c8c3..7bef806764643 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1531,11 +1531,8 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, dipn = htonl(dip); dev = mlxsw_sp->router->rifs[rif]->dev; n = neigh_lookup(&arp_tbl, &dipn, dev); - if (!n) { - netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n", - &dip); + if (!n) return; - } netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip); neigh_event_send(n, NULL); @@ -1562,11 +1559,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp, dev = mlxsw_sp->router->rifs[rif]->dev; n = neigh_lookup(&nd_tbl, &dip, dev); - if (!n) { - netdev_err(dev, "Failed to find matching neighbour for IP=%pI6c\n", - &dip); + if (!n) return; - } netdev_dbg(dev, "Updating neighbour with IP=%pI6c\n", &dip); neigh_event_send(n, NULL); @@ -2536,7 +2530,7 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh, { if (!removing) nh->should_offload = 1; - else if (nh->offloaded) + else nh->should_offload = 0; nh->update = 1; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index d39ffbfcc436f..f5863e5bec813 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -134,6 +134,12 @@ mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge, return NULL; } +bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev) +{ + return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); +} + static struct mlxsw_sp_bridge_device * mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, struct net_device *br_dev) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index c20dd00a1caec..899e7d53e6697 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -52,8 +52,7 @@ struct nfp_app; #define NFP_FLOWER_MASK_ELEMENT_RS 1 #define NFP_FLOWER_MASK_HASH_BITS 10 -#define NFP_FL_META_FLAG_NEW_MASK 128 -#define NFP_FL_META_FLAG_LAST_MASK 1 +#define NFP_FL_META_FLAG_MANAGE_MASK BIT(7) #define NFP_FL_MASK_REUSE_TIME_NS 40000 #define NFP_FL_MASK_ID_LOCATION 1 diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 3226ddc55f99b..d9582ccc00254 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -282,7 +282,7 @@ nfp_check_mask_add(struct nfp_app *app, char *mask_data, u32 mask_len, id = nfp_add_mask_table(app, mask_data, mask_len); if (id < 0) return false; - *meta_flags |= NFP_FL_META_FLAG_NEW_MASK; + *meta_flags |= NFP_FL_META_FLAG_MANAGE_MASK; } *mask_id = id; @@ -299,6 +299,9 @@ nfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len, if (!mask_entry) return false; + if (meta_flags) + *meta_flags &= ~NFP_FL_META_FLAG_MANAGE_MASK; + *mask_id = mask_entry->mask_id; mask_entry->ref_cnt--; if (!mask_entry->ref_cnt) { @@ -306,7 +309,7 @@ nfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len, nfp_release_mask_id(app, *mask_id); kfree(mask_entry); if (meta_flags) - *meta_flags |= NFP_FL_META_FLAG_LAST_MASK; + *meta_flags |= NFP_FL_META_FLAG_MANAGE_MASK; } return true; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index dc016dfec64d6..8e623d8fa78ee 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -306,7 +306,7 @@ nfp_net_get_link_ksettings(struct net_device *netdev, ls >= ARRAY_SIZE(ls_to_ethtool)) return 0; - cmd->base.speed = ls_to_ethtool[sts]; + cmd->base.speed = ls_to_ethtool[ls]; cmd->base.duplex = DUPLEX_FULL; return 0; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index d540a9dc77b3c..1c43aca8162db 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -297,6 +297,8 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, netdev->netdev_ops = &nfp_repr_netdev_ops; netdev->ethtool_ops = &nfp_port_ethtool_ops; + netdev->max_mtu = pf_netdev->max_mtu; + SWITCHDEV_SET_OPS(netdev, &nfp_port_switchdev_ops); if (nfp_app_has_tc(app)) { diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index a3c949ea7d1a2..958ff931e790a 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2025,21 +2025,6 @@ static int rtl8169_set_speed(struct net_device *dev, return ret; } -static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct rtl8169_private *tp = netdev_priv(dev); - int ret; - - del_timer_sync(&tp->timer); - - rtl_lock_work(tp); - ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd), - cmd->duplex, cmd->advertising); - rtl_unlock_work(tp); - - return ret; -} - static netdev_features_t rtl8169_fix_features(struct net_device *dev, netdev_features_t features) { @@ -2166,6 +2151,27 @@ static int rtl8169_get_link_ksettings(struct net_device *dev, return rc; } +static int rtl8169_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int rc; + u32 advertising; + + if (!ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising)) + return -EINVAL; + + del_timer_sync(&tp->timer); + + rtl_lock_work(tp); + rc = rtl8169_set_speed(dev, cmd->base.autoneg, cmd->base.speed, + cmd->base.duplex, advertising); + rtl_unlock_work(tp); + + return rc; +} + static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { @@ -2233,19 +2239,14 @@ static bool rtl8169_do_counters(struct net_device *dev, u32 counter_cmd) void __iomem *ioaddr = tp->mmio_addr; dma_addr_t paddr = tp->counters_phys_addr; u32 cmd; - bool ret; RTL_W32(CounterAddrHigh, (u64)paddr >> 32); + RTL_R32(CounterAddrHigh); cmd = (u64)paddr & DMA_BIT_MASK(32); RTL_W32(CounterAddrLow, cmd); RTL_W32(CounterAddrLow, cmd | counter_cmd); - ret = rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000); - - RTL_W32(CounterAddrLow, 0); - RTL_W32(CounterAddrHigh, 0); - - return ret; + return rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000); } static bool rtl8169_reset_counters(struct net_device *dev) @@ -2367,7 +2368,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, .get_link = ethtool_op_get_link, - .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, .set_msglevel = rtl8169_set_msglevel, .get_regs = rtl8169_get_regs, @@ -2379,6 +2379,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, .nway_reset = rtl8169_nway_reset, .get_link_ksettings = rtl8169_get_link_ksettings, + .set_link_ksettings = rtl8169_set_link_ksettings, }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index d2e88a30f57bb..db31963c5d9dd 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3212,18 +3212,37 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* ioremap the TSU registers */ if (mdp->cd->tsu) { struct resource *rtsu; + rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu); - if (IS_ERR(mdp->tsu_addr)) { - ret = PTR_ERR(mdp->tsu_addr); + if (!rtsu) { + dev_err(&pdev->dev, "no TSU resource\n"); + ret = -ENODEV; + goto out_release; + } + /* We can only request the TSU region for the first port + * of the two sharing this TSU for the probe to succeed... + */ + if (devno % 2 == 0 && + !devm_request_mem_region(&pdev->dev, rtsu->start, + resource_size(rtsu), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "can't request TSU resource.\n"); + ret = -EBUSY; + goto out_release; + } + mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start, + resource_size(rtsu)); + if (!mdp->tsu_addr) { + dev_err(&pdev->dev, "TSU region ioremap() failed.\n"); + ret = -ENOMEM; goto out_release; } mdp->port = devno % 2; ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER; } - /* initialize first or needed device */ - if (!devno || pd->needs_init) { + /* Need to init only the first port of the two sharing a TSU */ + if (devno % 2 == 0) { if (mdp->cd->chip_reset) mdp->cd->chip_reset(ndev); diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 13f72f5b18d20..09352ee43b55c 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -5726,7 +5726,7 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) * MCFW do not support VFs. */ rc = efx_ef10_vport_set_mac_address(efx); - } else { + } else if (rc) { efx_mcdi_display_error(efx, MC_CMD_VADAPTOR_SET_MAC, sizeof(inbuf), NULL, 0, rc); } diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 32bf1fecf8640..9b85cbd5a231b 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -77,6 +77,7 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, } if (buffer->flags & EFX_TX_BUF_SKB) { + EFX_WARN_ON_PARANOID(!pkts_compl || !bytes_compl); (*pkts_compl)++; (*bytes_compl) += buffer->skb->len; dev_consume_skb_any((struct sk_buff *)buffer->skb); @@ -426,12 +427,14 @@ static int efx_tx_map_data(struct efx_tx_queue *tx_queue, struct sk_buff *skb, static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) { struct efx_tx_buffer *buffer; + unsigned int bytes_compl = 0; + unsigned int pkts_compl = 0; /* Work backwards until we hit the original insert pointer value */ while (tx_queue->insert_count != tx_queue->write_count) { --tx_queue->insert_count; buffer = __efx_tx_queue_get_insert_buffer(tx_queue); - efx_dequeue_buffer(tx_queue, buffer, NULL, NULL); + efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl); } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 16bd509290844..0ad12c81a9e45 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -364,9 +364,15 @@ static void stmmac_eee_ctrl_timer(unsigned long arg) bool stmmac_eee_init(struct stmmac_priv *priv) { struct net_device *ndev = priv->dev; + int interface = priv->plat->interface; unsigned long flags; bool ret = false; + if ((interface != PHY_INTERFACE_MODE_MII) && + (interface != PHY_INTERFACE_MODE_GMII) && + !phy_interface_mode_is_rgmii(interface)) + goto out; + /* Using PCS we cannot dial with the phy registers at this stage * so we do not support extra feature like EEE. */ @@ -2564,6 +2570,7 @@ static int stmmac_open(struct net_device *dev) priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); priv->rx_copybreak = STMMAC_RX_COPYBREAK; + priv->mss = 0; ret = alloc_dma_desc_resources(priv); if (ret < 0) { diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index ed51018a813e7..b9d8d71a6ecc4 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1503,6 +1503,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); struct ip_tunnel_info *info = &geneve->info; + bool metadata = geneve->collect_md; __u8 tmp_vni[3]; __u32 vni; @@ -1511,32 +1512,24 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put_u32(skb, IFLA_GENEVE_ID, vni)) goto nla_put_failure; - if (rtnl_dereference(geneve->sock4)) { + if (!metadata && ip_tunnel_info_af(info) == AF_INET) { if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE, info->key.u.ipv4.dst)) goto nla_put_failure; - if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM, !!(info->key.tun_flags & TUNNEL_CSUM))) goto nla_put_failure; - } - #if IS_ENABLED(CONFIG_IPV6) - if (rtnl_dereference(geneve->sock6)) { + } else if (!metadata) { if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6, &info->key.u.ipv6.dst)) goto nla_put_failure; - if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, !(info->key.tun_flags & TUNNEL_CSUM))) goto nla_put_failure; - - if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, - !geneve->use_udp6_rx_checksums)) - goto nla_put_failure; - } #endif + } if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) || nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) || @@ -1546,10 +1539,13 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst)) goto nla_put_failure; - if (geneve->collect_md) { - if (nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA)) + if (metadata && nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA)) goto nla_put_failure; - } + + if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, + !geneve->use_udp6_rx_checksums)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 1f3295e274d0f..8feb84fd4ca71 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -409,7 +409,7 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) struct dst_entry *dst; int err, ret = NET_XMIT_DROP; struct flowi6 fl6 = { - .flowi6_iif = dev->ifindex, + .flowi6_oif = dev->ifindex, .daddr = ip6h->daddr, .saddr = ip6h->saddr, .flowi6_flags = FLOWI_FLAG_ANYSRC, diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d2aea961e0f41..fb1c9e095d0ca 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -480,7 +480,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) struct macvlan_dev, list); else vlan = macvlan_hash_lookup(port, eth->h_dest); - if (vlan == NULL) + if (!vlan || vlan->mode == MACVLAN_MODE_SOURCE) return RX_HANDLER_PASS; dev = vlan->dev; diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index c1e52b9dc58d3..5f93e6add5639 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -167,7 +167,7 @@ static int at803x_set_wol(struct phy_device *phydev, mac = (const u8 *) ndev->dev_addr; if (!is_valid_ether_addr(mac)) - return -EFAULT; + return -EINVAL; for (i = 0; i < 3; i++) { phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4d02b27df0445..a3f456b91c99d 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -2069,7 +2069,7 @@ static struct phy_driver marvell_drivers[] = { .flags = PHY_HAS_INTERRUPT, .probe = marvell_probe, .config_init = &m88e1145_config_init, - .config_aneg = &marvell_config_aneg, + .config_aneg = &m88e1101_config_aneg, .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index fdb43dd9b5cd4..6c45ff650ec78 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -622,6 +622,7 @@ static int ksz9031_read_status(struct phy_device *phydev) phydev->link = 0; if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev)) phydev->drv->config_intr(phydev); + return genphy_config_aneg(phydev); } return 0; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index bcb4755bcd957..cb85307f125b3 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -525,6 +525,7 @@ struct phylink *phylink_create(struct net_device *ndev, struct device_node *np, pl->link_config.pause = MLO_PAUSE_AN; pl->link_config.speed = SPEED_UNKNOWN; pl->link_config.duplex = DUPLEX_UNKNOWN; + pl->link_config.an_enabled = true; pl->ops = ops; __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); @@ -948,6 +949,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, mutex_lock(&pl->state_mutex); /* Configure the MAC to match the new settings */ linkmode_copy(pl->link_config.advertising, our_kset.link_modes.advertising); + pl->link_config.interface = config.interface; pl->link_config.speed = our_kset.base.speed; pl->link_config.duplex = our_kset.base.duplex; pl->link_config.an_enabled = our_kset.base.autoneg != AUTONEG_DISABLE; @@ -1426,9 +1428,8 @@ static void phylink_sfp_link_down(void *upstream) WARN_ON(!lockdep_rtnl_is_held()); set_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state); + queue_work(system_power_efficient_wq, &pl->resolve); flush_work(&pl->resolve); - - netif_carrier_off(pl->netdev); } static void phylink_sfp_link_up(void *upstream) diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 5cb5384697ea7..7ae815bee52d5 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -359,7 +359,8 @@ EXPORT_SYMBOL_GPL(sfp_register_upstream); void sfp_unregister_upstream(struct sfp_bus *bus) { rtnl_lock(); - sfp_unregister_bus(bus); + if (bus->sfp) + sfp_unregister_bus(bus); bus->upstream = NULL; bus->netdev = NULL; rtnl_unlock(); @@ -464,7 +465,8 @@ EXPORT_SYMBOL_GPL(sfp_register_socket); void sfp_unregister_socket(struct sfp_bus *bus) { rtnl_lock(); - sfp_unregister_bus(bus); + if (bus->netdev) + sfp_unregister_bus(bus); bus->sfp_dev = NULL; bus->sfp = NULL; bus->socket_ops = NULL; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index e365866600ba0..8c6b8918ec318 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -959,6 +959,7 @@ static __net_exit void ppp_exit_net(struct net *net) unregister_netdevice_many(&list); rtnl_unlock(); + mutex_destroy(&pn->all_ppp_mutex); idr_destroy(&pn->units_idr); } @@ -1002,17 +1003,18 @@ static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set) if (!ifname_is_set) snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index); + mutex_unlock(&pn->all_ppp_mutex); + ret = register_netdevice(ppp->dev); if (ret < 0) goto err_unit; atomic_inc(&ppp_unit_count); - mutex_unlock(&pn->all_ppp_mutex); - return 0; err_unit: + mutex_lock(&pn->all_ppp_mutex); unit_put(&pn->units_idr, ppp->file.index); err: mutex_unlock(&pn->all_ppp_mutex); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 4e1da1645b154..5aa59f41bf8c3 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -842,6 +842,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, struct pppoe_hdr *ph; struct net_device *dev; char *start; + int hlen; lock_sock(sk); if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { @@ -860,16 +861,16 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, if (total_len > (dev->mtu + dev->hard_header_len)) goto end; - - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, - 0, GFP_KERNEL); + hlen = LL_RESERVED_SPACE(dev); + skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len + + dev->needed_tailroom, 0, GFP_KERNEL); if (!skb) { error = -ENOMEM; goto end; } /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); + skb_reserve(skb, hlen); skb_reset_network_header(skb); skb->dev = dev; @@ -930,7 +931,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) /* Copy the data if there is no space for the header or if it's * read-only. */ - if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph))) goto abort; __skb_push(skb, sizeof(*ph)); diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 6c0c84c33e1fb..bfd4ded0a53fb 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -829,8 +829,11 @@ static ssize_t tap_do_read(struct tap_queue *q, DEFINE_WAIT(wait); ssize_t ret = 0; - if (!iov_iter_count(to)) + if (!iov_iter_count(to)) { + if (skb) + kfree_skb(skb); return 0; + } if (skb) goto put; @@ -1077,7 +1080,7 @@ static long tap_ioctl(struct file *file, unsigned int cmd, case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | - TUN_F_TSO_ECN)) + TUN_F_TSO_ECN | TUN_F_UFO)) return -EINVAL; rtnl_lock(); @@ -1154,11 +1157,14 @@ static int tap_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, int flags) { struct tap_queue *q = container_of(sock, struct tap_queue, sock); + struct sk_buff *skb = m->msg_control; int ret; - if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { + if (skb) + kfree_skb(skb); return -EINVAL; - ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, - m->msg_control); + } + ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, skb); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 42bb820a56c92..fa51b7b0e9eab 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -534,6 +534,14 @@ static void tun_queue_purge(struct tun_file *tfile) skb_queue_purge(&tfile->sk.sk_error_queue); } +static void tun_cleanup_tx_array(struct tun_file *tfile) +{ + if (tfile->tx_array.ring.queue) { + skb_array_cleanup(&tfile->tx_array); + memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); + } +} + static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -575,8 +583,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); } - if (tun) - skb_array_cleanup(&tfile->tx_array); + tun_cleanup_tx_array(tfile); sock_put(&tfile->sk); } } @@ -616,11 +623,13 @@ static void tun_detach_all(struct net_device *dev) /* Drop read queue */ tun_queue_purge(tfile); sock_put(&tfile->sk); + tun_cleanup_tx_array(tfile); } list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { tun_enable_queue(tfile); tun_queue_purge(tfile); sock_put(&tfile->sk); + tun_cleanup_tx_array(tfile); } BUG_ON(tun->numdisabled != 0); @@ -1326,6 +1335,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); if (err) goto err_redirect; + rcu_read_unlock(); return NULL; case XDP_TX: xdp_xmit = true; @@ -1358,7 +1368,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (xdp_xmit) { skb->dev = tun->dev; generic_xdp_tx(skb, xdp_prog); - rcu_read_lock(); + rcu_read_unlock(); return NULL; } @@ -1734,8 +1744,11 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, tun_debug(KERN_INFO, tun, "tun_do_read\n"); - if (!iov_iter_count(to)) + if (!iov_iter_count(to)) { + if (skb) + kfree_skb(skb); return 0; + } if (!skb) { /* Read frames from ring */ @@ -1851,22 +1864,24 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, { struct tun_file *tfile = container_of(sock, struct tun_file, socket); struct tun_struct *tun = __tun_get(tfile); + struct sk_buff *skb = m->msg_control; int ret; - if (!tun) - return -EBADFD; + if (!tun) { + ret = -EBADFD; + goto out_free_skb; + } if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { ret = -EINVAL; - goto out; + goto out_put_tun; } if (flags & MSG_ERRQUEUE) { ret = sock_recv_errqueue(sock->sk, m, total_len, SOL_PACKET, TUN_TX_TIMESTAMP); goto out; } - ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, - m->msg_control); + ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, skb); if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; @@ -1874,6 +1889,13 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, out: tun_put(tun); return ret; + +out_put_tun: + tun_put(tun); +out_free_skb: + if (skb) + kfree_skb(skb); + return ret; } static int tun_peek_len(struct socket *sock) @@ -2144,6 +2166,8 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } + + arg &= ~TUN_F_UFO; } /* This gives the user a way to test for new features in future by @@ -2609,6 +2633,8 @@ static int tun_chr_open(struct inode *inode, struct file * file) sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); + memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); + return 0; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 47cab1bde0659..9e1b74590682e 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -771,7 +771,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ int err; u8 iface_no; struct usb_cdc_parsed_header hdr; - u16 curr_ntb_format; + __le16 curr_ntb_format; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -889,7 +889,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ goto error2; } - if (curr_ntb_format == USB_CDC_NCM_NTB32_FORMAT) { + if (curr_ntb_format == cpu_to_le16(USB_CDC_NCM_NTB32_FORMAT)) { dev_info(&intf->dev, "resetting NTB format to 16-bit"); err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS | USB_DIR_OUT diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 0161f77641fac..a8dd1c7a08cbe 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2396,6 +2396,7 @@ static int lan78xx_reset(struct lan78xx_net *dev) buf = DEFAULT_BURST_CAP_SIZE / FS_USB_PKT_SIZE; dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE; dev->rx_qlen = 4; + dev->tx_qlen = 4; } ret = lan78xx_write_reg(dev, BURST_CAP, buf); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 8d4a6f7cba610..2092febfcb425 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -261,9 +261,11 @@ static void qmi_wwan_netdev_setup(struct net_device *net) net->hard_header_len = 0; net->addr_len = 0; net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + set_bit(EVENT_NO_IP_ALIGN, &dev->flags); netdev_dbg(net, "mode: raw IP\n"); } else if (!net->header_ops) { /* don't bother if already set */ ether_setup(net); + clear_bit(EVENT_NO_IP_ALIGN, &dev->flags); netdev_dbg(net, "mode: Ethernet\n"); } @@ -1202,6 +1204,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */ {QMI_FIXED_INTF(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */ {QMI_FIXED_INTF(0x1199, 0x907b, 10)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x9091, 8)}, /* Sierra Wireless EM7565 */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ @@ -1239,6 +1242,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 6510e5cc1817c..42baad125a7d0 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -484,7 +484,10 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) return -ENOLINK; } - skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); + if (test_bit(EVENT_NO_IP_ALIGN, &dev->flags)) + skb = __netdev_alloc_skb(dev->net, size, flags); + else + skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); if (!skb) { netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); usbnet_defer_kevent (dev, EVENT_RX_MEMORY); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index d1c7029ded7ce..cf95290b160c5 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1616,7 +1616,6 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, rq->rx_ring[i].basePA); rq->rx_ring[i].base = NULL; } - rq->buf_info[i] = NULL; } if (rq->data_ring.base) { @@ -1638,6 +1637,7 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq, (rq->rx_ring[0].size + rq->rx_ring[1].size); dma_free_coherent(&adapter->pdev->dev, sz, rq->buf_info[0], rq->buf_info_pa); + rq->buf_info[0] = rq->buf_info[1] = NULL; } } diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 7dc3bcac35066..67ecf2425b889 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -674,8 +674,9 @@ static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev, struct sock *sk, struct sk_buff *skb) { - /* don't divert multicast */ - if (ipv4_is_multicast(ip_hdr(skb)->daddr)) + /* don't divert multicast or local broadcast */ + if (ipv4_is_multicast(ip_hdr(skb)->daddr) || + ipv4_is_lbcast(ip_hdr(skb)->daddr)) return skb; if (qdisc_tx_is_default(vrf_dev)) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d7c49cf1d5e91..9e9202b50e732 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1623,26 +1623,19 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request, static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct nd_msg *msg; - const struct ipv6hdr *iphdr; const struct in6_addr *daddr; - struct neighbour *n; + const struct ipv6hdr *iphdr; struct inet6_dev *in6_dev; + struct neighbour *n; + struct nd_msg *msg; in6_dev = __in6_dev_get(dev); if (!in6_dev) goto out; - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg))) - goto out; - iphdr = ipv6_hdr(skb); daddr = &iphdr->daddr; - msg = (struct nd_msg *)(iphdr + 1); - if (msg->icmph.icmp6_code != 0 || - msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION) - goto out; if (ipv6_addr_loopback(daddr) || ipv6_addr_is_multicast(&msg->target)) @@ -2240,11 +2233,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_rdst *rdst, *fdst = NULL; const struct ip_tunnel_info *info; - struct ethhdr *eth; bool did_rsc = false; - struct vxlan_rdst *rdst, *fdst = NULL; struct vxlan_fdb *f; + struct ethhdr *eth; __be32 vni = 0; info = skb_tunnel_info(skb); @@ -2269,12 +2262,14 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (ntohs(eth->h_proto) == ETH_P_ARP) return arp_reduce(dev, skb, vni); #if IS_ENABLED(CONFIG_IPV6) - else if (ntohs(eth->h_proto) == ETH_P_IPV6) { - struct ipv6hdr *hdr, _hdr; - if ((hdr = skb_header_pointer(skb, - skb_network_offset(skb), - sizeof(_hdr), &_hdr)) && - hdr->nexthdr == IPPROTO_ICMPV6) + else if (ntohs(eth->h_proto) == ETH_P_IPV6 && + pskb_may_pull(skb, sizeof(struct ipv6hdr) + + sizeof(struct nd_msg)) && + ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { + struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1); + + if (m->icmph.icmp6_code == 0 && + m->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) return neigh_reduce(dev, skb, vni); } #endif @@ -3110,6 +3105,11 @@ static void vxlan_config_apply(struct net_device *dev, max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); + if (max_mtu < ETH_MIN_MTU) + max_mtu = ETH_MIN_MTU; + + if (!changelink && !conf->mtu) + dev->mtu = max_mtu; } if (dev->mtu > max_mtu) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 195dafb981314..d790ea20b95d9 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2577,9 +2577,13 @@ void ath10k_pci_hif_power_down(struct ath10k *ar) */ } -#ifdef CONFIG_PM - static int ath10k_pci_hif_suspend(struct ath10k *ar) +{ + /* Nothing to do; the important stuff is in the driver suspend. */ + return 0; +} + +static int ath10k_pci_suspend(struct ath10k *ar) { /* The grace timer can still be counting down and ar->ps_awake be true. * It is known that the device may be asleep after resuming regardless @@ -2592,6 +2596,12 @@ static int ath10k_pci_hif_suspend(struct ath10k *ar) } static int ath10k_pci_hif_resume(struct ath10k *ar) +{ + /* Nothing to do; the important stuff is in the driver resume. */ + return 0; +} + +static int ath10k_pci_resume(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct pci_dev *pdev = ar_pci->pdev; @@ -2615,7 +2625,6 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) return ret; } -#endif static bool ath10k_pci_validate_cal(void *data, size_t size) { @@ -2770,10 +2779,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .power_down = ath10k_pci_hif_power_down, .read32 = ath10k_pci_read32, .write32 = ath10k_pci_write32, -#ifdef CONFIG_PM .suspend = ath10k_pci_hif_suspend, .resume = ath10k_pci_hif_resume, -#endif .fetch_cal_eeprom = ath10k_pci_hif_fetch_cal_eeprom, }; @@ -3401,11 +3408,7 @@ static __maybe_unused int ath10k_pci_pm_suspend(struct device *dev) struct ath10k *ar = dev_get_drvdata(dev); int ret; - if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, - ar->running_fw->fw_file.fw_features)) - return 0; - - ret = ath10k_hif_suspend(ar); + ret = ath10k_pci_suspend(ar); if (ret) ath10k_warn(ar, "failed to suspend hif: %d\n", ret); @@ -3417,11 +3420,7 @@ static __maybe_unused int ath10k_pci_pm_resume(struct device *dev) struct ath10k *ar = dev_get_drvdata(dev); int ret; - if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, - ar->running_fw->fw_file.fw_features)) - return 0; - - ret = ath10k_hif_resume(ar); + ret = ath10k_pci_resume(ar); if (ret) ath10k_warn(ar, "failed to resume hif: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 49ed1afb913ca..fe3a8263b2241 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -179,6 +179,9 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, ssize_t len; int r; + if (count < 1) + return -EINVAL; + if (sc->cur_chan->nvifs > 1) return -EOPNOTSUPP; @@ -186,6 +189,8 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, if (copy_from_user(buf, user_buf, len)) return -EFAULT; + buf[len] = '\0'; + if (strtobool(buf, &start)) return -EINVAL; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 613caca7dc020..b3fa8ae804650 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4096,8 +4096,8 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, sdio_release_host(sdiodev->func[1]); fail: brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err); - device_release_driver(dev); device_release_driver(&sdiodev->func[2]->dev); + device_release_driver(dev); } struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index e8b5ff42f5a8f..c8e7b54a538ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -72,18 +72,21 @@ #define IWL9000_SMEM_OFFSET 0x400000 #define IWL9000_SMEM_LEN 0x68000 -#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" +#define IWL9000A_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" +#define IWL9000B_FW_PRE "iwlwifi-9000-pu-b0-jf-b0-" #define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" #define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" #define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" -#define IWL9000_MODULE_FIRMWARE(api) \ - IWL9000_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9000A_MODULE_FIRMWARE(api) \ + IWL9000A_FW_PRE __stringify(api) ".ucode" +#define IWL9000B_MODULE_FIRMWARE(api) \ + IWL9000B_FW_PRE __stringify(api) ".ucode" #define IWL9000RFB_MODULE_FIRMWARE(api) \ - IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode" + IWL9000RFB_FW_PRE __stringify(api) ".ucode" #define IWL9260A_MODULE_FIRMWARE(api) \ - IWL9260A_FW_PRE "-" __stringify(api) ".ucode" + IWL9260A_FW_PRE __stringify(api) ".ucode" #define IWL9260B_MODULE_FIRMWARE(api) \ - IWL9260B_FW_PRE "-" __stringify(api) ".ucode" + IWL9260B_FW_PRE __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_9000 10 @@ -193,7 +196,48 @@ const struct iwl_cfg iwl9460_2ac_cfg = { .nvm_ver = IWL9000_NVM_VERSION, .nvm_calib_ver = IWL9000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl9460_2ac_cfg_soc = { + .name = "Intel(R) Dual Band Wireless AC 9460", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, + .soc_latency = 5000, +}; + +const struct iwl_cfg iwl9461_2ac_cfg_soc = { + .name = "Intel(R) Dual Band Wireless AC 9461", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; + +const struct iwl_cfg iwl9462_2ac_cfg_soc = { + .name = "Intel(R) Dual Band Wireless AC 9462", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, }; const struct iwl_cfg iwl9560_2ac_cfg = { @@ -205,10 +249,23 @@ const struct iwl_cfg iwl9560_2ac_cfg = { .nvm_ver = IWL9000_NVM_VERSION, .nvm_calib_ver = IWL9000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, }; -MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +const struct iwl_cfg iwl9560_2ac_cfg_soc = { + .name = "Intel(R) Dual Band Wireless AC 9560", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; +MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c index a440140ed8dda..7eade165b7472 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -80,15 +80,15 @@ #define IWL_A000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-" #define IWL_A000_HR_MODULE_FIRMWARE(api) \ - IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" + IWL_A000_HR_FW_PRE __stringify(api) ".ucode" #define IWL_A000_JF_MODULE_FIRMWARE(api) \ - IWL_A000_JF_FW_PRE "-" __stringify(api) ".ucode" + IWL_A000_JF_FW_PRE __stringify(api) ".ucode" #define IWL_A000_HR_F0_QNJ_MODULE_FIRMWARE(api) \ - IWL_A000_HR_F0_FW_PRE "-" __stringify(api) ".ucode" + IWL_A000_HR_F0_FW_PRE __stringify(api) ".ucode" #define IWL_A000_JF_B0_QNJ_MODULE_FIRMWARE(api) \ - IWL_A000_JF_B0_FW_PRE "-" __stringify(api) ".ucode" + IWL_A000_JF_B0_FW_PRE __stringify(api) ".ucode" #define IWL_A000_HR_A0_QNJ_MODULE_FIRMWARE(api) \ - IWL_A000_HR_A0_FW_PRE "-" __stringify(api) ".ucode" + IWL_A000_HR_A0_FW_PRE __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_A000 10 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 5a40092febfb6..3bfc657f6b421 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -531,6 +531,8 @@ struct iwl_scan_config_v1 { } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ #define SCAN_TWO_LMACS 2 +#define SCAN_LB_LMAC_IDX 0 +#define SCAN_HB_LMAC_IDX 1 struct iwl_scan_config { __le32 flags; @@ -578,6 +580,7 @@ enum iwl_umac_scan_general_flags { IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9), IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = BIT(10), IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED = BIT(11), + IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL = BIT(13), }; /** @@ -631,12 +634,17 @@ struct iwl_scan_req_umac_tail { * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @general_flags: &enum iwl_umac_scan_general_flags - * @reserved2: for future use and alignment * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @extended_dwell: dwell time for channels 1, 6 and 11 * @active_dwell: dwell time for active scan * @passive_dwell: dwell time for passive scan * @fragmented_dwell: dwell time for fragmented passive scan + * @adwell_default_n_aps: for adaptive dwell the default number of APs + * per channel + * @adwell_default_n_aps_social: for adaptive dwell the default + * number of APs per social (1,6,11) channel + * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added + * to total scan time * @max_out_time: max out of serving channel time, per LMAC - for CDB there * are 2 LMACs * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs @@ -644,6 +652,8 @@ struct iwl_scan_req_umac_tail { * @channel_flags: &enum iwl_scan_channel_flags * @n_channels: num of channels in scan request * @reserved: for future use and alignment + * @reserved2: for future use and alignment + * @reserved3: for future use and alignment * @data: &struct iwl_scan_channel_cfg_umac and * &struct iwl_scan_req_umac_tail */ @@ -651,41 +661,64 @@ struct iwl_scan_req_umac { __le32 flags; __le32 uid; __le32 ooc_priority; - /* SCAN_GENERAL_PARAMS_API_S_VER_4 */ __le16 general_flags; - u8 reserved2; + u8 reserved; u8 scan_start_mac_id; - u8 extended_dwell; - u8 active_dwell; - u8 passive_dwell; - u8 fragmented_dwell; union { struct { + u8 extended_dwell; + u8 active_dwell; + u8 passive_dwell; + u8 fragmented_dwell; __le32 max_out_time; __le32 suspend_time; __le32 scan_priority; - /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */ + /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ u8 channel_flags; u8 n_channels; - __le16 reserved; + __le16 reserved2; u8 data[]; } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ struct { + u8 extended_dwell; + u8 active_dwell; + u8 passive_dwell; + u8 fragmented_dwell; __le32 max_out_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; __le32 scan_priority; - /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */ + /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ u8 channel_flags; u8 n_channels; - __le16 reserved; + __le16 reserved2; u8 data[]; } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */ + struct { + u8 active_dwell; + u8 passive_dwell; + u8 fragmented_dwell; + u8 adwell_default_n_aps; + u8 adwell_default_n_aps_social; + u8 reserved3; + __le16 adwell_max_budget; + __le32 max_out_time[SCAN_TWO_LMACS]; + __le32 suspend_time[SCAN_TWO_LMACS]; + __le32 scan_priority; + /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ + u8 channel_flags; + u8 n_channels; + __le16 reserved2; + u8 data[]; + } v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */ }; } __packed; -#define IWL_SCAN_REQ_UMAC_SIZE sizeof(struct iwl_scan_req_umac) +#define IWL_SCAN_REQ_UMAC_SIZE_V7 sizeof(struct iwl_scan_req_umac) +#define IWL_SCAN_REQ_UMAC_SIZE_V6 (sizeof(struct iwl_scan_req_umac) - \ + 2 * sizeof(u8) - sizeof(__le16)) #define IWL_SCAN_REQ_UMAC_SIZE_V1 (sizeof(struct iwl_scan_req_umac) - \ - 2 * sizeof(__le32)) + 2 * sizeof(__le32) - 2 * sizeof(u8) - \ + sizeof(__le16)) /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h index 87b4434224a1f..dfa111bb411e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h @@ -68,6 +68,9 @@ * @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW * @IWL_MVM_DQA_AUX_QUEUE: a queue reserved for aux frames * @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames + * @IWL_MVM_DQA_INJECT_MONITOR_QUEUE: a queue reserved for injection using + * monitor mode. Note this queue is the same as the queue for P2P device + * but we can't have active monitor mode along with P2P device anyway. * @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames * @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure * that we are never left without the possibility to connect to an AP. @@ -87,6 +90,7 @@ enum iwl_mvm_dqa_txq { IWL_MVM_DQA_CMD_QUEUE = 0, IWL_MVM_DQA_AUX_QUEUE = 1, IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2, + IWL_MVM_DQA_INJECT_MONITOR_QUEUE = 2, IWL_MVM_DQA_GCAST_QUEUE = 3, IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4, IWL_MVM_DQA_MIN_MGMT_QUEUE = 5, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 279248cd9cfb3..e988e4c371c43 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -262,6 +262,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, /* API Set 1 */ + IWL_UCODE_TLV_API_ADAPTIVE_DWELL = (__force iwl_ucode_tlv_api_t)32, IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34, IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL = (__force iwl_ucode_tlv_api_t)37, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 71cb1ecde0f72..e226179c32fa7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -364,6 +364,7 @@ struct iwl_cfg { u32 dccm2_len; u32 smem_offset; u32 smem_len; + u32 soc_latency; u16 nvm_ver; u16 nvm_calib_ver; u16 rx_with_siso_diversity:1, @@ -471,6 +472,10 @@ extern const struct iwl_cfg iwl9260_2ac_cfg; extern const struct iwl_cfg iwl9270_2ac_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg; +extern const struct iwl_cfg iwl9460_2ac_cfg_soc; +extern const struct iwl_cfg iwl9461_2ac_cfg_soc; +extern const struct iwl_cfg iwl9462_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_2ac_cfg_soc; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e90abbfba7182..ecd5c1df811ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -117,6 +117,7 @@ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 #define FH_RSCSR_RPA_EN BIT(25) +#define FH_RSCSR_RADA_EN BIT(26) #define FH_RSCSR_RXQ_POS 16 #define FH_RSCSR_RXQ_MASK 0x3F0000 @@ -128,7 +129,8 @@ struct iwl_rx_packet { * 31: flag flush RB request * 30: flag ignore TC (terminal counter) request * 29: flag fast IRQ request - * 28-26: Reserved + * 28-27: Reserved + * 26: RADA enabled * 25: Offload enabled * 24: RPF enabled * 23: RSS enabled diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index a2bf530eeae49..2f22e14e00fe8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -787,7 +787,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, u32 action) { struct iwl_mac_ctx_cmd cmd = {}; - u32 tfd_queue_msk = 0; + u32 tfd_queue_msk = BIT(mvm->snif_queue); int ret; WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 949e634182990..2ec27ceb8af9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -954,6 +954,7 @@ struct iwl_mvm { /* Tx queues */ u16 aux_queue; + u16 snif_queue; u16 probe_queue; u16 p2p_dev_queue; @@ -1042,6 +1043,7 @@ struct iwl_mvm { * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running * @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running + * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA */ enum iwl_mvm_status { IWL_MVM_STATUS_HW_RFKILL, @@ -1053,6 +1055,7 @@ enum iwl_mvm_status { IWL_MVM_STATUS_ROC_AUX_RUNNING, IWL_MVM_STATUS_D3_RECONFIG, IWL_MVM_STATUS_FIRMWARE_RUNNING, + IWL_MVM_STATUS_NEED_FLUSH_P2P, }; /* Keep track of completed init configuration */ @@ -1124,6 +1127,12 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } +static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_ADAPTIVE_DWELL); +} + static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) { /* For now we only use this mode to differentiate between diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 231878969332d..9fb40955d5f4f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -622,6 +622,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; + mvm->snif_queue = IWL_MVM_DQA_INJECT_MONITOR_QUEUE; mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 248699c2c4bff..819e6f66a5b5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -232,8 +232,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *stats, - struct iwl_rx_mpdu_desc *desc, int queue, - u8 *crypt_len) + struct iwl_rx_mpdu_desc *desc, u32 pkt_flags, + int queue, u8 *crypt_len) { u16 status = le16_to_cpu(desc->status); @@ -253,6 +253,8 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, return -1; stats->flag |= RX_FLAG_DECRYPTED; + if (pkt_flags & FH_RSCSR_RADA_EN) + stats->flag |= RX_FLAG_MIC_STRIPPED; *crypt_len = IEEE80211_CCMP_HDR_LEN; return 0; case IWL_RX_MPDU_STATUS_SEC_TKIP: @@ -270,6 +272,10 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_WEP) *crypt_len = IEEE80211_WEP_IV_LEN; + + if (pkt_flags & FH_RSCSR_RADA_EN) + stats->flag |= RX_FLAG_ICV_STRIPPED; + return 0; case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) @@ -810,7 +816,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status = IEEE80211_SKB_RXCB(skb); - if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, queue, &crypt_len)) { + if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, + le32_to_cpu(pkt->len_n_flags), queue, + &crypt_len)) { kfree_skb(skb); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 774122fed454f..e4fd476e9ccb0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -130,6 +130,19 @@ struct iwl_mvm_scan_params { u32 measurement_dwell; }; +static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm) +{ + struct iwl_scan_req_umac *cmd = mvm->scan_cmd; + + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) + return (void *)&cmd->v7.data; + + if (iwl_mvm_has_new_tx_api(mvm)) + return (void *)&cmd->v6.data; + + return (void *)&cmd->v1.data; +} + static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) { if (mvm->scan_rx_ant != ANT_NONE) @@ -1075,25 +1088,57 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, { struct iwl_mvm_scan_timing_params *timing = &scan_timing[params->type]; + if (iwl_mvm_is_regular_scan(params)) + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + else + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); + + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) { + if (params->measurement_dwell) { + cmd->v7.active_dwell = params->measurement_dwell; + cmd->v7.passive_dwell = params->measurement_dwell; + } else { + cmd->v7.active_dwell = IWL_SCAN_DWELL_ACTIVE; + cmd->v7.passive_dwell = IWL_SCAN_DWELL_PASSIVE; + } + cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; + + cmd->v7.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->v7.max_out_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + cmd->v7.suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); + if (iwl_mvm_is_cdb_supported(mvm)) { + cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + cmd->v7.suspend_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); + } + + return; + } + if (params->measurement_dwell) { - cmd->active_dwell = params->measurement_dwell; - cmd->passive_dwell = params->measurement_dwell; - cmd->extended_dwell = params->measurement_dwell; + cmd->v1.active_dwell = params->measurement_dwell; + cmd->v1.passive_dwell = params->measurement_dwell; + cmd->v1.extended_dwell = params->measurement_dwell; } else { - cmd->active_dwell = IWL_SCAN_DWELL_ACTIVE; - cmd->passive_dwell = IWL_SCAN_DWELL_PASSIVE; - cmd->extended_dwell = IWL_SCAN_DWELL_EXTENDED; + cmd->v1.active_dwell = IWL_SCAN_DWELL_ACTIVE; + cmd->v1.passive_dwell = IWL_SCAN_DWELL_PASSIVE; + cmd->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED; } - cmd->fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; + cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; if (iwl_mvm_has_new_tx_api(mvm)) { cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - cmd->v6.max_out_time[0] = cpu_to_le32(timing->max_out_time); - cmd->v6.suspend_time[0] = cpu_to_le32(timing->suspend_time); + cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); if (iwl_mvm_is_cdb_supported(mvm)) { - cmd->v6.max_out_time[1] = + cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(timing->max_out_time); - cmd->v6.suspend_time[1] = + cmd->v6.suspend_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(timing->suspend_time); } } else { @@ -1102,11 +1147,6 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->v1.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); } - - if (iwl_mvm_is_regular_scan(params)) - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - else - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); } static void @@ -1178,8 +1218,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int type) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; - void *cmd_data = iwl_mvm_has_new_tx_api(mvm) ? - (void *)&cmd->v6.data : (void *)&cmd->v1.data; + void *cmd_data = iwl_mvm_get_scan_req_umac_data(mvm); struct iwl_scan_req_umac_tail *sec_part = cmd_data + sizeof(struct iwl_scan_channel_cfg_umac) * mvm->fw->ucode_capa.n_scan_channels; @@ -1216,7 +1255,10 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; - if (iwl_mvm_has_new_tx_api(mvm)) { + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) { + cmd->v7.channel_flags = channel_flags; + cmd->v7.n_channels = params->n_channels; + } else if (iwl_mvm_has_new_tx_api(mvm)) { cmd->v6.channel_flags = channel_flags; cmd->v6.n_channels = params->n_channels; } else { @@ -1661,8 +1703,10 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) { int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; - if (iwl_mvm_has_new_tx_api(mvm)) - base_size = IWL_SCAN_REQ_UMAC_SIZE; + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) + base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; + else if (iwl_mvm_has_new_tx_api(mvm)) + base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) return base_size + diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index c4a343534c5ea..0d7929799942f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1700,29 +1700,29 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) sta->sta_id = IWL_MVM_INVALID_STA; } -static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) +static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 *queue, + u8 sta_id, u8 fifo) { unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? mvm->cfg->base_params->wd_timeout : IWL_WATCHDOG_DISABLED; if (iwl_mvm_has_new_tx_api(mvm)) { - int queue = iwl_mvm_tvqm_enable_txq(mvm, mvm->aux_queue, - mvm->aux_sta.sta_id, - IWL_MAX_TID_COUNT, - wdg_timeout); - mvm->aux_queue = queue; + int tvqm_queue = + iwl_mvm_tvqm_enable_txq(mvm, *queue, sta_id, + IWL_MAX_TID_COUNT, + wdg_timeout); + *queue = tvqm_queue; } else { struct iwl_trans_txq_scd_cfg cfg = { - .fifo = IWL_MVM_TX_FIFO_MCAST, - .sta_id = mvm->aux_sta.sta_id, + .fifo = fifo, + .sta_id = sta_id, .tid = IWL_MAX_TID_COUNT, .aggregate = false, .frame_limit = IWL_FRAME_LIMIT, }; - iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg, - wdg_timeout); + iwl_mvm_enable_txq(mvm, *queue, *queue, 0, &cfg, wdg_timeout); } } @@ -1741,7 +1741,9 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) /* 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); + iwl_mvm_enable_aux_snif_queue(mvm, &mvm->aux_queue, + mvm->aux_sta.sta_id, + IWL_MVM_TX_FIFO_MCAST); ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, MAC_INDEX_AUX, 0); @@ -1755,7 +1757,9 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) * 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); + iwl_mvm_enable_aux_snif_queue(mvm, &mvm->aux_queue, + mvm->aux_sta.sta_id, + IWL_MVM_TX_FIFO_MCAST); return 0; } @@ -1763,10 +1767,31 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; lockdep_assert_held(&mvm->mutex); - return iwl_mvm_add_int_sta_common(mvm, &mvm->snif_sta, vif->addr, + + /* Map snif queue to fifo - must happen before adding snif station */ + if (!iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_aux_snif_queue(mvm, &mvm->snif_queue, + mvm->snif_sta.sta_id, + IWL_MVM_TX_FIFO_BE); + + ret = iwl_mvm_add_int_sta_common(mvm, &mvm->snif_sta, vif->addr, mvmvif->id, 0); + if (ret) + return ret; + + /* + * For 22000 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_snif_queue(mvm, &mvm->snif_queue, + mvm->snif_sta.sta_id, + IWL_MVM_TX_FIFO_BE); + + return 0; } int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -1775,6 +1800,8 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); + iwl_mvm_disable_txq(mvm, mvm->snif_queue, mvm->snif_queue, + IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 4d0314912e947..e25cda9fbf6c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -132,6 +132,24 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) * executed, and a new time event means a new command. */ iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC); + + /* Do the same for the P2P device queue (STA) */ + if (test_and_clear_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) { + struct iwl_mvm_vif *mvmvif; + + /* + * NB: access to this pointer would be racy, but the flush bit + * can only be set when we had a P2P-Device VIF, and we have a + * flush of this work in iwl_mvm_prepare_mac_removal() so it's + * not really racy. + */ + + if (!WARN_ON(!mvm->p2p_device_vif)) { + mvmvif = iwl_mvm_vif_from_mac80211(mvm->p2p_device_vif); + iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true, + CMD_ASYNC); + } + } } static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) @@ -855,10 +873,12 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) + if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_remove_time_event(mvm, mvmvif, te_data); - else + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); + } iwl_mvm_roc_finished(mvm); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 6f2e2af23219a..887a504ce64a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -657,7 +657,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (ap_sta_id != IWL_MVM_INVALID_STA) sta_id = ap_sta_id; } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { - queue = mvm->aux_queue; + queue = mvm->snif_queue; + sta_id = mvm->snif_sta.sta_id; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 2ea74abad73de..53e269d540505 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1143,9 +1143,18 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, unsigned int default_timeout = cmd_q ? IWL_DEF_WD_TIMEOUT : mvm->cfg->base_params->wd_timeout; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) { + /* + * We can't know when the station is asleep or awake, so we + * must disable the queue hang detection. + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) && + vif && vif->type == NL80211_IFTYPE_AP) + return IWL_WATCHDOG_DISABLED; return iwlmvm_mod_params.tfd_q_hang_detect ? default_timeout : IWL_WATCHDOG_DISABLED; + } trigger = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS); txq_timer = (void *)trigger->data; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 858765fed8f85..0f7bd37bf1728 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -465,6 +465,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0x9110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x9130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8132, iwl8260_2ac_cfg)}, @@ -483,6 +485,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0000, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x4010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0110, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x1110, iwl8265_2ac_cfg)}, @@ -508,67 +511,144 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x3E01, iwl8275_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x1012, iwl8275_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0012, iwl8275_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x0014, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)}, /* 9000 Series */ - {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, - {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, - {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0214, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0060, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0260, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0064, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x00A4, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x02A4, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x00A0, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x02A0, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0060, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x0060, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x00A4, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0214, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0230, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0234, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0238, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x023C, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0260, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x02A0, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x02A4, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0034, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x271B, 0x0214, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x271C, 0x0214, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x0230, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0234, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0238, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x023C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0060, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0060, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x40A4, iwl9462_2ac_cfg_soc)}, /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, @@ -576,8 +656,15 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x0000, iwla000_2ax_cfg_hr)}, {IWL_PCI_DEVICE(0x34F0, 0x0070, iwla000_2ax_cfg_hr)}, {IWL_PCI_DEVICE(0x2720, 0x0078, iwla000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ac_cfg_hr_cdb)}, + {IWL_PCI_DEVICE(0x2720, 0x0030, iwla000_2ac_cfg_hr_cdb)}, {IWL_PCI_DEVICE(0x2720, 0x1080, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0090, iwla000_2ac_cfg_hr_cdb)}, + {IWL_PCI_DEVICE(0x2720, 0x0310, iwla000_2ac_cfg_hr_cdb)}, + {IWL_PCI_DEVICE(0x40C0, 0x0000, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x40C0, 0x0A10, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0000, iwla000_2ax_cfg_hr)}, + #endif /* CONFIG_IWLMVM */ {0} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 4fb7647995c39..9875ab5ce18c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -666,11 +666,15 @@ static inline u8 iwl_pcie_get_cmd_index(struct iwl_txq *q, u32 index) return index & (q->n_window - 1); } -static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, +static inline void *iwl_pcie_get_tfd(struct iwl_trans *trans, struct iwl_txq *txq, int idx) { - return txq->tfds + trans_pcie->tfd_size * iwl_pcie_get_cmd_index(txq, - idx); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (trans->cfg->use_tfh) + idx = iwl_pcie_get_cmd_index(txq, idx); + + return txq->tfds + trans_pcie->tfd_size * idx; } static inline void iwl_enable_rfkill_int(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 d74613fcb756c..6f45c8148b279 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -171,8 +171,6 @@ 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 */ @@ -181,7 +179,7 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) lockdep_assert_held(&txq->lock); iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, - iwl_pcie_get_tfd(trans_pcie, txq, idx)); + iwl_pcie_get_tfd(trans, txq, idx)); /* free SKB */ if (txq->entries) { @@ -367,11 +365,9 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_cmd_meta *out_meta) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); - struct iwl_tfh_tfd *tfd = - iwl_pcie_get_tfd(trans_pcie, txq, idx); + struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, idx); dma_addr_t tb_phys; bool amsdu; int i, len, tb1_len, tb2_len, hdr_len; @@ -568,8 +564,7 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, 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); + struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr); memset(tfd, 0, sizeof(*tfd)); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index c645d10d37072..4704137a26e0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -373,7 +373,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i, num_tbs; - void *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); + void *tfd = iwl_pcie_get_tfd(trans, txq, index); /* Sanity check on number of chunks */ num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd); @@ -1999,7 +1999,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, } trace_iwlwifi_dev_tx(trans->dev, skb, - iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), + iwl_pcie_get_tfd(trans, txq, txq->write_ptr), trans_pcie->tfd_size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, hdr_len); @@ -2073,7 +2073,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, IEEE80211_CCMP_HDR_LEN : 0; trace_iwlwifi_dev_tx(trans->dev, skb, - iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), + iwl_pcie_get_tfd(trans, txq, txq->write_ptr), trans_pcie->tfd_size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0); @@ -2406,7 +2406,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, IWL_FIRST_TB_SIZE); - tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr); /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len), iwl_pcie_tfd_get_num_tbs(trans, tfd)); diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index d5a3bf91a03e7..ab6d39e120695 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -852,12 +852,11 @@ void p54_unregister_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; -#ifdef CONFIG_P54_LEDS - p54_unregister_leds(priv); -#endif /* CONFIG_P54_LEDS */ - if (priv->registered) { priv->registered = false; +#ifdef CONFIG_P54_LEDS + p54_unregister_leds(priv); +#endif /* CONFIG_P54_LEDS */ ieee80211_unregister_hw(dev); } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6467ffac9811e..a59b54328c07b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3108,6 +3108,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) { struct hwsim_new_radio_params param = { 0 }; const char *hwname = NULL; + int ret; param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; @@ -3147,7 +3148,9 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) param.regd = hwsim_world_regdom_custom[idx]; } - return mac80211_hwsim_new_radio(info, ¶m); + ret = mac80211_hwsim_new_radio(info, ¶m); + kfree(hwname); + return ret; } static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) diff --git a/drivers/net/wireless/mediatek/Kconfig b/drivers/net/wireless/mediatek/Kconfig index 28843fed750a2..92ce4062f3077 100644 --- a/drivers/net/wireless/mediatek/Kconfig +++ b/drivers/net/wireless/mediatek/Kconfig @@ -11,4 +11,5 @@ config WLAN_VENDOR_MEDIATEK if WLAN_VENDOR_MEDIATEK source "drivers/net/wireless/mediatek/mt7601u/Kconfig" +source "drivers/net/wireless/mediatek/mt76/Kconfig" endif # WLAN_VENDOR_MEDIATEK diff --git a/drivers/net/wireless/mediatek/Makefile b/drivers/net/wireless/mediatek/Makefile index 9d5f182fd7fdc..a76be487d34cb 100644 --- a/drivers/net/wireless/mediatek/Makefile +++ b/drivers/net/wireless/mediatek/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_MT7601U) += mt7601u/ +obj-$(CONFIG_MT76) += mt76/ diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig new file mode 100644 index 0000000000000..fa072e16ab7b6 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -0,0 +1,6 @@ +config MT76 + tristate "MediaTek MT76x2 802.11ac chips support" + depends on MAC80211 + depends on PCI + ---help--- + This adds support for MediaTek MT76x2 802.11ac chips. diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile new file mode 100644 index 0000000000000..dfae4e60327b9 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -0,0 +1,20 @@ +EXTRA_CFLAGS += -Werror + +obj-m := mt76.o mt76x2e.o mt7603e.o + +CFLAGS_trace.o := -I$(src) +CFLAGS_mt76x2_trace.o := -I$(src) + +mt76-y := \ + mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o + +mt76x2e-y := \ + mt76x2_pci.o mt76x2_dma.o \ + mt76x2_main.o mt76x2_init.o mt76x2_debugfs.o mt76x2_tx.o \ + mt76x2_core.o mt76x2_mac.o mt76x2_eeprom.o mt76x2_mcu.o mt76x2_phy.o \ + mt76x2_dfs.o mt76x2_trace.o + +mt7603e-y := \ + mt7603_pci.o mt7603_soc.o mt7603_main.o mt7603_init.o mt7603_mcu.o \ + mt7603_core.o mt7603_dma.o mt7603_mac.o mt7603_eeprom.o \ + mt7603_beacon.o mt7603_debugfs.o diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c new file mode 100644 index 0000000000000..7c3612aaa8c4c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "mt76.h" + +static int +mt76_reg_set(void *data, u64 val) +{ + struct mt76_dev *dev = data; + + dev->bus->wr(dev, dev->debugfs_reg, val); + return 0; +} + +static int +mt76_reg_get(void *data, u64 *val) +{ + struct mt76_dev *dev = data; + + *val = dev->bus->rr(dev, dev->debugfs_reg); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); + +static int +mt76_queues_read(struct seq_file *s, void *data) +{ + struct mt76_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) { + struct mt76_queue *q = &dev->q_tx[i]; + + if (!q->ndesc) + continue; + + seq_printf(s, + "%d: queued=%d head=%d tail=%d swq_queued=%d\n", + i, q->queued, q->head, q->tail, q->swq_queued); + } + + return 0; +} + +struct dentry *mt76_register_debugfs(struct mt76_dev *dev) +{ + struct dentry *dir; + + dir = debugfs_create_dir("mt76", dev->hw->wiphy->debugfsdir); + if (!dir) + return NULL; + + debugfs_create_u8("led_pin", S_IRUSR | S_IWUSR, dir, &dev->led_pin); + debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); + debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev, + &fops_regval); + debugfs_create_blob("eeprom", S_IRUSR, dir, &dev->eeprom); + if (dev->otp.data) + debugfs_create_blob("otp", S_IRUSR, dir, &dev->otp); + debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); + + return dir; +} +EXPORT_SYMBOL_GPL(mt76_register_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c new file mode 100644 index 0000000000000..ecd409a4a89b1 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76.h" +#include "dma.h" + +#define DMA_DUMMY_TXWI ((void *) ~0) + +static int +mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + int size; + int i; + + spin_lock_init(&q->lock); + INIT_LIST_HEAD(&q->swq); + + size = q->ndesc * sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dev, size, &q->desc_dma, GFP_KERNEL); + if (!q->desc) + return -ENOMEM; + + size = q->ndesc * sizeof(*q->entry); + q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + + /* clear descriptors */ + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + + iowrite32(q->desc_dma, &q->regs->desc_base); + iowrite32(0, &q->regs->cpu_idx); + iowrite32(0, &q->regs->dma_idx); + iowrite32(q->ndesc, &q->regs->ring_size); + + return 0; +} + +static int +mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, + struct mt76_queue_buf *buf, int nbufs, u32 info, + struct sk_buff *skb, void *txwi) +{ + struct mt76_desc *desc; + u32 ctrl; + int i, idx = -1; + + if (txwi) + q->entry[q->head].txwi = DMA_DUMMY_TXWI; + + for (i = 0; i < nbufs; i += 2, buf += 2) { + u32 buf0 = buf[0].addr, buf1 = 0; + + ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); + if (i < nbufs - 1) { + buf1 = buf[1].addr; + ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); + } + + if (i == nbufs - 1) + ctrl |= MT_DMA_CTL_LAST_SEC0; + else if (i == nbufs - 2) + ctrl |= MT_DMA_CTL_LAST_SEC1; + + idx = q->head; + q->head = (q->head + 1) % q->ndesc; + + desc = &q->desc[idx]; + + WRITE_ONCE(desc->buf0, cpu_to_le32(buf0)); + WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); + WRITE_ONCE(desc->info, cpu_to_le32(info)); + WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); + + q->queued++; + } + + q->entry[idx].txwi = txwi; + q->entry[idx].skb = skb; + + return idx; +} + +static void +mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx, + struct mt76_queue_entry *prev_e) +{ + struct mt76_queue_entry *e = &q->entry[idx]; + __le32 __ctrl = READ_ONCE(q->desc[idx].ctrl); + u32 ctrl = le32_to_cpu(__ctrl); + + if (!e->txwi || !e->skb) { + __le32 addr = READ_ONCE(q->desc[idx].buf0); + u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); + + dma_unmap_single(dev->dev, le32_to_cpu(addr), len, + DMA_TO_DEVICE); + } + + if (!(ctrl & MT_DMA_CTL_LAST_SEC0)) { + __le32 addr = READ_ONCE(q->desc[idx].buf1); + u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN1, ctrl); + + dma_unmap_single(dev->dev, le32_to_cpu(addr), len, + DMA_TO_DEVICE); + } + + if (e->txwi == DMA_DUMMY_TXWI) + e->txwi = NULL; + + *prev_e = *e; + memset(e, 0, sizeof(*e)); +} + +static void +mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) +{ + q->head = ioread32(&q->regs->dma_idx); + q->tail = q->head; + iowrite32(q->head, &q->regs->cpu_idx); +} + +static void +mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush) +{ + struct mt76_queue *q = &dev->q_tx[qid]; + struct mt76_queue_entry entry; + bool wake = false; + int last; + + if (!q->ndesc) + return; + + spin_lock_bh(&q->lock); + if (flush) + last = -1; + else + last = ioread32(&q->regs->dma_idx); + + while (q->queued && q->tail != last) { + mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); + if (entry.schedule) + q->swq_queued--; + + if (entry.skb) + dev->drv->tx_complete_skb(dev, q, &entry, flush); + + if (entry.txwi) { + mt76_put_txwi(dev, entry.txwi); + wake = true; + } + + q->tail = (q->tail + 1) % q->ndesc; + q->queued--; + + if (!flush && q->tail == last) + last = ioread32(&q->regs->dma_idx); + } + + if (!flush) + mt76_txq_schedule(dev, q); + else + mt76_dma_sync_idx(dev, q); + + wake = wake && qid < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8; + spin_unlock_bh(&q->lock); + + if (wake) + ieee80211_wake_queue(dev->hw, qid); +} + +static void * +mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, + int *len, u32 *info, bool *more) +{ + struct mt76_queue_entry *e = &q->entry[idx]; + struct mt76_desc *desc = &q->desc[idx]; + dma_addr_t buf_addr; + void *buf = e->buf; + int buf_len = SKB_WITH_OVERHEAD(q->buf_size); + + buf_addr = le32_to_cpu(READ_ONCE(desc->buf0)); + if (len) { + u32 ctl = le32_to_cpu(READ_ONCE(desc->ctrl)); + *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctl); + *more = !(ctl & MT_DMA_CTL_LAST_SEC0); + } + + if (info) + *info = le32_to_cpu(desc->info); + + dma_unmap_single(dev->dev, buf_addr, buf_len, DMA_FROM_DEVICE); + e->buf = NULL; + + return buf; +} + +static void * +mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, + int *len, u32 *info, bool *more) +{ + int idx = q->tail; + + *more = false; + if (!q->queued) + return NULL; + + if (!flush && !(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + return NULL; + + q->tail = (q->tail + 1) % q->ndesc; + q->queued--; + + return mt76_dma_get_buf(dev, q, idx, len, info, more); +} + +static void +mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + iowrite32(q->head, &q->regs->cpu_idx); +} + +static int +mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi) +{ + dma_addr_t addr; + void *buf; + int frames = 0; + int len = SKB_WITH_OVERHEAD(q->buf_size); + int offset = q->buf_offset; + int idx; + void *(*alloc)(unsigned int fragsz); + + if (napi) + alloc = napi_alloc_frag; + else + alloc = netdev_alloc_frag; + + spin_lock_bh(&q->lock); + + while (q->queued < q->ndesc - 1) { + struct mt76_queue_buf qbuf; + + buf = alloc(q->buf_size); + if (!buf) + break; + + addr = dma_map_single(dev->dev, buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev->dev, addr)) { + skb_free_frag(buf); + break; + } + + qbuf.addr = addr + offset; + qbuf.len = len - offset; + idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); + frames++; + } + + if (frames) + mt76_dma_kick_queue(dev, q); + + spin_unlock_bh(&q->lock); + + return frames; +} + +static void +mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) +{ + void *buf; + bool more; + + spin_lock_bh(&q->lock); + do { + buf = mt76_dma_dequeue(dev, q, true, NULL, NULL, &more); + if (!buf) + break; + + skb_free_frag(buf); + } while (1); + spin_unlock_bh(&q->lock); +} + +static void +mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) +{ + struct mt76_queue *q = &dev->q_rx[qid]; + int i; + + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl &= ~cpu_to_le32(MT_DMA_CTL_DMA_DONE); + + mt76_dma_rx_cleanup(dev, q); + mt76_dma_sync_idx(dev, q); + mt76_dma_rx_fill(dev, q, false); +} + +static void +mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data, + int len, bool more) +{ + struct page *page = virt_to_head_page(data); + int offset = data - page_address(page); + struct sk_buff *skb = q->rx_head; + + offset += q->buf_offset; + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset, len, + q->buf_size); + + if (more) + return; + + q->rx_head = NULL; + dev->drv->rx_skb(dev, q - dev->q_rx, skb); +} + +static int +mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) +{ + struct sk_buff *skb; + unsigned char *data; + int len; + int done = 0; + bool more; + + while (done < budget) { + u32 info; + + data = mt76_dma_dequeue(dev, q, false, &len, &info, &more); + if (!data) + break; + + if (q->rx_head) { + mt76_add_fragment(dev, q, data, len, more); + continue; + } + + skb = build_skb(data, q->buf_size); + if (!skb) { + skb_free_frag(data); + continue; + } + + skb_reserve(skb, q->buf_offset); + if (skb->tail + len > skb->end) { + dev_kfree_skb(skb); + continue; + } + + if (q == &dev->q_rx[MT_RXQ_MCU]) { + u32 *rxfce = (u32 *) skb->cb; + *rxfce = info; + } + + __skb_put(skb, len); + done++; + + if (more) { + q->rx_head = skb; + continue; + } + + dev->drv->rx_skb(dev, q - dev->q_rx, skb); + } + + mt76_dma_rx_fill(dev, q, true); + return done; +} + +static int +mt76_dma_rx_poll(struct napi_struct *napi, int budget) +{ + struct mt76_dev *dev; + int qid, done; + + dev = container_of(napi->dev, struct mt76_dev, napi_dev); + qid = napi - dev->napi; + + done = mt76_dma_rx_process(dev, &dev->q_rx[qid], budget); + if (done < budget) { + napi_complete(napi); + dev->drv->rx_poll_complete(dev, qid); + } + mt76_rx_complete(dev, qid); + + return done; +} + +static int +mt76_dma_init(struct mt76_dev *dev) +{ + int i; + + init_dummy_netdev(&dev->napi_dev); + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { + netif_napi_add(&dev->napi_dev, &dev->napi[i], mt76_dma_rx_poll, + 64); + mt76_dma_rx_fill(dev, &dev->q_rx[i], false); + skb_queue_head_init(&dev->rx_skb[i]); + napi_enable(&dev->napi[i]); + } + + return 0; +} + +static const struct mt76_queue_ops mt76_dma_ops = { + .init = mt76_dma_init, + .alloc = mt76_dma_alloc_queue, + .add_buf = mt76_dma_add_buf, + .tx_cleanup = mt76_dma_tx_cleanup, + .rx_reset = mt76_dma_rx_reset, + .kick = mt76_dma_kick_queue, +}; + +int mt76_dma_attach(struct mt76_dev *dev) +{ + dev->queue_ops = &mt76_dma_ops; + return 0; +} +EXPORT_SYMBOL_GPL(mt76_dma_attach); + +void mt76_dma_cleanup(struct mt76_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) + mt76_dma_tx_cleanup(dev, i, true); + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { + netif_napi_del(&dev->napi[i]); + mt76_dma_rx_cleanup(dev, &dev->q_rx[i]); + } +} +EXPORT_SYMBOL_GPL(mt76_dma_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h new file mode 100644 index 0000000000000..1dad396979296 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __MT76_DMA_H +#define __MT76_DMA_H + +#define MT_RING_SIZE 0x10 + +#define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0) +#define MT_DMA_CTL_LAST_SEC1 BIT(14) +#define MT_DMA_CTL_BURST BIT(15) +#define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16) +#define MT_DMA_CTL_LAST_SEC0 BIT(30) +#define MT_DMA_CTL_DMA_DONE BIT(31) + +struct mt76_desc { + __le32 buf0; + __le32 ctrl; + __le32 buf1; + __le32 info; +} __packed __aligned(4); + +int mt76_dma_attach(struct mt76_dev *dev); +void mt76_dma_cleanup(struct mt76_dev *dev); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c new file mode 100644 index 0000000000000..530e5593765c8 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include "mt76.h" + +static int +mt76_get_of_eeprom(struct mt76_dev *dev, int len) +{ +#if defined(CONFIG_OF) && defined(CONFIG_MTD) + struct device_node *np = dev->dev->of_node; + struct mtd_info *mtd; + const __be32 *list; + const char *part; + phandle phandle; + int offset = 0; + int size; + size_t retlen; + int ret; + + if (!np) + return -ENOENT; + + list = of_get_property(np, "mediatek,mtd-eeprom", &size); + if (!list) + return -ENOENT; + + phandle = be32_to_cpup(list++); + if (!phandle) + return -ENOENT; + + np = of_find_node_by_phandle(phandle); + if (!np) + return -EINVAL; + + part = of_get_property(np, "label", NULL); + if (!part) + part = np->name; + + mtd = get_mtd_device_nm(part); + if (IS_ERR(mtd)) + return PTR_ERR(mtd); + + if (size <= sizeof(*list)) + return -EINVAL; + + offset = be32_to_cpup(list); + ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); + put_mtd_device(mtd); + if (ret) + return ret; + + if (retlen < len) + return -EINVAL; + + return 0; +#else + return -ENOENT; +#endif +} + +void +mt76_eeprom_override(struct mt76_dev *dev) +{ +#ifdef CONFIG_OF + struct device_node *np = dev->dev->of_node; + const u8 *mac; + + if (!np) + return; + + mac = of_get_mac_address(np); + if (mac) + memcpy(dev->macaddr, mac, ETH_ALEN); +#endif + + if (!is_valid_ether_addr(dev->macaddr)) { + eth_random_addr(dev->macaddr); + dev_info(dev->dev, + "Invalid MAC address, using random address %pM\n", + dev->macaddr); + } +} +EXPORT_SYMBOL_GPL(mt76_eeprom_override); + +int +mt76_eeprom_init(struct mt76_dev *dev, int len) +{ + dev->eeprom.size = len; + dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); + if (!dev->eeprom.data) + return -ENOMEM; + + return !mt76_get_of_eeprom(dev, len); +} +EXPORT_SYMBOL_GPL(mt76_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/firmware/LICENSE b/drivers/net/wireless/mediatek/mt76/firmware/LICENSE new file mode 100644 index 0000000000000..be614c0b4d055 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/firmware/LICENSE @@ -0,0 +1,39 @@ +Copyright (c) 2014, Ralink, A MediaTek Company +All rights reserved. + +Redistribution. Redistribution and use in binary form, without +modification, are permitted provided that the following conditions are +met: + +* Redistributions must reproduce the above copyright notice and the + following disclaimer in the documentation and/or other materials + provided with the distribution. +* Neither the name of Ralink Technology Corporation nor the names of its + suppliers may be used to endorse or promote products derived from this + software without specific prior written permission. +* No reverse engineering, decompilation, or disassembly of this software + is permitted. + +Limited patent license. Ralink Technology Corporation grants a world-wide, +royalty-free, non-exclusive license under patents it now or hereafter +owns or controls to make, have made, use, import, offer to sell and +sell ("Utilize") this software, but solely to the extent that any +such patent is necessary to Utilize the software alone, or in +combination with an operating system licensed under an approved Open +Source license as listed by the Open Source Initiative at +http://opensource.org/licenses. The patent license shall not apply to +any other combinations which include this software. No hardware per +se is licensed hereunder. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e1.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e1.bin new file mode 100755 index 0000000000000..829bdc519ca21 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e1.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e2.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e2.bin new file mode 100755 index 0000000000000..292767d6a2e04 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7603_e2.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e1.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e1.bin new file mode 100644 index 0000000000000..72aed6f475034 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e1.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e2.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e2.bin new file mode 100644 index 0000000000000..3fdbbd4d02134 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7628_e2.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7662.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7662.bin new file mode 120000 index 0000000000000..84657da49dd9d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/firmware/mt7662.bin @@ -0,0 +1 @@ +mt7662_firmware_e3_v1.9.bin \ No newline at end of file diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.7.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.7.bin new file mode 100755 index 0000000000000..101fc8394f396 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.7.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.9.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.9.bin new file mode 100755 index 0000000000000..26c6fbb278bc2 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_firmware_e3_v1.9.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7662_patch_e3_hdr_v0.0.2_P69.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_patch_e3_hdr_v0.0.2_P69.bin new file mode 100755 index 0000000000000..10b245e9c1784 Binary files /dev/null and b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_patch_e3_hdr_v0.0.2_P69.bin differ diff --git a/drivers/net/wireless/mediatek/mt76/firmware/mt7662_rom_patch.bin b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_rom_patch.bin new file mode 120000 index 0000000000000..846facbbd2f6e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/firmware/mt7662_rom_patch.bin @@ -0,0 +1 @@ +mt7662_patch_e3_hdr_v0.0.2_P69.bin \ No newline at end of file diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c new file mode 100644 index 0000000000000..a0e5608e7ad7f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "mt76.h" +#include + +#define CHAN2G(_idx, _freq) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +#define CHAN5G(_idx, _freq) { \ + .band = NL80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +static const struct ieee80211_channel mt76_channels_2ghz[] = { + CHAN2G(1, 2412), + CHAN2G(2, 2417), + CHAN2G(3, 2422), + CHAN2G(4, 2427), + CHAN2G(5, 2432), + CHAN2G(6, 2437), + CHAN2G(7, 2442), + CHAN2G(8, 2447), + CHAN2G(9, 2452), + CHAN2G(10, 2457), + CHAN2G(11, 2462), + CHAN2G(12, 2467), + CHAN2G(13, 2472), + CHAN2G(14, 2484), +}; + +static const struct ieee80211_channel mt76_channels_5ghz[] = { + CHAN5G(36, 5180), + CHAN5G(40, 5200), + CHAN5G(44, 5220), + CHAN5G(48, 5240), + + CHAN5G(52, 5260), + CHAN5G(56, 5280), + CHAN5G(60, 5300), + CHAN5G(64, 5320), + + CHAN5G(100, 5500), + CHAN5G(104, 5520), + CHAN5G(108, 5540), + CHAN5G(112, 5560), + CHAN5G(116, 5580), + CHAN5G(120, 5600), + CHAN5G(124, 5620), + CHAN5G(128, 5640), + CHAN5G(132, 5660), + CHAN5G(136, 5680), + CHAN5G(140, 5700), + + CHAN5G(149, 5745), + CHAN5G(153, 5765), + CHAN5G(157, 5785), + CHAN5G(161, 5805), + CHAN5G(165, 5825), +}; + +static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { + { .throughput = 0 * 1024, .blink_time = 334 }, + { .throughput = 1 * 1024, .blink_time = 260 }, + { .throughput = 5 * 1024, .blink_time = 220 }, + { .throughput = 10 * 1024, .blink_time = 190 }, + { .throughput = 20 * 1024, .blink_time = 170 }, + { .throughput = 50 * 1024, .blink_time = 150 }, + { .throughput = 70 * 1024, .blink_time = 130 }, + { .throughput = 100 * 1024, .blink_time = 110 }, + { .throughput = 200 * 1024, .blink_time = 80 }, + { .throughput = 300 * 1024, .blink_time = 50 }, +}; + +static int mt76_led_init(struct mt76_dev *dev) +{ + struct device_node *np = dev->dev->of_node; + struct ieee80211_hw *hw = dev->hw; + int led_pin; + + if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + return 0; + + snprintf(dev->led_name, sizeof(dev->led_name), + "mt76-%s", wiphy_name(hw->wiphy)); + + dev->led_cdev.name = dev->led_name; + dev->led_cdev.default_trigger = + ieee80211_create_tpt_led_trigger(hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, + mt76_tpt_blink, + ARRAY_SIZE(mt76_tpt_blink)); + + np = of_get_child_by_name(np, "led"); + if (np) { + if (!of_property_read_u32(np, "led-sources", &led_pin)) + dev->led_pin = led_pin; + dev->led_al = of_property_read_bool(np, "led-active-low"); + } + + return devm_led_classdev_register(dev->dev, &dev->led_cdev); +} + +static int +mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, + const struct ieee80211_channel *chan, int n_chan, + struct ieee80211_rate *rates, int n_rates, bool vht) +{ + struct ieee80211_supported_band *sband = &msband->sband; + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + void *chanlist; + u16 mcs_map; + int size; + + size = n_chan * sizeof(*chan); + chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); + if (!chanlist) + return -ENOMEM; + + msband->chan = devm_kzalloc(dev->dev, n_chan * sizeof(*msband->chan), + GFP_KERNEL); + if (!msband->chan) + return -ENOMEM; + + sband->channels = chanlist; + sband->n_channels = n_chan; + sband->bitrates = rates; + sband->n_bitrates = n_rates; + dev->chandef.chan = &sband->channels[0]; + + ht_cap = &sband->ht_cap; + ht_cap->ht_supported = true; + ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + ht_cap->mcs.rx_mask[0] = 0xff; + ht_cap->mcs.rx_mask[1] = 0xff; + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + + if (!vht) + return 0; + + vht_cap = &sband->vht_cap; + vht_cap->vht_supported = true; + + mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) | + (IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) | + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2)); + + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_SHORT_GI_80; + + return 0; +} + +static int +mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, + int n_rates) +{ + dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband; + + return mt76_init_sband(dev, &dev->sband_2g, + mt76_channels_2ghz, + ARRAY_SIZE(mt76_channels_2ghz), + rates, n_rates, false); +} + +static int +mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, + int n_rates, bool vht) +{ + dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband; + + return mt76_init_sband(dev, &dev->sband_5g, + mt76_channels_5ghz, + ARRAY_SIZE(mt76_channels_5ghz), + rates, n_rates, vht); +} + +static void +mt76_check_sband(struct mt76_dev *dev, int band) +{ + struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band]; + bool found = false; + int i; + + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; + + found = true; + break; + } + + if (found) + return; + + sband->n_channels = 0; + dev->hw->wiphy->bands[band] = NULL; +} + +int mt76_register_device(struct mt76_dev *dev, bool vht, + struct ieee80211_rate *rates, int n_rates) +{ + struct ieee80211_hw *hw = dev->hw; + struct wiphy *wiphy = hw->wiphy; + int ret; + + dev_set_drvdata(dev->dev, dev); + + spin_lock_init(&dev->lock); + spin_lock_init(&dev->cc_lock); + INIT_LIST_HEAD(&dev->txwi_cache); + + SET_IEEE80211_DEV(hw, dev->dev); + SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); + + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); + + wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + + hw->txq_data_size = sizeof(struct mt76_txq); + hw->max_tx_fragments = 16; + + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, PS_NULLFUNC_STACK); + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, TX_AMSDU); + ieee80211_hw_set(hw, TX_FRAG_LIST); + ieee80211_hw_set(hw, MFP_CAPABLE); + + wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + + if (dev->cap.has_2ghz) { + ret = mt76_init_sband_2g(dev, rates, n_rates); + if (ret) + return ret; + } + + if (dev->cap.has_5ghz) { + ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); + if (ret) + return ret; + } + + wiphy_read_of_freq_limits(dev->hw->wiphy); + mt76_check_sband(dev, NL80211_BAND_2GHZ); + mt76_check_sband(dev, NL80211_BAND_5GHZ); + + ret = mt76_led_init(dev); + if (ret) + return ret; + + return ieee80211_register_hw(hw); +} +EXPORT_SYMBOL_GPL(mt76_register_device); + +void mt76_unregister_device(struct mt76_dev *dev) +{ + struct ieee80211_hw *hw = dev->hw; + + ieee80211_unregister_hw(hw); + mt76_tx_free(dev); +} +EXPORT_SYMBOL_GPL(mt76_unregister_device); + +void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) +{ + if (!test_bit(MT76_STATE_RUNNING, &dev->state)) { + dev_kfree_skb(skb); + return; + } + + __skb_queue_tail(&dev->rx_skb[q], skb); +} +EXPORT_SYMBOL_GPL(mt76_rx); + +void mt76_set_channel(struct mt76_dev *dev) +{ + struct ieee80211_hw *hw = dev->hw; + struct cfg80211_chan_def *chandef = &hw->conf.chandef; + struct mt76_channel_state *state; + bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + dev->chandef = *chandef; + + if (!offchannel) + dev->main_chan = chandef->chan; + + if (chandef->chan != dev->main_chan) { + state = mt76_channel_state(dev, chandef->chan); + memset(state, 0, sizeof(*state)); + } +} +EXPORT_SYMBOL_GPL(mt76_set_channel); + +int mt76_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct mt76_dev *dev = hw->priv; + struct mt76_sband *sband; + struct ieee80211_channel *chan; + struct mt76_channel_state *state; + int ret = 0; + + if (idx == 0 && dev->drv->update_survey) + dev->drv->update_survey(dev); + + sband = &dev->sband_2g; + if (idx >= sband->sband.n_channels) { + idx -= sband->sband.n_channels; + sband = &dev->sband_5g; + } + + if (idx >= sband->sband.n_channels) + return -ENOENT; + + chan = &sband->sband.channels[idx]; + state = mt76_channel_state(dev, chan); + + memset(survey, 0, sizeof(*survey)); + survey->channel = chan; + survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; + if (chan == dev->main_chan) + survey->filled |= SURVEY_INFO_IN_USE; + + spin_lock_bh(&dev->cc_lock); + survey->time = div_u64(state->cc_active, 1000); + survey->time_busy = div_u64(state->cc_busy, 1000); + spin_unlock_bh(&dev->cc_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_get_survey); + +void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) + ieee80211_rx_napi(dev->hw, NULL, skb, &dev->napi[q]); +} diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c new file mode 100644 index 0000000000000..09a14dead6e37 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76.h" +#include "trace.h" + +static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) +{ + u32 val; + + val = ioread32(dev->regs + offset); + trace_reg_rr(dev, offset, val); + + return val; +} + +static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + trace_reg_wr(dev, offset, val); + iowrite32(val, dev->regs + offset); +} + +static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) +{ + val |= mt76_mmio_rr(dev, offset) & ~mask; + mt76_mmio_wr(dev, offset, val); + return val; +} + +static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data, + int len) +{ + __iowrite32_copy(dev->regs + offset, data, len >> 2); +} + +void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) +{ + static const struct mt76_bus_ops mt76_mmio_ops = { + .rr = mt76_mmio_rr, + .rmw = mt76_mmio_rmw, + .wr = mt76_mmio_wr, + .copy = mt76_mmio_copy, + }; + + dev->bus = &mt76_mmio_ops; + dev->regs = regs; +} +EXPORT_SYMBOL_GPL(mt76_mmio_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h new file mode 100644 index 0000000000000..aa0880bbea7f2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76_H +#define __MT76_H + +#include +#include +#include +#include +#include +#include +#include "util.h" + +#define MT_TX_RING_SIZE 256 +#define MT_MCU_RING_SIZE 32 +#define MT_RX_BUF_SIZE 2048 + +struct mt76_dev; + +struct mt76_bus_ops { + u32 (*rr)(struct mt76_dev *dev, u32 offset); + void (*wr)(struct mt76_dev *dev, u32 offset, u32 val); + u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val); + void (*copy)(struct mt76_dev *dev, u32 offset, const void *data, + int len); +}; + +enum mt76_txq_id { + MT_TXQ_VO = IEEE80211_AC_VO, + MT_TXQ_VI = IEEE80211_AC_VI, + MT_TXQ_BE = IEEE80211_AC_BE, + MT_TXQ_BK = IEEE80211_AC_BK, + MT_TXQ_PSD, + MT_TXQ_MCU, + MT_TXQ_BEACON, + MT_TXQ_CAB, + __MT_TXQ_MAX +}; + +enum mt76_rxq_id { + MT_RXQ_MAIN, + MT_RXQ_MCU, + __MT_RXQ_MAX +}; + +struct mt76_queue_buf { + dma_addr_t addr; + int len; +}; + +struct mt76_queue_entry { + union { + void *buf; + struct sk_buff *skb; + }; + struct mt76_txwi_cache *txwi; + bool schedule; +}; + +struct mt76_queue_regs { + u32 desc_base; + u32 ring_size; + u32 cpu_idx; + u32 dma_idx; +} __packed __aligned(4); + +struct mt76_queue { + struct mt76_queue_regs __iomem *regs; + + spinlock_t lock; + struct mt76_queue_entry *entry; + struct mt76_desc *desc; + + struct list_head swq; + int swq_queued; + + u16 head; + u16 tail; + int ndesc; + int queued; + int buf_size; + + u8 buf_offset; + u8 hw_idx; + + dma_addr_t desc_dma; + struct sk_buff *rx_head; +}; + +struct mt76_queue_ops { + int (*init)(struct mt76_dev *dev); + + int (*alloc)(struct mt76_dev *dev, struct mt76_queue *q); + + int (*add_buf)(struct mt76_dev *dev, struct mt76_queue *q, + struct mt76_queue_buf *buf, int nbufs, u32 info, + struct sk_buff *skb, void *txwi); + + void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush, + int *len, u32 *info, bool *more); + + void (*rx_reset)(struct mt76_dev *dev, enum mt76_rxq_id qid); + + void (*tx_cleanup)(struct mt76_dev *dev, enum mt76_txq_id qid, + bool flush); + + void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); +}; + +struct mt76_wcid { + u8 idx; + u8 hw_key_idx; + + __le16 tx_rate; + bool tx_rate_set; + u8 tx_rate_nss; + s8 max_txpwr_adj; +}; + +struct mt76_txq { + struct list_head list; + struct mt76_queue *hwq; + struct mt76_wcid *wcid; + + struct sk_buff_head retry_q; + + u16 agg_ssn; + bool send_bar; + bool aggr; +}; + +struct mt76_txwi_cache { + u32 txwi[8]; + dma_addr_t dma_addr; + struct list_head list; +}; + +enum { + MT76_STATE_INITIALIZED, + MT76_STATE_RUNNING, + MT76_SCANNING, + MT76_RESET, +}; + +struct mt76_hw_cap { + bool has_2ghz; + bool has_5ghz; +}; + +struct mt76_driver_ops { + u16 txwi_size; + + void (*update_survey)(struct mt76_dev *dev); + + int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, + struct ieee80211_sta *sta, u32 *tx_info); + + void (*tx_complete_skb)(struct mt76_dev *dev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); + + void (*rx_skb)(struct mt76_dev *dev, enum mt76_rxq_id q, + struct sk_buff *skb); + + void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q); +}; + +struct mt76_channel_state { + u64 cc_active; + u64 cc_busy; +}; + +struct mt76_sband { + struct ieee80211_supported_band sband; + struct mt76_channel_state *chan; +}; + +struct mt76_dev { + struct ieee80211_hw *hw; + struct cfg80211_chan_def chandef; + struct ieee80211_channel *main_chan; + + spinlock_t lock; + spinlock_t cc_lock; + const struct mt76_bus_ops *bus; + const struct mt76_driver_ops *drv; + void __iomem *regs; + struct device *dev; + + struct net_device napi_dev; + struct napi_struct napi[__MT_RXQ_MAX]; + struct sk_buff_head rx_skb[__MT_RXQ_MAX]; + + struct list_head txwi_cache; + struct mt76_queue q_tx[__MT_TXQ_MAX]; + struct mt76_queue q_rx[__MT_RXQ_MAX]; + const struct mt76_queue_ops *queue_ops; + + u8 macaddr[ETH_ALEN]; + u32 rev; + unsigned long state; + + struct mt76_sband sband_2g; + struct mt76_sband sband_5g; + struct debugfs_blob_wrapper eeprom; + struct debugfs_blob_wrapper otp; + struct mt76_hw_cap cap; + + u32 debugfs_reg; + + struct led_classdev led_cdev; + char led_name[32]; + bool led_al; + u8 led_pin; +}; + +enum mt76_phy_type { + MT_PHY_TYPE_CCK, + MT_PHY_TYPE_OFDM, + MT_PHY_TYPE_HT, + MT_PHY_TYPE_HT_GF, + MT_PHY_TYPE_VHT, +}; + +struct mt76_rate_power { + union { + struct { + s8 cck[4]; + s8 ofdm[8]; + s8 ht[16]; + s8 vht[10]; + }; + s8 all[38]; + }; +}; + +#define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) +#define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) +#define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) +#define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__) + +#define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val) +#define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0) + +#define mt76_get_field(_dev, _reg, _field) \ + FIELD_GET(_field, mt76_rr(dev, _reg)) + +#define mt76_rmw_field(_dev, _reg, _field, _val) \ + mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) + +#define mt76_hw(dev) (dev)->mt76.hw + +bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, + int timeout); + +#define mt76_poll(dev, ...) __mt76_poll(&((dev)->mt76), __VA_ARGS__) + +bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, + int timeout); + +#define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__) + +void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); + +static inline u16 mt76_chip(struct mt76_dev *dev) +{ + return dev->rev >> 16; +} + +static inline u16 mt76_rev(struct mt76_dev *dev) +{ + return dev->rev & 0xffff; +} + +#define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) +#define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) + +#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) +#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) + +static inline struct mt76_channel_state * +mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) +{ + struct mt76_sband *msband; + int idx; + + if (c->band == NL80211_BAND_2GHZ) + msband = &dev->sband_2g; + else + msband = &dev->sband_5g; + + idx = c - &msband->sband.channels[0]; + return &msband->chan[idx]; +} + +int mt76_register_device(struct mt76_dev *dev, bool vht, + struct ieee80211_rate *rates, int n_rates); +void mt76_unregister_device(struct mt76_dev *dev); + +struct dentry *mt76_register_debugfs(struct mt76_dev *dev); + +int mt76_eeprom_init(struct mt76_dev *dev, int len); +void mt76_eeprom_override(struct mt76_dev *dev); + +static inline struct ieee80211_txq * +mtxq_to_txq(struct mt76_txq *mtxq) +{ + void *ptr = mtxq; + + return container_of(ptr, struct ieee80211_txq, drv_priv); +} + +int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta); + +void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb); +void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, + struct mt76_wcid *wcid, struct sk_buff *skb); +void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); +void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq); +void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq); +void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, + bool send_bar); +void mt76_txq_schedule(struct mt76_dev *dev, struct mt76_queue *hwq); +void mt76_txq_schedule_all(struct mt76_dev *dev); +void mt76_release_buffered_frames(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u16 tids, int nframes, + enum ieee80211_frame_release_type reason, + bool more_data); +void mt76_set_channel(struct mt76_dev *dev); +int mt76_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + +/* internal */ +void mt76_tx_free(struct mt76_dev *dev); +void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t); +void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603.h new file mode 100644 index 0000000000000..ddb600888e108 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT7603_H +#define __MT7603_H + +#include "mt76.h" +#include "mt7603_regs.h" +#include + +#define MT7603_MAX_INTERFACES 4 +#define MT7603_WTBL_SIZE 128 +#define MT7603_WTBL_RESERVED (MT7603_WTBL_SIZE - 1) +#define MT7603_WTBL_STA (MT7603_WTBL_RESERVED - MT7603_MAX_INTERFACES) + +#define MT7603_RATE_RETRY 2 + +#define MT7603_RX_RING_SIZE 128 + +#define MT7603_FIRMWARE_E1 "mt7603_e1.bin" +#define MT7603_FIRMWARE_E2 "mt7603_e2.bin" +#define MT7628_FIRMWARE_E1 "mt7628_e1.bin" +#define MT7628_FIRMWARE_E2 "mt7628_e2.bin" + +#define MT7603_EEPROM_SIZE 1024 + +#define MT_AGG_SIZE_LIMIT(n) ((4 + 2 * (n & 1)) << (n / 2)) + +#define MT7603_PRE_TBTT_TIME 5000 /* ms */ + +#define MT7603_STATUS_TIMEOUT (10 * HZ) +#define MT7603_WATCHDOG_TIME 100 /* ms */ +#define MT7603_WATCHDOG_TIMEOUT 10 /* number of checks */ + +enum { + MT7603_REV_E1 = 0x00, + MT7603_REV_E2 = 0x10, + MT7628_REV_E1 = 0x8a00, +}; + +enum mt7603_bw { + MT_BW_20, + MT_BW_40, + MT_BW_80, +}; + +struct mt7603_mcu { + struct mutex mutex; + + wait_queue_head_t wait; + struct sk_buff_head res_q; + + struct mt76_queue q_rx; + u32 msg_seq; + + bool running; +}; + +struct mt7603_sta { + struct mt76_wcid wcid; /* must be first */ + + struct ieee80211_tx_rate rates[8]; + int rate_count; + int n_rates; + bool rate_probe; + + int pid; + + int ampdu_count; + int ampdu_tx_count; + int ampdu_acked; +}; + +struct mt7603_vif { + u8 idx; + + struct mt7603_sta sta; +}; + +#define MT7603_CB_DMA_DONE BIT(0) +#define MT7603_CB_TXS_DONE BIT(1) +#define MT7603_CB_TXS_FAILED BIT(2) + +enum mt7603_reset_cause { + RESET_CAUSE_TX_HANG, + RESET_CAUSE_TX_BUSY, + RESET_CAUSE_RX_BUSY, + RESET_CAUSE_BEACON_STUCK, + RESET_CAUSE_RX_PSE_BUSY, + __RESET_CAUSE_MAX +}; + +struct mt7603_cb { + unsigned long jiffies; + u8 wcid; + u8 pktid; + u8 flags; +}; + +struct mt7603_dev { + struct mt76_dev mt76; /* must be first */ + + struct mutex mutex; + + u32 irqmask; + spinlock_t irq_lock; + + u32 rxfilter; + + u8 vif_mask; + unsigned long wcid_mask[MT7603_WTBL_SIZE / BITS_PER_LONG]; + struct mt76_wcid __rcu *wcid[MT7603_WTBL_SIZE]; + + spinlock_t status_lock; + struct sk_buff_head status_list; + + struct mt7603_sta global_sta; + + u8 rx_chains; + u8 tx_chains; + + u8 rssi_offset[3]; + + u8 slottime; + s16 coverage_class; + + int beacon_int; + + struct mt7603_mcu mcu; + struct mt76_queue q_rx; + + u8 beacon_mask; + + u8 beacon_check; + u8 tx_hang_check; + u8 tx_dma_check; + u8 rx_dma_check; + u8 rx_pse_check; + + u16 tx_dma_idx[4]; + u16 rx_dma_idx; + + unsigned int reset_cause[__RESET_CAUSE_MAX]; + + struct delayed_work mac_work; + struct tasklet_struct tx_tasklet; + struct tasklet_struct pre_tbtt_tasklet; +}; + +extern const struct ieee80211_ops mt7603_ops; +extern struct pci_driver mt7603_pci_driver; +extern struct platform_driver mt76_wmac_driver; + +static inline bool is_mt7603(struct mt7603_dev *dev) +{ + return mt76xx_chip(dev) == 0x7603; +} + +static inline bool is_mt7628(struct mt7603_dev *dev) +{ + return mt76xx_chip(dev) == 0x7628; +} + +/* need offset to prevent conflict with ampdu_ack_len */ +#define MT_RATE_DRIVER_DATA_OFFSET 4 + +static inline struct mt7603_cb *mt7603_skb_cb(struct sk_buff *skb) +{ + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.ampdu_len) >= + (offsetof(struct ieee80211_tx_info, rate_driver_data) + + MT_RATE_DRIVER_DATA_OFFSET)); + BUILD_BUG_ON(sizeof(struct mt7603_cb) + MT_RATE_DRIVER_DATA_OFFSET > + IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE); + return ((void *) IEEE80211_SKB_CB(skb)->rate_driver_data) + + MT_RATE_DRIVER_DATA_OFFSET; +} + +u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr); + +struct mt7603_dev *mt7603_alloc_device(struct device *pdev); +irqreturn_t mt7603_irq_handler(int irq, void *dev_instance); + +int mt7603_register_device(struct mt7603_dev *dev); +void mt7603_unregister_device(struct mt7603_dev *dev); +int mt7603_eeprom_init(struct mt7603_dev *dev); +int mt7603_dma_init(struct mt7603_dev *dev); +void mt7603_dma_cleanup(struct mt7603_dev *dev); +int mt7603_mcu_init(struct mt7603_dev *dev); +int mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb); +void mt7603_mcu_rx_event(struct mt7603_dev *dev, struct sk_buff *skb); +void mt7603_init_debugfs(struct mt7603_dev *dev); + +void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set); + +static inline void mt7603_irq_enable(struct mt7603_dev *dev, u32 mask) +{ + mt7603_set_irq_mask(dev, 0, mask); +} + +static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) +{ + mt7603_set_irq_mask(dev, mask, 0); +} + +void mt7603_mac_reset(struct mt7603_dev *dev); +void mt7603_mac_dma_start(struct mt7603_dev *dev); +void mt7603_mac_start(struct mt7603_dev *dev); +void mt7603_mac_stop(struct mt7603_dev *dev); +void mt7603_mac_work(struct work_struct *work); +void mt7603_mac_set_timing(struct mt7603_dev *dev); +void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval); +int mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb); +void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); +struct sk_buff *mt7603_mac_status_skb(struct mt7603_dev *dev, + struct mt7603_sta *sta, int pktid); +void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); +void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ssn, + int ba_size); +void mt7603_mac_watchdog_reset(struct mt7603_dev *dev); + +int mt7603_mcu_set_channel(struct mt7603_dev *dev); +int mt7603_mcu_set_eeprom(struct mt7603_dev *dev); +int mt7603_mcu_set_timing(struct mt7603_dev *dev, int slot, int sifs, int rifs, + int eifs); +void mt7603_mcu_exit(struct mt7603_dev *dev); + +void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, const u8 *mac_addr); +void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx); +void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta); +void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, + struct ieee80211_tx_rate *probe_rate, + struct ieee80211_tx_rate *rates); +int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, + struct ieee80211_key_conf *key); +void mt7603_wtbl_set_ps(struct mt7603_dev *dev, int idx, bool val); + +int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); + +void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); + +void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); +void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); + +void mt7603_tbtt(struct mt7603_dev *dev); +void mt7603_pre_tbtt_tasklet(unsigned long arg); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603_beacon.c new file mode 100644 index 0000000000000..01962d40e1db6 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_beacon.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt7603.h" + +struct beacon_bc_data { + struct mt7603_dev *dev; + struct sk_buff_head q; + struct sk_buff *tail[MT7603_MAX_INTERFACES]; + int count[MT7603_MAX_INTERFACES]; +}; + +static void +mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7603_dev *dev = (struct mt7603_dev *) priv; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + struct sk_buff *skb = NULL; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_beacon_get(mt76_hw(dev), vif); + if (!skb) + return; + + mt76_tx_queue_skb(&dev->mt76, &dev->mt76.q_tx[MT_TXQ_BEACON], skb, + &mvif->sta.wcid, NULL); +} + +static void +mt7603_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct beacon_bc_data *data = priv; + struct mt7603_dev *dev = data->dev; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + struct ieee80211_tx_info *info; + struct sk_buff *skb; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->control.vif = vif; + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + mt76_skb_set_moredata(skb, true); + __skb_queue_tail(&data->q, skb); + data->tail[mvif->idx] = skb; + data->count[mvif->idx]++; +} + +void mt7603_tbtt(struct mt7603_dev *dev) +{ + u32 mask = MT_WF_ARB_CAB_START_BSSn(0) | + (MT_WF_ARB_CAB_START_BSS0n(1) * + ((1 << (MT7603_MAX_INTERFACES - 1)) - 1)); + + mt76_wr(dev, MT_WF_ARB_CAB_START, mask); +} + +void mt7603_pre_tbtt_tasklet(unsigned long arg) +{ + struct mt7603_dev *dev = (struct mt7603_dev *) arg; + struct mt76_queue *q; + struct beacon_bc_data data = {}; + struct sk_buff *skb; + int i, nframes; + + /* Flush all previous CAB queue packets */ + mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 0)); + + data.dev = dev; + __skb_queue_head_init(&data.q); + + q = &dev->mt76.q_tx[MT_TXQ_BEACON]; + spin_lock_bh(&q->lock); + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7603_update_beacon_iter, dev); + mt76_queue_kick(dev, q); + spin_unlock_bh(&q->lock); + + mt76_queue_tx_cleanup(dev, MT_TXQ_CAB, false); + + q = &dev->mt76.q_tx[MT_TXQ_CAB]; + do { + nframes = skb_queue_len(&data.q); + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7603_add_buffered_bc, &data); + } while (nframes != skb_queue_len(&data.q) && nframes < 8); + + if (!nframes) + goto out; + + for (i = 0; i < ARRAY_SIZE(data.tail); i++) { + if (!data.tail[i]) + continue; + + mt76_skb_set_moredata(data.tail[i], false); + } + + spin_lock_bh(&q->lock); + while ((skb = __skb_dequeue(&data.q)) != NULL) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + + mt76_tx_queue_skb(&dev->mt76, q, skb, &mvif->sta.wcid, NULL); + } + mt76_queue_kick(dev, q); + spin_unlock_bh(&q->lock); + + for (i = 0; i < ARRAY_SIZE(data.count); i++) + mt76_wr(dev, MT_WF_ARB_CAB_COUNT(i), + data.count[i] << MT_WF_ARB_CAB_COUNT_B0_SHIFT(i)); + +out: + mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false); + if (dev->mt76.q_tx[MT_TXQ_BEACON].queued > MT7603_MAX_INTERFACES) + dev->beacon_check++; +} + +void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval) +{ + u32 pre_tbtt = MT7603_PRE_TBTT_TIME / 64; + + if (idx >= 0) { + if (intval) + dev->beacon_mask |= BIT(idx); + else + dev->beacon_mask &= ~BIT(idx); + } + + if (!dev->beacon_mask || (!intval && idx < 0)) { + mt7603_irq_disable(dev, MT_INT_MAC_IRQ3); + mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK); + mt76_wr(dev, MT_HW_INT_MASK(3), 0); + return; + } + + dev->beacon_int = intval; + mt76_wr(dev, MT_TBTT, + FIELD_PREP(MT_TBTT_PERIOD, intval) | MT_TBTT_CAL_ENABLE); + + mt76_wr(dev, MT_TBTT_TIMER_CFG, 0x99); /* start timer */ + + mt76_rmw_field(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK, + MT_BCNQ_OPMODE_AP); + mt76_clear(dev, MT_ARB_SCR, + MT_ARB_SCR_TBTT_BCN_PRIO | MT_ARB_SCR_TBTT_BCAST_PRIO); + + mt76_wr(dev, MT_PRE_TBTT, pre_tbtt); + + mt76_set(dev, MT_HW_INT_MASK(3), + MT_HW_INT3_PRE_TBTT0 | MT_HW_INT3_TBTT0); + + mt76_set(dev, MT_WF_ARB_BCN_START, + MT_WF_ARB_BCN_START_BSSn(0) | + ((dev->beacon_mask >> 1) * MT_WF_ARB_BCN_START_BSS0n(1))); + mt7603_irq_enable(dev, MT_INT_MAC_IRQ3); + + if (dev->beacon_mask & ~BIT(0)) + mt76_set(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN); + else + mt76_clear(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_core.c b/drivers/net/wireless/mediatek/mt76/mt7603_core.c new file mode 100644 index 0000000000000..1d16258e97466 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_core.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt7603.h" + +void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->irq_lock, flags); + dev->irqmask &= ~clear; + dev->irqmask |= set; + mt76_wr(dev, MT_INT_MASK_CSR, dev->irqmask); + spin_unlock_irqrestore(&dev->irq_lock, flags); +} + +void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + mt7603_irq_enable(dev, MT_INT_RX_DONE(q)); +} + +irqreturn_t mt7603_irq_handler(int irq, void *dev_instance) +{ + struct mt7603_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) + return IRQ_NONE; + + intr &= dev->irqmask; + + if (intr & MT_INT_MAC_IRQ3) { + u32 hwintr = mt76_rr(dev, MT_HW_INT_STATUS(3)); + mt76_wr(dev, MT_HW_INT_STATUS(3), hwintr); + if (hwintr & MT_HW_INT3_PRE_TBTT0) + tasklet_schedule(&dev->pre_tbtt_tasklet); + if (hwintr & MT_HW_INT3_TBTT0) + mt7603_tbtt(dev); + } + + if (intr & MT_INT_TX_DONE_ALL) { + mt7603_irq_disable(dev, MT_INT_TX_DONE_ALL); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_RX_DONE(0)) { + mt7603_irq_disable(dev, MT_INT_RX_DONE(0)); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE(1)) { + mt7603_irq_disable(dev, MT_INT_RX_DONE(1)); + napi_schedule(&dev->mt76.napi[1]); + } + + return IRQ_HANDLED; +} + +u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr) +{ + u32 base = addr & GENMASK(31, 19); + u32 offset = addr & GENMASK(18, 0); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base); + + return MT_PCIE_REMAP_BASE_2 + offset; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603_debugfs.c new file mode 100644 index 0000000000000..f517c57da8d76 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_debugfs.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt7603.h" + +static int +mt7603_reset_read(struct seq_file *s, void *data) +{ + struct mt7603_dev *dev = dev_get_drvdata(s->private); + static const char * const reset_cause_str[] = { + [RESET_CAUSE_TX_HANG] = "TX hang", + [RESET_CAUSE_TX_BUSY] = "TX DMA busy stuck", + [RESET_CAUSE_RX_BUSY] = "RX DMA busy stuck", + [RESET_CAUSE_RX_PSE_BUSY] = "RX PSE busy stuck", + [RESET_CAUSE_BEACON_STUCK] = "Beacon stuck", + }; + int i; + + for (i = 0; i < ARRAY_SIZE(reset_cause_str); i++) { + if (!reset_cause_str[i]) + continue; + + seq_printf(s, "%20s: %u\n", reset_cause_str[i], dev->reset_cause[i]); + } + + return 0; +} + +void mt7603_init_debugfs(struct mt7603_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return; + + debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir, mt7603_reset_read); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_dma.c b/drivers/net/wireless/mediatek/mt76/mt7603_dma.c new file mode 100644 index 0000000000000..e8af81b3a2c9a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_dma.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt7603.h" +#include "mt7603_mac.h" +#include "dma.h" + +int +mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb) +{ + struct mt76_queue *q = &dev->mt76.q_tx[qid]; + struct mt76_queue_buf buf; + dma_addr_t addr; + + addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(dev->mt76.dev, addr)) + return -ENOMEM; + + buf.addr = addr; + buf.len = skb->len; + spin_lock_bh(&q->lock); + mt76_queue_add_buf(dev, q, &buf, 1, 0, skb, NULL); + mt76_queue_kick(dev, q); + spin_unlock_bh(&q->lock); + + return 0; +} + +static int +mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_queue *q, + int idx, int n_desc) +{ + int ret; + + q->hw_idx = idx; + q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + + ret = mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt7603_irq_enable(dev, MT_INT_TX_DONE(idx)); + + return 0; +} + +void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + __le32 *rxd = (__le32 *) skb->data; + __le32 *end = (__le32 *) &skb->data[skb->len]; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch(type) { + case PKT_TYPE_TXS: + for (rxd++; rxd + 5 <= end; rxd += 5) + mt7603_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; + case PKT_TYPE_RX_EVENT: + mt7603_mcu_rx_event(dev, skb); + return; + case PKT_TYPE_NORMAL: + if (mt7603_mac_fill_rx(dev, skb) == 0) { + mt76_rx(&dev->mt76, q, skb); + return; + } + /* fall through */ + default: + dev_kfree_skb(skb); + break; + } +} + +static int +mt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q, + int idx, int n_desc, int bufsize) +{ + int ret; + + q->regs = dev->mt76.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + q->buf_size = bufsize; + + ret = mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt7603_irq_enable(dev, MT_INT_RX_DONE(idx)); + + return 0; +} + +static void +mt7603_tx_tasklet(unsigned long data) +{ + struct mt7603_dev *dev = (struct mt7603_dev *) data; + int i; + + dev->tx_dma_check = 0; + for (i = MT_TXQ_MCU; i >= 0; i--) + mt76_queue_tx_cleanup(dev, i, false); + + mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL); +} + +int mt7603_dma_init(struct mt7603_dev *dev) +{ + static const u8 wmm_queue_map[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + int ret; + int i; + + mt76_dma_attach(&dev->mt76); + + init_waitqueue_head(&dev->mcu.wait); + skb_queue_head_init(&dev->mcu.res_q); + + tasklet_init(&dev->tx_tasklet, mt7603_tx_tasklet, (unsigned long) dev); + + mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_EN | + MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); + + mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); + + for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { + ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[i], wmm_queue_map[i], + MT_TX_RING_SIZE); + if (ret) + return ret; + } + + ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD], + MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); + if (ret) + return ret; + + ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], + MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); + if (ret) + return ret; + + ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_BEACON], + MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE); + if (ret) + return ret; + + ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_CAB], + MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE); + if (ret) + return ret; + + ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, + MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); + if (ret) + return ret; + + ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, + MT7603_RX_RING_SIZE, MT_RX_BUF_SIZE); + if (ret) + return ret; + + mt76_wr(dev, MT_DELAY_INT_CFG, 0); + return mt76_init_queues(dev); +} + +void mt7603_dma_cleanup(struct mt7603_dev *dev) +{ + mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_EN | + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); + + tasklet_kill(&dev->tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.c new file mode 100644 index 0000000000000..00899a09a4902 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt7603.h" +#include "mt7603_eeprom.h" + +static int +mt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data) +{ + u32 val; + int i; + + val = mt76_rr(dev, base + MT_EFUSE_CTRL); + val &= ~(MT_EFUSE_CTRL_AIN | + MT_EFUSE_CTRL_MODE); + val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); + val |= MT_EFUSE_CTRL_KICK; + mt76_wr(dev, base + MT_EFUSE_CTRL, val); + + if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) + return -ETIMEDOUT; + + udelay(2); + + val = mt76_rr(dev, base + MT_EFUSE_CTRL); + if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT || + WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) { + memset(data, 0xff, 16); + return 0; + } + + for (i = 0; i < 4; i++) { + val = mt76_rr(dev, base + MT_EFUSE_RDATA(i)); + put_unaligned_le32(val, data + 4 * i); + } + + return 0; +} + +static int +mt7603_efuse_init(struct mt7603_dev *dev) +{ + u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE); + int len = MT7603_EEPROM_SIZE; + void *buf; + int ret, i; + + if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY) + return 0; + + dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL); + dev->mt76.otp.size = len; + if (!dev->mt76.otp.data) + return -ENOMEM; + + buf = dev->mt76.otp.data; + for (i = 0; i + 16 <= len; i += 16) { + ret = mt7603_efuse_read(dev, base, i, buf + i); + if (ret) + return ret; + } + + return 0; +} + +static bool +mt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse) +{ + if (!efuse[MT_EE_TEMP_SENSOR_CAL]) + return false; + + if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0) + return false; + + if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0) + return false; + + if (!efuse[MT_EE_CP_FT_VERSION]) + return false; + + if (!efuse[MT_EE_XTAL_FREQ_OFFSET]) + return false; + + if (!efuse[MT_EE_XTAL_WF_RFCAL]) + return false; + + return true; +} + + +static void +mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse) +{ + static const u8 cal_free_bytes[] = { + MT_EE_TEMP_SENSOR_CAL, + MT_EE_TX_POWER_1_START_2G, + MT_EE_TX_POWER_1_START_2G + 1, + MT_EE_CP_FT_VERSION, + MT_EE_XTAL_FREQ_OFFSET, + MT_EE_XTAL_WF_RFCAL, + /* Skip for MT7628 */ + MT_EE_TX_POWER_0_START_2G, + MT_EE_TX_POWER_0_START_2G + 1, + }; + u8 *eeprom = dev->mt76.eeprom.data; + int n = ARRAY_SIZE(cal_free_bytes); + int i; + + if (!mt7603_has_cal_free_data(dev, efuse)) + return; + + if (is_mt7628(dev)) + n -= 2; + + for (i = 0; i < n; i++) { + int offset = cal_free_bytes[i]; + eeprom[offset] = efuse[offset]; + } +} + + +static int +mt7603_eeprom_load(struct mt7603_dev *dev) +{ + int ret; + + ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE); + if (ret < 0) + return ret; + + return mt7603_efuse_init(dev); +} + +static int mt7603_check_eeprom(struct mt76_dev *dev) +{ + u16 val = get_unaligned_le16(dev->eeprom.data); + + switch (val) { + case 0x7628: + case 0x7603: + return 0; + default: + return -EINVAL; + } +} + + +int mt7603_eeprom_init(struct mt7603_dev *dev) +{ + int ret; + + ret = mt7603_eeprom_load(dev); + if (ret < 0) + return ret; + + if (mt7603_check_eeprom(&dev->mt76) == 0) + mt7603_apply_cal_free_data(dev, dev->mt76.otp.data); + else + memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, + MT7603_EEPROM_SIZE); + + dev->mt76.cap.has_2ghz = true; + memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, + ETH_ALEN); + + mt76_eeprom_override(&dev->mt76); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.h new file mode 100644 index 0000000000000..b740341768b7c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_eeprom.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT7603_EEPROM_H +#define __MT7603_EEPROM_H + +#include "mt7603.h" + +enum mt7603_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_NIC_CONF_0 = 0x034, + MT_EE_NIC_CONF_1 = 0x036, + MT_EE_NIC_CONF_2 = 0x042, + + MT_EE_XTAL_TRIM_1 = 0x03a, + + MT_EE_RSSI_OFFSET_2G = 0x046, + MT_EE_WIFI_RF_SETTING = 0x048, + MT_EE_RSSI_OFFSET_5G = 0x04a, + + MT_EE_TX_POWER_DELTA_BW40 = 0x050, + MT_EE_TX_POWER_DELTA_BW80 = 0x052, + + MT_EE_TX_POWER_EXT_PA_5G = 0x054, + + MT_EE_TEMP_SENSOR_CAL = 0x055, + + MT_EE_TX_POWER_0_START_2G = 0x056, + MT_EE_TX_POWER_1_START_2G = 0x05c, + + /* used as byte arrays */ +#define MT_TX_POWER_GROUP_SIZE_5G 5 +#define MT_TX_POWER_GROUPS_5G 6 + MT_EE_TX_POWER_0_START_5G = 0x062, + + MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074, + MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076, + + MT_EE_TX_POWER_1_START_5G = 0x080, + + + MT_EE_TX_POWER_CCK = 0x0a0, + MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2, + MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4, + MT_EE_TX_POWER_OFDM_2G_54M = 0x0a6, + MT_EE_TX_POWER_HT_BPSK_QPSK = 0x0a8, + MT_EE_TX_POWER_HT_16_64_QAM = 0x0aa, + MT_EE_TX_POWER_HT_64_QAM = 0x0ac, + + MT_EE_ELAN_RX_MODE_GAIN = 0x0c0, + MT_EE_ELAN_RX_MODE_NF = 0x0c1, + MT_EE_ELAN_RX_MODE_P1DB = 0x0c2, + + MT_EE_ELAN_BYPASS_MODE_GAIN = 0x0c3, + MT_EE_ELAN_BYPASS_MODE_NF = 0x0c4, + MT_EE_ELAN_BYPASS_MODE_P1DB = 0x0c5, + + MT_EE_STEP_NUM_NEG_6_7 = 0x0c6, + MT_EE_STEP_NUM_NEG_4_5 = 0x0c8, + MT_EE_STEP_NUM_NEG_2_3 = 0x0ca, + MT_EE_STEP_NUM_NEG_0_1 = 0x0cc, + + MT_EE_REF_STEP_24G = 0x0ce, + + MT_EE_STEP_NUM_PLUS_1_2 = 0x0d0, + MT_EE_STEP_NUM_PLUS_3_4 = 0x0d2, + MT_EE_STEP_NUM_PLUS_5_6 = 0x0d4, + MT_EE_STEP_NUM_PLUS_7 = 0x0d6, + + MT_EE_CP_FT_VERSION = 0x0f0, + + MT_EE_XTAL_FREQ_OFFSET = 0x0f4, + MT_EE_XTAL_TRIM_2_COMP = 0x0f5, + MT_EE_XTAL_TRIM_3_COMP = 0x0f6, + MT_EE_XTAL_WF_RFCAL = 0x0f7, + + __MT_EE_MAX +}; + +enum mt7603_eeprom_source { + MT_EE_SRC_PROM, + MT_EE_SRC_EFUSE, + MT_EE_SRC_FLASH, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_init.c b/drivers/net/wireless/mediatek/mt76/mt7603_init.c new file mode 100644 index 0000000000000..94c36ff3c7e66 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_init.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt7603.h" +#include "mt7603_mac.h" +#include "mt7603_eeprom.h" + +struct mt7603_dev *mt7603_alloc_device(struct device *pdev) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = MT_TXD_SIZE, + .tx_prepare_skb = mt7603_tx_prepare_skb, + .tx_complete_skb = mt7603_tx_complete_skb, + .rx_skb = mt7603_queue_rx_skb, + .rx_poll_complete = mt7603_rx_poll_complete, + }; + struct ieee80211_hw *hw; + struct mt7603_dev *dev; + + hw = ieee80211_alloc_hw(sizeof(*dev), &mt7603_ops); + if (!hw) + return NULL; + + dev = hw->priv; + dev->mt76.dev = pdev; + dev->mt76.hw = hw; + dev->mt76.drv = &drv_ops; + + return dev; +} + +static void +mt7603_set_tmac_template(struct mt7603_dev *dev) +{ + u32 desc[5] = { + [1] = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 0xf), + [3] = MT_TXD5_SW_POWER_MGMT + }; + u32 addr; + int i; + + addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR); + addr += MT_CLIENT_TMAC_INFO_TEMPLATE; + for (i = 0; i < ARRAY_SIZE(desc); i++) + mt76_wr(dev, addr + 4 * i, desc[i]); +} + +static void +mt7603_dma_sched_init(struct mt7603_dev *dev) +{ + int page_size = 128; + int page_count; + int max_len = 1792; + int max_amsdu_len = 4096; + int max_mcu_len = 4096; + int max_beacon_len = 512 * 8 + max_len; + int max_mcast_count = 3; + int beacon_pages; + int mcu_pages; + int i; + + page_count = mt76_get_field(dev, MT_PSE_FC_P0, + MT_PSE_FC_P0_MAX_QUOTA); + beacon_pages = 4 * (max_beacon_len / page_size); + mcu_pages = max_mcu_len / page_size; + + mt76_wr(dev, MT_PSE_FRP, + FIELD_PREP(MT_PSE_FRP_P0, 7) | + FIELD_PREP(MT_PSE_FRP_P1, 6) | + FIELD_PREP(MT_PSE_FRP_P2_RQ2, 4)); + + mt76_wr(dev, MT_HIGH_PRIORITY_1, 0x55555553); + mt76_wr(dev, MT_HIGH_PRIORITY_2, 0x78555555); + + mt76_wr(dev, MT_QUEUE_PRIORITY_1, 0x2b1a096e); + mt76_wr(dev, MT_QUEUE_PRIORITY_2, 0x785f4d3c); + + mt76_wr(dev, MT_PRIORITY_MASK, 0xffffffff); + + mt76_wr(dev, MT_SCH_1, page_count | (2 << 28)); + mt76_wr(dev, MT_SCH_2, max_len / page_size); + + for (i = 0; i <= 4; i++) + mt76_wr(dev, MT_PAGE_COUNT(i), max_amsdu_len / page_size); + + mt76_wr(dev, MT_PAGE_COUNT(5), mcu_pages); + mt76_wr(dev, MT_PAGE_COUNT(7), beacon_pages); + + mt76_wr(dev, MT_PAGE_COUNT(8), + (max_mcast_count + 1) * max_len / page_size); + + mt76_wr(dev, MT_RSV_MAX_THRESH, page_count); + + if (is_mt7603(dev) && mt76xx_rev(dev) < MT7603_REV_E2) { + mt76_wr(dev, MT_GROUP_THRESH(0), page_count); + mt76_wr(dev, MT_BMAP_0, 0xffff); + } else { + mt76_wr(dev, MT_GROUP_THRESH(0), + page_count - beacon_pages - mcu_pages); + mt76_wr(dev, MT_GROUP_THRESH(1), beacon_pages); + mt76_wr(dev, MT_BMAP_0, 0x0080ff5f); + mt76_wr(dev, MT_GROUP_THRESH(2), mcu_pages); + mt76_wr(dev, MT_BMAP_1, 0x00000020); + } + + mt76_wr(dev, MT_SCH_4, 0); + + for (i = 0; i <= 15; i++) + mt76_wr(dev, MT_TXTIME_THRESH(i), 0xfffff); + + mt76_set(dev, MT_SCH_4, BIT(6)); +} + +static void +mt7603_phy_init(struct mt7603_dev *dev) +{ + int rx_chains = BIT(dev->rx_chains) - 1; + int tx_chains = dev->tx_chains - 1; + + mt76_rmw(dev, MT_WF_RMAC_RMCR, + (MT_WF_RMAC_RMCR_SMPS_MODE | + MT_WF_RMAC_RMCR_RX_STREAMS), + (FIELD_PREP(MT_WF_RMAC_RMCR_SMPS_MODE, 3) | + FIELD_PREP(MT_WF_RMAC_RMCR_RX_STREAMS, rx_chains))); + + mt76_rmw_field(dev, MT_TMAC_TCR, MT_TMAC_TCR_TX_STREAMS, + tx_chains); +} + +static void +mt7603_mac_init(struct mt7603_dev *dev) +{ + u8 bc_addr[ETH_ALEN]; + u32 addr; + int i; + + mt76_wr(dev, MT_AGG_BA_SIZE_LIMIT_0, + (MT_AGG_SIZE_LIMIT(0) << 0 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(1) << 1 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(2) << 2 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(3) << 3 * MT_AGG_BA_SIZE_LIMIT_SHIFT)); + + mt76_wr(dev, MT_AGG_BA_SIZE_LIMIT_1, + (MT_AGG_SIZE_LIMIT(4) << 0 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(5) << 1 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(6) << 2 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | + (MT_AGG_SIZE_LIMIT(7) << 3 * MT_AGG_BA_SIZE_LIMIT_SHIFT)); + + mt76_wr(dev, MT_AGG_LIMIT, + FIELD_PREP(MT_AGG_LIMIT_AC(0), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(1), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(2), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(3), 21)); + + mt76_wr(dev, MT_AGG_LIMIT_1, + FIELD_PREP(MT_AGG_LIMIT_AC(0), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(1), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(2), 21) | + FIELD_PREP(MT_AGG_LIMIT_AC(3), 21)); + + mt76_wr(dev, MT_AGG_CONTROL, + FIELD_PREP(MT_AGG_CONTROL_BAR_RATE, 0x80) | + FIELD_PREP(MT_AGG_CONTROL_CFEND_RATE, 0x69) | + MT_AGG_CONTROL_NO_BA_AR_RULE); + + mt76_wr(dev, MT_AGG_RETRY_CONTROL, + FIELD_PREP(MT_AGG_RETRY_CONTROL_BAR_LIMIT, 1) | + FIELD_PREP(MT_AGG_RETRY_CONTROL_RTS_LIMIT, 15)); + + mt76_rmw(dev, MT_DMA_DCR0, ~0xfffc, MT_RX_BUF_SIZE); + + mt76_rmw(dev, MT_DMA_VCFR0, BIT(0), BIT(13)); + mt76_rmw(dev, MT_DMA_TMCFR0, BIT(0) | BIT(1), BIT(13)); + + mt76_clear(dev, MT_WF_RMAC_TMR_PA, BIT(31)); + + mt76_set(dev, MT_WF_RMACDR, MT_WF_RMACDR_MAXLEN_20BIT); + mt76_rmw(dev, MT_WF_RMAC_MAXMINLEN, 0xffffff, 0x19000); + + mt76_wr(dev, MT_WF_RFCR1, 0); + + mt76_set(dev, MT_TMAC_TCR, MT_TMAC_TCR_RX_RIFS_MODE); + + mt7603_set_tmac_template(dev); + + /* Enable RX group to HIF */ + addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR); + mt76_set(dev, addr + MT_CLIENT_RXINF, MT_CLIENT_RXINF_RXSH_GROUPS); + + /* Enable RX group to MCU */ + mt76_set(dev, MT_DMA_DCR1, GENMASK(13, 11)); + + mt76_rmw_field(dev, MT_AGG_PCR_RTS, MT_AGG_PCR_RTS_PKT_THR, 3); + mt76_set(dev, MT_TMAC_PCR, MT_TMAC_PCR_SPE_EN); + mt76_wr(dev, MT_RXREQ, 4); + + /* Configure all rx packets to HIF */ + mt76_wr(dev, MT_DMA_RCFR0, 0xc0000000); + + /* Configure MCU txs selection with aggregation */ + mt76_wr(dev, MT_DMA_TCFR0, + FIELD_PREP(MT_DMA_TCFR_TXS_AGGR_TIMEOUT, 1) | /* 32 us */ + MT_DMA_TCFR_TXS_AGGR_COUNT); + + /* Configure HIF txs selection with aggregation */ + mt76_wr(dev, MT_DMA_TCFR1, + FIELD_PREP(MT_DMA_TCFR_TXS_AGGR_TIMEOUT, 1) | /* 32 us */ + MT_DMA_TCFR_TXS_AGGR_COUNT | /* Maximum count */ + MT_DMA_TCFR_TXS_QUEUE | /* Queue 1 */ + MT_DMA_TCFR_TXS_BIT_MAP); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_1, MT_PSE_WTBL_2_PHYS_ADDR); + + for (i = 0; i < MT7603_WTBL_SIZE; i++) + mt7603_wtbl_clear(dev, i); + + eth_broadcast_addr(bc_addr); + mt7603_wtbl_init(dev, MT7603_WTBL_RESERVED, -1, bc_addr); + dev->global_sta.wcid.idx = MT7603_WTBL_RESERVED; + rcu_assign_pointer(dev->wcid[MT7603_WTBL_RESERVED], + &dev->global_sta.wcid); + + mt76_rmw_field(dev, MT_LPON_BTEIR, MT_LPON_BTEIR_MBSS_MODE, 2); + mt76_rmw_field(dev, MT_WF_RMACDR, MT_WF_RMACDR_MBSSID_MASK, 2); + + mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7)); + mt76_wr(dev, MT_AGG_ARDCR, + FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 0) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), + max_t(int, 0, MT7603_RATE_RETRY - 2)) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7603_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7603_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7603_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7603_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7603_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7603_RATE_RETRY - 1)); + + mt76_wr(dev, MT_AGG_ARCR, + (FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | + MT_AGG_ARCR_RATE_DOWN_RATIO_EN | + FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) | + FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4))); + + mt76_set(dev, MT_WTBL_RMVTCR, MT_WTBL_RMVTCR_RX_MV_MODE); + + mt76_clear(dev, MT_SEC_SCR, MT_SEC_SCR_MASK_ORDER); + + /* Set secondary beacon time offsets */ + for (i = 0; i <= 4; i++) + mt76_rmw_field(dev, MT_LPON_SBTOR(i), MT_LPON_SBTOR_TIME_OFFSET, + (i + 1) * (20 + 4096)); +} + +static int +mt7603_init_hardware(struct mt7603_dev *dev) +{ + int ret; + + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + + ret = mt7603_eeprom_init(dev); + if (ret < 0) + return ret; + + ret = mt7603_dma_init(dev); + if (ret) + return ret; + + mt76_wr(dev, MT_WPDMA_GLO_CFG, 0x52000850); + mt7603_mac_dma_start(dev); + dev->rxfilter = mt76_rr(dev, MT_WF_RFCR); + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + + ret = mt7603_mcu_init(dev); + if (ret) + return ret; + + mt7603_dma_sched_init(dev); + mt7603_mcu_set_eeprom(dev); + mt7603_phy_init(dev); + mt7603_mac_init(dev); + + return 0; +} + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ +} + +static struct ieee80211_rate mt7603_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = MT7603_MAX_INTERFACES, + .types = BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 4, + .num_different_channels = 1, + .beacon_int_infra_match = true, + } +}; + +static void mt7603_led_set_config(struct mt76_dev *mt76, u8 delay_on, + u8 delay_off) +{ + struct mt7603_dev *dev = container_of(mt76, struct mt7603_dev, + mt76); + u32 val, addr; + + val = MT_LED_STATUS_DURATION(0xffff) | + MT_LED_STATUS_OFF(delay_off) | + MT_LED_STATUS_ON(delay_on); + + addr = mt7603_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); + mt76_wr(dev, addr, val); + addr = mt7603_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); + mt76_wr(dev, addr, val); + + val = MT_LED_CTRL_REPLAY(mt76->led_pin) | + MT_LED_CTRL_KICK(mt76->led_pin); + if (mt76->led_al) + val |= MT_LED_CTRL_POLARITY(mt76->led_pin); + addr = mt7603_reg_map(dev, MT_LED_CTRL); + mt76_wr(dev, addr, val); +} + +static int mt7603_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt7603_led_set_config(mt76, delta_on, delta_off); + return 0; +} + +static void mt7603_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + + if (!brightness) + mt7603_led_set_config(mt76, 0, 0xff); + else + mt7603_led_set_config(mt76, 0xff, 0); +} + +int mt7603_register_device(struct mt7603_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + int ret; + + mutex_init(&dev->mutex); + spin_lock_init(&dev->status_lock); + __skb_queue_head_init(&dev->status_list); + + INIT_DELAYED_WORK(&dev->mac_work, mt7603_mac_work); + tasklet_init(&dev->pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet, (unsigned long) dev); + + dev->rx_chains = 2; + dev->tx_chains = 2; + dev->slottime = 9; + + ret = mt7603_init_hardware(dev); + if (ret) + return ret; + + hw->queues = 4; + hw->max_rates = 3; + hw->max_report_rates = 7; + hw->max_rate_tries = 11; + + hw->sta_data_size = sizeof(struct mt7603_sta); + hw->vif_data_size = sizeof(struct mt7603_vif); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + + /* init led callbacks */ + dev->mt76.led_cdev.brightness_set = mt7603_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt7603_led_set_blink; + + ret = mt76_register_device(&dev->mt76, true, mt7603_rates, + ARRAY_SIZE(mt7603_rates)); + if (ret) + return ret; + + mt7603_init_debugfs(dev); + + return 0; +} + +void mt7603_unregister_device(struct mt7603_dev *dev) +{ + mt76_unregister_device(&dev->mt76); + mt7603_mac_status_skb(dev, NULL, -1); + mt7603_mcu_exit(dev); + mt7603_dma_cleanup(dev); + ieee80211_free_hw(mt76_hw(dev)); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_mac.c b/drivers/net/wireless/mediatek/mt76/mt7603_mac.c new file mode 100644 index 0000000000000..954fa6719c893 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_mac.c @@ -0,0 +1,1309 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt7603.h" +#include "mt7603_mac.h" + +#define MT_PSE_PAGE_SIZE 128 + +static u32 +mt7603_ac_queue_mask0(u32 mask) +{ + u32 ret = 0; + + ret |= GENMASK(3, 0) * !!(mask & BIT(0)); + ret |= GENMASK(8, 5) * !!(mask & BIT(1)); + ret |= GENMASK(13, 10) * !!(mask & BIT(2)); + ret |= GENMASK(19, 16) * !!(mask & BIT(3)); + return ret; +} + +static void +mt76_stop_tx_ac(struct mt7603_dev *dev, u32 mask) +{ + mt76_set(dev, MT_WF_ARB_TX_STOP_0, mt7603_ac_queue_mask0(mask)); +} + +static void +mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) +{ + mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); +} + +void mt7603_mac_set_timing(struct mt7603_dev *dev) +{ + u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 247) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 64); + u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 113) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 64); + int offset = 3 * dev->coverage_class; + u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); + int sifs; + + if (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) + sifs = 16; + else + sifs = 10; + + mt7603_mcu_set_timing(dev, dev->slottime + offset, sifs, 2, 360); + mt76_wr(dev, MT_TIMEOUT_CCK, cck + reg_offset); + mt76_wr(dev, MT_TIMEOUT_OFDM, ofdm + reg_offset); +} + +static void +mt7603_wtbl_update(struct mt7603_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); +} + +static u32 +mt7603_wtbl1_addr(int idx) +{ + return MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; +} + +static u32 +mt7603_wtbl2_addr(int idx) +{ + /* Mapped to WTBL2 */ + return MT_PCIE_REMAP_BASE_1 + idx * MT_WTBL2_SIZE; +} + +static u32 +mt7603_wtbl3_addr(int idx) +{ + u32 base = mt7603_wtbl2_addr(MT7603_WTBL_SIZE); + return base + idx * MT_WTBL3_SIZE; +} + +static u32 +mt7603_wtbl4_addr(int idx) +{ + u32 base = mt7603_wtbl3_addr(MT7603_WTBL_SIZE); + return base + idx * MT_WTBL4_SIZE; +} + +void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, + const u8 *mac_addr) +{ + const void *_mac = mac_addr; + u32 addr = mt7603_wtbl1_addr(idx); + u32 w0; + int i; + + w0 = FIELD_PREP(MT_WTBL1_W0_ADDR_HI, get_unaligned_le16(_mac + 4)); + if (vif < 0) + vif = 0; + else + w0 |= MT_WTBL1_W0_RX_CHECK_A1; + w0 |= FIELD_PREP(MT_WTBL1_W0_MUAR_IDX, vif); + + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + mt76_set(dev, addr + 0 * 4, w0); + mt76_set(dev, addr + 1 * 4, + FIELD_PREP(MT_WTBL1_W1_ADDR_LO, get_unaligned_le32(_mac))); + mt76_set(dev, addr + 2 * 4, MT_WTBL1_W2_ADMISSION_CONTROL); + + mt76_stop_tx_ac(dev, GENMASK(3, 0)); + addr = mt7603_wtbl2_addr(idx); + for (i = 0; i < MT_WTBL2_SIZE; i += 4) + mt76_wr(dev, addr + i, 0); + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); + mt76_start_tx_ac(dev, GENMASK(3, 0)); + + addr = mt7603_wtbl3_addr(idx); + for (i = 0; i < MT_WTBL3_SIZE; i += 4) + mt76_wr(dev, addr + i, 0); + + addr = mt7603_wtbl4_addr(idx); + for (i = 0; i < MT_WTBL4_SIZE; i += 4) + mt76_wr(dev, addr + i, 0); +} + +void mt7603_wtbl_set_ps(struct mt7603_dev *dev, int idx, bool val) +{ + u32 addr = mt7603_wtbl1_addr(idx); + + mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); + mt76_rmw_field(dev, addr + 3 * 4, MT_WTBL1_W3_POWER_SAVE, val); + mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); +} + +void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx) +{ + int wtbl2_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL2_SIZE; + int wtbl2_frame = idx / wtbl2_frame_size; + int wtbl2_entry = idx % wtbl2_frame_size; + + int wtbl3_base_frame = MT_WTBL3_OFFSET / MT_PSE_PAGE_SIZE; + int wtbl3_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL3_SIZE; + int wtbl3_frame = wtbl3_base_frame + idx / wtbl3_frame_size; + int wtbl3_entry = (idx % wtbl3_frame_size) * 2; + + int wtbl4_base_frame = MT_WTBL4_OFFSET / MT_PSE_PAGE_SIZE; + int wtbl4_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL4_SIZE; + int wtbl4_frame = wtbl4_base_frame + idx / wtbl4_frame_size; + int wtbl4_entry = idx % wtbl4_frame_size; + + u32 addr = MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; + int i; + + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + mt76_wr(dev, addr + 0 * 4, + MT_WTBL1_W0_RX_CHECK_A1 | + MT_WTBL1_W0_RX_CHECK_A2 | + MT_WTBL1_W0_RX_VALID); + mt76_wr(dev, addr + 1 * 4, 0); + mt76_wr(dev, addr + 2 * 4, 0); + + mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); + + mt76_wr(dev, addr + 3 * 4, + FIELD_PREP(MT_WTBL1_W3_WTBL2_FRAME_ID, wtbl2_frame) | + FIELD_PREP(MT_WTBL1_W3_WTBL2_ENTRY_ID, wtbl2_entry) | + FIELD_PREP(MT_WTBL1_W3_WTBL4_FRAME_ID, wtbl4_frame) | + MT_WTBL1_W3_I_PSM | MT_WTBL1_W3_KEEP_I_PSM); + mt76_wr(dev, addr + 4 * 4, + FIELD_PREP(MT_WTBL1_W4_WTBL3_FRAME_ID, wtbl3_frame) | + FIELD_PREP(MT_WTBL1_W4_WTBL3_ENTRY_ID, wtbl3_entry) | + FIELD_PREP(MT_WTBL1_W4_WTBL4_ENTRY_ID, wtbl4_entry)); + + mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); + + addr = mt7603_wtbl2_addr(idx); + + /* Clear BA information */ + mt76_wr(dev, addr + (15 * 4), 0); + + mt76_stop_tx_ac(dev, GENMASK(3, 0)); + for (i = 2; i <= 4; i++) + mt76_wr(dev, addr + (i * 4), 0); + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); + mt76_start_tx_ac(dev, GENMASK(3, 0)); + + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_RX_COUNT_CLEAR); + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_TX_COUNT_CLEAR); + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); +} + +void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta) +{ + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + u32 addr; + u32 val; + + addr = mt7603_wtbl1_addr(idx); + + val = mt76_rr(dev, addr + 2 * 4); + val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL; + val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR, sta->ht_cap.ampdu_factor) | + FIELD_PREP(MT_WTBL1_W2_MPDU_DENSITY, sta->ht_cap.ampdu_density) | + MT_WTBL1_W2_TXS_BAF_REPORT; + + if (sta->ht_cap.cap) + val |= MT_WTBL1_W2_HT; + if (sta->vht_cap.cap) + val |= MT_WTBL1_W2_VHT; + + mt76_wr(dev, addr + 2 * 4, val); + + addr = mt7603_wtbl2_addr(idx); + val = mt76_rr(dev, addr + 9 * 4); + val &= ~(MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | + MT_WTBL2_W9_SHORT_GI_80); + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) + val |= MT_WTBL2_W9_SHORT_GI_20; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + val |= MT_WTBL2_W9_SHORT_GI_40; + mt76_wr(dev, addr + 9 * 4, val); +} + +void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid) +{ + mt76_wr(dev, MT_BA_CONTROL_0, get_unaligned_le32(addr)); + mt76_wr(dev, MT_BA_CONTROL_1, + (get_unaligned_le16(addr + 4) | + FIELD_PREP(MT_BA_CONTROL_1_TID, tid) | + MT_BA_CONTROL_1_RESET)); +} + +void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ssn, + int ba_size) +{ + u32 addr = mt7603_wtbl2_addr(wcid); + u32 tid_mask = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | + (MT_WTBL2_W15_BA_WIN_SIZE << + (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT)); + u32 tid_val; + int i; + + if (ba_size < 0) { + /* disable */ + mt76_clear(dev, addr + (15 * 4), tid_mask); + return; + } + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + mt7603_mac_stop(dev); + switch (tid) { + case 0: + mt76_rmw_field(dev, addr + (2 * 4), MT_WTBL2_W2_TID0_SN, ssn); + break; + case 1: + mt76_rmw_field(dev, addr + (2 * 4), MT_WTBL2_W2_TID1_SN, ssn); + break; + case 2: + mt76_rmw_field(dev, addr + (2 * 4), MT_WTBL2_W2_TID2_SN_LO, + ssn); + mt76_rmw_field(dev, addr + (3 * 4), MT_WTBL2_W3_TID2_SN_HI, + ssn >> 8); + break; + case 3: + mt76_rmw_field(dev, addr + (3 * 4), MT_WTBL2_W3_TID3_SN, ssn); + break; + case 4: + mt76_rmw_field(dev, addr + (3 * 4), MT_WTBL2_W3_TID4_SN, ssn); + break; + case 5: + mt76_rmw_field(dev, addr + (3 * 4), MT_WTBL2_W3_TID5_SN_LO, + ssn); + mt76_rmw_field(dev, addr + (4 * 4), MT_WTBL2_W4_TID5_SN_HI, + ssn >> 4); + break; + case 6: + mt76_rmw_field(dev, addr + (4 * 4), MT_WTBL2_W4_TID6_SN, ssn); + break; + case 7: + mt76_rmw_field(dev, addr + (4 * 4), MT_WTBL2_W4_TID7_SN, ssn); + break; + } + mt7603_wtbl_update(dev, wcid, MT_WTBL_UPDATE_WTBL2); + mt7603_mac_start(dev); + + for (i = 7; i > 0; i--) { + if (ba_size >= MT_AGG_SIZE_LIMIT(i)) + break; + } + + tid_val = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | + i << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT); + + mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); +} + +static int +mt7603_get_rate(struct mt7603_dev *dev, struct ieee80211_supported_band *sband, + int idx, bool cck) +{ + int offset = 0; + int len = sband->n_bitrates; + int i; + + if (cck) { + if (WARN_ON_ONCE(sband == &dev->mt76.sband_5g.sband)) + return 0; + + idx &= ~BIT(2); /* short preamble */ + } else if (sband == &dev->mt76.sband_2g.sband) { + offset = 4; + } + + for (i = offset; i < len; i++) { + if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) + return i; + } + + WARN_ON_ONCE(1); + return 0; +} + +int +mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_supported_band *sband; + __le32 *rxd = (__le32 *) skb->data; + u32 rxd0 = le32_to_cpu(rxd[0]); + u32 rxd1 = le32_to_cpu(rxd[1]); + u32 rxd2 = le32_to_cpu(rxd[2]); + bool remove_pad; + int i; + + memset(status, 0, sizeof(*status)); + + i = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); + sband = (i & 1) ? &dev->mt76.sband_5g.sband : &dev->mt76.sband_2g.sband; + i >>= 1; + + status->band = sband->band; + if (i < sband->n_channels) + status->freq = sband->channels[i].center_freq; + + if (rxd2 & MT_RXD2_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && + !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + } + + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; + + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) + return -EINVAL; + + if (WARN_ON_ONCE(!sband->channels)) + return -EINVAL; + + rxd += 4; + if (rxd0 & MT_RXD0_NORMAL_GROUP_4) { + rxd += 4; + if ((u8 *) rxd - skb->data >= skb->len) + return -EINVAL; + } + if (rxd0 & MT_RXD0_NORMAL_GROUP_1) { + rxd += 4; + if ((u8 *) rxd - skb->data >= skb->len) + return -EINVAL; + } + if (rxd0 & MT_RXD0_NORMAL_GROUP_2) { + rxd += 2; + if ((u8 *) rxd - skb->data >= skb->len) + return -EINVAL; + } + if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { + u32 rxdg0 = le32_to_cpu(rxd[0]); + u32 rxdg3 = le32_to_cpu(rxd[3]); + bool cck = false; + + i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0); + switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) { + case MT_PHY_TYPE_CCK: + cck = true; + /* fall through */ + case MT_PHY_TYPE_OFDM: + i = mt7603_get_rate(dev, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + break; + case MT_PHY_TYPE_VHT: + status->encoding = RX_ENC_VHT; + break; + default: + WARN_ON(1); + } + + if (rxdg0 & MT_RXV1_HT_SHORT_GI) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * + FIELD_GET(MT_RXV1_HT_STBC, rxdg0); + + status->rate_idx = i; + + status->chains = BIT(0) | BIT(1); + status->chain_signal[0] = FIELD_GET(MT_RXV4_IB_RSSI0, rxdg3) + + dev->rssi_offset[0]; + status->chain_signal[1] = FIELD_GET(MT_RXV4_IB_RSSI1, rxdg3) + + dev->rssi_offset[1]; + status->signal = max(status->chain_signal[0], status->chain_signal[1]); + + rxd += 6; + if ((u8 *) rxd - skb->data >= skb->len) + return -EINVAL; + } + + skb_pull(skb, (u8 *) rxd - skb->data + 2 * remove_pad); + + return 0; +} + +static u16 +mt7603_mac_tx_rate_val(struct mt7603_dev *dev, + const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw) +{ + u8 phy, nss, rate_idx; + u16 rateval; + + *bw = 0; + if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + *bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->mt76.chandef.chan->band; + u16 val; + + nss = 1; + r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + } + + rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | + FIELD_PREP(MT_TX_RATE_MODE, phy)); + + if (stbc && nss == 1) + rateval |= MT_TX_RATE_STBC; + + return rateval; +} + +void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, + struct ieee80211_tx_rate *probe_rate, + struct ieee80211_tx_rate *rates) +{ + int wcid = sta->wcid.idx; + u32 addr = mt7603_wtbl2_addr(wcid); + bool stbc = false; + int n_rates = sta->n_rates; + u8 bw, bw_prev, bw_idx = 0; + u16 val[4]; + u16 probe_val; + u32 w9 = mt76_rr(dev, addr + 9 * 4); + int count; + int i; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return; + + for (i = 0, count = 0; i < n_rates; i++) + count += max_t(int, 2 * MT7603_RATE_RETRY, rates[i].count); + for (i = n_rates; i < 4; i++) + rates[i] = rates[n_rates - 1]; + + w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | + MT_WTBL2_W9_SHORT_GI_80; + + val[0] = mt7603_mac_tx_rate_val(dev, &rates[0], stbc, &bw); + bw_prev = bw; + + if (probe_rate) { + probe_val = mt7603_mac_tx_rate_val(dev, probe_rate, stbc, &bw); + if (bw) + bw_idx = 1; + else + bw_prev = 0; + } else { + probe_val = val[0]; + } + + w9 |= FIELD_PREP(MT_WTBL2_W9_CC_BW_SEL, bw); + w9 |= FIELD_PREP(MT_WTBL2_W9_BW_CAP, bw); + + val[1] = mt7603_mac_tx_rate_val(dev, &rates[1], stbc, &bw); + if (bw_prev) { + bw_idx = 3; + bw_prev = bw; + } + + val[2] = mt7603_mac_tx_rate_val(dev, &rates[2], stbc, &bw); + if (bw_prev) { + bw_idx = 5; + bw_prev = bw; + } + + val[3] = mt7603_mac_tx_rate_val(dev, &rates[3], stbc, &bw); + if (bw_prev) + bw_idx = 7; + + w9 |= FIELD_PREP(MT_WTBL2_W9_CHANGE_BW_RATE, + bw_idx ? bw_idx - 1 : 7); + + mt76_wr(dev, MT_WTBL_RIUCR0, w9); + + mt76_wr(dev, MT_WTBL_RIUCR1, + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[0])); + + mt76_wr(dev, MT_WTBL_RIUCR2, + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[0] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); + + mt76_wr(dev, MT_WTBL_RIUCR3, + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[2]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); + + mt76_wr(dev, MT_WTBL_UPDATE, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | + MT_WTBL_UPDATE_RATE_UPDATE | + MT_WTBL_UPDATE_TX_COUNT_CLEAR); + + if (!sta->wcid.tx_rate_set) + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + sta->rate_count = count; + sta->wcid.tx_rate_set = true; +} + +static enum mt7603_cipher_type +mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) +{ + memset(key_data, 0, 32); + if (!key) + return MT_CIPHER_NONE; + + if (key->keylen > 32) + return MT_CIPHER_NONE; + + memcpy(key_data, key->key, key->keylen); + + switch(key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + default: + return MT_CIPHER_NONE; + } +} + +int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, + struct ieee80211_key_conf *key) +{ + enum mt7603_cipher_type cipher; + u32 addr = mt7603_wtbl3_addr(wcid); + u8 key_data[32]; + int key_len = sizeof(key_data); + + cipher = mt7603_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EOPNOTSUPP; + + if (key && (cipher == MT_CIPHER_WEP40 || cipher == MT_CIPHER_WEP104)) { + addr += key->keyidx * 16; + key_len = 16; + } + + mt76_wr_copy(dev, addr, key_data, key_len); + + addr = mt7603_wtbl1_addr(wcid); + mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_KEY_TYPE, cipher); + if (key) + mt76_rmw_field(dev, addr, MT_WTBL1_W0_KEY_IDX, key->keyidx); + mt76_rmw_field(dev, addr, MT_WTBL1_W0_RX_KEY_VALID, !!key); + + return 0; +} + +static int +mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + int pid, struct ieee80211_key_conf *key) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_vif *vif = info->control.vif; + struct mt7603_vif *mvif; + int wlan_idx; + int hdr_len = ieee80211_get_hdrlen_from_skb(skb); + int tx_count = 8; + u8 frame_type, frame_subtype; + u16 fc = le16_to_cpu(hdr->frame_control); + u8 vif_idx = 0; + u8 bw; + + if (vif) { + mvif = (struct mt7603_vif *) vif->drv_priv; + vif_idx = mvif->idx; + if (vif_idx && q >= &dev->mt76.q_tx[MT_TXQ_BEACON]) + vif_idx += 0x10; + } + + if (sta) { + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + tx_count = msta->rate_count; + } + + if (wcid) + wlan_idx = wcid->idx; + else + wlan_idx = MT7603_WTBL_RESERVED; + + frame_type = (fc & IEEE80211_FCTL_FTYPE) >> 2; + frame_subtype = (fc & IEEE80211_FCTL_STYPE) >> 4; + + txwi[0] = cpu_to_le32( + FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_Q_IDX, q->hw_idx) + ); + txwi[1] = cpu_to_le32( + MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_OWN_MAC, vif_idx) | + FIELD_PREP(MT_TXD1_TID, skb->priority & + IEEE80211_QOS_CTL_TID_MASK) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, hdr_len / 2) | + FIELD_PREP(MT_TXD1_WLAN_IDX, wlan_idx) | + FIELD_PREP(MT_TXD1_PROTECTED, !!key) + ); + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { + txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK); + pid = MT_PID_NOACK; + } + + txwi[2] = cpu_to_le32( + FIELD_PREP(MT_TXD2_FRAME_TYPE, frame_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, frame_subtype) | + FIELD_PREP(MT_TXD2_MULTICAST, is_multicast_ether_addr(hdr->addr1)) + ); + + if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) + txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); + + txwi[4] = 0; + txwi[5] = cpu_to_le32( + MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT | + FIELD_PREP(MT_TXD5_PID, pid) + ); + txwi[6] = 0; + + if (rate->idx >= 0 && rate->count && + !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { + bool stbc = info->flags & IEEE80211_TX_CTL_STBC; + u16 rateval = mt7603_mac_tx_rate_val(dev, rate, stbc, &bw); + + txwi[6] |= cpu_to_le32( + MT_TXD6_FIXED_RATE | + MT_TXD6_FIXED_BW | + FIELD_PREP(MT_TXD6_BW, bw) | + FIELD_PREP(MT_TXD6_TX_RATE, rateval) + ); + + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + txwi[6] |= cpu_to_le32(MT_TXD6_SGI); + + if (!(rate->flags & IEEE80211_TX_RC_MCS)) + txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); + + tx_count = rate->count; + } + + /* use maximum tx count for beacons */ + if (q->hw_idx == MT_TX_HW_QUEUE_BCN) + tx_count = 0x1f; + + txwi[3] = cpu_to_le32( + FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count) | + FIELD_PREP(MT_TXD3_SEQ, le16_to_cpu(hdr->seq_ctrl)) + ); + + if (key) { + u64 pn = atomic64_inc_return(&key->tx_pn); + txwi[3] |= cpu_to_le32(MT_TXD3_PN_VALID); + txwi[4] = cpu_to_le32(pn & GENMASK(31, 0)); + txwi[5] |= cpu_to_le32(FIELD_PREP(MT_TXD5_PN_HIGH, pn >> 32)); + } + + txwi[7] = 0; + + return 0; +} + +static int +mt7603_add_tx_status_skb(struct mt7603_dev *dev, struct mt7603_sta *msta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt7603_cb *cb = mt7603_skb_cb(skb); + int pid; + + if (!msta) + return 0; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + return 0; + + if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_CTL_RATE_CTRL_PROBE)) && + info->control.rates[0].idx < 0) + return 0; + + spin_lock_bh(&dev->status_lock); + + memset(cb, 0, sizeof(*cb)); + msta->pid = (msta->pid + 1) & MT_PID_INDEX; + if (!msta->pid || msta->pid == MT_PID_NOACK) + msta->pid = 1; + + pid = msta->pid; + cb->wcid = msta->wcid.idx; + cb->pktid = pid; + cb->jiffies = jiffies; + + __skb_queue_tail(&dev->status_list, skb); + + spin_unlock_bh(&dev->status_lock); + return pid; +} + +int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; + int pid; + + if (!wcid) + wcid = &dev->global_sta.wcid; + + pid = mt7603_add_tx_status_skb(dev, msta, skb); + if (!pid) + skb->next = skb->prev = NULL; + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + spin_lock_bh(&dev->mt76.lock); + msta->rate_probe = true; + mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0], + msta->rates); + spin_unlock_bh(&dev->mt76.lock); + } + + mt7603_mac_write_txwi(dev, txwi_ptr, skb, q, wcid, sta, pid, key); + + return 0; +} + +static bool +mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, + struct ieee80211_tx_info *info, __le32 *txs_data) +{ + bool final_mpdu; + bool ack_timeout; + bool fixed_rate; + bool probe; + bool ampdu; + int count; + u32 txs; + u8 pid; + int idx; + int i; + + fixed_rate = info->status.rates[0].count; + probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); + + txs = le32_to_cpu(txs_data[4]); + final_mpdu = txs & MT_TXS4_ACKED_MPDU; + ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU); + pid = FIELD_GET(MT_TXS4_PID, txs); + count = FIELD_GET(MT_TXS4_TX_COUNT, txs); + + txs = le32_to_cpu(txs_data[0]); + ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; + + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) { + if (!fixed_rate && !ack_timeout) + sta->ampdu_acked++; + info->flags |= IEEE80211_TX_STAT_ACK; + } + + if (!fixed_rate) + sta->ampdu_count++; + + sta->ampdu_tx_count = max_t(int, sta->ampdu_tx_count, count); + if (ampdu && !final_mpdu) + return false; + + if (fixed_rate) { + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & IEEE80211_TX_STAT_ACK); + } else { + info->status.ampdu_len = sta->ampdu_count; + info->status.ampdu_ack_len = sta->ampdu_acked; + } + + if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) + info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; + + count = sta->ampdu_tx_count; + + sta->ampdu_count = 0; + sta->ampdu_acked = 0; + sta->ampdu_tx_count = 0; + + if (fixed_rate && !probe) { + info->status.rates[0].count = count; + return true; + } + + for (i = 0, idx = 0; i < ARRAY_SIZE(info->status.rates); i++) { + int cur_count = min_t(int, count, 2 * MT7603_RATE_RETRY); + + if (!i && probe) { + cur_count = 1; + } else { + info->status.rates[i] = sta->rates[idx]; + idx++; + } + + if (i && info->status.rates[i].idx < 0) { + info->status.rates[i - 1].count += count; + break; + } + + if (!count) { + info->status.rates[i].idx = -1; + break; + } + + info->status.rates[i].count = cur_count; + count -= cur_count; + } + + return true; +} + +static void +mt7603_skb_done(struct mt7603_dev *dev, struct sk_buff *skb, u8 flags) +{ + struct mt7603_cb *cb = mt7603_skb_cb(skb); + u8 done = MT7603_CB_DMA_DONE | MT7603_CB_TXS_DONE; + + flags |= cb->flags; + cb->flags = flags; + + if ((flags & done) != done) + return; + + if (flags & MT7603_CB_TXS_FAILED) + ieee80211_free_txskb(mt76_hw(dev), skb); + else + ieee80211_tx_status(mt76_hw(dev), skb); +} + +struct sk_buff * +mt7603_mac_status_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pktid) +{ + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&dev->status_list, skb, tmp) { + struct mt7603_cb *cb = mt7603_skb_cb(skb); + if (sta && cb->wcid != sta->wcid.idx) + continue; + + __skb_unlink(skb, &dev->status_list); + if (cb->pktid == pktid) + return skb; + + mt7603_skb_done(dev, skb, + MT7603_CB_TXS_FAILED | MT7603_CB_TXS_DONE); + } + + return NULL; +} + +static bool +mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid, + __le32 *txs_data) +{ + struct sk_buff *skb; + + if (!pid) + return false; + + spin_lock_bh(&dev->status_lock); + skb = mt7603_mac_status_skb(dev, sta, pid); + spin_unlock_bh(&dev->status_lock); + + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + spin_lock_bh(&dev->mt76.lock); + if (sta->rate_probe) { + mt7603_wtbl_set_rates(dev, sta, NULL, sta->rates); + sta->rate_probe = false; + } + spin_unlock_bh(&dev->mt76.lock); + } + mt7603_fill_txs(dev, sta, info, txs_data); + mt7603_skb_done(dev, skb, MT7603_CB_TXS_DONE); + } + + return !!skb; +} + +void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt7603_sta *msta = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + void *priv; + u32 txs; + u8 wcidx; + u8 pid; + + txs = le32_to_cpu(txs_data[4]); + pid = FIELD_GET(MT_TXS4_PID, txs); + txs = le32_to_cpu(txs_data[3]); + wcidx = FIELD_GET(MT_TXS3_WCID, txs); + + if (pid == MT_PID_NOACK) + return; + + if (wcidx >= ARRAY_SIZE(dev->wcid)) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->wcid[wcidx]); + if (!wcid) + goto out; + + priv = msta = container_of(wcid, struct mt7603_sta, wcid); + sta = container_of(priv, struct ieee80211_sta, drv_priv); + + pid &= MT_PID_INDEX; + if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) + goto out; + + if (wcidx >= MT7603_WTBL_STA) + goto out; + + if (mt7603_fill_txs(dev, msta, &info, txs_data)) + ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); + +out: + rcu_read_unlock(); +} + +void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + struct sk_buff *skb = e->skb; + bool free = true; + + if (!e->txwi) { + dev_kfree_skb_any(skb); + return; + } + + if (q - dev->mt76.q_tx < 4) + dev->tx_hang_check = 0; + + /* will be freed by tx status handling codepath */ + if (skb->prev) { + spin_lock_bh(&dev->status_lock); + if (!flush) { + mt7603_skb_done(dev, skb, MT7603_CB_DMA_DONE); + free = false; + } else { + __skb_unlink(skb, &dev->status_list); + } + spin_unlock_bh(&dev->status_lock); + } + + if (free) + ieee80211_free_txskb(mdev->hw, skb); +} + +static bool +wait_for_wpdma(struct mt7603_dev *dev) +{ + return mt76_poll(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, + 0, 1000); +} + +void mt7603_mac_reset(struct mt7603_dev *dev) +{ + u32 addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR); + + /* Reset PSE */ + mt76_clear(dev, MT_PSE_RESET, MT_PSE_RESET_SW_S); + mt76_set(dev, MT_PSE_RESET, MT_PSE_RESET_SW); + if (!mt76_poll_msec(dev, MT_PSE_RESET, MT_PSE_RESET_SW_S, + MT_PSE_RESET_SW_S, 500)) { + mt76_clear(dev, MT_PSE_RESET, MT_PSE_RESET_SW); + goto out; + } + mt76_clear(dev, MT_PSE_RESET, MT_PSE_RESET_SW_S); + + mt76_set(dev, addr + MT_CLIENT_RESET_TX, MT_CLIENT_RESET_TX_R_E_1); + mt76_poll_msec(dev, addr + MT_CLIENT_RESET_TX, + MT_CLIENT_RESET_TX_R_E_1_S, + MT_CLIENT_RESET_TX_R_E_1_S, 500); + + mt76_set(dev, addr + MT_CLIENT_RESET_TX, MT_CLIENT_RESET_TX_R_E_2); + mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET); + + mt76_poll_msec(dev, addr + MT_CLIENT_RESET_TX, + MT_CLIENT_RESET_TX_R_E_2_S, + MT_CLIENT_RESET_TX_R_E_2_S, 500); + + mt76_clear(dev, addr + MT_CLIENT_RESET_TX, + MT_CLIENT_RESET_TX_R_E_1 | MT_CLIENT_RESET_TX_R_E_2); +out: + mt76_clear(dev, MT_PSE_RESET, MT_PSE_RESET_QUEUES); +} + +void mt7603_mac_dma_start(struct mt7603_dev *dev) +{ + mt7603_mac_start(dev); + + wait_for_wpdma(dev); + udelay(50); + + mt76_set(dev, MT_WPDMA_GLO_CFG, + (MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_EN | + FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE)); + + mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL); +} + +void mt7603_mac_start(struct mt7603_dev *dev) +{ + mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + mt76_wr(dev, MT_WF_ARB_TX_START_0, ~0); + mt76_set(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); +} + +void mt7603_mac_stop(struct mt7603_dev *dev) +{ + mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + mt76_wr(dev, MT_WF_ARB_TX_START_0, 0); + mt76_clear(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); +} + +void mt7603_mac_watchdog_reset(struct mt7603_dev *dev) +{ + int beacon_int = dev->beacon_int; + u32 mask = dev->irqmask; + int i; + + ieee80211_stop_queues(dev->mt76.hw); + set_bit(MT76_RESET, &dev->mt76.state); + + tasklet_disable(&dev->tx_tasklet); + tasklet_disable(&dev->pre_tbtt_tasklet); + napi_disable(&dev->mt76.napi[0]); + napi_disable(&dev->mt76.napi[1]); + + mutex_lock(&dev->mutex); + mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); + msleep(1); + + mt7603_irq_disable(dev, mask); + + mt7603_beacon_set_timer(dev, -1, 0); + mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); + + mt7603_mac_reset(dev); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_tx); i++) + mt76_queue_tx_cleanup(dev, i, true); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++) + mt76_queue_rx_reset(dev, i); + + mt7603_mac_dma_start(dev); + + mt7603_irq_enable(dev, mask); + clear_bit(MT76_RESET, &dev->mt76.state); + + mt7603_beacon_set_timer(dev, -1, beacon_int); + mutex_unlock(&dev->mutex); + + tasklet_enable(&dev->tx_tasklet); + tasklet_enable(&dev->pre_tbtt_tasklet); + napi_enable(&dev->mt76.napi[0]); + napi_enable(&dev->mt76.napi[1]); + ieee80211_wake_queues(dev->mt76.hw); +} + +static bool mt7603_rx_dma_busy(struct mt7603_dev *dev) +{ + u32 val; + + if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_RX_DMA_BUSY)) + return false; + + mt76_wr(dev, 0x4244, 0x28000000); + val = mt76_rr(dev, 0x4244); + return !!(val & BIT(8)); +} + +static bool mt7603_tx_dma_busy(struct mt7603_dev *dev) +{ + u32 val; + + if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_TX_DMA_BUSY)) + return false; + + mt76_wr(dev, 0x4244, 0x98000000); + val = mt76_rr(dev, 0x4244); + return (val & BIT(8)) && (val & 0xf) != 0xf; +} + +static bool mt7603_tx_hang(struct mt7603_dev *dev) +{ + struct mt76_queue *q; + u32 dma_idx, prev_dma_idx; + int i; + + for (i = 0; i < 4; i++) { + q = &dev->mt76.q_tx[i]; + + if (!q->queued) + continue; + + prev_dma_idx = dev->tx_dma_idx[i]; + dev->tx_dma_idx[i] = dma_idx = ioread32(&q->regs->dma_idx); + + if (dma_idx == prev_dma_idx && + dma_idx != ioread32(&q->regs->cpu_idx)) + break; + } + + return i < 4; +} + +static bool mt7603_rx_pse_busy(struct mt7603_dev *dev) +{ + u32 addr, val; + + mt76_wr(dev, 0x4244, 0x28000000); + if (mt76_rr(dev, 0x4244) & BIT(8)) + return false; + + addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_STATUS); + mt76_wr(dev, addr, 3); + val = mt76_rr(dev, addr) >> 16; + + return (val & 0x8001) == 0x8001 || (val & 0xe001) == 0xe001; +} + +static bool +mt7603_watchdog_check(struct mt7603_dev *dev, u8 *counter, + enum mt7603_reset_cause cause, + bool (*check)(struct mt7603_dev *dev)) +{ + if (check) { + if (!check(dev) && *counter < MT7603_WATCHDOG_TIMEOUT) { + *counter = 0; + return false; + } + + (*counter)++; + } + + if (*counter < MT7603_WATCHDOG_TIMEOUT) + return false; + + dev->reset_cause[cause]++; + return true; +} + +void mt7603_mac_work(struct work_struct *work) +{ + struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mac_work.work); + struct sk_buff *skb; + bool reset = false; + + spin_lock_bh(&dev->status_lock); + while ((skb = skb_peek(&dev->status_list)) != NULL) { + struct mt7603_cb *cb = mt7603_skb_cb(skb); + if (time_is_after_jiffies(cb->jiffies + MT7603_STATUS_TIMEOUT)) + break; + + __skb_unlink(skb, &dev->status_list); + mt7603_skb_done(dev, skb, + MT7603_CB_TXS_FAILED | MT7603_CB_TXS_DONE); + } + spin_unlock_bh(&dev->status_lock); + + mutex_lock(&dev->mutex); + + if (WARN_ON_ONCE(mt7603_watchdog_check(dev, &dev->tx_dma_check, + RESET_CAUSE_TX_BUSY, + mt7603_tx_dma_busy)) || + WARN_ON_ONCE(mt7603_watchdog_check(dev, &dev->rx_dma_check, + RESET_CAUSE_RX_BUSY, + mt7603_rx_dma_busy)) || + WARN_ON_ONCE(mt7603_watchdog_check(dev, &dev->tx_hang_check, + RESET_CAUSE_TX_HANG, + mt7603_tx_hang)) || + WARN_ON_ONCE(mt7603_watchdog_check(dev, &dev->rx_pse_check, + RESET_CAUSE_RX_PSE_BUSY, + mt7603_rx_pse_busy)) || + WARN_ON_ONCE(mt7603_watchdog_check(dev, &dev->beacon_check, + RESET_CAUSE_BEACON_STUCK, + NULL))) { + dev->beacon_check = 0; + dev->tx_dma_check = 0; + dev->tx_hang_check = 0; + dev->rx_dma_check = 0; + dev->rx_pse_check = 0; + dev->rx_dma_idx = ~0; + memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx)); + reset = true; + } + + mutex_unlock(&dev->mutex); + + if (reset) + mt7603_mac_watchdog_reset(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + msecs_to_jiffies(MT7603_WATCHDOG_TIME)); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_mac.h b/drivers/net/wireless/mediatek/mt76/mt7603_mac.h new file mode 100644 index 0000000000000..a03b3b25d8d1b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_mac.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT7603_MAC_H +#define __MT7603_MAC_H + +#define MT_RXD0_LENGTH GENMASK(15, 0) +#define MT_RXD0_PKT_TYPE GENMASK(31, 29) + +#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) +#define MT_RXD0_NORMAL_IP_SUM BIT(23) +#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) +#define MT_RXD0_NORMAL_GROUP_1 BIT(25) +#define MT_RXD0_NORMAL_GROUP_2 BIT(26) +#define MT_RXD0_NORMAL_GROUP_3 BIT(27) +#define MT_RXD0_NORMAL_GROUP_4 BIT(28) + +enum rx_pkt_type { + PKT_TYPE_TXS = 0, + PKT_TYPE_TXRXV = 1, + PKT_TYPE_NORMAL = 2, + PKT_TYPE_RX_DUP_RFB = 3, + PKT_TYPE_RX_TMR = 4, + PKT_TYPE_RETRIEVE = 5, + PKT_TYPE_RX_EVENT = 7, +}; + +#define MT_RXD1_NORMAL_BSSID GENMASK(31, 26) +#define MT_RXD1_NORMAL_PAYLOAD_FORMAT GENMASK(25, 24) +#define MT_RXD1_NORMAL_HDR_TRANS BIT(23) +#define MT_RXD1_NORMAL_HDR_OFFSET BIT(22) +#define MT_RXD1_NORMAL_MAC_HDR_LEN GENMASK(21, 16) +#define MT_RXD1_NORMAL_CH_FREQ GENMASK(15, 8) +#define MT_RXD1_NORMAL_KEY_ID GENMASK(7, 6) +#define MT_RXD1_NORMAL_BEACON_UC BIT(5) +#define MT_RXD1_NORMAL_BEACON_MC BIT(4) +#define MT_RXD1_NORMAL_BCAST BIT(3) +#define MT_RXD1_NORMAL_MCAST BIT(2) +#define MT_RXD1_NORMAL_U2M BIT(1) +#define MT_RXD1_NORMAL_HTC_VLD BIT(0) + +#define MT_RXD2_NORMAL_NON_AMPDU BIT(31) +#define MT_RXD2_NORMAL_NON_AMPDU_SUB BIT(30) +#define MT_RXD2_NORMAL_NDATA BIT(29) +#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) +#define MT_RXD2_NORMAL_FRAG BIT(27) +#define MT_RXD2_NORMAL_UDF_VALID BIT(26) +#define MT_RXD2_NORMAL_LLC_MIS BIT(25) +#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) +#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) +#define MT_RXD2_NORMAL_LEN_MISMATCH BIT(22) +#define MT_RXD2_NORMAL_TKIP_MIC_ERR BIT(21) +#define MT_RXD2_NORMAL_ICV_ERR BIT(20) +#define MT_RXD2_NORMAL_CLM BIT(19) +#define MT_RXD2_NORMAL_CM BIT(18) +#define MT_RXD2_NORMAL_FCS_ERR BIT(17) +#define MT_RXD2_NORMAL_SW_BIT BIT(16) +#define MT_RXD2_NORMAL_SEC_MODE GENMASK(15, 12) +#define MT_RXD2_NORMAL_TID GENMASK(11, 8) +#define MT_RXD2_NORMAL_WLAN_IDX GENMASK(7, 0) + +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) +#define MT_RXD3_NORMAL_PF_MODE BIT(29) +#define MT_RXD3_NORMAL_CLS_BITMAP GENMASK(28, 19) +#define MT_RXD3_NORMAL_WOL GENMASK(18, 14) +#define MT_RXD3_NORMAL_MAGIC_PKT BIT(13) +#define MT_RXD3_NORMAL_OFLD GENMASK(12, 11) +#define MT_RXD3_NORMAL_CLS BIT(10) +#define MT_RXD3_NORMAL_PATTERN_DROP BIT(9) +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(8) +#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) + +#define MT_RXV1_VHTA1_B5_B4 GENMASK(31, 30) +#define MT_RXV1_VHTA2_B8_B1 GENMASK(29, 22) +#define MT_RXV1_HT_NO_SOUND BIT(21) +#define MT_RXV1_HT_SMOOTH BIT(20) +#define MT_RXV1_HT_SHORT_GI BIT(19) +#define MT_RXV1_HT_AGGR BIT(18) +#define MT_RXV1_VHTA1_B22 BIT(17) +#define MT_RXV1_FRAME_MODE GENMASK(16, 15) +#define MT_RXV1_TX_MODE GENMASK(14, 12) +#define MT_RXV1_HT_EXT_LTF GENMASK(11, 10) +#define MT_RXV1_HT_AD_CODE BIT(9) +#define MT_RXV1_HT_STBC GENMASK(8, 7) +#define MT_RXV1_TX_RATE GENMASK(6, 0) + +#define MT_RXV2_VHTA1_B16_B6 GENMASK(31, 21) +#define MT_RXV2_LENGTH GENMASK(20, 0) + +#define MT_RXV3_F_AGC1_CAL_GAIN GENMASK(31, 29) +#define MT_RXV3_F_AGC1_EQ_CAL BIT(28) +#define MT_RXV3_RCPI1 GENMASK(27, 20) +#define MT_RXV3_F_AGC0_CAL_GAIN GENMASK(19, 17) +#define MT_RXV3_F_AGC0_EQ_CAL BIT(16) +#define MT_RXV3_RCPI0 GENMASK(15, 8) +#define MT_RXV3_SEL_ANT BIT(7) +#define MT_RXV3_ACI_DET_X BIT(6) +#define MT_RXV3_OFDM_FREQ_TRANS_DETECT BIT(5) +#define MT_RXV3_VHTA1_B21_B17 GENMASK(4, 0) + +#define MT_RXV4_F_AGC_CAL_GAIN GENMASK(31, 29) +#define MT_RXV4_F_AGC2_EQ_CAL BIT(28) +#define MT_RXV4_IB_RSSI1 GENMASK(27, 20) +#define MT_RXV4_F_AGC_LPF_GAIN_X GENMASK(19, 16) +#define MT_RXV4_WB_RSSI_X GENMASK(15, 8) +#define MT_RXV4_IB_RSSI0 GENMASK(7, 0) + +#define MT_RXV5_LTF_SNR0 GENMASK(31, 26) +#define MT_RXV5_LTF_PROC_TIME GENMASK(25, 19) +#define MT_RXV5_FOE GENMASK(18, 7) +#define MT_RXV5_C_AGC_SATE GENMASK(6, 4) +#define MT_RXV5_F_AGC_LNA_GAIN_0 GENMASK(3, 2) +#define MT_RXV5_F_AGC_LNA_GAIN_1 GENMASK(1, 0) + +#define MT_RXV6_C_AGC_STATE GENMASK(30, 28) +#define MT_RXV6_NS_TS_FIELD GENMASK(27, 25) +#define MT_RXV6_RX_VALID BIT(24) +#define MT_RXV6_NF2 GENMASK(23, 16) +#define MT_RXV6_NF1 GENMASK(15, 8) +#define MT_RXV6_NF0 GENMASK(7, 0) + +enum mt7603_tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +#define MT_TXD_SIZE (8 * 4) + +#define MT_TXD0_P_IDX BIT(31) +#define MT_TXD0_Q_IDX GENMASK(30, 27) +#define MT_TXD0_UTXB BIT(26) +#define MT_TXD0_UNXV BIT(25) +#define MT_TXD0_UDP_TCP_SUM BIT(24) +#define MT_TXD0_IP_SUM BIT(23) +#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) +#define MT_TXD0_TX_BYTES GENMASK(15, 0) + +#define MT_TXD1_OWN_MAC GENMASK(31, 26) +#define MT_TXD1_PROTECTED BIT(23) +#define MT_TXD1_TID GENMASK(22, 20) +#define MT_TXD1_NO_ACK BIT(19) +#define MT_TXD1_HDR_PAD GENMASK(18, 16) +#define MT_TXD1_LONG_FORMAT BIT(15) +#define MT_TXD1_HDR_FORMAT GENMASK(14, 13) +#define MT_TXD1_HDR_INFO GENMASK(12, 8) +#define MT_TXD1_WLAN_IDX GENMASK(7, 0) + +#define MT_TXD2_FIX_RATE BIT(31) +#define MT_TXD2_TIMING_MEASURE BIT(30) +#define MT_TXD2_BA_DISABLE BIT(29) +#define MT_TXD2_POWER_OFFSET GENMASK(28, 24) +#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) +#define MT_TXD2_FRAG GENMASK(15, 14) +#define MT_TXD2_HTC_VLD BIT(13) +#define MT_TXD2_DURATION BIT(12) +#define MT_TXD2_BIP BIT(11) +#define MT_TXD2_MULTICAST BIT(10) +#define MT_TXD2_RTS BIT(9) +#define MT_TXD2_SOUNDING BIT(8) +#define MT_TXD2_NDPA BIT(7) +#define MT_TXD2_NDP BIT(6) +#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) +#define MT_TXD2_SUB_TYPE GENMASK(3, 0) + +#define MT_TXD3_SN_VALID BIT(31) +#define MT_TXD3_PN_VALID BIT(30) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) +#define MT_TXD3_TX_COUNT GENMASK(10, 6) + +#define MT_TXD4_PN_LOW GENMASK(31, 0) + +#define MT_TXD5_PN_HIGH GENMASK(31, 16) +#define MT_TXD5_SW_POWER_MGMT BIT(13) +#define MT_TXD5_BA_SEQ_CTRL BIT(12) +#define MT_TXD5_DA_SELECT BIT(11) +#define MT_TXD5_TX_STATUS_HOST BIT(10) +#define MT_TXD5_TX_STATUS_MCU BIT(9) +#define MT_TXD5_TX_STATUS_FMT BIT(8) +#define MT_TXD5_PID GENMASK(7, 0) + +#define MT_TXD6_SGI BIT(31) +#define MT_TXD6_LDPC BIT(30) +#define MT_TXD6_TX_RATE GENMASK(29, 18) +#define MT_TXD6_I_TXBF BIT(17) +#define MT_TXD6_E_TXBF BIT(16) +#define MT_TXD6_DYN_BW BIT(15) +#define MT_TXD6_ANT_PRI GENMASK(14, 12) +#define MT_TXD6_SPE_EN BIT(11) +#define MT_TXD6_FIXED_BW BIT(10) +#define MT_TXD6_BW GENMASK(9, 8) +#define MT_TXD6_ANT_ID GENMASK(7, 2) +#define MT_TXD6_FIXED_RATE BIT(0) + +#define MT_TX_RATE_STBC BIT(11) +#define MT_TX_RATE_NSS GENMASK(10, 9) +#define MT_TX_RATE_MODE GENMASK(8, 6) +#define MT_TX_RATE_IDX GENMASK(5, 0) + +#define MT_TXS0_ANTENNA GENMASK(31, 26) +#define MT_TXS0_TID GENMASK(25, 22) +#define MT_TXS0_BA_ERROR BIT(22) +#define MT_TXS0_PS_FLAG BIT(21) +#define MT_TXS0_TXOP_TIMEOUT BIT(20) +#define MT_TXS0_BIP_ERROR BIT(19) + +#define MT_TXS0_QUEUE_TIMEOUT BIT(18) +#define MT_TXS0_RTS_TIMEOUT BIT(17) +#define MT_TXS0_ACK_TIMEOUT BIT(16) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) + +#define MT_TXS0_TX_STATUS_HOST BIT(15) +#define MT_TXS0_TX_STATUS_MCU BIT(14) +#define MT_TXS0_TXS_FORMAT BIT(13) +#define MT_TXS0_FIXED_RATE BIT(12) +#define MT_TXS0_TX_RATE GENMASK(11, 0) + +#define MT_TXS1_F0_TIMESTAMP GENMASK(31, 0) +#define MT_TXS1_F1_NOISE_2 GENMASK(23, 16) +#define MT_TXS1_F1_NOISE_1 GENMASK(15, 8) +#define MT_TXS1_F1_NOISE_0 GENMASK(7, 0) + +#define MT_TXS2_F0_FRONT_TIME GENMASK(24, 0) +#define MT_TXS2_F1_RCPI_2 GENMASK(23, 16) +#define MT_TXS2_F1_RCPI_1 GENMASK(15, 8) +#define MT_TXS2_F1_RCPI_0 GENMASK(7, 0) + +#define MT_TXS3_WCID GENMASK(31, 24) +#define MT_TXS3_RXV_SEQNO GENMASK(23, 16) +#define MT_TXS3_TX_DELAY GENMASK(15, 0) + +#define MT_TXS4_LAST_TX_RATE GENMASK(31, 29) +#define MT_TXS4_TX_COUNT GENMASK(28, 24) +#define MT_TXS4_AMPDU BIT(23) +#define MT_TXS4_ACKED_MPDU BIT(22) +#define MT_TXS4_PID GENMASK(21, 14) +#define MT_TXS4_BW GENMASK(13, 12) +#define MT_TXS4_F0_SEQNO GENMASK(11, 0) +#define MT_TXS4_F1_TSSI GENMASK(11, 0) + +#define MT_PID_NOACK GENMASK(7, 0) +#define MT_PID_INDEX GENMASK(7, 0) + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_main.c b/drivers/net/wireless/mediatek/mt76/mt7603_main.c new file mode 100644 index 0000000000000..2243f9d6c81a8 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_main.c @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "mt7603.h" +#include "mt7603_eeprom.h" + +static int +mt7603_start(struct ieee80211_hw *hw) +{ + struct mt7603_dev *dev = hw->priv; + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + MT7603_WATCHDOG_TIME); + mt7603_mac_start(dev); + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + + return 0; +} + +static void +mt7603_stop(struct ieee80211_hw *hw) +{ + struct mt7603_dev *dev = hw->priv; + + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + cancel_delayed_work_sync(&dev->mac_work); + mt7603_mac_watchdog_reset(dev); + mt7603_mac_stop(dev); +} + +static void +mt7603_txq_init(struct mt7603_dev *dev, struct ieee80211_txq *txq) +{ + struct mt76_txq *mtxq; + + if (!txq) + return; + + mtxq = (struct mt76_txq *) txq->drv_priv; + if (txq->sta) { + struct mt7603_sta *sta = (struct mt7603_sta *) txq->sta->drv_priv; + mtxq->wcid = &sta->wcid; + } else { + struct mt7603_vif *mvif = (struct mt7603_vif *) txq->vif->drv_priv; + mtxq->wcid = &mvif->sta.wcid; + } + + mt76_txq_init(&dev->mt76, txq); +} + +static int +mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + struct mt7603_dev *dev = hw->priv; + u8 bc_addr[ETH_ALEN]; + int idx; + int ret = 0; + + mutex_lock(&dev->mutex); + + mvif->idx = ffs(~dev->vif_mask) - 1; + if (mvif->idx >= MT7603_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), + get_unaligned_le32(vif->addr)); + mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), + (get_unaligned_le16(vif->addr + 4) | + MT_MAC_ADDR1_VALID)); + + idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; + dev->vif_mask |= BIT(mvif->idx); + mvif->sta.wcid.idx = idx; + mvif->sta.wcid.hw_key_idx = -1; + + eth_broadcast_addr(bc_addr); + mt7603_wtbl_init(dev, idx, mvif->idx, bc_addr); + + rcu_assign_pointer(dev->wcid[idx], &mvif->sta.wcid); + mt7603_txq_init(dev, vif->txq); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} + +static void +mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + struct mt7603_dev *dev = hw->priv; + int idx = mvif->sta.wcid.idx; + + mt7603_beacon_set_timer(dev, mvif->idx, 0); + + rcu_assign_pointer(dev->wcid[idx], NULL); + mt76_txq_remove(&dev->mt76, vif->txq); + + mutex_lock(&dev->mutex); + dev->vif_mask &= ~BIT(mvif->idx); + mutex_unlock(&dev->mutex); +} + +static int +mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) +{ + u8 *rssi_data = (u8 *) dev->mt76.eeprom.data; + int idx, ret; + + u8 bw = MT_BW_20; + + mt7603_mac_stop(dev); + + dev->mt76.chandef = *def; + mt76_rmw_field(dev, MT_AGG_BWCR, MT_AGG_BWCR_BW, bw); + ret = mt7603_mcu_set_channel(dev); + if (ret) + return ret; + + if (def->chan->band == NL80211_BAND_5GHZ) { + idx = 1; + rssi_data += MT_EE_RSSI_OFFSET_5G; + } else { + idx = 0; + rssi_data += MT_EE_RSSI_OFFSET_2G; + } + + memcpy(dev->rssi_offset, rssi_data, sizeof(dev->rssi_offset)); + + idx |= (def->chan - mt76_hw(dev)->wiphy->bands[def->chan->band]->channels) << 1; + mt76_wr(dev, MT_WF_RMAC_CH_FREQ, idx); + mt7603_mac_start(dev); + + return 0; +} + +static int +mt7603_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt7603_dev *dev = hw->priv; + int ret = 0; + + mutex_lock(&dev->mutex); + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = mt7603_set_channel(dev, &hw->conf.chandef); + mt7603_mac_set_timing(dev); + } + + mutex_unlock(&dev->mutex); + + return ret; +} + +static void +mt7603_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct mt7603_dev *dev = hw->priv; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + dev->rxfilter &= ~(_hw); \ + dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + dev->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI); + + MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_UC | + MT_WF_RFCR_DROP_OTHER_TIM | + MT_WF_RFCR_DROP_A3_MAC | + MT_WF_RFCR_DROP_A3_BSSID); + + MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); + + MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_NDPA); + + *total_flags = flags; + mt76_wr(dev, MT_WF_RFCR, dev->rxfilter); +} + +static void +mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + + mutex_lock(&dev->mutex); + + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID)) { + if (info->assoc || info->ibss_joined) { + mt76_wr(dev, MT_BSSID0(mvif->idx), + get_unaligned_le32(info->bssid)); + mt76_wr(dev, MT_BSSID1(mvif->idx), + (get_unaligned_le16(info->bssid + 4) | + MT_BSSID1_VALID)); + } else { + mt76_wr(dev, MT_BSSID0(mvif->idx), 0); + mt76_wr(dev, MT_BSSID1(mvif->idx), 0); + } + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + dev->slottime = info->use_short_slot ? 9 : 20; + mt7603_mac_set_timing(dev); + } + + if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON_INT)) { + int beacon_int = !!info->enable_beacon * info->beacon_int; + tasklet_disable(&dev->pre_tbtt_tasklet); + mt7603_beacon_set_timer(dev, mvif->idx, beacon_int); + tasklet_enable(&dev->pre_tbtt_tasklet); + } + + mutex_unlock(&dev->mutex); +} + +static int +mt7603_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + int i, idx; + int ret = 0; + + mutex_lock(&dev->mutex); + + idx = mt76_wcid_alloc(dev->wcid_mask, MT7603_WTBL_STA - 1); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt7603_txq_init(dev, sta->txq[i]); + + msta->wcid.idx = idx; + mt7603_wtbl_init(dev, idx, mvif->idx, sta->addr); + mt7603_wtbl_update_cap(dev, sta); + + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} + +static int +mt7603_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + int i; + + mutex_lock(&dev->mutex); + rcu_assign_pointer(dev->wcid[idx], NULL); + mt7603_wtbl_clear(dev, idx); + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76_txq_remove(&dev->mt76, sta->txq[i]); + + mt76_wcid_free(dev->wcid_mask, idx); + + mutex_unlock(&dev->mutex); + + return 0; +} + +static void +mt7603_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + + switch (cmd) { + case STA_NOTIFY_SLEEP: + mt7603_wtbl_set_ps(dev, idx, true); + mt76_stop_tx_queues(&dev->mt76, sta, false); + break; + case STA_NOTIFY_AWAKE: + mt7603_wtbl_set_ps(dev, idx, false); + break; + } +} + +static int +mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_vif *mvif = (struct mt7603_vif *) vif->drv_priv; + struct mt7603_sta *msta = sta ? (struct mt7603_sta *) sta->drv_priv : NULL; + struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->sta.wcid; + int idx = key->keyidx; + + /* + * The hardware does not support per-STA RX GTK, fall back + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else { + if (idx == wcid->hw_key_idx) + wcid->hw_key_idx = -1; + + key = NULL; + } + + return mt7603_wtbl_set_key(dev, wcid->idx, key); +} + +static int +mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt7603_dev *dev = hw->priv; + u16 cw_min = (1 << 5) - 1; + u16 cw_max = (1 << 10) - 1; + u32 val; + + queue = dev->mt76.q_tx[queue].hw_idx; + + if (params->cw_min) + cw_min = params->cw_min; + if (params->cw_max) + cw_max = params->cw_max; + + mutex_lock(&dev->mutex); + mt7603_mac_stop(dev); + + val = mt76_rr(dev, MT_WMM_TXOP(queue)); + val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(queue)); + val |= params->txop << MT_WMM_TXOP_SHIFT(queue); + mt76_wr(dev, MT_WMM_TXOP(queue), val); + + val = mt76_rr(dev, MT_WMM_AIFSN); + val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(queue)); + val |= params->aifs << MT_WMM_AIFSN_SHIFT(queue); + mt76_wr(dev, MT_WMM_AIFSN, val); + + val = mt76_rr(dev, MT_WMM_CWMIN); + val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(queue)); + val |= cw_min << MT_WMM_CWMIN_SHIFT(queue); + mt76_wr(dev, MT_WMM_CWMIN, val); + + val = mt76_rr(dev, MT_WMM_CWMAX(queue)); + val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(queue)); + val |= cw_max << MT_WMM_CWMAX_SHIFT(queue); + mt76_wr(dev, MT_WMM_CWMAX(queue), val); + + mt7603_mac_start(dev); + mutex_unlock(&dev->mutex); + + return 0; +} + +static void +mt7603_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) +{ + struct mt7603_dev *dev = hw->priv; + + set_bit(MT76_SCANNING, &dev->mt76.state); + mt7603_beacon_set_timer(dev, -1, 0); +} + +static void +mt7603_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7603_dev *dev = hw->priv; + + clear_bit(MT76_SCANNING, &dev->mt76.state); + mt7603_beacon_set_timer(dev, -1, dev->beacon_int); + mt76_txq_schedule_all(&dev->mt76); +} + +static void +mt7603_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ +} + +static int +mt7603_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) +{ + return -EINVAL; +} + +static int +mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct mt7603_dev *dev = hw->priv; + struct ieee80211_sta *sta = params->sta; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + u8 ba_size = params->buf_size; + + if (!txq) + return -EINVAL; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt7603_mac_rx_ba_reset(dev, sta->addr, tid); + break; + case IEEE80211_AMPDU_RX_STOP: + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, *ssn, ba_size); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); + mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, *ssn, -1); + break; + case IEEE80211_AMPDU_TX_START: + mtxq->agg_ssn = *ssn << 4; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, *ssn, -1); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + + return 0; +} + +static void +mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = hw->priv; + struct mt7603_sta *msta = (struct mt7603_sta *) sta->drv_priv; + struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); + int i; + + spin_lock_bh(&dev->mt76.lock); + for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { + msta->rates[i].idx = sta_rates->rate[i].idx; + msta->rates[i].count = sta_rates->rate[i].count; + msta->rates[i].flags = sta_rates->rate[i].flags; + + if (msta->rates[i].idx < 0 || !msta->rates[i].count) + break; + } + msta->n_rates = i; + mt7603_wtbl_set_rates(dev, msta, NULL, msta->rates); + msta->rate_probe = false; + spin_unlock_bh(&dev->mt76.lock); +} + +static void mt7603_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) +{ + struct mt7603_dev *dev = hw->priv; + dev->coverage_class = coverage_class; + mt7603_mac_set_timing(dev); +} + +static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct mt7603_dev *dev = hw->priv; + struct mt76_wcid *wcid = &dev->global_sta.wcid; + + mt76_tx(&dev->mt76, control->sta, wcid, skb); +} + +const struct ieee80211_ops mt7603_ops = { + .tx = mt7603_tx, + .start = mt7603_start, + .stop = mt7603_stop, + .add_interface = mt7603_add_interface, + .remove_interface = mt7603_remove_interface, + .config = mt7603_config, + .configure_filter = mt7603_configure_filter, + .bss_info_changed = mt7603_bss_info_changed, + .sta_add = mt7603_sta_add, + .sta_remove = mt7603_sta_remove, + .sta_notify = mt7603_sta_notify, + .set_key = mt7603_set_key, + .conf_tx = mt7603_conf_tx, + .sw_scan_start = mt7603_sw_scan, + .sw_scan_complete = mt7603_sw_scan_complete, + .flush = mt7603_flush, + .ampdu_action = mt7603_ampdu_action, + .get_txpower = mt7603_get_txpower, + .wake_tx_queue = mt76_wake_tx_queue, + .sta_rate_tbl_update = mt7603_sta_rate_tbl_update, + .release_buffered_frames = mt76_release_buffered_frames, + .set_coverage_class = mt7603_set_coverage_class, +}; + +MODULE_LICENSE("Dual BSD/GPL"); + +static int __init mt7603_init(void) +{ + int ret; + + ret = platform_driver_register(&mt76_wmac_driver); + if (ret) + return ret; + +#ifdef CONFIG_PCI + ret = pci_register_driver(&mt7603_pci_driver); + if (ret) + platform_driver_unregister(&mt76_wmac_driver); +#endif + return ret; +} + +static void __exit mt7603_exit(void) +{ +#ifdef CONFIG_PCI + pci_unregister_driver(&mt7603_pci_driver); +#endif + platform_driver_unregister(&mt76_wmac_driver); +} + +module_init(mt7603_init); +module_exit(mt7603_exit); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603_mcu.c new file mode 100644 index 0000000000000..e04eb0ce6784f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_mcu.c @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt7603.h" +#include "mt7603_mcu.h" +#include "mt7603_eeprom.h" + +#define MCU_SKB_RESERVE 8 + +struct mt7603_fw_trailer { + char fw_ver[10]; + char build_date[15]; + __le32 dl_len; +} __packed; + +static struct sk_buff *mt7603_mcu_msg_alloc(const void *data, int len) +{ + struct sk_buff *skb; + + skb = alloc_skb(len + sizeof(struct mt7603_mcu_txd), + GFP_KERNEL); + skb_reserve(skb, sizeof(struct mt7603_mcu_txd)); + if (data && len) + memcpy(skb_put(skb, len), data, len); + + return skb; +} + +void mt7603_mcu_rx_event(struct mt7603_dev *dev, struct sk_buff *skb) +{ + skb_queue_tail(&dev->mcu.res_q, skb); + wake_up(&dev->mcu.wait); +} + +static struct sk_buff * +mt7603_mcu_get_response(struct mt7603_dev *dev, unsigned long expires) +{ + unsigned long timeout; + + if (!time_is_after_jiffies(expires)) + return NULL; + + timeout = expires - jiffies; + wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q), + timeout); + return skb_dequeue(&dev->mcu.res_q); +} + +static int +__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd, int query, int *wait_seq) +{ + int hdrlen = dev->mcu.running ? sizeof(struct mt7603_mcu_txd) : 12; + struct mt7603_mcu_txd *txd; + u8 seq; + + if (!skb) + return -EINVAL; + + seq = ++dev->mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mcu.msg_seq & 0xf; + + txd = (struct mt7603_mcu_txd *) skb_push(skb, hdrlen); + memset(txd, 0, hdrlen); + + txd->len = cpu_to_le16(skb->len); + if (cmd == -MCU_CMD_FW_SCATTER) + txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE_FW); + else + txd->pq_id = cpu_to_le16(MCU_PORT_QUEUE); + txd->pkt_type = MCU_PKT_ID; + txd->seq = seq; + + if (cmd < 0) { + txd->cid = -cmd; + } else { + txd->cid = MCU_CMD_EXT_CID; + txd->ext_cid = cmd; + if (query != MCU_Q_NA) + txd->ext_cid_ack = 1; + } + + txd->set_query = query; + + if (wait_seq) + *wait_seq = seq; + + return mt7603_tx_queue_mcu(dev, MT_TXQ_MCU, skb); +} + +static int +mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb, int cmd, int query, + struct sk_buff **skb_ret) +{ + unsigned long expires = jiffies + HZ; + struct mt7603_mcu_rxd *rxd; + int ret, seq; + + mutex_lock(&dev->mcu.mutex); + + ret = __mt7603_mcu_msg_send(dev, skb, cmd, query, &seq); + if (ret) + goto out; + + while (1) { + skb = mt7603_mcu_get_response(dev, expires); + if (!skb) { + printk("MCU message %d (seq %d) timed out\n", cmd, seq); + dev->tx_dma_check = MT7603_WATCHDOG_TIMEOUT; + ret = -ETIMEDOUT; + break; + } + + rxd = (struct mt7603_mcu_rxd *) skb->data; + skb_pull(skb, sizeof(*rxd)); + + if (seq != rxd->seq) + continue; + + if (skb_ret) + *skb_ret = skb; + else + dev_kfree_skb(skb); + + break; + } + +out: + mutex_unlock(&dev->mcu.mutex); + + return ret; +} + +static int +mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len) +{ + struct { + __le32 addr; + __le32 len; + __le32 mode; + } req = { + .addr = cpu_to_le32(addr), + .len = cpu_to_le32(len), + .mode = cpu_to_le32(BIT(31)), + }; + struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); + + return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, MCU_Q_NA, NULL); +} + +static int +mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len) +{ + struct sk_buff *skb; + int ret = 0; + + while (len > 0) { + int cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd), len); + + skb = mt7603_mcu_msg_alloc(data, cur_len); + if (!skb) + return -ENOMEM; + + ret = __mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER, MCU_Q_NA, NULL); + if (ret) + break; + + data += cur_len; + len -= cur_len; + } + + return ret; +} + +static int +mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr) +{ + struct { + __le32 override; + __le32 addr; + } req = { + .override = cpu_to_le32(addr ? 1 : 0), + .addr = cpu_to_le32(addr), + }; + struct sk_buff *skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); + + return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ, MCU_Q_NA, NULL); +} + +static int +mt7603_mcu_restart(struct mt7603_dev *dev) +{ + struct sk_buff *skb = mt7603_mcu_msg_alloc(NULL, 0); + + return mt7603_mcu_msg_send(dev, skb, -MCU_CMD_RESTART_DL_REQ, MCU_Q_NA, NULL); +} + +static int +mt7603_load_firmware(struct mt7603_dev *dev) +{ + const struct firmware *fw; + const struct mt7603_fw_trailer *hdr; + const char *firmware; + int dl_len; + u32 addr, val; + int ret; + + if (is_mt7628(dev)) { + if (mt76xx_rev(dev) == MT7628_REV_E1) + firmware = MT7628_FIRMWARE_E1; + else + firmware = MT7628_FIRMWARE_E2; + } else { + if (mt76xx_rev(dev) < MT7603_REV_E2) + firmware = MT7603_FIRMWARE_E1; + else + firmware = MT7603_FIRMWARE_E2; + } + + ret = request_firmware(&fw, firmware, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7603_fw_trailer *) (fw->data + fw->size - sizeof(*hdr)); + + dev_info(dev->mt76.dev, "Firmware Version: %.10s\n", hdr->fw_ver); + dev_info(dev->mt76.dev, "Build Time: %.15s\n", hdr->build_date); + + addr = mt7603_reg_map(dev, 0x50012498); + mt76_wr(dev, addr, 0x5); + mt76_wr(dev, addr, 0x5); + udelay(1); + + /* switch to bypass mode */ + mt76_rmw(dev, MT_SCH_4, MT_SCH_4_FORCE_QID, + MT_SCH_4_BYPASS | FIELD_PREP(MT_SCH_4_FORCE_QID, 5)); + + val = mt76_rr(dev, MT_TOP_MISC2); + if (val & BIT(1)) { + dev_info(dev->mt76.dev, "Firmware already running...\n"); + goto running; + } + + if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(0) | BIT(1), BIT(0), 500)) { + dev_err(dev->mt76.dev, "Timeout waiting for ROM code to become ready\n"); + ret = -EIO; + goto out; + } + + dl_len = le32_to_cpu(hdr->dl_len) + 4; + ret = mt7603_mcu_init_download(dev, MCU_FIRMWARE_ADDRESS, dl_len); + if (ret) { + dev_err(dev->mt76.dev, "Download request failed\n"); + goto out; + } + + ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len); + if (ret) { + dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); + goto out; + } + + ret = mt7603_mcu_start_firmware(dev, MCU_FIRMWARE_ADDRESS); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start firmware\n"); + goto out; + } + + if (!mt76_poll_msec(dev, MT_TOP_MISC2, BIT(1), BIT(1), 500)) { + dev_err(dev->mt76.dev, "Timeout waiting for firmware to initialize\n"); + ret = -EIO; + goto out; + } + +running: + mt76_clear(dev, MT_SCH_4, MT_SCH_4_FORCE_QID | MT_SCH_4_BYPASS); + + mt76_set(dev, MT_SCH_4, BIT(8)); + mt76_clear(dev, MT_SCH_4, BIT(8)); + + dev->mcu.running = true; + printk("firmware init done\n"); + +out: + release_firmware(fw); + + return ret; +} + +int mt7603_mcu_init(struct mt7603_dev *dev) +{ + mutex_init(&dev->mcu.mutex); + return mt7603_load_firmware(dev); +} + +void mt7603_mcu_exit(struct mt7603_dev *dev) +{ + struct sk_buff *skb; + + mt7603_mcu_restart(dev); + + while ((skb = skb_dequeue(&dev->mcu.res_q)) != NULL) + dev_kfree_skb(skb); +} + +int mt7603_mcu_set_eeprom(struct mt7603_dev *dev) +{ + static const u16 req_fields[] = { +#define WORD(_start) \ + _start, \ + _start + 1 +#define GROUP_2G(_start) \ + WORD(_start), \ + WORD(_start + 2), \ + WORD(_start + 4) + + MT_EE_NIC_CONF_0 + 1, + WORD(MT_EE_NIC_CONF_1), + MT_EE_WIFI_RF_SETTING, + MT_EE_TX_POWER_DELTA_BW40, + MT_EE_TX_POWER_DELTA_BW80 + 1, + MT_EE_TX_POWER_EXT_PA_5G, + MT_EE_TEMP_SENSOR_CAL, + GROUP_2G(MT_EE_TX_POWER_0_START_2G), + GROUP_2G(MT_EE_TX_POWER_1_START_2G), + WORD(MT_EE_TX_POWER_CCK), + WORD(MT_EE_TX_POWER_OFDM_2G_6M), + WORD(MT_EE_TX_POWER_OFDM_2G_24M), + WORD(MT_EE_TX_POWER_OFDM_2G_54M), + WORD(MT_EE_TX_POWER_HT_BPSK_QPSK), + WORD(MT_EE_TX_POWER_HT_16_64_QAM), + WORD(MT_EE_TX_POWER_HT_64_QAM), + MT_EE_ELAN_RX_MODE_GAIN, + MT_EE_ELAN_RX_MODE_NF, + MT_EE_ELAN_RX_MODE_P1DB, + MT_EE_ELAN_BYPASS_MODE_GAIN, + MT_EE_ELAN_BYPASS_MODE_NF, + MT_EE_ELAN_BYPASS_MODE_P1DB, + WORD(MT_EE_STEP_NUM_NEG_6_7), + WORD(MT_EE_STEP_NUM_NEG_4_5), + WORD(MT_EE_STEP_NUM_NEG_2_3), + WORD(MT_EE_STEP_NUM_NEG_0_1), + WORD(MT_EE_REF_STEP_24G), + WORD(MT_EE_STEP_NUM_PLUS_1_2), + WORD(MT_EE_STEP_NUM_PLUS_3_4), + WORD(MT_EE_STEP_NUM_PLUS_5_6), + MT_EE_STEP_NUM_PLUS_7, + MT_EE_XTAL_FREQ_OFFSET, + MT_EE_XTAL_TRIM_2_COMP, + MT_EE_XTAL_TRIM_3_COMP, + MT_EE_XTAL_WF_RFCAL, + + /* unknown fields below */ + WORD(0x24), + 0x34, + 0x39, + 0x3b, + WORD(0x42), + WORD(0x9e), + 0xf2, + WORD(0xf8), + 0xfa, + 0x12e, + WORD(0x130), WORD(0x132), WORD(0x134), WORD(0x136), + WORD(0x138), WORD(0x13a), WORD(0x13c), WORD(0x13e), + +#undef GROUP_2G +#undef WORD + + }; + struct req_data { + u16 addr; + u8 val; + u8 pad; + } __packed; + struct { + u8 buffer_mode; + u8 len; + u8 pad[2]; + } req_hdr = { + .buffer_mode = 1, + .len = ARRAY_SIZE(req_fields) - 1, + }; + struct sk_buff *skb; + struct req_data *data; + const int size = 0xff * sizeof(struct req_data); + u8 *eep = (u8 *) dev->mt76.eeprom.data; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(req_fields) * sizeof(*data) > size); + + skb = mt7603_mcu_msg_alloc(NULL, size + sizeof(req_hdr)); + memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr)); + data = (struct req_data *) skb_put(skb, size); + memset(data, 0, size); + + for (i = 0; i < ARRAY_SIZE(req_fields); i++) { + data[i].addr = cpu_to_le16(req_fields[i]); + data[i].val = eep[req_fields[i]]; + data[i].pad = 0; + } + + return mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE, MCU_Q_SET, NULL); +} + +static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev) +{ + struct { + u8 center_channel; + u8 tssi; + u8 temp_comp; + u8 target_power[2]; + u8 rate_power_delta[14]; + u8 bw_power_delta; + u8 ch_power_delta[6]; + u8 temp_comp_power[17]; + u8 reserved; + } req = { + .center_channel = dev->mt76.chandef.chan->hw_value, +#define EEP_VAL(n) ((u8 *) dev->mt76.eeprom.data)[n] + .tssi = EEP_VAL(MT_EE_NIC_CONF_1 + 1), + .temp_comp = EEP_VAL(MT_EE_NIC_CONF_1), + .target_power = { + EEP_VAL(MT_EE_TX_POWER_0_START_2G + 2), + EEP_VAL(MT_EE_TX_POWER_1_START_2G + 2) + }, + .bw_power_delta = EEP_VAL(MT_EE_TX_POWER_DELTA_BW40), + .ch_power_delta = { + EEP_VAL(MT_EE_TX_POWER_0_START_2G + 3), + EEP_VAL(MT_EE_TX_POWER_0_START_2G + 4), + EEP_VAL(MT_EE_TX_POWER_0_START_2G + 5), + EEP_VAL(MT_EE_TX_POWER_1_START_2G + 3), + EEP_VAL(MT_EE_TX_POWER_1_START_2G + 4), + EEP_VAL(MT_EE_TX_POWER_1_START_2G + 5) + }, +#undef EEP_VAL + }; + struct sk_buff *skb; + u8 *eep = (u8 *) dev->mt76.eeprom.data; + + memcpy(req.rate_power_delta, eep + MT_EE_TX_POWER_CCK, + sizeof(req.rate_power_delta)); + + memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7, + sizeof(req.temp_comp_power)); + + skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); + return mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_SET_TX_POWER_CTRL, MCU_Q_SET, NULL); +} + +int mt7603_mcu_set_channel(struct mt7603_dev *dev) +{ + struct { + u8 control_chan; + u8 center_chan; + u8 bw; + u8 tx_streams; + u8 rx_streams; + u8 _res0[7]; + u8 txpower[21]; + u8 _res1[3]; + } req = { + .control_chan = dev->mt76.chandef.chan->hw_value, + .center_chan = dev->mt76.chandef.chan->hw_value, + .bw = MT_BW_20, + .tx_streams = dev->tx_chains, + .rx_streams = dev->rx_chains, + }; + struct sk_buff *skb; + int ret; + + memset(req.txpower, 0xff, sizeof(req.txpower)); + skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); + ret = mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_CHANNEL_SWITCH, MCU_Q_SET, NULL); + if (ret) + return ret; + + return mt7603_mcu_set_tx_power(dev); +} + +int mt7603_mcu_set_timing(struct mt7603_dev *dev, int slot, int sifs, int rifs, + int eifs) +{ + struct { + u8 slot_time; + u8 sifs_time; + u8 rifs_time; + u8 __res0; + __le16 eifs_time; + __le16 __res1; + } req = { + .slot_time = slot, + .sifs_time = sifs, + .rifs_time = cpu_to_le16(rifs), + .eifs_time = cpu_to_le16(eifs), + }; + struct sk_buff *skb; + + skb = mt7603_mcu_msg_alloc(&req, sizeof(req)); + return mt7603_mcu_msg_send(dev, skb, MCU_EXT_CMD_SLOT_TIME_SET, MCU_Q_SET, NULL); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_mcu.h b/drivers/net/wireless/mediatek/mt76/mt7603_mcu.h new file mode 100644 index 0000000000000..38eb5addad027 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_mcu.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT7603_MCU_H +#define __MT7603_MCU_H + +struct mt7603_mcu_txd { + __le16 len; + __le16 pq_id; + + u8 cid; + u8 pkt_type; + u8 set_query; + u8 seq; + + u8 uc_d2b0_rev; + u8 ext_cid; + u8 uc_d2b2_rev; + u8 ext_cid_ack; + + u32 au4_d3_to_d7_rev[5]; +} __packed __aligned(4); + +struct mt7603_mcu_rxd { + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + __le16 __rsv; + + u8 ext_eid; + u8 __rsv1[3]; +}; + +#define MCU_PKT_ID 0xa0 +#define MCU_PORT_QUEUE 0x8000 +#define MCU_PORT_QUEUE_FW 0xc000 + +#define MCU_FIRMWARE_ADDRESS 0x100000 + +enum { + MCU_Q_QUERY, + MCU_Q_SET, + MCU_Q_RESERVED, + MCU_Q_NA +}; + +enum { + MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, + MCU_CMD_FW_START_REQ = 0x02, + MCU_CMD_INIT_ACCESS_REG = 0x3, + MCU_CMD_PATCH_START_REQ = 0x05, + MCU_CMD_PATCH_FINISH_REQ = 0x07, + MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_HIF_LOOPBACK = 0x20, + MCU_CMD_CH_PRIVILEGE = 0x20, + MCU_CMD_ACCESS_REG = 0xC2, + MCU_CMD_EXT_CID = 0xED, + MCU_CMD_FW_SCATTER = 0xEE, + MCU_CMD_RESTART_DL_REQ = 0xEF, +}; + +enum { + MCU_EXT_CMD_RF_REG_ACCESS = 0x02, + MCU_EXT_CMD_RF_TEST = 0x04, + MCU_EXT_CMD_RADIO_ON_OFF_CTRL = 0x05, + MCU_EXT_CMD_WIFI_RX_DISABLE = 0x06, + MCU_EXT_CMD_PM_STATE_CTRL = 0x07, + MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_NIC_CAPABILITY = 0x09, + MCU_EXT_CMD_PWR_SAVING = 0x0A, + MCU_EXT_CMD_MULTIPLE_REG_ACCESS = 0x0E, + MCU_EXT_CMD_AP_PWR_SAVING_CAPABILITY = 0xF, + MCU_EXT_CMD_SEC_ADDREMOVE_KEY = 0x10, + MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, + MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, + MCU_EXT_CMD_PS_RETRIEVE_START = 0x14, + MCU_EXT_CMD_LED_CTRL = 0x17, + MCU_EXT_CMD_PACKET_FILTER = 0x18, + MCU_EXT_CMD_PWR_MGT_BIT_WIFI = 0x1B, + MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_THERMAL_PROTECT = 0x23, + MCU_EXT_CMD_EDCA_SET = 0x27, + MCU_EXT_CMD_SLOT_TIME_SET = 0x28, + MCU_EXT_CMD_CONFIG_INTERNAL_SETTING = 0x29, + MCU_EXT_CMD_NOA_OFFLOAD_CTRL = 0x2B, + MCU_EXT_CMD_GET_THEMAL_SENSOR = 0x2C, + MCU_EXT_CMD_WAKEUP_OPTION = 0x2E, + MCU_EXT_CMD_AC_QUEUE_CONTROL = 0x31, + MCU_EXT_CMD_BCN_UPDATE = 0x33 +}; + +enum { + MCU_EXT_EVENT_CMD_RESULT = 0x0, + MCU_EXT_EVENT_RF_REG_ACCESS = 0x2, + MCU_EXT_EVENT_MULTI_CR_ACCESS = 0x0E, + MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, + MCU_EXT_EVENT_BEACON_LOSS = 0x1A, + MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, + MCU_EXT_EVENT_BCN_UPDATE = 0x31, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_pci.c b/drivers/net/wireless/mediatek/mt76/mt7603_pci.c new file mode 100644 index 0000000000000..0452e65432ffd --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_pci.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt7603.h" + +static const struct pci_device_id mt76pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7603) }, + { }, +}; + +static int +mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mt7603_dev *dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dev = mt7603_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + + dev->mt76.rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_printk(KERN_INFO, dev->mt76.dev, "ASIC revision: %04x\n", dev->mt76.rev); + + ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt7603_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt7603_register_device(dev); + if (ret) + goto error; + + return 0; +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void +mt76pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + + mt7603_unregister_device(dev); +} + +MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +MODULE_FIRMWARE(MT7603_FIRMWARE_E1); +MODULE_FIRMWARE(MT7603_FIRMWARE_E2); + +struct pci_driver mt7603_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76pci_device_table, + .probe = mt76pci_probe, + .remove = mt76pci_remove, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_regs.h b/drivers/net/wireless/mediatek/mt76/mt7603_regs.h new file mode 100644 index 0000000000000..8b54154ed9768 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_regs.h @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT7603_REGS_H +#define __MT7603_REGS_H + +#define MT_HW_REV 0x1000 +#define MT_HW_CHIPID 0x1008 +#define MT_TOP_MISC2 0x1134 + +#define MT_MCU_BASE 0x2000 +#define MT_MCU(ofs) (MT_MCU_BASE + (ofs)) + +#define MT_MCU_PCIE_REMAP_1 MT_MCU(0x500) +#define MT_MCU_PCIE_REMAP_1_OFFSET GENMASK(17, 0) +#define MT_MCU_PCIE_REMAP_1_BASE GENMASK(31, 18) + +#define MT_MCU_PCIE_REMAP_2 MT_MCU(0x504) +#define MT_MCU_PCIE_REMAP_2_OFFSET GENMASK(18, 0) +#define MT_MCU_PCIE_REMAP_2_BASE GENMASK(31, 19) + +#define MT_HIF_BASE 0x4000 +#define MT_HIF(ofs) (MT_HIF_BASE + (ofs)) + +#define MT_INT_SOURCE_CSR MT_HIF(0x200) +#define MT_INT_MASK_CSR MT_HIF(0x204) +#define MT_DELAY_INT_CFG MT_HIF(0x210) + +#define MT_INT_RX_DONE(_n) BIT(_n) +#define MT_INT_RX_DONE_ALL GENMASK(1, 0) +#define MT_INT_TX_DONE_ALL GENMASK(19, 4) +#define MT_INT_TX_DONE(_n) BIT(_n + 4) + +#define MT_INT_RX_COHERENT BIT(20) +#define MT_INT_TX_COHERENT BIT(21) +#define MT_INT_MAC_IRQ3 BIT(27) + +#define MT_INT_MCU_CMD BIT(30) + +#define MT_WPDMA_GLO_CFG MT_HIF(0x208) +#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) +#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) +#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) +#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) +#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) +#define MT_WPDMA_GLO_CFG_SW_RESET BIT(24) +#define MT_WPDMA_GLO_CFG_FORCE_TX_EOF BIT(25) +#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) +#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) + +#define MT_WPDMA_RST_IDX MT_HIF(0x20c) + +#define MT_TX_RING_BASE MT_HIF(0x300) +#define MT_RX_RING_BASE MT_HIF(0x400) + +#define MT_TXTIME_THRESH_BASE MT_HIF(0x500) +#define MT_TXTIME_THRESH(n) (MT_TXTIME_THRESH_BASE + ((n) * 4)) + +#define MT_PAGE_COUNT_BASE MT_HIF(0x540) +#define MT_PAGE_COUNT(n) (MT_PAGE_COUNT_BASE + ((n) * 4)) + +#define MT_SCH_1 MT_HIF(0x588) +#define MT_SCH_2 MT_HIF(0x58c) +#define MT_SCH_3 MT_HIF(0x590) + +#define MT_SCH_4 MT_HIF(0x594) +#define MT_SCH_4_FORCE_QID GENMASK(4, 0) +#define MT_SCH_4_BYPASS BIT(5) + +#define MT_GROUP_THRESH_BASE MT_HIF(0x598) +#define MT_GROUP_THRESH(n) (MT_GROUP_THRESH_BASE + ((n) * 4)) + +#define MT_QUEUE_PRIORITY_1 MT_HIF(0x580) +#define MT_QUEUE_PRIORITY_2 MT_HIF(0x584) + +#define MT_BMAP_0 MT_HIF(0x5b0) +#define MT_BMAP_1 MT_HIF(0x5b4) +#define MT_BMAP_2 MT_HIF(0x5b8) + +#define MT_HIGH_PRIORITY_1 MT_HIF(0x5bc) +#define MT_HIGH_PRIORITY_2 MT_HIF(0x5c0) + +#define MT_PRIORITY_MASK MT_HIF(0x5c4) + +#define MT_RSV_MAX_THRESH MT_HIF(0x5c8) + +#define MT_PSE_BASE 0x8000 +#define MT_PSE(ofs) (MT_PSE_BASE + (ofs)) + +#define MT_PSE_RESET MT_PSE(0x16c) +#define MT_PSE_RESET_SW BIT(0) +#define MT_PSE_RESET_SW_S BIT(1) +#define MT_PSE_RESET_QUEUES GENMASK(6, 2) + +#define MT_PSE_FC_P0 MT_PSE(0x120) +#define MT_PSE_FC_P0_MIN_RESERVE GENMASK(11, 0) +#define MT_PSE_FC_P0_MAX_QUOTA GENMASK(27, 16) + +#define MT_PSE_FRP MT_PSE(0x138) +#define MT_PSE_FRP_P0 GENMASK(2, 0) +#define MT_PSE_FRP_P1 GENMASK(5, 3) +#define MT_PSE_FRP_P2_RQ0 GENMASK(8, 6) +#define MT_PSE_FRP_P2_RQ1 GENMASK(11, 9) +#define MT_PSE_FRP_P2_RQ2 GENMASK(14, 12) + +#define MT_FC_RSV_COUNT_0 MT_PSE(0x13c) +#define MT_FC_RSV_COUNT_0_P0 GENMASK(11, 0) +#define MT_FC_RSV_COUNT_0_P1 GENMASK(27, 16) + +#define MT_FC_SP2_Q0Q1 MT_PSE(0x14c) +#define MT_FC_SP2_Q0Q1_SRC_COUNT_Q0 GENMASK(11, 0) +#define MT_FC_SP2_Q0Q1_SRC_COUNT_Q1 GENMASK(27, 16) + +#define MT_WF_PHY_BASE 0x10000 +#define MT_WF_PHY_OFFSET 0x1000 +#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) + +#define MT_WF_PHY_CR_RXTD_BASE MT_WF_PHY(0x65c) +#define MT_WF_PHY_CR_RXTD(n) (MT_WF_PHY_CR_RXTD_BASE + ((n) * 4)) + +#define MT_WF_PHY_CR_TSSI_BASE MT_WF_PHY(0xd00) +#define MT_WF_PHY_CR_TSSI(phy, n) (MT_WF_PHY_CR_TSSI_BASE + \ + ((phy) * MT_WF_PHY_OFFSET) + \ + ((n) * 4)) + +#define MT_WF_AGG_BASE 0x21200 +#define MT_WF_AGG(ofs) (MT_WF_AGG_BASE + (ofs)) + +#define MT_AGG_ARCR MT_WF_AGG(0x010) +#define MT_AGG_ARCR_INIT_RATE1 BIT(0) +#define MT_AGG_ARCR_FB_SGI_DISABLE BIT(1) +#define MT_AGG_ARCR_RATE8_DOWN_WRAP BIT(2) +#define MT_AGG_ARCR_RTS_RATE_THR GENMASK(12, 8) +#define MT_AGG_ARCR_RATE_DOWN_RATIO GENMASK(17, 16) +#define MT_AGG_ARCR_RATE_DOWN_RATIO_EN BIT(19) +#define MT_AGG_ARCR_RATE_UP_EXTRA_TH GENMASK(22, 20) +#define MT_AGG_ARCR_SPE_DIS_TH GENMASK(27, 24) + + +#define MT_AGG_ARUCR MT_WF_AGG(0x014) +#define MT_AGG_ARDCR MT_WF_AGG(0x018) +#define MT_AGG_ARxCR_LIMIT_SHIFT(_n) (4 * _n) +#define MT_AGG_ARxCR_LIMIT(_n) GENMASK(2 + MT_AGG_ARxCR_LIMIT_SHIFT(_n), \ + MT_AGG_ARxCR_LIMIT_SHIFT(_n)) + +#define MT_AGG_LIMIT MT_WF_AGG(0x040) +#define MT_AGG_LIMIT_1 MT_WF_AGG(0x044) +#define MT_AGG_LIMIT_AC(n) GENMASK(((n) + 1) * 8 - 1, (n) * 8) + +#define MT_AGG_BA_SIZE_LIMIT_0 MT_WF_AGG(0x048) +#define MT_AGG_BA_SIZE_LIMIT_1 MT_WF_AGG(0x04c) +#define MT_AGG_BA_SIZE_LIMIT_SHIFT 8 + +#define MT_AGG_PCR MT_WF_AGG(0x050) +#define MT_AGG_PCR_MM BIT(16) +#define MT_AGG_PCR_GF BIT(17) +#define MT_AGG_PCR_BW40 BIT(18) +#define MT_AGG_PCR_RIFS BIT(19) +#define MT_AGG_PCR_BW80 BIT(20) +#define MT_AGG_PCR_BW160 BIT(21) +#define MT_AGG_PCR_ERP BIT(22) + +#define MT_AGG_PCR_RTS MT_WF_AGG(0x054) +#define MT_AGG_PCR_RTS_THR GENMASK(19, 0) +#define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25) + +#define MT_AGG_CONTROL MT_WF_AGG(0x070) +#define MT_AGG_CONTROL_NO_BA_RULE BIT(0) +#define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1) +#define MT_AGG_CONTROL_CFEND_SPE_EN BIT(3) +#define MT_AGG_CONTROL_CFEND_RATE GENMASK(15, 4) +#define MT_AGG_CONTROL_BAR_SPE_EN BIT(19) +#define MT_AGG_CONTROL_BAR_RATE GENMASK(31, 24) + +#define MT_AGG_TMP MT_WF_AGG(0x0d8) + +#define MT_AGG_BWCR MT_WF_AGG(0x0ec) +#define MT_AGG_BWCR_BW GENMASK(3, 2) + +#define MT_AGG_RETRY_CONTROL MT_WF_AGG(0x0f4) +#define MT_AGG_RETRY_CONTROL_RTS_LIMIT GENMASK(11, 7) +#define MT_AGG_RETRY_CONTROL_BAR_LIMIT GENMASK(15, 12) + +#define MT_WF_DMA_BASE 0x21c00 +#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) + +#define MT_DMA_DCR0 MT_WF_DMA(0x000) +#define MT_DMA_DCR1 MT_WF_DMA(0x004) +#define MT_DMA_RCFR0 MT_WF_DMA(0x070) +#define MT_DMA_VCFR0 MT_WF_DMA(0x07c) + +#define MT_DMA_TCFR0 MT_WF_DMA(0x080) +#define MT_DMA_TCFR1 MT_WF_DMA(0x084) +#define MT_DMA_TCFR_TXS_AGGR_TIMEOUT GENMASK(27, 16) +#define MT_DMA_TCFR_TXS_QUEUE BIT(14) +#define MT_DMA_TCFR_TXS_AGGR_COUNT GENMASK(12, 8) +#define MT_DMA_TCFR_TXS_BIT_MAP GENMASK(6, 0) + +#define MT_DMA_TMCFR0 MT_WF_DMA(0x088) + +#define MT_WF_ARB_BASE 0x21400 +#define MT_WF_ARB(ofs) (MT_WF_ARB_BASE + (ofs)) + +#define MT_WMM_AIFSN MT_WF_ARB(0x020) +#define MT_WMM_AIFSN_MASK GENMASK(3, 0) +#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_CWMAX_BASE MT_WF_ARB(0x028) +#define MT_WMM_CWMAX(_n) (MT_WMM_CWMAX_BASE + (((_n) / 2) << 2)) +#define MT_WMM_CWMAX_SHIFT(_n) (((_n) & 1) * 16) +#define MT_WMM_CWMAX_MASK GENMASK(15, 0) + +#define MT_WMM_CWMIN MT_WF_ARB(0x040) +#define MT_WMM_CWMIN_MASK GENMASK(7, 0) +#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 8) + +#define MT_WF_ARB_RQCR MT_WF_ARB(0x070) +#define MT_WF_ARB_RQCR_RX_START BIT(0) +#define MT_WF_ARB_RQCR_RXV_START BIT(4) +#define MT_WF_ARB_RQCR_RXV_R_EN BIT(7) +#define MT_WF_ARB_RQCR_RXV_T_EN BIT(8) + +#define MT_ARB_SCR MT_WF_ARB(0x080) +#define MT_ARB_SCR_BCNQ_OPMODE_MASK GENMASK(1, 0) +#define MT_ARB_SCR_BCNQ_OPMODE_SHIFT(n) (n * 2) +#define MT_ARB_SCR_TX_DISABLE BIT(8) +#define MT_ARB_SCR_RX_DISABLE BIT(9) +#define MT_ARB_SCR_BCNQ_EMPTY_SKIP BIT(28) +#define MT_ARB_SCR_TTTT_BTIM_PRIO BIT(29) +#define MT_ARB_SCR_TBTT_BCN_PRIO BIT(30) +#define MT_ARB_SCR_TBTT_BCAST_PRIO BIT(31) + +enum { + MT_BCNQ_OPMODE_STA = 0, + MT_BCNQ_OPMODE_AP = 1, + MT_BCNQ_OPMODE_ADHOC = 2, +}; + +#define MT_WF_ARB_TX_START_0 MT_WF_ARB(0x100) +#define MT_WF_ARB_TX_START_1 MT_WF_ARB(0x104) +#define MT_WF_ARB_TX_FLUSH_0 MT_WF_ARB(0x108) +#define MT_WF_ARB_TX_FLUSH_1 MT_WF_ARB(0x10c) +#define MT_WF_ARB_TX_STOP_0 MT_WF_ARB(0x110) +#define MT_WF_ARB_TX_STOP_1 MT_WF_ARB(0x114) + +#define MT_WF_ARB_BCN_START MT_WF_ARB(0x118) +#define MT_WF_ARB_BCN_START_BSSn(n) BIT(0 + (n)) +#define MT_WF_ARB_BCN_START_T_PRE_TTTT BIT(10) +#define MT_WF_ARB_BCN_START_T_TTTT BIT(11) +#define MT_WF_ARB_BCN_START_T_PRE_TBTT BIT(12) +#define MT_WF_ARB_BCN_START_T_TBTT BIT(13) +#define MT_WF_ARB_BCN_START_T_SLOT_IDLE BIT(14) +#define MT_WF_ARB_BCN_START_T_TX_START BIT(15) +#define MT_WF_ARB_BCN_START_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) + +#define MT_WF_ARB_BCN_FLUSH MT_WF_ARB(0x11c) +#define MT_WF_ARB_BCN_FLUSH_BSSn(n) BIT(0 + (n)) +#define MT_WF_ARB_BCN_FLUSH_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) + +#define MT_WF_ARB_CAB_START MT_WF_ARB(0x120) +#define MT_WF_ARB_CAB_START_BSSn(n) BIT(0 + (n)) +#define MT_WF_ARB_CAB_START_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) + +#define MT_WF_ARB_CAB_FLUSH MT_WF_ARB(0x124) +#define MT_WF_ARB_CAB_FLUSH_BSSn(n) BIT(0 + (n)) +#define MT_WF_ARB_CAB_FLUSH_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) + +#define MT_WF_ARB_CAB_COUNT(n) MT_WF_ARB(0x128 + (n) * 4) +#define MT_WF_ARB_CAB_COUNT_SHIFT 4 +#define MT_WF_ARB_CAB_COUNT_MASK GENMASK(3, 0) +#define MT_WF_ARB_CAB_COUNT_B0_REG(n) MT_WF_ARB_CAB_COUNT(((n) > 12 ? 2 : \ + ((n) > 4 ? 1 : 0))) +#define MT_WF_ARB_CAB_COUNT_B0_SHIFT(n) (((n) > 12 ? (n) - 12 : \ + ((n) > 4 ? (n) - 4 : \ + (n) ? (n) + 3 : 0)) * 4) + +#define MT_WF_TMAC_BASE 0x21600 +#define MT_WF_TMAC(ofs) (MT_WF_TMAC_BASE + (ofs)) + +#define MT_TMAC_TCR MT_WF_TMAC(0x000) +#define MT_TMAC_TCR_BLINK_SEL GENMASK(7, 6) +#define MT_TMAC_TCR_PRE_RTS_GUARD GENMASK(11, 8) +#define MT_TMAC_TCR_PRE_RTS_SEC_IDLE GENMASK(13, 12) +#define MT_TMAC_TCR_RTS_SIGTA BIT(14) +#define MT_TMAC_TCR_LDPC_OFS BIT(15) +#define MT_TMAC_TCR_TX_STREAMS GENMASK(17, 16) +#define MT_TMAC_TCR_SCH_IDLE_SEL GENMASK(19, 18) +#define MT_TMAC_TCR_SCH_DET_PER_IOD BIT(20) +#define MT_TMAC_TCR_DCH_DET_DISABLE BIT(21) +#define MT_TMAC_TCR_TX_RIFS BIT(22) +#define MT_TMAC_TCR_RX_RIFS_MODE BIT(23) +#define MT_TMAC_TCR_TXOP_TBTT_CTL BIT(24) +#define MT_TMAC_TCR_TBTT_TX_STOP_CTL BIT(25) +#define MT_TMAC_TCR_TXOP_BURST_STOP BIT(26) +#define MT_TMAC_TCR_RDG_RA_MODE BIT(27) +#define MT_TMAC_TCR_RDG_RESP BIT(29) +#define MT_TMAC_TCR_RDG_NO_PENDING BIT(30) +#define MT_TMAC_TCR_SMOOTHING BIT(31) + +#define MT_WMM_TXOP_BASE MT_WF_TMAC(0x010) +#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) +#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) +#define MT_WMM_TXOP_MASK GENMASK(15, 0) + +#define MT_TIMEOUT_CCK MT_WF_TMAC(0x090) +#define MT_TIMEOUT_OFDM MT_WF_TMAC(0x094) +#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) +#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) + +#define MT_RXREQ MT_WF_TMAC(0x0a0) +#define MT_RXREQ_DELAY GENMASK(8, 0) + +#define MT_IFS MT_WF_TMAC(0x0a4) +#define MT_IFS_EIFS GENMASK(8, 0) +#define MT_IFS_RIFS GENMASK(14, 10) +#define MT_IFS_SIFS GENMASK(22, 16) +#define MT_IFS_SLOT GENMASK(30, 24) + +#define MT_TMAC_PCR MT_WF_TMAC(0x0b4) +#define MT_TMAC_PCR_RATE GENMASK(8, 0) +#define MT_TMAC_PCR_RATE_FIXED BIT(15) +#define MT_TMAC_PCR_ANT_ID GENMASK(21, 16) +#define MT_TMAC_PCR_ANT_ID_SEL BIT(22) +#define MT_TMAC_PCR_SPE_EN BIT(23) +#define MT_TMAC_PCR_ANT_PRI GENMASK(26, 24) +#define MT_TMAC_PCR_ANT_PRI_SEL GENMASK(27) + +#define MT_WF_RMAC_BASE 0x21800 +#define MT_WF_RMAC(ofs) (MT_WF_RMAC_BASE + (ofs)) + +#define MT_WF_RFCR MT_WF_RMAC(0x000) +#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) +#define MT_WF_RFCR_DROP_FCSFAIL BIT(1) +#define MT_WF_RFCR_DROP_VERSION BIT(3) +#define MT_WF_RFCR_DROP_PROBEREQ BIT(4) +#define MT_WF_RFCR_DROP_MCAST BIT(5) +#define MT_WF_RFCR_DROP_BCAST BIT(6) +#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) +#define MT_WF_RFCR_DROP_A3_MAC BIT(8) +#define MT_WF_RFCR_DROP_A3_BSSID BIT(9) +#define MT_WF_RFCR_DROP_A2_BSSID BIT(10) +#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) +#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) +#define MT_WF_RFCR_DROP_CTL_RSV BIT(13) +#define MT_WF_RFCR_DROP_CTS BIT(14) +#define MT_WF_RFCR_DROP_RTS BIT(15) +#define MT_WF_RFCR_DROP_DUPLICATE BIT(16) +#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) +#define MT_WF_RFCR_DROP_OTHER_UC BIT(18) +#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) +#define MT_WF_RFCR_DROP_NDPA BIT(20) +#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) + +#define MT_BSSID0(idx) MT_WF_RMAC(0x004 + idx * 8) +#define MT_BSSID1(idx) MT_WF_RMAC(0x008 + idx * 8) +#define MT_BSSID1_VALID BIT(16) + +#define MT_MAC_ADDR0(idx) MT_WF_RMAC(0x024 + idx * 8) +#define MT_MAC_ADDR1(idx) MT_WF_RMAC(0x028 + idx * 8) +#define MT_MAC_ADDR1_ADDR GENMASK(15, 0) +#define MT_MAC_ADDR1_VALID BIT(16) + +#define MT_BA_CONTROL_0 MT_WF_RMAC(0x068) +#define MT_BA_CONTROL_1 MT_WF_RMAC(0x06c) +#define MT_BA_CONTROL_1_ADDR GENMASK(15, 0) +#define MT_BA_CONTROL_1_TID GENMASK(19, 16) +#define MT_BA_CONTROL_1_IGNORE_TID BIT(20) +#define MT_BA_CONTROL_1_IGNORE_ALL BIT(21) +#define MT_BA_CONTROL_1_RESET BIT(22) + +#define MT_WF_RMACDR MT_WF_RMAC(0x078) +#define MT_WF_RMACDR_TSF_PROBERSP_DIS BIT(0) +#define MT_WF_RMACDR_TSF_TIM BIT(4) +#define MT_WF_RMACDR_MBSSID_MASK GENMASK(25, 24) +#define MT_WF_RMACDR_CHECK_HTC_BY_RATE BIT(26) +#define MT_WF_RMACDR_MAXLEN_20BIT BIT(30) + +#define MT_WF_RMAC_RMCR MT_WF_RMAC(0x080) +#define MT_WF_RMAC_RMCR_SMPS_MODE GENMASK(21, 20) +#define MT_WF_RMAC_RMCR_RX_STREAMS GENMASK(24, 22) +#define MT_WF_RMAC_RMCR_SMPS_RTS BIT(25) + +#define MT_WF_RMAC_CH_FREQ MT_WF_RMAC(0x090) +#define MT_WF_RMAC_MAXMINLEN MT_WF_RMAC(0x098) +#define MT_WF_RFCR1 MT_WF_RMAC(0x0a4) +#define MT_WF_RMAC_TMR_PA MT_WF_RMAC(0x0e0) + +#define MT_WF_SEC_BASE 0x21a00 +#define MT_WF_SEC(ofs) (MT_WF_SEC_BASE + (ofs)) + +#define MT_SEC_SCR MT_WF_SEC(0x004) +#define MT_SEC_SCR_MASK_ORDER GENMASK(1, 0) + +#define MT_WTBL_OFF_BASE 0x23000 +#define MT_WTBL_OFF(n) (MT_WTBL_OFF_BASE + (n)) + +#define MT_WTBL_UPDATE MT_WTBL_OFF(0x000) +#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0) +#define MT_WTBL_UPDATE_WTBL2 BIT(11) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) +#define MT_WTBL_UPDATE_RATE_UPDATE BIT(13) +#define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14) +#define MT_WTBL_UPDATE_RX_COUNT_CLEAR BIT(15) +#define MT_WTBL_UPDATE_BUSY BIT(16) + +#define MT_WTBL_RMVTCR MT_WTBL_OFF(0x008) +#define MT_WTBL_RMVTCR_RX_MV_MODE BIT(23) + +#define MT_LPON_BASE 0x24000 +#define MT_LPON(n) (MT_LPON_BASE + (n)) + +#define MT_LPON_BTEIR MT_LPON(0x020) +#define MT_LPON_BTEIR_MBSS_MODE GENMASK(31, 29) + +#define MT_PRE_TBTT MT_LPON(0x030) +#define MT_PRE_TBTT_MASK GENMASK(7, 0) +#define MT_PRE_TBTT_SHIFT 8 + +#define MT_TBTT MT_LPON(0x034) +#define MT_TBTT_PERIOD GENMASK(15, 0) +#define MT_TBTT_DTIM_PERIOD GENMASK(23, 16) +#define MT_TBTT_TBTT_WAKE_PERIOD GENMASK(27, 24) +#define MT_TBTT_DTIM_WAKE_PERIOD GENMASK(30, 28) +#define MT_TBTT_CAL_ENABLE BIT(31) + +#define MT_TBTT_TIMER_CFG MT_LPON(0x05c) + +#define MT_LPON_SBTOR(n) MT_LPON(0x0a0) +#define MT_LPON_SBTOR_SUB_BSS_EN BIT(29) +#define MT_LPON_SBTOR_TIME_OFFSET GENMASK(19, 0) + +#define MT_INT_WAKEUP_BASE 0x24400 +#define MT_INT_WAKEUP(n) (MT_INT_WAKEUP_BASE + (n)) + +#define MT_HW_INT_STATUS(n) MT_INT_WAKEUP(0x3c + (n) * 8) +#define MT_HW_INT_MASK(n) MT_INT_WAKEUP(0x40 + (n) * 8) + +#define MT_HW_INT3_TBTT0 BIT(15) +#define MT_HW_INT3_PRE_TBTT0 BIT(31) + +#define MT_WTBL1_BASE 0x28000 + +#define MT_WTBL_ON_BASE (MT_WTBL1_BASE + 0x2000) +#define MT_WTBL_ON(_n) (MT_WTBL_ON_BASE + (_n)) + +#define MT_WTBL_RIUCR0 MT_WTBL_ON(0x200) + +#define MT_WTBL_RIUCR1 MT_WTBL_ON(0x204) +#define MT_WTBL_RIUCR1_RATE0 GENMASK(11, 0) +#define MT_WTBL_RIUCR1_RATE1 GENMASK(23, 12) +#define MT_WTBL_RIUCR1_RATE2_LO GENMASK(31, 24) + +#define MT_WTBL_RIUCR2 MT_WTBL_ON(0x208) +#define MT_WTBL_RIUCR2_RATE2_HI GENMASK(3, 0) +#define MT_WTBL_RIUCR2_RATE3 GENMASK(15, 4) +#define MT_WTBL_RIUCR2_RATE4 GENMASK(27, 16) +#define MT_WTBL_RIUCR2_RATE5_LO GENMASK(31, 28) + +#define MT_WTBL_RIUCR3 MT_WTBL_ON(0x20c) +#define MT_WTBL_RIUCR3_RATE5_HI GENMASK(7, 0) +#define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) +#define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) + +#define MT_PCIE_REMAP_BASE_1 0x40000 +#define MT_PCIE_REMAP_BASE_2 0x80000 + +#define MT_TX_HW_QUEUE_MGMT 4 +#define MT_TX_HW_QUEUE_MCU 5 +#define MT_TX_HW_QUEUE_BCN 7 +#define MT_TX_HW_QUEUE_BMC 8 + +#define MT_LED_BASE_PHYS 0x80024000 +#define MT_LED_PHYS(_n) (MT_LED_BASE_PHYS + (_n)) + +#define MT_LED_CTRL MT_LED_PHYS(0x00) + +#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) +#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) +#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) +#define MT_LED_CTRL_TX_MANUAL_BLINK(_n) BIT(3 + (8 * (_n))) +#define MT_LED_CTRL_TX_OVER_BLINK(_n) BIT(5 + (8 * (_n))) +#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) + +#define MT_LED_STATUS_0(_n) MT_LED_PHYS(0x10 + ((_n) * 8)) +#define MT_LED_STATUS_1(_n) MT_LED_PHYS(0x14 + ((_n) * 8)) +#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) +#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ + MT_LED_STATUS_OFF_MASK) +#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) +#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ + MT_LED_STATUS_ON_MASK) +#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 0) +#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ + MT_LED_STATUS_DURATION_MASK) + +#define MT_CLIENT_BASE_PHYS_ADDR 0x800c0000 + +#define MT_CLIENT_TMAC_INFO_TEMPLATE 0x040 + +#define MT_CLIENT_STATUS 0x06c + +#define MT_CLIENT_RESET_TX 0x070 +#define MT_CLIENT_RESET_TX_R_E_1 BIT(16) +#define MT_CLIENT_RESET_TX_R_E_2 BIT(17) +#define MT_CLIENT_RESET_TX_R_E_1_S BIT(20) +#define MT_CLIENT_RESET_TX_R_E_2_S BIT(21) + + +#define MT_EFUSE_BASE 0x81070000 + +#define MT_EFUSE_BASE_CTRL 0x000 +#define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) + +#define MT_EFUSE_CTRL 0x008 +#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) +#define MT_EFUSE_CTRL_MODE GENMASK(7, 6) +#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) +#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) +#define MT_EFUSE_CTRL_AIN GENMASK(25, 16) +#define MT_EFUSE_CTRL_VALID BIT(29) +#define MT_EFUSE_CTRL_KICK BIT(30) +#define MT_EFUSE_CTRL_SEL BIT(31) + +#define MT_EFUSE_WDATA(_i) (0x010 + ((_i) * 4)) +#define MT_EFUSE_RDATA(_i) (0x030 + ((_i) * 4)) + +#define MT_CLIENT_RXINF 0x068 +#define MT_CLIENT_RXINF_RXSH_GROUPS GENMASK(2, 0) + +#define MT_PSE_BASE_PHYS_ADDR 0xa0000000 + +#define MT_PSE_WTBL_2_PHYS_ADDR 0xa5000000 + +#define MT_WTBL1_SIZE (8 * 4) +#define MT_WTBL2_SIZE (16 * 4) +#define MT_WTBL3_OFFSET (MT7603_WTBL_SIZE * MT_WTBL2_SIZE) +#define MT_WTBL3_SIZE (16 * 4) +#define MT_WTBL4_OFFSET (MT7603_WTBL_SIZE * MT_WTBL3_SIZE + \ + MT_WTBL3_OFFSET) +#define MT_WTBL4_SIZE (8 * 4) + +#define MT_WTBL1_W0_ADDR_HI GENMASK(15, 0) +#define MT_WTBL1_W0_MUAR_IDX GENMASK(21, 16) +#define MT_WTBL1_W0_RX_CHECK_A1 BIT(22) +#define MT_WTBL1_W0_KEY_IDX GENMASK(24, 23) +#define MT_WTBL1_W0_RX_CHECK_KEY_IDX BIT(25) +#define MT_WTBL1_W0_RX_KEY_VALID BIT(26) +#define MT_WTBL1_W0_RX_IK_VALID BIT(27) +#define MT_WTBL1_W0_RX_VALID BIT(28) +#define MT_WTBL1_W0_RX_CHECK_A2 BIT(29) +#define MT_WTBL1_W0_RX_DATA_VALID BIT(30) +#define MT_WTBL1_W0_WRITE_BURST BIT(31) + +#define MT_WTBL1_W1_ADDR_LO GENMASK(31, 0) + +#define MT_WTBL1_W2_MPDU_DENSITY GENMASK(2, 0) +#define MT_WTBL1_W2_KEY_TYPE GENMASK(6, 3) +#define MT_WTBL1_W2_EVEN_PN BIT(7) +#define MT_WTBL1_W2_TO_DS BIT(8) +#define MT_WTBL1_W2_FROM_DS BIT(9) +#define MT_WTBL1_W2_HEADER_TRANS BIT(10) +#define MT_WTBL1_W2_AMPDU_FACTOR GENMASK(13, 11) +#define MT_WTBL1_W2_PWR_MGMT BIT(14) +#define MT_WTBL1_W2_RDG BIT(15) +#define MT_WTBL1_W2_RTS BIT(16) +#define MT_WTBL1_W2_CFACK BIT(17) +#define MT_WTBL1_W2_RDG_BA BIT(18) +#define MT_WTBL1_W2_SMPS BIT(19) +#define MT_WTBL1_W2_TXS_BAF_REPORT BIT(20) +#define MT_WTBL1_W2_DYN_BW BIT(21) +#define MT_WTBL1_W2_LDPC BIT(22) +#define MT_WTBL1_W2_ITXBF BIT(23) +#define MT_WTBL1_W2_ETXBF BIT(24) +#define MT_WTBL1_W2_TXOP_PS BIT(25) +#define MT_WTBL1_W2_MESH BIT(26) +#define MT_WTBL1_W2_QOS BIT(27) +#define MT_WTBL1_W2_HT BIT(28) +#define MT_WTBL1_W2_VHT BIT(29) +#define MT_WTBL1_W2_ADMISSION_CONTROL BIT(30) +#define MT_WTBL1_W2_GROUP_ID BIT(31) + +#define MT_WTBL1_W3_WTBL2_FRAME_ID GENMASK(10, 0) +#define MT_WTBL1_W3_WTBL2_ENTRY_ID GENMASK(15, 11) +#define MT_WTBL1_W3_WTBL4_FRAME_ID GENMASK(26, 16) +#define MT_WTBL1_W3_CHECK_PER BIT(27) +#define MT_WTBL1_W3_KEEP_I_PSM BIT(28) +#define MT_WTBL1_W3_I_PSM BIT(29) +#define MT_WTBL1_W3_POWER_SAVE BIT(30) +#define MT_WTBL1_W3_SKIP_TX BIT(31) + +#define MT_WTBL1_W4_WTBL3_FRAME_ID GENMASK(10, 0) +#define MT_WTBL1_W4_WTBL3_ENTRY_ID GENMASK(16, 11) +#define MT_WTBL1_W4_WTBL4_ENTRY_ID GENMASK(22, 17) +#define MT_WTBL1_W4_PARTIAL_AID GENMASK(31, 23) + + +#define MT_WTBL2_W0_PN_LO GENMASK(31, 0) + +#define MT_WTBL2_W1_PN_HI GENMASK(15, 0) +#define MT_WTBL2_W1_NON_QOS_SEQNO GENMASK(27, 16) + +#define MT_WTBL2_W2_TID0_SN GENMASK(11, 0) +#define MT_WTBL2_W2_TID1_SN GENMASK(23, 12) +#define MT_WTBL2_W2_TID2_SN_LO GENMASK(31, 24) + +#define MT_WTBL2_W3_TID2_SN_HI GENMASK(3, 0) +#define MT_WTBL2_W3_TID3_SN GENMASK(15, 4) +#define MT_WTBL2_W3_TID4_SN GENMASK(27, 16) +#define MT_WTBL2_W3_TID5_SN_LO GENMASK(31, 28) + +#define MT_WTBL2_W4_TID5_SN_HI GENMASK(7, 0) +#define MT_WTBL2_W4_TID6_SN GENMASK(19, 8) +#define MT_WTBL2_W4_TID7_SN GENMASK(31, 20) + +#define MT_WTBL2_W5_TX_COUNT_RATE1 GENMASK(15, 0) +#define MT_WTBL2_W5_FAIL_COUNT_RATE1 GENAMSK(31, 16) + +#define MT_WTBL2_W6_TX_COUNT_RATE2 GENMASK(7, 0) +#define MT_WTBL2_W6_TX_COUNT_RATE3 GENMASK(15, 8) +#define MT_WTBL2_W6_TX_COUNT_RATE4 GENMASK(23, 16) +#define MT_WTBL2_W6_TX_COUNT_RATE5 GENMASK(31, 24) + +#define MT_WTBL2_W7_TX_COUNT_CUR_BW GENMASK(15, 0) +#define MT_WTBL2_W7_FAIL_COUNT_CUR_BW GENMASK(31, 16) + +#define MT_WTBL2_W8_TX_COUNT_OTHER_BW GENMASK(15, 0) +#define MT_WTBL2_W8_FAIL_COUNT_OTHER_BW GENMASK(31, 16) + +#define MT_WTBL2_W9_POWER_OFFSET GENMASK(4, 0) +#define MT_WTBL2_W9_SPATIAL_EXT BIT(5) +#define MT_WTBL2_W9_ANT_PRIORITY GENMASK(8, 6) +#define MT_WTBL2_W9_CC_BW_SEL GENMASK(10, 9) +#define MT_WTBL2_W9_CHANGE_BW_RATE GENMASK(13, 11) +#define MT_WTBL2_W9_BW_CAP GENMASK(15, 14) +#define MT_WTBL2_W9_SHORT_GI_20 BIT(16) +#define MT_WTBL2_W9_SHORT_GI_40 BIT(17) +#define MT_WTBL2_W9_SHORT_GI_80 BIT(18) +#define MT_WTBL2_W9_SHORT_GI_160 BIT(19) +#define MT_WTBL2_W9_MPDU_FAIL_COUNT GENMASK(25, 23) +#define MT_WTBL2_W9_MPDU_OK_COUNT GENMASK(28, 26) +#define MT_WTBL2_W9_RATE_IDX GENMASK(31, 29) + +#define MT_WTBL2_W10_RATE1 GENMASK(11, 0) +#define MT_WTBL2_W10_RATE2 GENMASK(23, 12) +#define MT_WTBL2_W10_RATE3_LO GENMASK(31, 24) + +#define MT_WTBL2_W11_RATE3_HI GENMASK(3, 0) +#define MT_WTBL2_W11_RATE4 GENMASK(15, 4) +#define MT_WTBL2_W11_RATE5 GENMASK(27, 16) +#define MT_WTBL2_W11_RATE6_LO GENMASK(31, 28) + +#define MT_WTBL2_W12_RATE6_HI GENMASK(7, 0) +#define MT_WTBL2_W12_RATE7 GENMASK(19, 8) +#define MT_WTBL2_W12_RATE8 GENMASK(31, 20) + +#define MT_WTBL2_W13_AVG_RCPI0 GENMASK(7, 0) +#define MT_WTBL2_W13_AVG_RCPI1 GENMASK(15, 8) +#define MT_WTBL2_W13_AVG_RCPI2 GENAMSK(23, 16) + +#define MT_WTBL2_W14_CC_NOISE_1S GENMASK(6, 0) +#define MT_WTBL2_W14_CC_NOISE_2S GENMASK(13, 7) +#define MT_WTBL2_W14_CC_NOISE_3S GENMASK(20, 14) +#define MT_WTBL2_W14_CHAN_EST_RMS GENMASK(24, 21) +#define MT_WTBL2_W14_CC_NOISE_SEL BIT(15) +#define MT_WTBL2_W14_ANT_SEL GENMASK(31, 26) + +#define MT_WTBL2_W15_BA_WIN_SIZE GENMASK(2, 0) +#define MT_WTBL2_W15_BA_WIN_SIZE_SHIFT 3 +#define MT_WTBL2_W15_BA_EN_TIDS GENMASK(31, 24) + +#define MT_WTBL1_OR (MT_WTBL1_BASE + 0x2300) +#define MT_WTBL1_OR_PSM_WRITE BIT(31) + +enum mt7603_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_TKIP, + MT_CIPHER_TKIP_NO_MIC, + MT_CIPHER_AES_CCMP, + MT_CIPHER_WEP104, + MT_CIPHER_BIP_CMAC_128, + MT_CIPHER_WEP128, + MT_CIPHER_WAPI, +}; + + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603_soc.c b/drivers/net/wireless/mediatek/mt76/mt7603_soc.c new file mode 100644 index 0000000000000..4ebe2f1758dbb --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7603_soc.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt7603.h" + +static int +mt76_wmac_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mt7603_dev *dev; + void __iomem *mem_base; + int irq; + int ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get device IRQ\n"); + return irq; + } + + mem_base = devm_ioremap_resource(&pdev->dev, res); + if (!mem_base) { + dev_err(&pdev->dev, "Failed to get memory resource\n"); + return -EINVAL; + } + + dev = mt7603_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + mt76_mmio_init(&dev->mt76, mem_base); + + dev->mt76.rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_printk(KERN_INFO, dev->mt76.dev, "ASIC revision: %04x\n", dev->mt76.rev); + + ret = devm_request_irq(dev->mt76.dev, irq, mt7603_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt7603_register_device(dev); + if (ret) + goto error; + + return 0; +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static int +mt76_wmac_remove(struct platform_device *pdev) +{ + struct mt76_dev *mdev = platform_get_drvdata(pdev); + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + + mt7603_unregister_device(dev); + + return 0; +} + +static const struct of_device_id of_wmac_match[] = { + { .compatible = "mediatek,mt7628-wmac" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_wmac_match); +MODULE_FIRMWARE(MT7628_FIRMWARE_E1); +MODULE_FIRMWARE(MT7628_FIRMWARE_E2); + +struct platform_driver mt76_wmac_driver = { + .probe = mt76_wmac_probe, + .remove = mt76_wmac_remove, + .driver = { + .name = "mt76_wmac", + .of_match_table = of_wmac_match, + }, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h new file mode 100644 index 0000000000000..a12dfce8c0d1d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_H +#define __MT76x2_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT7662_FIRMWARE "mt7662.bin" +#define MT7662_ROM_PATCH "mt7662_rom_patch.bin" +#define MT7662_EEPROM_SIZE 512 + +#define MT76x2_RX_RING_SIZE 256 +#define MT_RX_HEADROOM 32 + +#define MT_MAX_CHAINS 2 + +#define MT_CALIBRATE_INTERVAL HZ + +#include "mt76.h" +#include "mt76x2_regs.h" +#include "mt76x2_mac.h" +#include "mt76x2_dfs.h" + +struct mt76x2_mcu { + struct mutex mutex; + + wait_queue_head_t wait; + struct sk_buff_head res_q; + + u32 msg_seq; +}; + +struct mt76x2_rx_freq_cal { + s8 high_gain[MT_MAX_CHAINS]; + s8 rssi_offset[MT_MAX_CHAINS]; + s8 lna_gain; + u32 mcu_gain; +}; + +struct mt76x2_calibration { + struct mt76x2_rx_freq_cal rx; + + u8 agc_gain_init[MT_MAX_CHAINS]; + u8 agc_gain_cur[MT_MAX_CHAINS]; + + int avg_rssi[MT_MAX_CHAINS]; + int avg_rssi_all; + + s8 agc_gain_adjust; + s8 low_gain; + + u8 temp; + + bool init_cal_done; + bool tssi_cal_done; + bool tssi_comp_pending; + bool dpd_cal_done; + bool channel_cal_done; +}; + +struct mt76x2_dev { + struct mt76_dev mt76; /* must be first */ + + struct mac_address macaddr_list[8]; + + struct mutex mutex; + + const u16 *beacon_offsets; + unsigned long wcid_mask[128 / BITS_PER_LONG]; + + int txpower_conf; + int txpower_cur; + + u8 txdone_seq; + DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x2_tx_status); + + struct mt76x2_mcu mcu; + struct sk_buff *rx_head; + + struct tasklet_struct tx_tasklet; + struct tasklet_struct pre_tbtt_tasklet; + struct delayed_work cal_work; + struct delayed_work mac_work; + + u32 aggr_stats[32]; + + struct mt76_wcid global_wcid; + struct mt76_wcid __rcu *wcid[128]; + + spinlock_t irq_lock; + u32 irqmask; + + struct sk_buff *beacons[8]; + u8 beacon_mask; + u8 beacon_data_mask; + + u32 rev; + u32 rxfilter; + + u16 chainmask; + + struct mt76x2_calibration cal; + + s8 target_power; + s8 target_power_delta[2]; + struct mt76_rate_power rate_power; + bool enable_tpc; + + u8 coverage_class; + u8 slottime; + + struct mt76x2_dfs_pattern_detector dfs_pd; +}; + +struct mt76x2_vif { + u8 idx; + + struct mt76_wcid group_wcid; +}; + +struct mt76x2_sta { + struct mt76_wcid wcid; /* must be first */ + + struct mt76x2_tx_status status; + int n_frames; +}; + +static inline bool is_mt7612(struct mt76x2_dev *dev) +{ + return (dev->rev >> 16) == 0x7612; +} + +void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set); + +static inline void mt76x2_irq_enable(struct mt76x2_dev *dev, u32 mask) +{ + mt76x2_set_irq_mask(dev, 0, mask); +} + +static inline void mt76x2_irq_disable(struct mt76x2_dev *dev, u32 mask) +{ + mt76x2_set_irq_mask(dev, mask, 0); +} + +extern const struct ieee80211_ops mt76x2_ops; + +struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); +int mt76x2_register_device(struct mt76x2_dev *dev); +void mt76x2_init_debugfs(struct mt76x2_dev *dev); + +irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance); +void mt76x2_phy_power_on(struct mt76x2_dev *dev); +int mt76x2_init_hardware(struct mt76x2_dev *dev); +void mt76x2_stop_hardware(struct mt76x2_dev *dev); +int mt76x2_eeprom_init(struct mt76x2_dev *dev); +int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel); +void mt76x2_set_tx_ackto(struct mt76x2_dev *dev); + +int mt76x2_phy_start(struct mt76x2_dev *dev); +int mt76x2_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef); +int mt76x2_phy_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain); +void mt76x2_phy_calibrate(struct work_struct *work); +void mt76x2_phy_set_txpower(struct mt76x2_dev *dev); + +int mt76x2_mcu_init(struct mt76x2_dev *dev); +int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, + u8 bw_index, bool scan); +int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on); +int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, + u8 channel); +int mt76x2_mcu_cleanup(struct mt76x2_dev *dev); + +int mt76x2_dma_init(struct mt76x2_dev *dev); +void mt76x2_dma_cleanup(struct mt76x2_dev *dev); + +void mt76x2_cleanup(struct mt76x2_dev *dev); + +int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, int cmd, int seq); +void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb); +int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); +void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); + +void mt76x2_pre_tbtt_tasklet(unsigned long arg); + +void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); + +void mt76x2_update_channel(struct mt76_dev *mdev); + +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, + const struct ieee80211_tx_rate *rate); +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); +void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c new file mode 100644 index 0000000000000..2629779e8d3e3 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" +#include "mt76x2_trace.h" + +void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->irq_lock, flags); + dev->irqmask &= ~clear; + dev->irqmask |= set; + mt76_wr(dev, MT_INT_MASK_CSR, dev->irqmask); + spin_unlock_irqrestore(&dev->irq_lock, flags); +} + +void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + + mt76x2_irq_enable(dev, MT_INT_RX_DONE(q)); +} + +irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) +{ + struct mt76x2_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) + return IRQ_NONE; + + trace_dev_irq(dev, intr, dev->irqmask); + + intr &= dev->irqmask; + + if (intr & MT_INT_TX_DONE_ALL) { + mt76x2_irq_disable(dev, MT_INT_TX_DONE_ALL); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_RX_DONE(0)) { + mt76x2_irq_disable(dev, MT_INT_RX_DONE(0)); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE(1)) { + mt76x2_irq_disable(dev, MT_INT_RX_DONE(1)); + napi_schedule(&dev->mt76.napi[1]); + } + + if (intr & MT_INT_PRE_TBTT) + tasklet_schedule(&dev->pre_tbtt_tasklet); + + /* send buffered multicast frames now */ + if (intr & MT_INT_TBTT) + mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); + + if (intr & MT_INT_TX_STAT) { + mt76x2_mac_poll_tx_status(dev, true); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_GPTIMER) { + mt76x2_irq_disable(dev, MT_INT_GPTIMER); + tasklet_schedule(&dev->dfs_pd.dfs_tasklet); + } + + return IRQ_HANDLED; +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c new file mode 100644 index 0000000000000..612feb593d7d6 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" + +static int +mt76x2_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = file->private; + int i, j; + + for (i = 0; i < 4; i++) { + seq_puts(file, "Length: "); + for (j = 0; j < 8; j++) + seq_printf(file, "%8d | ", i * 8 + j + 1); + seq_puts(file, "\n"); + seq_puts(file, "Count: "); + for (j = 0; j < 8; j++) + seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); + seq_puts(file, "\n"); + seq_puts(file, "--------"); + for (j = 0; j < 8; j++) + seq_puts(file, "-----------"); + seq_puts(file, "\n"); + } + + return 0; +} + +static int +mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt76x2_ampdu_stat_read, inode->i_private); +} + +static void +seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) +{ + int i; + + seq_printf(file, "%10s:", str); + for (i = 0; i < len; i++) + seq_printf(file, " %2d", val[i]); + seq_puts(file, "\n"); +} + +static int read_txpower(struct seq_file *file, void *data) +{ + struct mt76x2_dev *dev = dev_get_drvdata(file->private); + + seq_printf(file, "Target power: %d\n", dev->target_power); + + seq_puts_array(file, "Delta", dev->target_power_delta, + ARRAY_SIZE(dev->target_power_delta)); + seq_puts_array(file, "CCK", dev->rate_power.cck, + ARRAY_SIZE(dev->rate_power.cck)); + seq_puts_array(file, "OFDM", dev->rate_power.ofdm, + ARRAY_SIZE(dev->rate_power.ofdm)); + seq_puts_array(file, "HT", dev->rate_power.ht, + ARRAY_SIZE(dev->rate_power.ht)); + seq_puts_array(file, "VHT", dev->rate_power.vht, + ARRAY_SIZE(dev->rate_power.vht)); + return 0; +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt76x2_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int +mt76x2_dfs_stat_read(struct seq_file *file, void *data) +{ + int i; + struct mt76x2_dev *dev = file->private; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + seq_printf(file, "engine: %d\n", i); + seq_printf(file, " hw pattern detected:\t%d\n", + dfs_pd->stats[i].hw_pattern); + seq_printf(file, " hw pulse discarded:\t%d\n", + dfs_pd->stats[i].hw_pulse_discarded); + } + + return 0; +} + +static int +mt76x2_dfs_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt76x2_dfs_stat_read, inode->i_private); +} + +static const struct file_operations fops_dfs_stat = { + .open = mt76x2_dfs_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void mt76x2_init_debugfs(struct mt76x2_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return; + + debugfs_create_u8("temperature", S_IRUSR, dir, &dev->cal.temp); + debugfs_create_bool("tpc", S_IRUSR | S_IWUSR, dir, &dev->enable_tpc); + + debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); + debugfs_create_file("dfs_stats", S_IRUSR, dir, dev, &fops_dfs_stat); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, + read_txpower); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c new file mode 100644 index 0000000000000..5b452a5960168 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2016 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76x2.h" + +#define RADAR_SPEC(m, len, el, eh, wl, wh, \ + w_tolerance, tl, th, t_tolerance, \ + bl, bh, event_exp, power_jmp) \ +{ \ + .mode = m, \ + .avg_len = len, \ + .e_low = el, \ + .e_high = eh, \ + .w_low = wl, \ + .w_high = wh, \ + .w_margin = w_tolerance, \ + .t_low = tl, \ + .t_high = th, \ + .t_margin = t_tolerance, \ + .b_low = bl, \ + .b_high = bh, \ + .event_expiration = event_exp, \ + .pwr_jmp = power_jmp \ +} + +static const struct mt76x2_radar_specs etsi_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, + 0x7fffffff, 0x155cc0, 0x19cc), + RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, + 0x7fffffff, 0x155cc0, 0x19dd), + RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, + 0x7fffffff, 0x2191c0, 0x15cc) +}; + +static const struct mt76x2_radar_specs fcc_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0xfe808, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0xfe808, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0, + 0x7fffffff, 0xfe808, 0x16cc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0xfe808, 0x19dd), + RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0xfe808, 0x12cc), + RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0x57bcf00, 0x1289) +}; + +static const struct mt76x2_radar_specs jp_w56_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0x14c080, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289), + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, + 0x7fffffff, 0x14c080, 0x13dc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289), + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0, + 0x7fffffff, 0x14c080, 0x16cc), + RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, + 0x7fffffff, 0x14c080, 0x19dd), + RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, + 0x7fffffff, 0x14c080, 0x12cc), + RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, + 0x3938700, 0X57bcf00, 0x1289) +}; + +static const struct mt76x2_radar_specs jp_w53_radar_specs[] = { + /* 20MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + /* 40MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + /* 80MHz */ + RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 }, + RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, + 0x7fffffff, 0x14c080, 0x16cc), + { 0 } +}; + +static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, + u8 enable) +{ + u32 data; + + data = (1 << 1) | enable; + mt76_wr(dev, MT_BBP(DFS, 36), data); +} + +static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) +{ + bool ret = false; + u32 current_ts, delta_ts; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); + delta_ts = current_ts - dfs_pd->chirp_pulse_ts; + dfs_pd->chirp_pulse_ts = current_ts; + + /* 12 sec */ + if (delta_ts <= (12 * (1 << 20))) { + if (++dfs_pd->chirp_pulse_cnt > 8) + ret = true; + } else { + dfs_pd->chirp_pulse_cnt = 1; + } + + return ret; +} + +static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev, + struct mt76x2_dfs_hw_pulse *pulse) +{ + u32 data; + + /* select channel */ + data = (MT_DFS_CH_EN << 16) | pulse->engine; + mt76_wr(dev, MT_BBP(DFS, 0), data); + + /* reported period */ + pulse->period = mt76_rr(dev, MT_BBP(DFS, 19)); + + /* reported width */ + pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20)); + pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23)); + + /* reported burst number */ + pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); +} + +static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, + struct mt76x2_dfs_hw_pulse *pulse) +{ + bool ret = false; + + if (!pulse->period || !pulse->w1) + return false; + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + if (pulse->engine > 3) + break; + + if (pulse->engine == 3) { + ret = mt76x2_dfs_check_chirp(dev); + break; + } + + /* check short pulse*/ + if (pulse->w1 < 120) + ret = (pulse->period >= 2900 && + (pulse->period <= 4700 || + pulse->period >= 6400) && + (pulse->period <= 6800 || + pulse->period >= 10200) && + pulse->period <= 61600); + else if (pulse->w1 < 130) /* 120 - 130 */ + ret = (pulse->period >= 2900 && + pulse->period <= 61600); + else + ret = (pulse->period >= 3500 && + pulse->period <= 10100); + break; + case NL80211_DFS_ETSI: + if (pulse->engine >= 3) + break; + + ret = (pulse->period >= 4900 && + (pulse->period <= 10200 || + pulse->period >= 12400) && + pulse->period <= 100100); + break; + case NL80211_DFS_JP: + if (dev->mt76.chandef.chan->center_freq >= 5250 && + dev->mt76.chandef.chan->center_freq <= 5350) { + /* JPW53 */ + if (pulse->w1 <= 130) + ret = (pulse->period >= 28360 && + (pulse->period <= 28700 || + pulse->period >= 76900) && + pulse->period <= 76940); + break; + } + + if (pulse->engine > 3) + break; + + if (pulse->engine == 3) { + ret = mt76x2_dfs_check_chirp(dev); + break; + } + + /* check short pulse*/ + if (pulse->w1 < 120) + ret = (pulse->period >= 2900 && + (pulse->period <= 4700 || + pulse->period >= 6400) && + (pulse->period <= 6800 || + pulse->period >= 27560) && + (pulse->period <= 27960 || + pulse->period >= 28360) && + (pulse->period <= 28700 || + pulse->period >= 79900) && + pulse->period <= 80100); + else if (pulse->w1 < 130) /* 120 - 130 */ + ret = (pulse->period >= 2900 && + (pulse->period <= 10100 || + pulse->period >= 27560) && + (pulse->period <= 27960 || + pulse->period >= 28360) && + (pulse->period <= 28700 || + pulse->period >= 79900) && + pulse->period <= 80100); + else + ret = (pulse->period >= 3900 && + pulse->period <= 10100); + break; + case NL80211_DFS_UNSET: + default: + return false; + } + + return ret; +} + +static void mt76x2_dfs_tasklet(unsigned long arg) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *)arg; + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + u32 engine_mask; + int i; + + if (test_bit(MT76_SCANNING, &dev->mt76.state)) + goto out; + + engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); + if (!(engine_mask & 0xf)) + goto out; + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + struct mt76x2_dfs_hw_pulse pulse; + + if (!(engine_mask & (1 << i))) + continue; + + pulse.engine = i; + mt76x2_dfs_get_hw_pulse(dev, &pulse); + + if (!mt76x2_dfs_check_hw_pulse(dev, &pulse)) { + dfs_pd->stats[i].hw_pulse_discarded++; + continue; + } + + /* hw detector rx radar pattern */ + dfs_pd->stats[i].hw_pattern++; + ieee80211_radar_detected(dev->mt76.hw); + + /* reset hw detector */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + + return; + } + + /* reset hw detector */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + +out: + mt76x2_irq_enable(dev, MT_INT_GPTIMER); +} + +static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) +{ + u32 data; + u8 i, shift; + const struct mt76x2_radar_specs *radar_specs; + + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_40: + shift = MT_DFS_NUM_ENGINES; + break; + case NL80211_CHAN_WIDTH_80: + shift = 2 * MT_DFS_NUM_ENGINES; + break; + default: + shift = 0; + break; + } + + switch (dev->dfs_pd.region) { + case NL80211_DFS_FCC: + radar_specs = &fcc_radar_specs[shift]; + break; + case NL80211_DFS_ETSI: + radar_specs = &etsi_radar_specs[shift]; + break; + case NL80211_DFS_JP: + if (dev->mt76.chandef.chan->center_freq >= 5250 && + dev->mt76.chandef.chan->center_freq <= 5350) + radar_specs = &jp_w53_radar_specs[shift]; + else + radar_specs = &jp_w56_radar_specs[shift]; + break; + case NL80211_DFS_UNSET: + default: + return; + } + + data = (MT_DFS_VGA_MASK << 16) | + (MT_DFS_PWR_GAIN_OFFSET << 12) | + (MT_DFS_PWR_DOWN_TIME << 8) | + (MT_DFS_SYM_ROUND << 4) | + (MT_DFS_DELTA_DELAY & 0xf); + mt76_wr(dev, MT_BBP(DFS, 2), data); + + data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK; + mt76_wr(dev, MT_BBP(DFS, 3), data); + + for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { + /* configure engine */ + mt76_wr(dev, MT_BBP(DFS, 0), i); + + /* detection mode + avg_len */ + data = ((radar_specs[i].avg_len & 0x1ff) << 16) | + (radar_specs[i].mode & 0xf); + mt76_wr(dev, MT_BBP(DFS, 4), data); + + /* dfs energy */ + data = ((radar_specs[i].e_high & 0x0fff) << 16) | + (radar_specs[i].e_low & 0x0fff); + mt76_wr(dev, MT_BBP(DFS, 5), data); + + /* dfs period */ + mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low); + mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high); + + /* dfs burst */ + mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low); + mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high); + + /* dfs width */ + data = ((radar_specs[i].w_high & 0x0fff) << 16) | + (radar_specs[i].w_low & 0x0fff); + mt76_wr(dev, MT_BBP(DFS, 14), data); + + /* dfs margins */ + data = (radar_specs[i].w_margin << 16) | + radar_specs[i].t_margin; + mt76_wr(dev, MT_BBP(DFS, 15), data); + + /* dfs event expiration */ + mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration); + + /* dfs pwr adj */ + mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp); + } + + /* reset status */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + mt76_wr(dev, MT_BBP(DFS, 36), 0x3); + + /* enable detection*/ + mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); + mt76_wr(dev, 0x212c, 0x0c350001); +} + +void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev) +{ + u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31; + + agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8)); + agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4)); + + val_r8 = (agc_r8 & 0x00007e00) >> 9; + val_r4 = agc_r4 & ~0x1f000000; + val_r4 += (((val_r8 + 1) >> 1) << 24); + mt76_wr(dev, MT_BBP(AGC, 4), val_r4); + + dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4); + dfs_r31 += val_r8; + dfs_r31 -= (agc_r8 & 0x00000038) >> 3; + dfs_r31 = (dfs_r31 << 16) | 0x00000307; + mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31); + + mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071); +} + +void mt76x2_dfs_init_params(struct mt76x2_dev *dev) +{ + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + + tasklet_kill(&dev->dfs_pd.dfs_tasklet); + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) { + mt76x2_dfs_set_bbp_params(dev); + /* enable debug mode */ + mt76x2_dfs_set_capture_mode_ctrl(dev, true); + + mt76x2_irq_enable(dev, MT_INT_GPTIMER); + mt76_rmw_field(dev, MT_INT_TIMER_EN, + MT_INT_TIMER_EN_GP_TIMER_EN, 1); + } else { + /* disable hw detector */ + mt76_wr(dev, MT_BBP(DFS, 0), 0); + /* clear detector status */ + mt76_wr(dev, MT_BBP(DFS, 1), 0xf); + mt76_wr(dev, 0x212c, 0); + + mt76x2_irq_disable(dev, MT_INT_GPTIMER); + mt76_rmw_field(dev, MT_INT_TIMER_EN, + MT_INT_TIMER_EN_GP_TIMER_EN, 0); + } +} + +void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) +{ + struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + + dfs_pd->region = NL80211_DFS_UNSET; + tasklet_init(&dfs_pd->dfs_tasklet, mt76x2_dfs_tasklet, + (unsigned long)dev); +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h new file mode 100644 index 0000000000000..9ac69b6a116d5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_DFS_H +#define __MT76x2_DFS_H + +#include +#include + +#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ +#define MT_DFS_NUM_ENGINES 4 + +/* bbp params */ +#define MT_DFS_SYM_ROUND 0 +#define MT_DFS_DELTA_DELAY 2 +#define MT_DFS_VGA_MASK 0 +#define MT_DFS_PWR_GAIN_OFFSET 3 +#define MT_DFS_PWR_DOWN_TIME 0xf +#define MT_DFS_RX_PE_MASK 0xff +#define MT_DFS_PKT_END_MASK 0 +#define MT_DFS_CH_EN 0xf + +struct mt76x2_radar_specs { + u8 mode; + u16 avg_len; + u16 e_low; + u16 e_high; + u16 w_low; + u16 w_high; + u16 w_margin; + u32 t_low; + u32 t_high; + u16 t_margin; + u32 b_low; + u32 b_high; + u32 event_expiration; + u16 pwr_jmp; +}; + +struct mt76x2_dfs_hw_pulse { + u8 engine; + u32 period; + u32 w1; + u32 w2; + u32 burst; +}; + +struct mt76x2_dfs_engine_stats { + u32 hw_pattern; + u32 hw_pulse_discarded; +}; + +struct mt76x2_dfs_pattern_detector { + enum nl80211_dfs_regions region; + + u8 chirp_pulse_cnt; + u32 chirp_pulse_ts; + + struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; + struct tasklet_struct dfs_tasklet; +}; + +void mt76x2_dfs_init_params(struct mt76x2_dev *dev); +void mt76x2_dfs_init_detector(struct mt76x2_dev *dev); +void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev); + +#endif /* __MT76x2_DFS_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c new file mode 100644 index 0000000000000..0a3f729a7156f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76x2.h" +#include "mt76x2_dma.h" + +int +mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, int cmd, int seq) +{ + struct mt76_queue *q = &dev->mt76.q_tx[qid]; + struct mt76_queue_buf buf; + dma_addr_t addr; + u32 tx_info; + + tx_info = MT_MCU_MSG_TYPE_CMD | + FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | + FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | + FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | + FIELD_PREP(MT_MCU_MSG_LEN, skb->len); + + addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->mt76.dev, addr)) + return -ENOMEM; + + buf.addr = addr; + buf.len = skb->len; + spin_lock_bh(&q->lock); + mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); + mt76_queue_kick(dev, q); + spin_unlock_bh(&q->lock); + + return 0; +} + +static int +mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, + int idx, int n_desc) +{ + int ret; + + q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + + ret = mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt76x2_irq_enable(dev, MT_INT_TX_DONE(idx)); + + return 0; +} + +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + void *rxwi = skb->data; + + if (q == MT_RXQ_MCU) { + skb_queue_tail(&dev->mcu.res_q, skb); + wake_up(&dev->mcu.wait); + return; + } + + skb_pull(skb, sizeof(struct mt76x2_rxwi)); + if (mt76x2_mac_process_rx(dev, skb, rxwi)) { + dev_kfree_skb(skb); + return; + } + + mt76_rx(&dev->mt76, q, skb); +} + +static int +mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, + int idx, int n_desc, int bufsize) +{ + int ret; + + q->regs = dev->mt76.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + q->buf_size = bufsize; + + ret = mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt76x2_irq_enable(dev, MT_INT_RX_DONE(idx)); + + return 0; +} + +static void +mt76x2_tx_tasklet(unsigned long data) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) data; + int i; + + mt76x2_mac_process_tx_status_fifo(dev); + + for (i = MT_TXQ_MCU; i >= 0; i--) + mt76_queue_tx_cleanup(dev, i, false); + + mt76x2_mac_poll_tx_status(dev, false); + mt76x2_irq_enable(dev, MT_INT_TX_DONE_ALL); +} + +int mt76x2_dma_init(struct mt76x2_dev *dev) +{ + static const u8 wmm_queue_map[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + int ret; + int i; + struct mt76_txwi_cache __maybe_unused *t; + struct mt76_queue *q; + + BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x2_txwi)); + BUILD_BUG_ON(sizeof(struct mt76x2_rxwi) > MT_RX_HEADROOM); + + mt76_dma_attach(&dev->mt76); + + init_waitqueue_head(&dev->mcu.wait); + skb_queue_head_init(&dev->mcu.res_q); + + tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev); + + mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); + + for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { + ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i], + wmm_queue_map[i], MT_TX_RING_SIZE); + if (ret) + return ret; + } + + ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD], + MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); + if (ret) + return ret; + + ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], + MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); + if (ret) + return ret; + + ret = mt76x2_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, + MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); + if (ret) + return ret; + + q = &dev->mt76.q_rx[MT_RXQ_MAIN]; + q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x2_rxwi); + ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE); + if (ret) + return ret; + + return mt76_init_queues(dev); +} + +void mt76x2_dma_cleanup(struct mt76x2_dev *dev) +{ + tasklet_kill(&dev->tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h new file mode 100644 index 0000000000000..47f79d83fcb48 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_DMA_H +#define __MT76x2_DMA_H + +#include "dma.h" + +#define MT_TXD_INFO_LEN GENMASK(13, 0) +#define MT_TXD_INFO_NEXT_VLD BIT(16) +#define MT_TXD_INFO_TX_BURST BIT(17) +#define MT_TXD_INFO_80211 BIT(19) +#define MT_TXD_INFO_TSO BIT(20) +#define MT_TXD_INFO_CSO BIT(21) +#define MT_TXD_INFO_WIV BIT(24) +#define MT_TXD_INFO_QSEL GENMASK(26, 25) +#define MT_TXD_INFO_TCO BIT(29) +#define MT_TXD_INFO_UCO BIT(30) +#define MT_TXD_INFO_ICO BIT(31) + +#define MT_RX_FCE_INFO_LEN GENMASK(13, 0) +#define MT_RX_FCE_INFO_SELF_GEN BIT(15) +#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16) +#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20) +#define MT_RX_FCE_INFO_PCIE_INTR BIT(24) +#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25) +#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27) +#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30) + +/* MCU request message header */ +#define MT_MCU_MSG_LEN GENMASK(15, 0) +#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16) +#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20) +#define MT_MCU_MSG_PORT GENMASK(29, 27) +#define MT_MCU_MSG_TYPE GENMASK(31, 30) +#define MT_MCU_MSG_TYPE_CMD BIT(30) + +enum mt76x2_qsel { + MT_QSEL_MGMT, + MT_QSEL_HCCA, + MT_QSEL_EDCA, + MT_QSEL_EDCA_2, +}; + +enum dma_msg_port { + WLAN_PORT, + CPU_RX_PORT, + CPU_TX_PORT, + HOST_PORT, + VIRTUAL_CPU_RX_PORT, + VIRTUAL_CPU_TX_PORT, + DISCARD, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c new file mode 100644 index 0000000000000..440b7e7d73a9d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" +#include "mt76x2_eeprom.h" + +#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 + +static int +mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field, + void *dest, int len) +{ + if (field + len > dev->mt76.eeprom.size) + return -1; + + memcpy(dest, dev->mt76.eeprom.data + field, len); + return 0; +} + +static int +mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) +{ + void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; + + memcpy(dev->mt76.macaddr, src, ETH_ALEN); + return 0; +} + +static void +mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev) +{ + u16 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); + + switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { + case BOARD_TYPE_5GHZ: + dev->mt76.cap.has_5ghz = true; + break; + case BOARD_TYPE_2GHZ: + dev->mt76.cap.has_2ghz = true; + break; + default: + dev->mt76.cap.has_2ghz = true; + dev->mt76.cap.has_5ghz = true; + break; + } +} + +static int +mt76x2_efuse_read(struct mt76x2_dev *dev, u16 addr, u8 *data) +{ + u32 val; + int i; + + val = mt76_rr(dev, MT_EFUSE_CTRL); + val &= ~(MT_EFUSE_CTRL_AIN | + MT_EFUSE_CTRL_MODE); + val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); + val |= MT_EFUSE_CTRL_KICK; + mt76_wr(dev, MT_EFUSE_CTRL, val); + + if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) + return -ETIMEDOUT; + + udelay(2); + + val = mt76_rr(dev, MT_EFUSE_CTRL); + if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { + memset(data, 0xff, 16); + return 0; + } + + for (i = 0; i < 4; i++) { + val = mt76_rr(dev, MT_EFUSE_DATA(i)); + put_unaligned_le32(val, data + 4 * i); + } + + return 0; +} + +static int +mt76x2_get_efuse_data(struct mt76x2_dev *dev, void *buf, int len) +{ + int ret, i; + + for (i = 0; i + 16 <= len; i += 16) { + ret = mt76x2_efuse_read(dev, i, buf + i); + if (ret) + return ret; + } + + return 0; +} + +static bool +mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +{ + u16 *efuse_w = (u16 *) efuse; + + if (efuse_w[MT_EE_NIC_CONF_0] != 0) + return false; + + if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) + return false; + + if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) + return false; + + if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) + return false; + + return true; +} + +static void +mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +{ +#define GROUP_5G(_id) \ + MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ + MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ + MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ + MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 + + static const u8 cal_free_bytes[] = { + MT_EE_XTAL_TRIM_1, + MT_EE_TX_POWER_EXT_PA_5G + 1, + MT_EE_TX_POWER_0_START_2G, + MT_EE_TX_POWER_0_START_2G + 1, + MT_EE_TX_POWER_1_START_2G, + MT_EE_TX_POWER_1_START_2G + 1, + GROUP_5G(0), + GROUP_5G(1), + GROUP_5G(2), + GROUP_5G(3), + GROUP_5G(4), + GROUP_5G(5), + MT_EE_RF_2G_TSSI_OFF_TXPOWER, + MT_EE_RF_2G_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, + }; + u8 *eeprom = dev->mt76.eeprom.data; + u8 prev_grp0[4] = { + eeprom[MT_EE_TX_POWER_0_START_5G], + eeprom[MT_EE_TX_POWER_0_START_5G + 1], + eeprom[MT_EE_TX_POWER_1_START_5G], + eeprom[MT_EE_TX_POWER_1_START_5G + 1] + }; + u16 val; + int i; + + if (!mt76x2_has_cal_free_data(dev, efuse)) + return; + + for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { + int offset = cal_free_bytes[i]; + + eeprom[offset] = efuse[offset]; + } + + if (!(efuse[MT_EE_TX_POWER_0_START_5G] | + efuse[MT_EE_TX_POWER_0_START_5G + 1])) + memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); + if (!(efuse[MT_EE_TX_POWER_1_START_5G] | + efuse[MT_EE_TX_POWER_1_START_5G + 1])) + memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); + + val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); + if (val != 0xffff) + eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; + + val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); + if (val != 0xffff) + eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; + + val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); + if (val != 0xffff) + eeprom[MT_EE_BT_PMUCFG] = val & 0xff; +} + +static int mt76x2_check_eeprom(struct mt76x2_dev *dev) +{ + u16 val = get_unaligned_le16(dev->mt76.eeprom.data); + + if (!val) + val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); + + switch (val) { + case 0x7662: + case 0x7612: + return 0; + default: + dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); + return -EINVAL; + } +} + +static int +mt76x2_eeprom_load(struct mt76x2_dev *dev) +{ + void *efuse; + int len = MT7662_EEPROM_SIZE; + bool found; + int ret; + + ret = mt76_eeprom_init(&dev->mt76, len); + if (ret < 0) + return ret; + + found = ret; + if (found) + found = !mt76x2_check_eeprom(dev); + + dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL); + dev->mt76.otp.size = len; + if (!dev->mt76.otp.data) + return -ENOMEM; + + efuse = dev->mt76.otp.data; + + if (mt76x2_get_efuse_data(dev, efuse, len)) + goto out; + + if (found) { + mt76x2_apply_cal_free_data(dev, efuse); + } else { + /* FIXME: check if efuse data is complete */ + found = true; + memcpy(dev->mt76.eeprom.data, efuse, len); + } + +out: + if (!found) + return -ENOENT; + + return 0; +} + +static inline int +mt76x2_sign_extend(u32 val, unsigned int size) +{ + bool sign = val & BIT(size - 1); + + val &= BIT(size - 1) - 1; + + return sign ? val : -val; +} + +static inline int +mt76x2_sign_extend_optional(u32 val, unsigned int size) +{ + bool enable = val & BIT(size); + + return enable ? mt76x2_sign_extend(val, size) : 0; +} + +static bool +field_valid(u8 val) +{ + return val != 0 && val != 0xff; +} + +static void +mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) +{ + s8 *dest = dev->cal.rx.high_gain; + + if (!field_valid(val)) { + dest[0] = 0; + dest[1] = 0; + return; + } + + dest[0] = mt76x2_sign_extend(val, 4); + dest[1] = mt76x2_sign_extend(val >> 4, 4); +} + +static void +mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) +{ + s8 *dest = dev->cal.rx.rssi_offset; + + if (!field_valid(val)) { + dest[chain] = 0; + return; + } + + dest[chain] = mt76x2_sign_extend_optional(val, 7); +} + +static enum mt76x2_cal_channel_group +mt76x2_get_cal_channel_group(int channel) +{ + if (channel >= 184 && channel <= 196) + return MT_CH_5G_JAPAN; + if (channel <= 48) + return MT_CH_5G_UNII_1; + if (channel <= 64) + return MT_CH_5G_UNII_2; + if (channel <= 114) + return MT_CH_5G_UNII_2E_1; + if (channel <= 144) + return MT_CH_5G_UNII_2E_2; + return MT_CH_5G_UNII_3; +} + +static u8 +mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) +{ + enum mt76x2_cal_channel_group group; + + group = mt76x2_get_cal_channel_group(channel); + switch (group) { + case MT_CH_5G_JAPAN: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); + case MT_CH_5G_UNII_1: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; + case MT_CH_5G_UNII_2: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); + case MT_CH_5G_UNII_2E_1: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; + case MT_CH_5G_UNII_2E_2: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); + default: + return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; + } +} + +void mt76x2_read_rx_gain(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + int channel = chan->hw_value; + s8 lna_5g[3], lna_2g; + u8 lna; + u16 val; + + if (chan->band == NL80211_BAND_2GHZ) + val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; + else + val = mt76x2_get_5g_rx_gain(dev, channel); + + mt76x2_set_rx_gain_group(dev, val); + + if (chan->band == NL80211_BAND_2GHZ) { + val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); + mt76x2_set_rssi_offset(dev, 0, val); + mt76x2_set_rssi_offset(dev, 1, val >> 8); + } else { + val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); + mt76x2_set_rssi_offset(dev, 0, val); + mt76x2_set_rssi_offset(dev, 1, val >> 8); + } + + val = mt76x2_eeprom_get(dev, MT_EE_LNA_GAIN); + lna_2g = val & 0xff; + lna_5g[0] = val >> 8; + + val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); + lna_5g[1] = val >> 8; + + val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); + lna_5g[2] = val >> 8; + + if (!field_valid(lna_5g[1])) + lna_5g[1] = lna_5g[0]; + + if (!field_valid(lna_5g[2])) + lna_5g[2] = lna_5g[0]; + + dev->cal.rx.mcu_gain = (lna_2g & 0xff); + dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; + dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; + dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; + + val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); + if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) + lna_2g = 0; + if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) + memset(lna_5g, 0, sizeof(lna_5g)); + + if (chan->band == NL80211_BAND_2GHZ) + lna = lna_2g; + else if (channel <= 64) + lna = lna_5g[0]; + else if (channel <= 128) + lna = lna_5g[1]; + else + lna = lna_5g[2]; + + if (lna == 0xff) + lna = 0; + + dev->cal.rx.lna_gain = mt76x2_sign_extend(lna, 8); +} + +static s8 +mt76x2_rate_power_val(u8 val) +{ + if (!field_valid(val)) + return 0; + + return mt76x2_sign_extend_optional(val, 7); +} + +void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t) +{ + bool is_5ghz; + u16 val; + + is_5ghz = dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ; + + memset(t, 0, sizeof(*t)); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_CCK); + t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val); + t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8); + + if (is_5ghz) + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); + else + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); + t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val); + t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8); + + if (is_5ghz) + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); + else + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); + t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val); + t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); + t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val); + t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); + t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val); + t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); + t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val); + t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); + t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val); + t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0); + t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val); + t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4); + t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val); + t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8); + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); + if (!is_5ghz) + val >>= 8; + t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); +} + +static void +mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, + int chain, int offset) +{ + int channel = dev->mt76.chandef.chan->hw_value; + int delta_idx; + u8 data[6]; + u16 val; + + if (channel < 6) + delta_idx = 3; + else if (channel < 11) + delta_idx = 4; + else + delta_idx = 5; + + mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); + + t->chain[chain].tssi_slope = data[0]; + t->chain[chain].tssi_offset = data[1]; + t->chain[chain].target_power = data[2]; + t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); + + val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); + t->target_power = val >> 8; +} + +static void +mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, + int chain, int offset) +{ + int channel = dev->mt76.chandef.chan->hw_value; + enum mt76x2_cal_channel_group group; + int delta_idx; + u16 val; + u8 data[5]; + + group = mt76x2_get_cal_channel_group(channel); + offset += group * MT_TX_POWER_GROUP_SIZE_5G; + + if (channel >= 192) + delta_idx = 4; + else if (channel >= 484) + delta_idx = 3; + else if (channel < 44) + delta_idx = 3; + else if (channel < 52) + delta_idx = 4; + else if (channel < 58) + delta_idx = 3; + else if (channel < 98) + delta_idx = 4; + else if (channel < 106) + delta_idx = 3; + else if (channel < 116) + delta_idx = 4; + else if (channel < 130) + delta_idx = 3; + else if (channel < 149) + delta_idx = 4; + else if (channel < 157) + delta_idx = 3; + else + delta_idx = 4; + + mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); + + t->chain[chain].tssi_slope = data[0]; + t->chain[chain].tssi_offset = data[1]; + t->chain[chain].target_power = data[2]; + t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); + + val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); + t->target_power = val & 0xff; +} + +void mt76x2_get_power_info(struct mt76x2_dev *dev, + struct mt76x2_tx_power_info *t) +{ + u16 bw40, bw80; + + memset(t, 0, sizeof(*t)); + + bw40 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); + bw80 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); + + if (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) { + bw40 >>= 8; + mt76x2_get_power_info_5g(dev, t, 0, MT_EE_TX_POWER_0_START_5G); + mt76x2_get_power_info_5g(dev, t, 1, MT_EE_TX_POWER_1_START_5G); + } else { + mt76x2_get_power_info_2g(dev, t, 0, MT_EE_TX_POWER_0_START_2G); + mt76x2_get_power_info_2g(dev, t, 1, MT_EE_TX_POWER_1_START_2G); + } + + if (mt76x2_tssi_enabled(dev) || !field_valid(t->target_power)) + t->target_power = t->chain[0].target_power; + + t->delta_bw40 = mt76x2_rate_power_val(bw40); + t->delta_bw80 = mt76x2_rate_power_val(bw80); +} + +int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) +{ + enum nl80211_band band = dev->mt76.chandef.chan->band; + u16 val, slope; + u8 bounds; + + memset(t, 0, sizeof(*t)); + + val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); + if (!(val & MT_EE_NIC_CONF_1_TEMP_TX_ALC)) + return -EINVAL; + + if (!mt76x2_ext_pa_enabled(dev, band)) + return -EINVAL; + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; + if (!(val & BIT(7))) + return -EINVAL; + + t->temp_25_ref = val & 0x7f; + if (band == NL80211_BAND_5GHZ) { + slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); + bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + } else { + slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); + bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; + } + + t->high_slope = slope & 0xff; + t->low_slope = slope >> 8; + t->lower_bound = 0 - (bounds & 0xf); + t->upper_bound = (bounds >> 4) & 0xf; + + return 0; +} + +bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band) +{ + u16 conf0 = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); + + if (band == NL80211_BAND_5GHZ) + return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); + else + return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); +} + +int mt76x2_eeprom_init(struct mt76x2_dev *dev) +{ + int ret; + + ret = mt76x2_eeprom_load(dev); + if (ret) + return ret; + + mt76x2_eeprom_parse_hw_cap(dev); + mt76x2_eeprom_get_macaddr(dev); + mt76_eeprom_override(&dev->mt76); + dev->mt76.macaddr[0] &= ~BIT(1); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h new file mode 100644 index 0000000000000..063d6c8451c99 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_EEPROM_H +#define __MT76x2_EEPROM_H + +#include "mt76x2.h" + +enum mt76x2_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_PCI_ID = 0x00A, + MT_EE_NIC_CONF_0 = 0x034, + MT_EE_NIC_CONF_1 = 0x036, + MT_EE_NIC_CONF_2 = 0x042, + + MT_EE_XTAL_TRIM_1 = 0x03a, + MT_EE_XTAL_TRIM_2 = 0x09e, + + MT_EE_LNA_GAIN = 0x044, + MT_EE_RSSI_OFFSET_2G_0 = 0x046, + MT_EE_RSSI_OFFSET_2G_1 = 0x048, + MT_EE_RSSI_OFFSET_5G_0 = 0x04a, + MT_EE_RSSI_OFFSET_5G_1 = 0x04c, + + MT_EE_TX_POWER_DELTA_BW40 = 0x050, + MT_EE_TX_POWER_DELTA_BW80 = 0x052, + + MT_EE_TX_POWER_EXT_PA_5G = 0x054, + + MT_EE_TX_POWER_0_START_2G = 0x056, + MT_EE_TX_POWER_1_START_2G = 0x05c, + + /* used as byte arrays */ +#define MT_TX_POWER_GROUP_SIZE_5G 5 +#define MT_TX_POWER_GROUPS_5G 6 + MT_EE_TX_POWER_0_START_5G = 0x062, + + MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074, + MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076, + + MT_EE_TX_POWER_1_START_5G = 0x080, + + MT_EE_TX_POWER_CCK = 0x0a0, + MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2, + MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4, + MT_EE_TX_POWER_OFDM_5G_6M = 0x0b2, + MT_EE_TX_POWER_OFDM_5G_24M = 0x0b4, + MT_EE_TX_POWER_HT_MCS0 = 0x0a6, + MT_EE_TX_POWER_HT_MCS4 = 0x0a8, + MT_EE_TX_POWER_HT_MCS8 = 0x0aa, + MT_EE_TX_POWER_HT_MCS12 = 0x0ac, + MT_EE_TX_POWER_VHT_MCS0 = 0x0ba, + MT_EE_TX_POWER_VHT_MCS4 = 0x0bc, + MT_EE_TX_POWER_VHT_MCS8 = 0x0be, + + MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2, + MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4, + + MT_EE_RF_2G_TSSI_OFF_TXPOWER = 0x0f6, + MT_EE_RF_2G_RX_HIGH_GAIN = 0x0f8, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN = 0x0fa, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN = 0x0fc, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN = 0x0fe, + + MT_EE_BT_RCAL_RESULT = 0x138, + MT_EE_BT_VCDL_CALIBRATION = 0x13c, + MT_EE_BT_PMUCFG = 0x13e, + + __MT_EE_MAX +}; + +#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8) +#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9) +#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) + +#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) +#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) +#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) +#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) + +#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) +#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) +#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) +#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) +#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) +#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) + +enum mt76x2_board_type { + BOARD_TYPE_2GHZ = 1, + BOARD_TYPE_5GHZ = 2, +}; + +enum mt76x2_cal_channel_group { + MT_CH_5G_JAPAN, + MT_CH_5G_UNII_1, + MT_CH_5G_UNII_2, + MT_CH_5G_UNII_2E_1, + MT_CH_5G_UNII_2E_2, + MT_CH_5G_UNII_3, + __MT_CH_MAX +}; + +struct mt76x2_tx_power_info { + u8 target_power; + + s8 delta_bw40; + s8 delta_bw80; + + struct { + s8 tssi_slope; + s8 tssi_offset; + s8 target_power; + s8 delta; + } chain[MT_MAX_CHAINS]; +}; + +struct mt76x2_temp_comp { + u8 temp_25_ref; + int lower_bound; /* J */ + int upper_bound; /* J */ + unsigned int high_slope; /* J / dB */ + unsigned int low_slope; /* J / dB */ +}; + +static inline int +mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field) +{ + if ((field & 1) || field >= __MT_EE_MAX) + return -1; + + return get_unaligned_le16(dev->mt76.eeprom.data + field); +} + +void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t); +void mt76x2_get_power_info(struct mt76x2_dev *dev, + struct mt76x2_tx_power_info *t); +int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); +bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band); +void mt76x2_read_rx_gain(struct mt76x2_dev *dev); + +static inline bool +mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev) +{ + return mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TEMP_TX_ALC; +} + +static inline bool +mt76x2_tssi_enabled(struct mt76x2_dev *dev) +{ + return !mt76x2_temp_tx_alc_enabled(dev) && + (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TX_ALC_EN); +} + +static inline bool +mt76x2_has_ext_lna(struct mt76x2_dev *dev) +{ + u32 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); + + if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) + return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; + else + return val & MT_EE_NIC_CONF_1_LNA_EXT_5G; +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c new file mode 100644 index 0000000000000..d3f03a8aee901 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -0,0 +1,839 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" +#include "mt76x2_eeprom.h" +#include "mt76x2_mcu.h" + +struct mt76x2_reg_pair { + u32 reg; + u32 value; +}; + +static bool +mt76x2_wait_for_mac(struct mt76x2_dev *dev) +{ + int i; + + for (i = 0; i < 500; i++) { + switch (mt76_rr(dev, MT_MAC_CSR0)) { + case 0: + case ~0: + break; + default: + return true; + } + usleep_range(5000, 10000); + } + + return false; +} + +static bool +wait_for_wpdma(struct mt76x2_dev *dev) +{ + return mt76_poll(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, + 0, 1000); +} + +static void +mt76x2_mac_pbf_init(struct mt76x2_dev *dev) +{ + u32 val; + + val = MT_PBF_SYS_CTRL_MCU_RESET | + MT_PBF_SYS_CTRL_DMA_RESET | + MT_PBF_SYS_CTRL_MAC_RESET | + MT_PBF_SYS_CTRL_PBF_RESET | + MT_PBF_SYS_CTRL_ASY_RESET; + + mt76_set(dev, MT_PBF_SYS_CTRL, val); + mt76_clear(dev, MT_PBF_SYS_CTRL, val); + + mt76_wr(dev, MT_PBF_TX_MAX_PCNT, 0xefef3f1f); + mt76_wr(dev, MT_PBF_RX_MAX_PCNT, 0xfebf); +} + +static void +mt76x2_write_reg_pairs(struct mt76x2_dev *dev, + const struct mt76x2_reg_pair *data, int len) +{ + while (len > 0) { + mt76_wr(dev, data->reg, data->value); + len--; + data++; + } +} + +static void +mt76_write_mac_initvals(struct mt76x2_dev *dev) +{ +#define DEFAULT_PROT_CFG \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f) | \ + MT_PROT_CFG_RTS_THRESH) + +#define DEFAULT_PROT_CFG_20 \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2004) | \ + FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x17)) + +#define DEFAULT_PROT_CFG_40 \ + (FIELD_PREP(MT_PROT_CFG_RATE, 0x2084) | \ + FIELD_PREP(MT_PROT_CFG_CTRL, 1) | \ + FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ + FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f)) + + static const struct mt76x2_reg_pair vals[] = { + /* Copied from MediaTek reference source */ + { MT_PBF_SYS_CTRL, 0x00080c00 }, + { MT_PBF_CFG, 0x1efebcff }, + { MT_FCE_PSE_CTRL, 0x00000001 }, + { MT_MAC_SYS_CTRL, 0x0000000c }, + { MT_MAX_LEN_CFG, 0x003e3f00 }, + { MT_AMPDU_MAX_LEN_20M1S, 0xaaa99887 }, + { MT_AMPDU_MAX_LEN_20M2S, 0x000000aa }, + { MT_XIFS_TIME_CFG, 0x33a40d0a }, + { MT_BKOFF_SLOT_CFG, 0x00000209 }, + { MT_TBTT_SYNC_CFG, 0x00422010 }, + { MT_PWR_PIN_CFG, 0x00000000 }, + { 0x1238, 0x001700c8 }, + { MT_TX_SW_CFG0, 0x00101001 }, + { MT_TX_SW_CFG1, 0x00010000 }, + { MT_TX_SW_CFG2, 0x00000000 }, + { MT_TXOP_CTRL_CFG, 0x0400583f }, + { MT_TX_RTS_CFG, 0x00100020 }, + { MT_TX_TIMEOUT_CFG, 0x000a2290 }, + { MT_TX_RETRY_CFG, 0x47f01f0f }, + { MT_EXP_ACK_TIME, 0x002c00dc }, + { MT_TX_PROT_CFG6, 0xe3f42004 }, + { MT_TX_PROT_CFG7, 0xe3f42084 }, + { MT_TX_PROT_CFG8, 0xe3f42104 }, + { MT_PIFS_TX_CFG, 0x00060fff }, + { MT_RX_FILTR_CFG, 0x00015f97 }, + { MT_LEGACY_BASIC_RATE, 0x0000017f }, + { MT_HT_BASIC_RATE, 0x00004003 }, + { MT_PN_PAD_MODE, 0x00000002 }, + { MT_TXOP_HLDR_ET, 0x00000002 }, + { 0xa44, 0x00000000 }, + { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, + { MT_TSO_CTRL, 0x00000000 }, + { MT_AUX_CLK_CFG, 0x00000000 }, + { MT_DACCLK_EN_DLY_CFG, 0x00000000 }, + { MT_TX_ALC_CFG_4, 0x00000000 }, + { MT_TX_ALC_VGA3, 0x00000000 }, + { MT_TX_PWR_CFG_0, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_1, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_2, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_3, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_4, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_7, 0x3a3a3a3a }, + { MT_TX_PWR_CFG_8, 0x0000003a }, + { MT_TX_PWR_CFG_9, 0x0000003a }, + { MT_EFUSE_CTRL, 0x0000d000 }, + { MT_PAUSE_ENABLE_CONTROL1, 0x0000000a }, + { MT_FCE_WLAN_FLOW_CONTROL1, 0x60401c18 }, + { MT_WPDMA_DELAY_INT_CFG, 0x94ff0000 }, + { MT_TX_SW_CFG3, 0x00000004 }, + { MT_HT_FBK_TO_LEGACY, 0x00001818 }, + { MT_VHT_HT_FBK_CFG1, 0xedcba980 }, + { MT_PROT_AUTO_TX_CFG, 0x00830083 }, + { MT_HT_CTRL_CFG, 0x000001ff }, + }; + struct mt76x2_reg_pair prot_vals[] = { + { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG }, + { MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG }, + { MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 }, + { MT_MM40_PROT_CFG, DEFAULT_PROT_CFG_40 }, + { MT_GF20_PROT_CFG, DEFAULT_PROT_CFG_20 }, + { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, + }; + + mt76x2_write_reg_pairs(dev, vals, ARRAY_SIZE(vals)); + mt76x2_write_reg_pairs(dev, prot_vals, ARRAY_SIZE(prot_vals)); +} + +static void +mt76x2_fixup_xtal(struct mt76x2_dev *dev) +{ + u16 eep_val; + s8 offset = 0; + + eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2); + + offset = eep_val & 0x7f; + if ((eep_val & 0xff) == 0xff) + offset = 0; + else if (eep_val & 0x80) + offset = 0 - offset; + + eep_val >>= 8; + if (eep_val == 0x00 || eep_val == 0xff) { + eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1); + eep_val &= 0xff; + + if (eep_val == 0x00 || eep_val == 0xff) + eep_val = 0x14; + } + + eep_val &= 0x7f; + mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); + mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); + + eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); + switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { + case 0: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); + break; + case 1: + mt76_wr(dev, MT_XO_CTRL7, 0x5c1feed0); + break; + default: + break; + } +} + +static void +mt76x2_init_beacon_offsets(struct mt76x2_dev *dev) +{ + u16 base = MT_BEACON_BASE; + u32 regs[4] = {}; + int i; + + for (i = 0; i < 16; i++) { + u16 addr = dev->beacon_offsets[i]; + + regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); + } + + for (i = 0; i < 4; i++) + mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); +} + +int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) +{ + static const u8 null_addr[ETH_ALEN] = {}; + const u8 *macaddr = dev->mt76.macaddr; + u32 val; + int i, k; + + if (!mt76x2_wait_for_mac(dev)) + return -ETIMEDOUT; + + val = mt76_rr(dev, MT_WPDMA_GLO_CFG); + + val &= ~(MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY | + MT_WPDMA_GLO_CFG_DMA_BURST_SIZE); + val |= FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3); + + mt76_wr(dev, MT_WPDMA_GLO_CFG, val); + + mt76x2_mac_pbf_init(dev); + mt76_write_mac_initvals(dev); + mt76x2_fixup_xtal(dev); + + mt76_clear(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP); + + if (is_mt7612(dev)) + mt76_clear(dev, MT_COEXCFG0, MT_COEXCFG0_COEX_EN); + + mt76_set(dev, MT_EXT_CCA_CFG, 0x0000f000); + mt76_clear(dev, MT_TX_ALC_CFG_4, BIT(31)); + + mt76_wr(dev, MT_RF_BYPASS_0, 0x06000000); + mt76_wr(dev, MT_RF_SETTING_0, 0x08800000); + usleep_range(5000, 10000); + mt76_wr(dev, MT_RF_BYPASS_0, 0x00000000); + + mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); + mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); + + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(macaddr)); + mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(macaddr + 4)); + + mt76_wr(dev, MT_MAC_BSSID_DW0, get_unaligned_le32(macaddr)); + mt76_wr(dev, MT_MAC_BSSID_DW1, get_unaligned_le16(macaddr + 4) | + FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ + MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); + + /* Fire a pre-TBTT interrupt 8 ms before TBTT */ + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, + 8 << 4); + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, + MT_DFS_GP_INTERVAL); + mt76_wr(dev, MT_INT_TIMER_EN, 0); + + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); + if (!hard) + return 0; + + for (i = 0; i < 256 / 32; i++) + mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); + + for (i = 0; i < 256; i++) + mt76x2_mac_wcid_setup(dev, i, 0, NULL); + + for (i = 0; i < 16; i++) + for (k = 0; k < 4; k++) + mt76x2_mac_shared_key_setup(dev, i, k, NULL); + + for (i = 0; i < 8; i++) { + mt76x2_mac_set_bssid(dev, i, null_addr); + mt76x2_mac_set_beacon(dev, i, NULL); + } + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + mt76_set(dev, MT_MAC_APC_BSSID_H(0), MT_MAC_APC_BSSID0_H_EN); + + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + + mt76x2_init_beacon_offsets(dev); + + mt76x2_set_tx_ackto(dev); + + return 0; +} + +int mt76x2_mac_start(struct mt76x2_dev *dev) +{ + int i; + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + + mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + wait_for_wpdma(dev); + usleep_range(50, 100); + + mt76_set(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_EN); + + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); + + mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + + mt76x2_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_TX_STAT); + + return 0; +} + +void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) +{ + bool stopped = false; + u32 rts_cfg; + int i; + + mt76_wr(dev, MT_MAC_SYS_CTRL, 0); + + rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG); + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT); + + /* Wait for MAC to become idle */ + for (i = 0; i < 300; i++) { + if (mt76_rr(dev, MT_MAC_STATUS) & + (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) + continue; + + if (mt76_rr(dev, MT_BBP(IBI, 12))) + continue; + + stopped = true; + break; + } + + if (force && !stopped) { + mt76_set(dev, MT_BBP(CORE, 4), BIT(1)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(1)); + + mt76_set(dev, MT_BBP(CORE, 4), BIT(0)); + mt76_clear(dev, MT_BBP(CORE, 4), BIT(0)); + } + + mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); +} + +void mt76x2_mac_resume(struct mt76x2_dev *dev) +{ + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); +} + +static void +mt76x2_power_on_rf_patch(struct mt76x2_dev *dev) +{ + mt76_set(dev, 0x10130, BIT(0) | BIT(16)); + udelay(1); + + mt76_clear(dev, 0x1001c, 0xff); + mt76_set(dev, 0x1001c, 0x30); + + mt76_wr(dev, 0x10014, 0x484f); + udelay(1); + + mt76_set(dev, 0x10130, BIT(17)); + udelay(125); + + mt76_clear(dev, 0x10130, BIT(16)); + udelay(50); + + mt76_set(dev, 0x1014c, BIT(19) | BIT(20)); +} + +static void +mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit) +{ + int shift = unit ? 8 : 0; + + /* Enable RF BG */ + mt76_set(dev, 0x10130, BIT(0) << shift); + udelay(10); + + /* Enable RFDIG LDO/AFE/ABB/ADDA */ + mt76_set(dev, 0x10130, (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift); + udelay(10); + + /* Switch RFDIG power to internal LDO */ + mt76_clear(dev, 0x10130, BIT(2) << shift); + udelay(10); + + mt76x2_power_on_rf_patch(dev); + + mt76_set(dev, 0x530, 0xf); +} + +static void +mt76x2_power_on(struct mt76x2_dev *dev) +{ + u32 val; + + /* Turn on WL MTCMOS */ + mt76_set(dev, MT_WLAN_MTC_CTRL, MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP); + + val = MT_WLAN_MTC_CTRL_STATE_UP | + MT_WLAN_MTC_CTRL_PWR_ACK | + MT_WLAN_MTC_CTRL_PWR_ACK_S; + + mt76_poll(dev, MT_WLAN_MTC_CTRL, val, val, 1000); + + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0x7f << 16); + udelay(10); + + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xf << 24); + udelay(10); + + mt76_set(dev, MT_WLAN_MTC_CTRL, 0xf << 24); + mt76_clear(dev, MT_WLAN_MTC_CTRL, 0xfff); + + /* Turn on AD/DA power down */ + mt76_clear(dev, 0x11204, BIT(3)); + + /* WLAN function enable */ + mt76_set(dev, 0x10080, BIT(0)); + + /* Release BBP software reset */ + mt76_clear(dev, 0x10064, BIT(18)); + + mt76x2_power_on_rf(dev, 0); + mt76x2_power_on_rf(dev, 1); +} + +void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) +{ + u8 ackto, sifs, slottime = dev->slottime; + + slottime += 3 * dev->coverage_class; + + sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, + MT_XIFS_TIME_CFG_OFDM_SIFS); + + ackto = slottime + sifs; + mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, + MT_TX_TIMEOUT_CFG_ACKTO, ackto); +} + +static void +mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) +{ + u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL); + + if (enable) + val |= (MT_WLAN_FUN_CTRL_WLAN_EN | + MT_WLAN_FUN_CTRL_WLAN_CLK_EN); + else + val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN | + MT_WLAN_FUN_CTRL_WLAN_CLK_EN); + + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); +} + +static void +mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) +{ + u32 val; + + val = mt76_rr(dev, MT_WLAN_FUN_CTRL); + + val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; + + if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { + val |= MT_WLAN_FUN_CTRL_WLAN_RESET_RF; + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + val &= ~MT_WLAN_FUN_CTRL_WLAN_RESET_RF; + } + + mt76_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + mt76x2_set_wlan_state(dev, enable); +} + +int mt76x2_init_hardware(struct mt76x2_dev *dev) +{ + static const u16 beacon_offsets[16] = { + /* 1024 byte per beacon */ + 0xc000, + 0xc400, + 0xc800, + 0xcc00, + 0xd000, + 0xd400, + 0xd800, + 0xdc00, + + /* BSS idx 8-15 not used for beacons */ + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + }; + u32 val; + int ret; + + dev->beacon_offsets = beacon_offsets; + tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, + (unsigned long) dev); + + dev->chainmask = 0x202; + dev->global_wcid.idx = 255; + dev->global_wcid.hw_key_idx = -1; + dev->slottime = 9; + + val = mt76_rr(dev, MT_WPDMA_GLO_CFG); + val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | + MT_WPDMA_GLO_CFG_BIG_ENDIAN | + MT_WPDMA_GLO_CFG_HDR_SEG_LEN; + val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; + mt76_wr(dev, MT_WPDMA_GLO_CFG, val); + + mt76x2_reset_wlan(dev, true); + mt76x2_power_on(dev); + + ret = mt76x2_eeprom_init(dev); + if (ret) + return ret; + + ret = mt76x2_mac_reset(dev, true); + if (ret) + return ret; + + ret = mt76x2_dma_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + ret = mt76x2_mac_start(dev); + if (ret) + return ret; + + ret = mt76x2_mcu_init(dev); + if (ret) + return ret; + + mt76x2_mac_stop(dev, false); + dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + + return 0; +} + +void mt76x2_stop_hardware(struct mt76x2_dev *dev) +{ + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + mt76x2_mcu_set_radio_state(dev, false); + mt76x2_mac_stop(dev, false); +} + +void mt76x2_cleanup(struct mt76x2_dev *dev) +{ + mt76x2_stop_hardware(dev); + mt76x2_dma_cleanup(dev); + mt76x2_mcu_cleanup(dev); +} + +struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x2_txwi), + .update_survey = mt76x2_update_channel, + .tx_prepare_skb = mt76x2_tx_prepare_skb, + .tx_complete_skb = mt76x2_tx_complete_skb, + .rx_skb = mt76x2_queue_rx_skb, + .rx_poll_complete = mt76x2_rx_poll_complete, + }; + struct ieee80211_hw *hw; + struct mt76x2_dev *dev; + + hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x2_ops); + if (!hw) + return NULL; + + dev = hw->priv; + dev->mt76.dev = pdev; + dev->mt76.hw = hw; + dev->mt76.drv = &drv_ops; + mutex_init(&dev->mutex); + spin_lock_init(&dev->irq_lock); + + return dev; +} + +static void mt76x2_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt76x2_dev *dev = hw->priv; + + dev->dfs_pd.region = request->dfs_region; +} + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ +} + +static struct ieee80211_rate mt76x2_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(0, 60), + OFDM_RATE(1, 90), + OFDM_RATE(2, 120), + OFDM_RATE(3, 180), + OFDM_RATE(4, 240), + OFDM_RATE(5, 360), + OFDM_RATE(6, 480), + OFDM_RATE(7, 540), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = 8, + .types = BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), + } +}; + +static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on, + u8 delay_off) +{ + struct mt76x2_dev *dev = container_of(mt76, struct mt76x2_dev, + mt76); + u32 val; + + val = MT_LED_STATUS_DURATION(0xff) | + MT_LED_STATUS_OFF(delay_off) | + MT_LED_STATUS_ON(delay_on); + + mt76_wr(dev, MT_LED_S0(mt76->led_pin), val); + mt76_wr(dev, MT_LED_S1(mt76->led_pin), val); + + val = MT_LED_CTRL_REPLAY(mt76->led_pin) | + MT_LED_CTRL_KICK(mt76->led_pin); + if (mt76->led_al) + val |= MT_LED_CTRL_POLARITY(mt76->led_pin); + mt76_wr(dev, MT_LED_CTRL, val); +} + +static int mt76x2_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt76x2_led_set_config(mt76, delta_on, delta_off); + return 0; +} + +static void mt76x2_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct mt76_dev *mt76 = container_of(led_cdev, struct mt76_dev, + led_cdev); + + if (!brightness) + mt76x2_led_set_config(mt76, 0, 0xff); + else + mt76x2_led_set_config(mt76, 0xff, 0); +} + +int mt76x2_register_device(struct mt76x2_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + void *status_fifo; + int fifo_size; + int i, ret; + + fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status)); + status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); + if (!status_fifo) + return -ENOMEM; + + kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); + + ret = mt76x2_init_hardware(dev); + if (ret) + return ret; + + hw->queues = 4; + hw->max_rates = 1; + hw->max_report_rates = 7; + hw->max_rate_tries = 1; + hw->extra_tx_headroom = 2; + + hw->sta_data_size = sizeof(struct mt76x2_sta); + hw->vif_data_size = sizeof(struct mt76x2_vif); + + for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { + u8 *addr = dev->macaddr_list[i].addr; + + memcpy(addr, dev->mt76.macaddr, ETH_ALEN); + + if (!i) + continue; + + addr[0] |= BIT(1); + addr[0] ^= ((i - 1) << 2); + } + wiphy->addresses = dev->macaddr_list; + wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + + wiphy->reg_notifier = mt76x2_regd_notifier; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); + INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); + INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); + + dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + + mt76x2_dfs_init_detector(dev); + + /* init led callbacks */ + dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; + + ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, + ARRAY_SIZE(mt76x2_rates)); + if (ret) + goto fail; + + mt76x2_init_debugfs(dev); + + return 0; + +fail: + mt76x2_stop_hardware(dev); + return ret; +} + + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c new file mode 100644 index 0000000000000..39fc1d7b65cea --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -0,0 +1,755 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" +#include "mt76x2_mcu.h" +#include "mt76x2_eeprom.h" +#include "mt76x2_trace.h" + +void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) +{ + idx &= 7; + mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); + mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR, + get_unaligned_le16(addr + 4)); +} + +static void +mt76x2_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (idx >= 8) + idx = 0; + + if (status->band == NL80211_BAND_2GHZ) + idx += 4; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) { + idx -= 8; + status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + } + + if (idx >= 4) + idx = 0; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + status->enc_flags |= RX_ENC_FLAG_HT_GF; + /* fall through */ + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + status->rate_idx = idx; + break; + case MT_PHY_TYPE_VHT: + status->encoding = RX_ENC_VHT; + status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); + status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; + break; + default: + WARN_ON(1); + return; + } + + if (rate & MT_RXWI_RATE_LDPC) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + if (rate & MT_RXWI_RATE_SGI) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + if (rate & MT_RXWI_RATE_STBC) + status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + status->bw = RATE_INFO_BW_40; + break; + case MT_PHY_BW_80: + status->bw = RATE_INFO_BW_80; + break; + default: + break; + } +} + +static __le16 +mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val) +{ + u16 rateval; + u8 phy, rate_idx; + u8 nss = 1; + u8 bw = 0; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 4); + phy = MT_PHY_TYPE_VHT; + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + bw = 2; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->mt76.chandef.chan->band; + u16 val; + + r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + bw = 0; + } + + rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); + rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); + rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rateval |= MT_RXWI_RATE_SGI; + + *nss_val = nss; + return cpu_to_le16(rateval); +} + +void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop) +{ + u32 val = mt76_rr(dev, MT_WCID_DROP(idx)); + u32 bit = MT_WCID_DROP_MASK(idx); + + /* prevent unnecessary writes */ + if ((val & bit) != (bit * drop)) + mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); +} + +void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate) +{ + spin_lock_bh(&dev->mt76.lock); + wcid->tx_rate = mt76x2_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); + wcid->tx_rate_set = true; + spin_unlock_bh(&dev->mt76.lock); +} + +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); + u16 txwi_flags = 0; + u8 nss; + s8 txpwr_adj, max_txpwr_adj; + + memset(txwi, 0, sizeof(*txwi)); + + if (wcid) + txwi->wcid = wcid->idx; + else + txwi->wcid = 0xff; + + txwi->pktid = 1; + + spin_lock_bh(&dev->mt76.lock); + if (rate->idx < 0 || !rate->count) { + txwi->rate = wcid->tx_rate; + max_txpwr_adj = wcid->max_txpwr_adj; + nss = wcid->tx_rate_nss; + } else { + txwi->rate = mt76x2_mac_tx_rate_val(dev, rate, &nss); + max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, rate); + } + spin_unlock_bh(&dev->mt76.lock); + + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->txpower_conf, + max_txpwr_adj); + txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); + + if (mt76xx_rev(dev) >= MT76XX_REV_E4) + txwi->txstream = 0x13; + else if (mt76xx_rev(dev) >= MT76XX_REV_E3 && + !(txwi->rate & cpu_to_le16(rate_ht_mask))) + txwi->txstream = 0x93; + + if (info->flags & IEEE80211_TX_CTL_LDPC) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); + if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); + if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + txwi_flags |= MT_TXWI_FLAGS_MMPS; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + txwi->pktid |= MT_TXWI_PKTID_PROBE; + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { + u8 ba_size = IEEE80211_MIN_AMPDU_BUF; + + ba_size <<= sta->ht_cap.ampdu_factor; + ba_size = min_t(int, 63, ba_size - 1); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + ba_size = 0; + txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); + + txwi_flags |= MT_TXWI_FLAGS_AMPDU | + FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, + sta->ht_cap.ampdu_density); + } + + txwi->flags |= cpu_to_le16(txwi_flags); + txwi->len_ctl = cpu_to_le16(skb->len); +} + +static void mt76x2_remove_hdr_pad(struct sk_buff *skb) +{ + int len = ieee80211_get_hdrlen_from_skb(skb); + + memmove(skb->data + 2, skb->data, len); + skb_pull(skb, 2); +} + +int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, + void *rxi) +{ + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct mt76x2_rxwi *rxwi = rxi; + u32 ctl = le32_to_cpu(rxwi->ctl); + u16 rate = le16_to_cpu(rxwi->rate); + int len; + + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) + mt76x2_remove_hdr_pad(skb); + + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + } + + len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + if (WARN_ON_ONCE(len > skb->len)) + return -EINVAL; + + pskb_trim(skb, len); + status->chains = BIT(0) | BIT(1); + status->chain_signal[0] = mt76x2_phy_get_rssi(dev, rxwi->rssi[0], 0); + status->chain_signal[1] = mt76x2_phy_get_rssi(dev, rxwi->rssi[1], 1); + status->signal = max(status->chain_signal[0], status->chain_signal[1]); + status->freq = dev->mt76.chandef.chan->center_freq; + status->band = dev->mt76.chandef.chan->band; + + mt76x2_mac_process_rate(status, rate); + + return 0; +} + +static void +mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, + enum nl80211_band band) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + txrate->idx = 0; + txrate->flags = 0; + txrate->count = 1; + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (band == NL80211_BAND_2GHZ) + idx += 4; + + txrate->idx = idx; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) + idx -= 8; + + txrate->idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; + /* fall through */ + case MT_PHY_TYPE_HT: + txrate->flags |= IEEE80211_TX_RC_MCS; + txrate->idx = idx; + break; + case MT_PHY_TYPE_VHT: + txrate->flags |= IEEE80211_TX_RC_VHT_MCS; + txrate->idx = idx; + break; + default: + WARN_ON(1); + return; + } + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + break; + case MT_PHY_BW_80: + txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + break; + default: + WARN_ON(1); + break; + } + + if (rate & MT_RXWI_RATE_SGI) + txrate->flags |= IEEE80211_TX_RC_SHORT_GI; +} + +static void +mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev, + struct ieee80211_tx_info *info, + struct mt76x2_tx_status *st, int n_frames) +{ + struct ieee80211_tx_rate *rate = info->status.rates; + int cur_idx, last_rate; + int i; + + if (!n_frames) + return; + + last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); + mt76x2_mac_process_tx_rate(&rate[last_rate], st->rate, + dev->mt76.chandef.chan->band); + if (last_rate < IEEE80211_TX_MAX_RATES - 1) + rate[last_rate + 1].idx = -1; + + cur_idx = rate[last_rate].idx + st->retry; + for (i = 0; i <= last_rate; i++) { + rate[i].flags = rate[last_rate].flags; + rate[i].idx = max_t(int, 0, cur_idx - i); + rate[i].count = 1; + } + + if (last_rate > 0) + rate[last_rate - 1].count = st->retry + 1 - last_rate; + + info->status.ampdu_len = n_frames; + info->status.ampdu_ack_len = st->success ? n_frames : 0; + + if (st->pktid & MT_TXWI_PKTID_PROBE) + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + + if (st->aggr) + info->flags |= IEEE80211_TX_CTL_AMPDU | + IEEE80211_TX_STAT_AMPDU; + + if (!st->ack_req) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else if (st->success) + info->flags |= IEEE80211_TX_STAT_ACK; +} + +static void +mt76x2_send_tx_status(struct mt76x2_dev *dev, struct mt76x2_tx_status *stat, + u8 *update) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; + struct mt76x2_sta *msta = NULL; + + rcu_read_lock(); + if (stat->wcid < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[stat->wcid]); + + if (wcid) { + void *priv; + + priv = msta = container_of(wcid, struct mt76x2_sta, wcid); + sta = container_of(priv, struct ieee80211_sta, + drv_priv); + } + + if (msta && stat->aggr) { + u32 stat_val, stat_cache; + + stat_val = stat->rate; + stat_val |= ((u32) stat->retry) << 16; + stat_cache = msta->status.rate; + stat_cache |= ((u32) msta->status.retry) << 16; + + if (*update == 0 && stat_val == stat_cache && + stat->wcid == msta->status.wcid && msta->n_frames < 32) { + msta->n_frames++; + goto out; + } + + mt76x2_mac_fill_tx_status(dev, &info, &msta->status, + msta->n_frames); + + msta->status = *stat; + msta->n_frames = 1; + *update = 0; + } else { + mt76x2_mac_fill_tx_status(dev, &info, stat, 1); + *update = 1; + } + + ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); + +out: + rcu_read_unlock(); +} + +void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) +{ + struct mt76x2_tx_status stat = {}; + unsigned long flags; + u8 update = 1; + + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return; + + trace_mac_txstat_poll(dev); + + while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { + u32 stat1, stat2; + + spin_lock_irqsave(&dev->irq_lock, flags); + stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); + stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); + if (!(stat1 & MT_TX_STAT_FIFO_VALID)) { + spin_unlock_irqrestore(&dev->irq_lock, flags); + break; + } + + spin_unlock_irqrestore(&dev->irq_lock, flags); + + stat.valid = 1; + stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); + stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); + stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); + stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); + stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); + stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); + stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); + trace_mac_txstat_fetch(dev, &stat); + + if (!irq) { + mt76x2_send_tx_status(dev, &stat, &update); + continue; + } + + kfifo_put(&dev->txstatus_fifo, stat); + } +} + +static void +mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, + void *txwi_ptr) +{ + struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); + struct mt76x2_txwi *txwi = txwi_ptr; + + mt76x2_mac_poll_tx_status(dev, false); + + txi->tries = 0; + txi->jiffies = jiffies; + txi->wcid = txwi->wcid; + txi->pktid = txwi->pktid; + trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); + mt76x2_tx_complete(dev, skb); +} + +void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) +{ + struct mt76x2_tx_status stat; + u8 update = 1; + + while (kfifo_get(&dev->txstatus_fifo, &stat)) + mt76x2_send_tx_status(dev, &stat, &update); +} + +void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + + if (e->txwi) + mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); + else + dev_kfree_skb_any(e->skb); +} + +static enum mt76x2_cipher_type +mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) +{ + memset(key_data, 0, 32); + if (!key) + return MT_CIPHER_NONE; + + if (key->keylen > 32) + return MT_CIPHER_NONE; + + memcpy(key_data, key->key, key->keylen); + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + default: + return MT_CIPHER_NONE; + } +} + +void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac) +{ + struct mt76_wcid_addr addr = {}; + u32 attr; + + attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | + FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); + + mt76_wr(dev, MT_WCID_ATTR(idx), attr); + + mt76_wr(dev, MT_WCID_TX_RATE(idx), 0); + mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0); + + if (idx >= 128) + return; + + if (mac) + memcpy(addr.macaddr, mac, ETH_ALEN); + + mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); +} + +int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, + struct ieee80211_key_conf *key) +{ + enum mt76x2_cipher_type cipher; + u8 key_data[32]; + u8 iv_data[8]; + + cipher = mt76x2_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EOPNOTSUPP; + + mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); + mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); + + memset(iv_data, 0, sizeof(iv_data)); + if (key) { + mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + iv_data[3] = key->keyidx << 6; + if (cipher >= MT_CIPHER_TKIP) + iv_data[3] |= 0x20; + } + + mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); + + return 0; +} + +int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key) +{ + enum mt76x2_cipher_type cipher; + u8 key_data[32]; + u32 val; + + cipher = mt76x2_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EOPNOTSUPP; + + val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); + val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); + val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); + mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); + + mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, + sizeof(key_data)); + + return 0; +} + +static int +mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) +{ + int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; + struct mt76x2_txwi txwi; + + if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x2_txwi))) + return -ENOSPC; + + mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL); + txwi.flags |= cpu_to_le16(MT_TXWI_FLAGS_TS); + + mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); + offset += sizeof(txwi); + + mt76_wr_copy(dev, offset, skb->data, skb->len); + return 0; +} + +static int +__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) +{ + int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; + int beacon_addr = dev->beacon_offsets[bcn_idx]; + int ret = 0; + int i; + + /* Prevent corrupt transmissions during update */ + mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); + + if (skb) { + ret = mt76_write_beacon(dev, beacon_addr, skb); + if (!ret) + dev->beacon_data_mask |= BIT(bcn_idx) & + dev->beacon_mask; + } else { + dev->beacon_data_mask &= ~BIT(bcn_idx); + for (i = 0; i < beacon_len; i += 4) + mt76_wr(dev, beacon_addr + i, 0); + } + + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); + + return ret; +} + +int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, + struct sk_buff *skb) +{ + bool force_update = false; + int bcn_idx = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { + if (vif_idx == i) { + force_update = !!dev->beacons[i] ^ !!skb; + + if (dev->beacons[i]) + dev_kfree_skb(dev->beacons[i]); + + dev->beacons[i] = skb; + __mt76x2_mac_set_beacon(dev, bcn_idx, skb); + } else if (force_update && dev->beacons[i]) { + __mt76x2_mac_set_beacon(dev, bcn_idx, dev->beacons[i]); + } + + bcn_idx += !!dev->beacons[i]; + } + + for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { + if (!(dev->beacon_data_mask & BIT(i))) + break; + + __mt76x2_mac_set_beacon(dev, i, NULL); + } + + mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, + bcn_idx - 1); + return 0; +} + +void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) +{ + u8 old_mask = dev->beacon_mask; + bool en; + u32 reg; + + if (val) { + dev->beacon_mask |= BIT(vif_idx); + } else { + dev->beacon_mask &= ~BIT(vif_idx); + mt76x2_mac_set_beacon(dev, vif_idx, NULL); + } + + if (!!old_mask == !!dev->beacon_mask) + return; + + en = dev->beacon_mask; + + mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); + reg = MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_TIMER_EN; + mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); + + if (en) + mt76x2_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); + else + mt76x2_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); +} + +void mt76x2_update_channel(struct mt76_dev *mdev) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76_channel_state *state; + u32 active, busy; + + state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + + busy = mt76_rr(dev, MT_CH_BUSY); + active = busy + mt76_rr(dev, MT_CH_IDLE); + + spin_lock_bh(&dev->mt76.cc_lock); + state->cc_busy += busy; + state->cc_active += active; + spin_unlock_bh(&dev->mt76.cc_lock); +} + +void mt76x2_mac_work(struct work_struct *work) +{ + struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev, + mac_work.work); + int i, idx; + + mt76x2_update_channel(&dev->mt76); + for (i = 0, idx = 0; i < 16; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->aggr_stats[idx++] += val & 0xffff; + dev->aggr_stats[idx++] += val >> 16; + } + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + MT_CALIBRATE_INTERVAL); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h new file mode 100644 index 0000000000000..8a8a25e32d5f9 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_MAC_H +#define __MT76x2_MAC_H + +#include "mt76.h" + +struct mt76x2_dev; +struct mt76x2_sta; +struct mt76x2_vif; +struct mt76x2_txwi; + +struct mt76x2_tx_status { + u8 valid:1; + u8 success:1; + u8 aggr:1; + u8 ack_req:1; + u8 wcid; + u8 pktid; + u8 retry; + u16 rate; +} __packed __aligned(2); + +struct mt76x2_tx_info { + unsigned long jiffies; + u8 tries; + + u8 wcid; + u8 pktid; + u8 retry; +}; + +struct mt76x2_rxwi { + __le32 rxinfo; + + __le32 ctl; + + __le16 tid_sn; + __le16 rate; + + u8 rssi[4]; + + __le32 bbp_rxinfo[4]; +}; + +#define MT_RXINFO_BA BIT(0) +#define MT_RXINFO_DATA BIT(1) +#define MT_RXINFO_NULL BIT(2) +#define MT_RXINFO_FRAG BIT(3) +#define MT_RXINFO_UNICAST BIT(4) +#define MT_RXINFO_MULTICAST BIT(5) +#define MT_RXINFO_BROADCAST BIT(6) +#define MT_RXINFO_MYBSS BIT(7) +#define MT_RXINFO_CRCERR BIT(8) +#define MT_RXINFO_ICVERR BIT(9) +#define MT_RXINFO_MICERR BIT(10) +#define MT_RXINFO_AMSDU BIT(11) +#define MT_RXINFO_HTC BIT(12) +#define MT_RXINFO_RSSI BIT(13) +#define MT_RXINFO_L2PAD BIT(14) +#define MT_RXINFO_AMPDU BIT(15) +#define MT_RXINFO_DECRYPT BIT(16) +#define MT_RXINFO_BSSIDX3 BIT(17) +#define MT_RXINFO_WAPI_KEY BIT(18) +#define MT_RXINFO_PN_LEN GENMASK(21, 19) +#define MT_RXINFO_SW_FTYPE0 BIT(22) +#define MT_RXINFO_SW_FTYPE1 BIT(23) +#define MT_RXINFO_PROBE_RESP BIT(24) +#define MT_RXINFO_BEACON BIT(25) +#define MT_RXINFO_DISASSOC BIT(26) +#define MT_RXINFO_DEAUTH BIT(27) +#define MT_RXINFO_ACTION BIT(28) +#define MT_RXINFO_TCP_SUM_ERR BIT(30) +#define MT_RXINFO_IP_SUM_ERR BIT(31) + +#define MT_RXWI_CTL_WCID GENMASK(7, 0) +#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) +#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) +#define MT_RXWI_CTL_UDF GENMASK(15, 13) +#define MT_RXWI_CTL_MPDU_LEN GENMASK(29, 16) +#define MT_RXWI_CTL_EOF BIT(31) + +#define MT_RXWI_TID GENMASK(3, 0) +#define MT_RXWI_SN GENMASK(15, 4) + +#define MT_RXWI_RATE_INDEX GENMASK(5, 0) +#define MT_RXWI_RATE_LDPC BIT(6) +#define MT_RXWI_RATE_BW GENMASK(8, 7) +#define MT_RXWI_RATE_SGI BIT(9) +#define MT_RXWI_RATE_STBC BIT(10) +#define MT_RXWI_RATE_LDPC_EXSYM BIT(11) +#define MT_RXWI_RATE_PHY GENMASK(15, 13) + +#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) +#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) + +#define MT_TX_PWR_ADJ GENMASK(3, 0) + +enum mt76x2_phy_bandwidth { + MT_PHY_BW_20, + MT_PHY_BW_40, + MT_PHY_BW_80, +}; + +#define MT_TXWI_FLAGS_FRAG BIT(0) +#define MT_TXWI_FLAGS_MMPS BIT(1) +#define MT_TXWI_FLAGS_CFACK BIT(2) +#define MT_TXWI_FLAGS_TS BIT(3) +#define MT_TXWI_FLAGS_AMPDU BIT(4) +#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) +#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) +#define MT_TXWI_FLAGS_NDPS BIT(10) +#define MT_TXWI_FLAGS_RTSBWSIG BIT(11) +#define MT_TXWI_FLAGS_NDP_BW GENMASK(13, 12) +#define MT_TXWI_FLAGS_SOUND BIT(14) +#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) + +#define MT_TXWI_ACK_CTL_REQ BIT(0) +#define MT_TXWI_ACK_CTL_NSEQ BIT(1) +#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) + +#define MT_TXWI_PKTID_PROBE BIT(7) + +struct mt76x2_txwi { + __le16 flags; + __le16 rate; + u8 ack_ctl; + u8 wcid; + __le16 len_ctl; + __le32 iv; + __le32 eiv; + u8 aid; + u8 txstream; + u8 ctl2; + u8 pktid; +} __packed __aligned(4); + +static inline struct mt76x2_tx_info * +mt76x2_skb_tx_info(struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + return (void *) info->status.status_driver_data; +} + +int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard); +int mt76x2_mac_start(struct mt76x2_dev *dev); +void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force); +void mt76x2_mac_resume(struct mt76x2_dev *dev); +void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); + +int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, + void *rxi); +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta); +void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac); +int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, + struct ieee80211_key_conf *key); +void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate); +void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop); + +int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key); + +int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, + struct sk_buff *skb); +void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val); + +void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq); +void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev); + +void mt76x2_mac_work(struct work_struct *work); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c new file mode 100644 index 0000000000000..2cef48edb2752 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76x2.h" + +static int +mt76x2_start(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mutex); + + ret = mt76x2_mac_start(dev); + if (ret) + goto out; + + ret = mt76x2_phy_start(dev); + if (ret) + goto out; + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, + MT_CALIBRATE_INTERVAL); + + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + +out: + mutex_unlock(&dev->mutex); + return ret; +} + +static void +mt76x2_stop(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x2_stop_hardware(dev); + mutex_unlock(&dev->mutex); +} + +static void +mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq) +{ + struct mt76_txq *mtxq; + + if (!txq) + return; + + mtxq = (struct mt76_txq *) txq->drv_priv; + if (txq->sta) { + struct mt76x2_sta *sta; + + sta = (struct mt76x2_sta *) txq->sta->drv_priv; + mtxq->wcid = &sta->wcid; + } else { + struct mt76x2_vif *mvif; + + mvif = (struct mt76x2_vif *) txq->vif->drv_priv; + mtxq->wcid = &mvif->group_wcid; + } + + mt76_txq_init(&dev->mt76, txq); +} + +static int +mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + unsigned int idx = 0; + int ret = 0; + + if (vif->addr[0] & BIT(1)) + idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7); + + /* + * Client mode typically only has one configurable BSSID register, + * which is used for bssidx=0. This is linked to the MAC address. + * Since mac80211 allows changing interface types, and we cannot + * force the use of the primary MAC address for a station mode + * interface, we need some other way of configuring a per-interface + * remote BSSID. + * The hardware provides an AP-Client feature, where bssidx 0-7 are + * used for AP mode and bssidx 8-15 for client mode. + * We shift the station interface bss index by 8 to force the + * hardware to recognize the BSSID. + * The resulting bssidx mismatch for unicast frames is ignored by hw. + */ + if (vif->type == NL80211_IFTYPE_STATION) + idx += 8; + + mvif->idx = idx; + mvif->group_wcid.idx = 254 - idx; + mvif->group_wcid.hw_key_idx = -1; + mt76x2_txq_init(dev, vif->txq); + + return ret; +} + +static void +mt76x2_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + mt76_txq_remove(&dev->mt76, vif->txq); +} + +static int +mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) +{ + int ret; + + mt76_set_channel(&dev->mt76); + + tasklet_disable(&dev->pre_tbtt_tasklet); + cancel_delayed_work_sync(&dev->cal_work); + + mt76x2_mac_stop(dev, true); + ret = mt76x2_phy_set_channel(dev, chandef); + + /* channel cycle counters read-and-clear */ + mt76_rr(dev, MT_CH_IDLE); + mt76_rr(dev, MT_CH_BUSY); + + mt76x2_dfs_init_params(dev); + + mt76x2_mac_resume(dev); + tasklet_enable(&dev->pre_tbtt_tasklet); + + return ret; +} + +static int +mt76x2_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + int ret = 0; + + mutex_lock(&dev->mutex); + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + dev->txpower_conf = hw->conf.power_level * 2; + + if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { + mt76x2_phy_set_txpower(dev); + mt76x2_tx_set_txpwr_auto(dev, dev->txpower_conf); + } + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt76x2_set_channel(dev, &hw->conf.chandef); + ieee80211_wake_queues(hw); + } + + mutex_unlock(&dev->mutex); + + return ret; +} + +static void +mt76x2_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct mt76x2_dev *dev = hw->priv; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + dev->rxfilter &= ~(_hw); \ + dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + mutex_lock(&dev->mutex); + + dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; + + MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); + MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); + MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | + MT_RX_FILTR_CFG_CTS | + MT_RX_FILTR_CFG_CFEND | + MT_RX_FILTR_CFG_CFACK | + MT_RX_FILTR_CFG_BA | + MT_RX_FILTR_CFG_CTRL_RSV); + MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); + + *total_flags = flags; + mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + + mutex_unlock(&dev->mutex); +} + +static void +mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + + mutex_lock(&dev->mutex); + + if (changed & BSS_CHANGED_BSSID) + mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); + + if (changed & BSS_CHANGED_BEACON_INT) + mt76_rmw_field(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_INTVAL, + info->beacon_int << 4); + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + tasklet_disable(&dev->pre_tbtt_tasklet); + mt76x2_mac_set_beacon_enable(dev, mvif->idx, + info->enable_beacon); + tasklet_enable(&dev->pre_tbtt_tasklet); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + dev->slottime = slottime; + mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, + MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); + } + + mutex_unlock(&dev->mutex); +} + +static int +mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + int ret = 0; + int idx = 0; + int i; + + mutex_lock(&dev->mutex); + + idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + + msta->wcid.idx = idx; + msta->wcid.hw_key_idx = -1; + mt76x2_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76x2_mac_wcid_set_drop(dev, idx, false); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76x2_txq_init(dev, sta->txq[i]); + + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} + +static int +mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + int i; + + mutex_lock(&dev->mutex); + rcu_assign_pointer(dev->wcid[idx], NULL); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76_txq_remove(&dev->mt76, sta->txq[i]); + mt76x2_mac_wcid_set_drop(dev, idx, true); + mt76_wcid_free(dev->wcid_mask, idx); + mt76x2_mac_wcid_setup(dev, idx, 0, NULL); + mutex_unlock(&dev->mutex); + + return 0; +} + +static void +mt76x2_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +{ + struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x2_dev *dev = hw->priv; + int idx = msta->wcid.idx; + + switch (cmd) { + case STA_NOTIFY_SLEEP: + mt76x2_mac_wcid_set_drop(dev, idx, true); + mt76_stop_tx_queues(&dev->mt76, sta, true); + break; + case STA_NOTIFY_AWAKE: + mt76x2_mac_wcid_set_drop(dev, idx, false); + break; + } +} + +static int +mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x2_sta *msta; + struct mt76_wcid *wcid; + int idx = key->keyidx; + int ret; + + /* + * The hardware does not support per-STA RX GTK, fall back + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + msta = sta ? (struct mt76x2_sta *) sta->drv_priv : NULL; + wcid = msta ? &msta->wcid : &mvif->group_wcid; + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else { + if (idx == wcid->hw_key_idx) + wcid->hw_key_idx = -1; + + key = NULL; + } + + if (!msta) { + if (key || wcid->hw_key_idx == idx) { + ret = mt76x2_mac_wcid_set_key(dev, wcid->idx, key); + if (ret) + return ret; + } + + return mt76x2_mac_shared_key_setup(dev, mvif->idx, idx, key); + } + + return mt76x2_mac_wcid_set_key(dev, msta->wcid.idx, key); +} + +static int +mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt76x2_dev *dev = hw->priv; + u8 cw_min = 5, cw_max = 10; + u32 val; + + if (params->cw_min) + cw_min = fls(params->cw_min); + if (params->cw_max) + cw_max = fls(params->cw_max); + + val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | + FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | + FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | + FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); + mt76_wr(dev, MT_EDCA_CFG_AC(queue), val); + + val = mt76_rr(dev, MT_WMM_TXOP(queue)); + val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(queue)); + val |= params->txop << MT_WMM_TXOP_SHIFT(queue); + mt76_wr(dev, MT_WMM_TXOP(queue), val); + + val = mt76_rr(dev, MT_WMM_AIFSN); + val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(queue)); + val |= params->aifs << MT_WMM_AIFSN_SHIFT(queue); + mt76_wr(dev, MT_WMM_AIFSN, val); + + val = mt76_rr(dev, MT_WMM_CWMIN); + val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(queue)); + val |= cw_min << MT_WMM_CWMIN_SHIFT(queue); + mt76_wr(dev, MT_WMM_CWMIN, val); + + val = mt76_rr(dev, MT_WMM_CWMAX); + val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(queue)); + val |= cw_max << MT_WMM_CWMAX_SHIFT(queue); + mt76_wr(dev, MT_WMM_CWMAX, val); + + return 0; +} + +static void +mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac) +{ + struct mt76x2_dev *dev = hw->priv; + + tasklet_disable(&dev->pre_tbtt_tasklet); + set_bit(MT76_SCANNING, &dev->mt76.state); +} + +static void +mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + clear_bit(MT76_SCANNING, &dev->mt76.state); + tasklet_enable(&dev->pre_tbtt_tasklet); + mt76_txq_schedule_all(&dev->mt76); +} + +static void +mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ +} + +static int +mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) +{ + struct mt76x2_dev *dev = hw->priv; + + *dbm = dev->txpower_cur / 2; + return 0; +} + +static int +mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct ieee80211_sta *sta = params->sta; + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + + if (!txq) + return -EINVAL; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, + BIT(16 + tid)); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); + break; + case IEEE80211_AMPDU_TX_START: + mtxq->agg_ssn = *ssn << 4; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + + return 0; +} + +static void +mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); + struct ieee80211_tx_rate rate = {}; + + if (!rates) + return; + + rate.idx = rates->rate[0].idx; + rate.flags = rates->rate[0].flags; + mt76x2_mac_wcid_set_rate(dev, &msta->wcid, &rate); + msta->wcid.max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, &rate); +} + +static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + dev->coverage_class = coverage_class; + mt76x2_set_tx_ackto(dev); + mutex_unlock(&dev->mutex); +} + +const struct ieee80211_ops mt76x2_ops = { + .tx = mt76x2_tx, + .start = mt76x2_start, + .stop = mt76x2_stop, + .add_interface = mt76x2_add_interface, + .remove_interface = mt76x2_remove_interface, + .config = mt76x2_config, + .configure_filter = mt76x2_configure_filter, + .bss_info_changed = mt76x2_bss_info_changed, + .sta_add = mt76x2_sta_add, + .sta_remove = mt76x2_sta_remove, + .sta_notify = mt76x2_sta_notify, + .set_key = mt76x2_set_key, + .conf_tx = mt76x2_conf_tx, + .sw_scan_start = mt76x2_sw_scan, + .sw_scan_complete = mt76x2_sw_scan_complete, + .flush = mt76x2_flush, + .ampdu_action = mt76x2_ampdu_action, + .get_txpower = mt76x2_get_txpower, + .wake_tx_queue = mt76_wake_tx_queue, + .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, + .release_buffered_frames = mt76_release_buffered_frames, + .set_coverage_class = mt76x2_set_coverage_class, + .get_survey = mt76_get_survey, +}; + diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c new file mode 100644 index 0000000000000..d45737ee1412c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt76x2.h" +#include "mt76x2_mcu.h" +#include "mt76x2_dma.h" +#include "mt76x2_eeprom.h" + +struct mt76x2_fw_header { + __le32 ilm_len; + __le32 dlm_len; + __le16 build_ver; + __le16 fw_ver; + u8 pad[4]; + char build_time[16]; +}; + +struct mt76x2_patch_header { + char build_time[16]; + char platform[4]; + char hw_version[4]; + char patch_version[4]; + u8 pad[2]; +}; + +static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len) +{ + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_KERNEL); + memcpy(skb_put(skb, len), data, len); + + return skb; +} + +static struct sk_buff * +mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires) +{ + unsigned long timeout; + + if (!time_is_after_jiffies(expires)) + return NULL; + + timeout = expires - jiffies; + wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q), + timeout); + return skb_dequeue(&dev->mcu.res_q); +} + +static int +mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, + enum mcu_cmd cmd) +{ + unsigned long expires = jiffies + HZ; + int ret; + u8 seq; + + if (!skb) + return -EINVAL; + + mutex_lock(&dev->mcu.mutex); + + seq = ++dev->mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mcu.msg_seq & 0xf; + + ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); + if (ret) + goto out; + + while (1) { + u32 *rxfce; + bool check_seq = false; + + skb = mt76x2_mcu_get_response(dev, expires); + if (!skb) { + dev_err(dev->mt76.dev, + "MCU message %d (seq %d) timed out\n", cmd, + seq); + ret = -ETIMEDOUT; + break; + } + + rxfce = (u32 *) skb->cb; + + if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) + check_seq = true; + + dev_kfree_skb(skb); + if (check_seq) + break; + } + +out: + mutex_unlock(&dev->mcu.mutex); + + return ret; +} + +static int +mt76pci_load_rom_patch(struct mt76x2_dev *dev) +{ + const struct firmware *fw = NULL; + struct mt76x2_patch_header *hdr; + bool rom_protect = !is_mt7612(dev); + int len, ret = 0; + __le32 *cur; + u32 patch_mask, patch_reg; + + if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) { + dev_err(dev->mt76.dev, + "Could not get hardware semaphore for ROM PATCH\n"); + return -ETIMEDOUT; + } + + if (mt76xx_rev(dev) >= MT76XX_REV_E3) { + patch_mask = BIT(0); + patch_reg = MT_MCU_CLOCK_CTL; + } else { + patch_mask = BIT(1); + patch_reg = MT_MCU_COM_REG0; + } + + if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) { + dev_info(dev->mt76.dev, "ROM patch already applied\n"); + goto out; + } + + ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size <= sizeof(*hdr)) { + ret = -EIO; + dev_err(dev->mt76.dev, "Failed to load firmware\n"); + goto out; + } + + hdr = (struct mt76x2_patch_header *) fw->data; + dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); + + cur = (__le32 *) (fw->data + sizeof(*hdr)); + len = fw->size - sizeof(*hdr); + mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + + /* Trigger ROM */ + mt76_wr(dev, MT_MCU_INT_LEVEL, 4); + + if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) { + dev_err(dev->mt76.dev, "Failed to load ROM patch\n"); + ret = -ETIMEDOUT; + } + +out: + /* release semaphore */ + if (rom_protect) + mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1); + release_firmware(fw); + return ret; +} + +static int +mt76pci_load_firmware(struct mt76x2_dev *dev) +{ + const struct firmware *fw; + const struct mt76x2_fw_header *hdr; + int i, len, ret; + __le32 *cur; + u32 offset, val; + + ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto error; + + hdr = (const struct mt76x2_fw_header *) fw->data; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) + goto error; + + val = le16_to_cpu(hdr->fw_ver); + dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); + + val = le16_to_cpu(hdr->build_ver); + dev_info(dev->mt76.dev, "Build: %x\n", val); + dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); + + cur = (__le32 *) (fw->data + sizeof(*hdr)); + len = le32_to_cpu(hdr->ilm_len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len); + + cur += len / sizeof(*cur); + len = le32_to_cpu(hdr->dlm_len); + + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + offset = MT_MCU_DLM_ADDR_E3; + else + offset = MT_MCU_DLM_ADDR; + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); + mt76_wr_copy(dev, offset, cur, len); + + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + + val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); + if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) + mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); + + /* trigger firmware */ + mt76_wr(dev, MT_MCU_INT_LEVEL, 2); + for (i = 200; i > 0; i--) { + val = mt76_rr(dev, MT_MCU_COM_REG0); + + if (val & 1) + break; + + msleep(10); + } + + if (!i) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + release_firmware(fw); + return -ETIMEDOUT; + } + + dev_info(dev->mt76.dev, "Firmware running!\n"); + + release_firmware(fw); + + return ret; + +error: + dev_err(dev->mt76.dev, "Invalid firmware\n"); + release_firmware(fw); + return -ENOENT; +} + +static int +mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, + u32 val) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(func), + .value = cpu_to_le32(val), + }; + + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_FUN_SET_OP); +} + +int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, + u8 channel) +{ + struct sk_buff *skb; + struct { + u8 cr_mode; + u8 temp; + u8 ch; + u8 _pad0; + + __le32 cfg; + } __packed __aligned(4) msg = { + .cr_mode = type, + .temp = temp_level, + .ch = channel, + }; + u32 val; + + val = BIT(31); + val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; + val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; + msg.cfg = cpu_to_le32(val); + + /* first set the channel without the extension channel info */ + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_LOAD_CR); +} + +int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, + u8 bw_index, bool scan) +{ + struct sk_buff *skb; + struct { + u8 idx; + u8 scan; + u8 bw; + u8 _pad0; + + __le16 chainmask; + u8 ext_chan; + u8 _pad1; + + } __packed __aligned(4) msg = { + .idx = channel, + .scan = scan, + .bw = bw, + .chainmask = cpu_to_le16(dev->chainmask), + }; + + /* first set the channel without the extension channel info */ + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); + + usleep_range(5000, 10000); + + msg.ext_chan = 0xe0 + bw_index; + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); +} + +int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) +{ + struct sk_buff *skb; + struct { + __le32 mode; + __le32 level; + } __packed __aligned(4) msg = { + .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), + .level = cpu_to_le32(0), + }; + + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_POWER_SAVING_OP); +} + +int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, + u32 param) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(type), + .value = cpu_to_le32(param), + }; + int ret; + + mt76_clear(dev, MT_MCU_COM_REG0, BIT(31)); + + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + ret = mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); + if (ret) + return ret; + + if (WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0, + BIT(31), BIT(31), 100))) + return -ETIMEDOUT; + + return 0; +} + +int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, + struct mt76x2_tssi_comp *tssi_data) +{ + struct sk_buff *skb; + struct { + __le32 id; + struct mt76x2_tssi_comp data; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(MCU_CAL_TSSI_COMP), + .data = *tssi_data, + }; + + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); +} + +int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, + bool force) +{ + struct sk_buff *skb; + struct { + __le32 channel; + __le32 gain_val; + } __packed __aligned(4) msg = { + .channel = cpu_to_le32(channel), + .gain_val = cpu_to_le32(gain), + }; + + if (force) + msg.channel |= cpu_to_le32(BIT(31)); + + skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); + return mt76x2_mcu_msg_send(dev, skb, CMD_INIT_GAIN_OP); +} + +int mt76x2_mcu_init(struct mt76x2_dev *dev) +{ + int ret; + + mutex_init(&dev->mcu.mutex); + + ret = mt76pci_load_rom_patch(dev); + if (ret) + return ret; + + ret = mt76pci_load_firmware(dev); + if (ret) + return ret; + + mt76x2_mcu_function_select(dev, Q_SELECT, 1); + return 0; +} + +int mt76x2_mcu_cleanup(struct mt76x2_dev *dev) +{ + struct sk_buff *skb; + + mt76_wr(dev, MT_MCU_INT_LEVEL, 1); + usleep_range(20000, 30000); + + while ((skb = skb_dequeue(&dev->mcu.res_q)) != NULL) + dev_kfree_skb(skb); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h new file mode 100644 index 0000000000000..d7a7e83262ced --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_MCU_H +#define __MT76x2_MCU_H + +/* Register definitions */ +#define MT_MCU_CPU_CTL 0x0704 +#define MT_MCU_CLOCK_CTL 0x0708 +#define MT_MCU_RESET_CTL 0x070C +#define MT_MCU_INT_LEVEL 0x0718 +#define MT_MCU_COM_REG0 0x0730 +#define MT_MCU_COM_REG1 0x0734 +#define MT_MCU_COM_REG2 0x0738 +#define MT_MCU_COM_REG3 0x073C +#define MT_MCU_PCIE_REMAP_BASE1 0x0740 +#define MT_MCU_PCIE_REMAP_BASE2 0x0744 +#define MT_MCU_PCIE_REMAP_BASE3 0x0748 +#define MT_MCU_PCIE_REMAP_BASE4 0x074C + +#define MT_LED_CTRL 0x0770 +#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) +#define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) +#define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) +#define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) + +#define MT_LED_TX_BLINK_0 0x0774 +#define MT_LED_TX_BLINK_1 0x0778 + +#define MT_LED_S0_BASE 0x077C +#define MT_LED_S0(_n) (MT_LED_S0_BASE + 8 * (_n)) +#define MT_LED_S1_BASE 0x0780 +#define MT_LED_S1(_n) (MT_LED_S1_BASE + 8 * (_n)) +#define MT_LED_STATUS_OFF_MASK GENMASK(31, 24) +#define MT_LED_STATUS_OFF(_v) (((_v) << __ffs(MT_LED_STATUS_OFF_MASK)) & \ + MT_LED_STATUS_OFF_MASK) +#define MT_LED_STATUS_ON_MASK GENMASK(23, 16) +#define MT_LED_STATUS_ON(_v) (((_v) << __ffs(MT_LED_STATUS_ON_MASK)) & \ + MT_LED_STATUS_ON_MASK) +#define MT_LED_STATUS_DURATION_MASK GENMASK(15, 8) +#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ + MT_LED_STATUS_DURATION_MASK) + +#define MT_MCU_SEMAPHORE_00 0x07B0 +#define MT_MCU_SEMAPHORE_01 0x07B4 +#define MT_MCU_SEMAPHORE_02 0x07B8 +#define MT_MCU_SEMAPHORE_03 0x07BC + +#define MT_MCU_ROM_PATCH_OFFSET 0x80000 +#define MT_MCU_ROM_PATCH_ADDR 0x90000 + +#define MT_MCU_ILM_OFFSET 0x80000 +#define MT_MCU_ILM_ADDR 0x80000 + +#define MT_MCU_DLM_OFFSET 0x100000 +#define MT_MCU_DLM_ADDR 0x90000 +#define MT_MCU_DLM_ADDR_E3 0x90800 + +enum mcu_cmd { + CMD_FUN_SET_OP = 1, + CMD_LOAD_CR = 2, + CMD_INIT_GAIN_OP = 3, + CMD_DYNC_VGA_OP = 6, + CMD_TDLS_CH_SW = 7, + CMD_BURST_WRITE = 8, + CMD_READ_MODIFY_WRITE = 9, + CMD_RANDOM_READ = 10, + CMD_BURST_READ = 11, + CMD_RANDOM_WRITE = 12, + CMD_LED_MODE_OP = 16, + CMD_POWER_SAVING_OP = 20, + CMD_WOW_CONFIG = 21, + CMD_WOW_QUERY = 22, + CMD_WOW_FEATURE = 24, + CMD_CARRIER_DETECT_OP = 28, + CMD_RADOR_DETECT_OP = 29, + CMD_SWITCH_CHANNEL_OP = 30, + CMD_CALIBRATION_OP = 31, + CMD_BEACON_OP = 32, + CMD_ANTENNA_OP = 33, +}; + +enum mcu_function { + Q_SELECT = 1, + BW_SETTING = 2, + USB2_SW_DISCONNECT = 2, + USB3_SW_DISCONNECT = 3, + LOG_FW_DEBUG_MSG = 4, + GET_FW_VERSION = 5, +}; + +enum mcu_power_mode { + RADIO_OFF = 0x30, + RADIO_ON = 0x31, + RADIO_OFF_AUTO_WAKEUP = 0x32, + RADIO_OFF_ADVANCE = 0x33, + RADIO_ON_ADVANCE = 0x34, +}; + +enum mcu_calibration { + MCU_CAL_R = 1, + MCU_CAL_TEMP_SENSOR, + MCU_CAL_RXDCOC, + MCU_CAL_RC, + MCU_CAL_SX_LOGEN, + MCU_CAL_LC, + MCU_CAL_TX_LOFT, + MCU_CAL_TXIQ, + MCU_CAL_TSSI, + MCU_CAL_TSSI_COMP, + MCU_CAL_DPD, + MCU_CAL_RXIQC_FI, + MCU_CAL_RXIQC_FD, + MCU_CAL_PWRON, + MCU_CAL_TX_SHAPING, +}; + +enum mt76x2_mcu_cr_mode { + MT_RF_CR, + MT_BBP_CR, + MT_RF_BBP_CR, + MT_HL_TEMP_CR_UPDATE, +}; + +struct mt76x2_tssi_comp { + u8 pa_mode; + u8 cal_mode; + u16 pad; + + u8 slope0; + u8 slope1; + u8 offset0; + u8 offset1; +} __packed __aligned(4); + +int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, + u32 param); +int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); +int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, + bool force); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c new file mode 100644 index 0000000000000..e66f047ea4481 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt76x2.h" +#include "mt76x2_trace.h" + +static const struct pci_device_id mt76pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7662) }, + { PCI_DEVICE(0x14c3, 0x7612) }, + { PCI_DEVICE(0x14c3, 0x7602) }, + { }, +}; + +static int +mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mt76x2_dev *dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dev = mt76x2_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + + dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + + ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x2_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt76x2_register_device(dev); + if (ret) + goto error; + + /* Fix up ASPM configuration */ + + /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ + mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); + + /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ + mt76_rmw_field(dev, 0x15a0c, 0xf << 28, 0xf); + + /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ + mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); + + return 0; + +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void +mt76pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + + mt76_unregister_device(mdev); + mt76x2_cleanup(dev); + ieee80211_free_hw(mdev->hw); +} + +MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +MODULE_FIRMWARE(MT7662_FIRMWARE); +MODULE_FIRMWARE(MT7662_ROM_PATCH); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct pci_driver mt76pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76pci_device_table, + .probe = mt76pci_probe, + .remove = mt76pci_remove, +}; + +module_pci_driver(mt76pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c new file mode 100644 index 0000000000000..126497172284c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76x2.h" +#include "mt76x2_mcu.h" +#include "mt76x2_eeprom.h" + +static void +mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) +{ + s8 gain; + + gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); + gain -= offset / 2; + mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); +} + +static void +mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset) +{ + s8 gain; + + gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); + gain += offset; + mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); +} + +static void +mt76x2_apply_gain_adj(struct mt76x2_dev *dev) +{ + s8 *gain_adj = dev->cal.rx.high_gain; + + mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]); + mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]); + + mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]); + mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]); +} + +static u32 +mt76x2_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4) +{ + u32 val = 0; + + val |= (v1 & (BIT(6) - 1)) << 0; + val |= (v2 & (BIT(6) - 1)) << 8; + val |= (v3 & (BIT(6) - 1)) << 16; + val |= (v4 & (BIT(6) - 1)) << 24; + return val; +} + +int mt76x2_phy_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) +{ + struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; + + rssi += cal->rssi_offset[chain]; + rssi -= cal->lna_gain; + + return rssi; +} + +static u8 +mt76x2_txpower_check(int value) +{ + if (value < 0) + return 0; + if (value > 0x2f) + return 0x2f; + return value; +} + +static void +mt76x2_add_rate_power_offset(struct mt76_rate_power *r, int offset) +{ + int i; + + for (i = 0; i < sizeof(r->all); i++) + r->all[i] += offset; +} + +static void +mt76x2_limit_rate_power(struct mt76_rate_power *r, int limit) +{ + int i; + + for (i = 0; i < sizeof(r->all); i++) + if (r->all[i] > limit) + r->all[i] = limit; +} + +static int +mt76x2_get_max_power(struct mt76_rate_power *r) +{ + int i; + s8 ret = 0; + + for (i = 0; i < sizeof(r->all); i++) + ret = max(ret, r->all[i]); + + return ret; +} + +void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) +{ + enum nl80211_chan_width width = dev->mt76.chandef.width; + struct mt76x2_tx_power_info txp; + int txp_0, txp_1, delta = 0; + struct mt76_rate_power t = {}; + + mt76x2_get_power_info(dev, &txp); + + if (width == NL80211_CHAN_WIDTH_40) + delta = txp.delta_bw40; + else if (width == NL80211_CHAN_WIDTH_80) + delta = txp.delta_bw80; + + if (txp.target_power > dev->txpower_conf) + delta -= txp.target_power - dev->txpower_conf; + + mt76x2_get_rate_power(dev, &t); + mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power + + txp.chain[0].delta); + mt76x2_limit_rate_power(&t, dev->txpower_conf); + dev->txpower_cur = mt76x2_get_max_power(&t); + mt76x2_add_rate_power_offset(&t, -(txp.chain[0].target_power + + txp.chain[0].delta + delta)); + dev->target_power = txp.chain[0].target_power; + dev->target_power_delta[0] = txp.chain[0].delta + delta; + dev->target_power_delta[1] = txp.chain[1].delta + delta; + dev->rate_power = t; + + txp_0 = mt76x2_txpower_check(txp.chain[0].target_power + + txp.chain[0].delta + delta); + + txp_1 = mt76x2_txpower_check(txp.chain[1].target_power + + txp.chain[1].delta + delta); + + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1); + + mt76_wr(dev, MT_TX_PWR_CFG_0, + mt76x2_tx_power_mask(t.cck[0], t.cck[2], t.ofdm[0], t.ofdm[2])); + mt76_wr(dev, MT_TX_PWR_CFG_1, + mt76x2_tx_power_mask(t.ofdm[4], t.ofdm[6], t.ht[0], t.ht[2])); + mt76_wr(dev, MT_TX_PWR_CFG_2, + mt76x2_tx_power_mask(t.ht[4], t.ht[6], t.ht[8], t.ht[10])); + mt76_wr(dev, MT_TX_PWR_CFG_3, + mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.ht[0], t.ht[2])); + mt76_wr(dev, MT_TX_PWR_CFG_4, + mt76x2_tx_power_mask(t.ht[4], t.ht[6], 0, 0)); + mt76_wr(dev, MT_TX_PWR_CFG_7, + mt76x2_tx_power_mask(t.ofdm[6], t.vht[8], t.ht[6], t.vht[8])); + mt76_wr(dev, MT_TX_PWR_CFG_8, + mt76x2_tx_power_mask(t.ht[14], t.vht[8], t.vht[8], 0)); + mt76_wr(dev, MT_TX_PWR_CFG_9, + mt76x2_tx_power_mask(t.ht[6], t.vht[8], t.vht[8], 0)); +} + +static bool +mt76x2_channel_silent(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + + return ((chan->flags & IEEE80211_CHAN_RADAR) && + chan->dfs_state != NL80211_DFS_AVAILABLE); +} + +static bool +mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + u32 flag = 0; + + if (!mt76x2_tssi_enabled(dev)) + return false; + + if (mt76x2_channel_silent(dev)) + return false; + + if (chan->band == NL80211_BAND_2GHZ) + flag |= BIT(0); + + if (mt76x2_ext_pa_enabled(dev, chan->band)) + flag |= BIT(8); + + mt76x2_mcu_calibrate(dev, MCU_CAL_TSSI, flag); + dev->cal.tssi_cal_done = true; + return true; +} + +static void +mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + bool is_5ghz = chan->band == NL80211_BAND_5GHZ; + + if (dev->cal.channel_cal_done) + return; + + if (mt76x2_channel_silent(dev)) + return; + + if (!dev->cal.tssi_cal_done) + mt76x2_phy_tssi_init_cal(dev); + + if (!mac_stopped) + mt76x2_mac_stop(dev, false); + + if (is_5ghz) + mt76x2_mcu_calibrate(dev, MCU_CAL_LC, 0); + + mt76x2_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz); + mt76x2_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz); + mt76x2_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz); + mt76x2_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0); + mt76x2_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0); + + if (!mac_stopped) + mt76x2_mac_resume(dev); + + mt76x2_apply_gain_adj(dev); + + dev->cal.channel_cal_done = true; +} + +static void +mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, enum nl80211_band band) +{ + u32 pa_mode[2]; + u32 pa_mode_adj; + + if (band == NL80211_BAND_2GHZ) { + pa_mode[0] = 0x010055ff; + pa_mode[1] = 0x00550055; + + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); + + if (mt76x2_ext_pa_enabled(dev, band)) { + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); + } else { + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200); + } + } else { + pa_mode[0] = 0x0000ffff; + pa_mode[1] = 0x00ff00ff; + + if (mt76x2_ext_pa_enabled(dev, band)) { + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); + } else { + mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); + mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); + } + mt76_wr(dev, MT_TX_ALC_CFG_4, 0); + + if (mt76x2_ext_pa_enabled(dev, band)) + pa_mode_adj = 0x04000000; + else + pa_mode_adj = 0; + + mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj); + mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj); + } + + mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]); + mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]); + mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); + mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); + + if (mt76x2_ext_pa_enabled(dev, band)) { + u32 val; + + if (band == NL80211_BAND_2GHZ) + val = 0x3c3c023c; + else + val = 0x363c023c; + + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818); + } else { + if (band == NL80211_BAND_2GHZ) { + u32 val = 0x0f3c3c3c; + + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606); + } else { + mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c); + mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28); + mt76_wr(dev, MT_TX_ALC_CFG_4, 0); + } + } +} + +static void +mt76x2_configure_tx_delay(struct mt76x2_dev *dev, enum nl80211_band band, u8 bw) +{ + u32 cfg0, cfg1; + + if (mt76x2_ext_pa_enabled(dev, band)) { + cfg0 = bw ? 0x000b0c01 : 0x00101101; + cfg1 = 0x00011414; + } else { + cfg0 = bw ? 0x000b0b01 : 0x00101001; + cfg1 = 0x00021414; + } + mt76_wr(dev, MT_TX_SW_CFG0, cfg0); + mt76_wr(dev, MT_TX_SW_CFG1, cfg1); + + mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_CCK_SIFS, + 13 + (bw ? 1 : 0)); +} + +static void +mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl) +{ + int core_val, agc_val; + + switch (width) { + case NL80211_CHAN_WIDTH_80: + core_val = 3; + agc_val = 7; + break; + case NL80211_CHAN_WIDTH_40: + core_val = 2; + agc_val = 3; + break; + default: + core_val = 0; + agc_val = 1; + break; + } + + mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); + mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); +} + +static void +mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) +{ + switch (band) { + case NL80211_BAND_2GHZ: + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + case NL80211_BAND_5GHZ: + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + } + + mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, + primary_upper); +} + +static void +mt76x2_set_rx_chains(struct mt76x2_dev *dev) +{ + u32 val; + + val = mt76_rr(dev, MT_BBP(AGC, 0)); + val &= ~(BIT(3) | BIT(4)); + + if (dev->chainmask & BIT(1)) + val |= BIT(3); + + mt76_wr(dev, MT_BBP(AGC, 0), val); +} + +static void +mt76x2_set_tx_dac(struct mt76x2_dev *dev) +{ + if (dev->chainmask & BIT(1)) + mt76_set(dev, MT_BBP(TXBE, 5), 3); + else + mt76_clear(dev, MT_BBP(TXBE, 5), 3); +} + +static void +mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest) +{ + dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); + dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); +} + +static int +mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -62; + case NL80211_CHAN_WIDTH_40: + return -65; + default: + return -68; + } +} + +static int +mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -76; + case NL80211_CHAN_WIDTH_40: + return -79; + default: + return -82; + } +} + +static void +mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) +{ + u32 val; + u8 gain_val[2]; + + gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; + gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; + + if (dev->mt76.chandef.width >= NL80211_CHAN_WIDTH_40) + val = 0x1e42 << 16; + else + val = 0x1836 << 16; + + val |= 0xf8; + + mt76_wr(dev, MT_BBP(AGC, 8), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); + mt76_wr(dev, MT_BBP(AGC, 9), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); + + if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) + mt76x2_dfs_adjust_agc(dev); +} + +static void +mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) +{ + u32 false_cca; + u8 limit = dev->cal.low_gain > 1 ? 4 : 16; + + false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); + if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) + dev->cal.agc_gain_adjust += 2; + else if (false_cca < 10 && dev->cal.agc_gain_adjust > 0) + dev->cal.agc_gain_adjust -= 2; + else + return; + + mt76x2_phy_set_gain_val(dev); +} + +static void +mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) +{ + u32 val = mt76_rr(dev, MT_BBP(AGC, 20)); + int rssi0 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI0, val); + int rssi1 = (s8) FIELD_GET(MT_BBP_AGC20_RSSI1, val); + u8 *gain = dev->cal.agc_gain_init; + u8 gain_delta; + int low_gain; + + dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + (rssi0 << 8); + dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + (rssi1 << 8); + dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] + + dev->cal.avg_rssi[1]) / 512; + + low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + + (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); + + if (dev->cal.low_gain == low_gain) { + mt76x2_phy_adjust_vga_gain(dev); + return; + } + + dev->cal.low_gain = low_gain; + + if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) + mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); + else + mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); + + if (low_gain) { + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); + mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); + mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); + if (mt76x2_has_ext_lna(dev)) + gain_delta = 10; + else + gain_delta = 14; + } else { + mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); + if (dev->mt76.chandef.width == NL80211_CHAN_WIDTH_80) + mt76_wr(dev, MT_BBP(AGC, 35), 0x10101014); + else + mt76_wr(dev, MT_BBP(AGC, 35), 0x11111116); + mt76_wr(dev, MT_BBP(AGC, 37), 0x2121262C); + gain_delta = 0; + } + + dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; + dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; + dev->cal.agc_gain_adjust = 0; + mt76x2_phy_set_gain_val(dev); +} + +int mt76x2_phy_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_channel *chan = chandef->chan; + bool scan = test_bit(MT76_SCANNING, &dev->mt76.state); + enum nl80211_band band = chan->band; + u8 channel; + + u32 ext_cca_chan[4] = { + [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(0)), + [1] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(1)), + [2] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(2)), + [3] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 3) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA1, 2) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA2, 1) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA3, 0) | + FIELD_PREP(MT_EXT_CCA_CFG_CCA_MASK, BIT(3)), + }; + int ch_group_index; + u8 bw, bw_index; + int freq, freq1; + int ret; + u8 sifs = 13; + + dev->cal.channel_cal_done = false; + freq = chandef->chan->center_freq; + freq1 = chandef->center_freq1; + channel = chan->hw_value; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + bw = 1; + if (freq1 > freq) { + bw_index = 1; + ch_group_index = 0; + } else { + bw_index = 3; + ch_group_index = 1; + } + channel += 2 - ch_group_index * 4; + break; + case NL80211_CHAN_WIDTH_80: + ch_group_index = (freq - freq1 + 30) / 20; + if (WARN_ON(ch_group_index < 0 || ch_group_index > 3)) + ch_group_index = 0; + bw = 2; + bw_index = ch_group_index; + channel += 6 - ch_group_index * 4; + break; + default: + bw = 0; + bw_index = 0; + ch_group_index = 0; + break; + } + + mt76x2_read_rx_gain(dev); + mt76x2_phy_set_txpower_regs(dev, band); + mt76x2_configure_tx_delay(dev, band, bw); + mt76x2_phy_set_txpower(dev); + + mt76x2_set_rx_chains(dev); + mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); + mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); + mt76x2_set_tx_dac(dev); + + mt76_rmw(dev, MT_EXT_CCA_CFG, + (MT_EXT_CCA_CFG_CCA0 | + MT_EXT_CCA_CFG_CCA1 | + MT_EXT_CCA_CFG_CCA2 | + MT_EXT_CCA_CFG_CCA3 | + MT_EXT_CCA_CFG_CCA_MASK), + ext_cca_chan[ch_group_index]); + + if (chandef->width >= NL80211_CHAN_WIDTH_40) + sifs++; + + mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, sifs); + + ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); + if (ret) + return ret; + + mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); + + /* Enable LDPC Rx */ + if (mt76xx_rev(dev) >= MT76XX_REV_E3) + mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); + + if (!dev->cal.init_cal_done) { + u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); + + if (val != 0xff) + mt76x2_mcu_calibrate(dev, MCU_CAL_R, 0); + } + + mt76x2_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel); + + /* Rx LPF calibration */ + if (!dev->cal.init_cal_done) + mt76x2_mcu_calibrate(dev, MCU_CAL_RC, 0); + + dev->cal.init_cal_done = true; + + mt76_wr(dev, MT_BBP(AGC, 61), 0xFF64A4E2); + mt76_wr(dev, MT_BBP(AGC, 7), 0x08081010); + mt76_wr(dev, MT_BBP(AGC, 11), 0x00000404); + mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); + mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x04101B3F); + + if (scan) + return 0; + + dev->cal.low_gain = -1; + mt76x2_phy_channel_calibrate(dev, true); + mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init); + memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, + sizeof(dev->cal.agc_gain_cur)); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); + + return 0; +} + +static void +mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + struct mt76x2_tx_power_info txp; + struct mt76x2_tssi_comp t = {}; + + if (!dev->cal.tssi_cal_done) + return; + + if (!dev->cal.tssi_comp_pending) { + /* TSSI trigger */ + t.cal_mode = BIT(0); + mt76x2_mcu_tssi_comp(dev, &t); + dev->cal.tssi_comp_pending = true; + } else { + if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) + return; + + dev->cal.tssi_comp_pending = false; + mt76x2_get_power_info(dev, &txp); + + if (mt76x2_ext_pa_enabled(dev, chan->band)) + t.pa_mode = 1; + + t.cal_mode = BIT(1); + t.slope0 = txp.chain[0].tssi_slope; + t.offset0 = txp.chain[0].tssi_offset; + t.slope1 = txp.chain[1].tssi_slope; + t.offset1 = txp.chain[1].tssi_offset; + mt76x2_mcu_tssi_comp(dev, &t); + + if (t.pa_mode || dev->cal.dpd_cal_done) + return; + + usleep_range(10000, 20000); + mt76x2_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value); + dev->cal.dpd_cal_done = true; + } +} + +static void +mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) +{ + struct mt76x2_temp_comp t; + int temp, db_diff; + + if (mt76x2_get_temp_comp(dev, &t)) + return; + + temp = mt76_get_field(dev, MT_TEMP_SENSOR, MT_TEMP_SENSOR_VAL); + temp -= t.temp_25_ref; + temp = (temp * 1789) / 1000 + 25; + dev->cal.temp = temp; + + if (temp > 25) + db_diff = (temp - 25) / t.high_slope; + else + db_diff = (25 - temp) / t.low_slope; + + db_diff = min(db_diff, t.upper_bound); + db_diff = max(db_diff, t.lower_bound); + + mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + db_diff * 2); + mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, + db_diff * 2); +} + +void mt76x2_phy_calibrate(struct work_struct *work) +{ + struct mt76x2_dev *dev; + + dev = container_of(work, struct mt76x2_dev, cal_work.work); + mt76x2_phy_channel_calibrate(dev, false); + mt76x2_phy_tssi_compensate(dev); + mt76x2_phy_temp_compensate(dev); + mt76x2_phy_update_channel_gain(dev); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, + MT_CALIBRATE_INTERVAL); +} + +int mt76x2_phy_start(struct mt76x2_dev *dev) +{ + int ret; + + ret = mt76x2_mcu_set_radio_state(dev, true); + if (ret) + return ret; + + mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); + + return ret; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h new file mode 100644 index 0000000000000..ce3ab85c8b0f5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x2_REGS_H +#define __MT76x2_REGS_H + +#define MT_ASIC_VERSION 0x0000 + +#define MT76XX_REV_E3 0x22 +#define MT76XX_REV_E4 0x33 + +#define MT_CMB_CTRL 0x0020 +#define MT_CMB_CTRL_XTAL_RDY BIT(22) +#define MT_CMB_CTRL_PLL_LD BIT(23) + +#define MT_EFUSE_CTRL 0x0024 +#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) +#define MT_EFUSE_CTRL_MODE GENMASK(7, 6) +#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) +#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) +#define MT_EFUSE_CTRL_AIN GENMASK(25, 16) +#define MT_EFUSE_CTRL_KICK BIT(30) +#define MT_EFUSE_CTRL_SEL BIT(31) + +#define MT_EFUSE_DATA_BASE 0x0028 +#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2)) + +#define MT_COEXCFG0 0x0040 +#define MT_COEXCFG0_COEX_EN BIT(0) + +#define MT_WLAN_FUN_CTRL 0x0080 +#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0) +#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1) +#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2) + +#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */ + +#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4) +#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5) +#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6) +#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7) + +#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */ +#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */ + +#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */ + +#define MT_XO_CTRL0 0x0100 +#define MT_XO_CTRL1 0x0104 +#define MT_XO_CTRL2 0x0108 +#define MT_XO_CTRL3 0x010c +#define MT_XO_CTRL4 0x0110 + +#define MT_XO_CTRL5 0x0114 +#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8) + +#define MT_XO_CTRL6 0x0118 +#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8) + +#define MT_XO_CTRL7 0x011c + +#define MT_WLAN_MTC_CTRL 0x10148 +#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0) +#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12) +#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13) +#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16) +#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20) +#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21) +#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22) +#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24) +#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25) +#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26) +#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27) +#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28) + +#define MT_INT_SOURCE_CSR 0x0200 +#define MT_INT_MASK_CSR 0x0204 + +#define MT_INT_RX_DONE(_n) BIT(_n) +#define MT_INT_RX_DONE_ALL GENMASK(1, 0) +#define MT_INT_TX_DONE_ALL GENMASK(13, 4) +#define MT_INT_TX_DONE(_n) BIT(_n + 4) +#define MT_INT_RX_COHERENT BIT(16) +#define MT_INT_TX_COHERENT BIT(17) +#define MT_INT_ANY_COHERENT BIT(18) +#define MT_INT_MCU_CMD BIT(19) +#define MT_INT_TBTT BIT(20) +#define MT_INT_PRE_TBTT BIT(21) +#define MT_INT_TX_STAT BIT(22) +#define MT_INT_AUTO_WAKEUP BIT(23) +#define MT_INT_GPTIMER BIT(24) +#define MT_INT_RXDELAYINT BIT(26) +#define MT_INT_TXDELAYINT BIT(27) + +#define MT_WPDMA_GLO_CFG 0x0208 +#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) +#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) +#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) +#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) +#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) +#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) +#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) + +#define MT_WPDMA_RST_IDX 0x020c + +#define MT_WPDMA_DELAY_INT_CFG 0x0210 + +#define MT_WMM_AIFSN 0x0214 +#define MT_WMM_AIFSN_MASK GENMASK(3, 0) +#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_CWMIN 0x0218 +#define MT_WMM_CWMIN_MASK GENMASK(3, 0) +#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_CWMAX 0x021c +#define MT_WMM_CWMAX_MASK GENMASK(3, 0) +#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_TXOP_BASE 0x0220 +#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) +#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) +#define MT_WMM_TXOP_MASK GENMASK(15, 0) + +#define MT_TSO_CTRL 0x0250 +#define MT_HEADER_TRANS_CTRL_REG 0x0260 + +#define MT_TX_RING_BASE 0x0300 +#define MT_RX_RING_BASE 0x03c0 + +#define MT_TX_HW_QUEUE_MCU 8 +#define MT_TX_HW_QUEUE_MGMT 9 + +#define MT_PBF_SYS_CTRL 0x0400 +#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0) +#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1) +#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2) +#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3) +#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4) + +#define MT_PBF_CFG 0x0404 +#define MT_PBF_CFG_TX0Q_EN BIT(0) +#define MT_PBF_CFG_TX1Q_EN BIT(1) +#define MT_PBF_CFG_TX2Q_EN BIT(2) +#define MT_PBF_CFG_TX3Q_EN BIT(3) +#define MT_PBF_CFG_RX0Q_EN BIT(4) +#define MT_PBF_CFG_RX_DROP_EN BIT(8) + +#define MT_PBF_TX_MAX_PCNT 0x0408 +#define MT_PBF_RX_MAX_PCNT 0x040c + +#define MT_BCN_OFFSET_BASE 0x041c +#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) + +#define MT_RF_BYPASS_0 0x0504 +#define MT_RF_BYPASS_1 0x0508 +#define MT_RF_SETTING_0 0x050c + +#define MT_RF_DATA_WRITE 0x0524 + +#define MT_RF_CTRL 0x0528 +#define MT_RF_CTRL_ADDR GENMASK(11, 0) +#define MT_RF_CTRL_WRITE BIT(12) +#define MT_RF_CTRL_BUSY BIT(13) +#define MT_RF_CTRL_IDX BIT(16) + +#define MT_RF_DATA_READ 0x052c + +#define MT_FCE_PSE_CTRL 0x0800 +#define MT_FCE_PARAMETERS 0x0804 +#define MT_FCE_CSO 0x0808 + +#define MT_FCE_L2_STUFF 0x080c +#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0) +#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1) +#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2) +#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3) +#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4) +#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5) +#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8) +#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16) +#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24) + +#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824 + +#define MT_PAUSE_ENABLE_CONTROL1 0x0a38 + +#define MT_MAC_CSR0 0x1000 + +#define MT_MAC_SYS_CTRL 0x1004 +#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0) +#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1) +#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2) +#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3) + +#define MT_MAC_ADDR_DW0 0x1008 +#define MT_MAC_ADDR_DW1 0x100c + +#define MT_MAC_BSSID_DW0 0x1010 +#define MT_MAC_BSSID_DW1 0x1014 +#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0) +#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16) +#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18) +#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21) +#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22) +#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23) +#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24) + +#define MT_MAX_LEN_CFG 0x1018 + +#define MT_AMPDU_MAX_LEN_20M1S 0x1030 +#define MT_AMPDU_MAX_LEN_20M2S 0x1034 +#define MT_AMPDU_MAX_LEN_40M1S 0x1038 +#define MT_AMPDU_MAX_LEN_40M2S 0x103c +#define MT_AMPDU_MAX_LEN 0x1040 + +#define MT_WCID_DROP_BASE 0x106c +#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4) +#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32) + +#define MT_BCN_BYPASS_MASK 0x108c + +#define MT_MAC_APC_BSSID_BASE 0x1090 +#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8)) +#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4)) +#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0) +#define MT_MAC_APC_BSSID0_H_EN BIT(16) + +#define MT_XIFS_TIME_CFG 0x1100 +#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0) +#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8) +#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16) +#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20) +#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29) + +#define MT_BKOFF_SLOT_CFG 0x1104 +#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0) +#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8) + +#define MT_CH_TIME_CFG 0x110c +#define MT_CH_TIME_CFG_TIMER_EN BIT(0) +#define MT_CH_TIME_CFG_TX_AS_BUSY BIT(1) +#define MT_CH_TIME_CFG_RX_AS_BUSY BIT(2) +#define MT_CH_TIME_CFG_NAV_AS_BUSY BIT(3) +#define MT_CH_TIME_CFG_EIFS_AS_BUSY BIT(4) +#define MT_CH_TIME_CFG_MDRDY_CNT_EN BIT(5) +#define MT_CH_TIME_CFG_CH_TIMER_CLR GENMASK(9, 8) +#define MT_CH_TIME_CFG_MDRDY_CLR GENMASK(11, 10) + +#define MT_PBF_LIFE_TIMER 0x1110 + +#define MT_BEACON_TIME_CFG 0x1114 +#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0) +#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16) +#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17) +#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19) +#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20) +#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24) + +#define MT_TBTT_SYNC_CFG 0x1118 +#define MT_TBTT_TIMER_CFG 0x1124 + +#define MT_INT_TIMER_CFG 0x1128 +#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0) +#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16) + +#define MT_INT_TIMER_EN 0x112c +#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0) +#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1) + +#define MT_CH_IDLE 0x1130 +#define MT_CH_BUSY 0x1134 +#define MT_EXT_CH_BUSY 0x1138 +#define MT_ED_CCA_TIMER 0x1140 + +#define MT_MAC_STATUS 0x1200 +#define MT_MAC_STATUS_TX BIT(0) +#define MT_MAC_STATUS_RX BIT(1) + +#define MT_PWR_PIN_CFG 0x1204 +#define MT_AUX_CLK_CFG 0x120c + +#define MT_BB_PA_MODE_CFG0 0x1214 +#define MT_BB_PA_MODE_CFG1 0x1218 +#define MT_RF_PA_MODE_CFG0 0x121c +#define MT_RF_PA_MODE_CFG1 0x1220 + +#define MT_RF_PA_MODE_ADJ0 0x1228 +#define MT_RF_PA_MODE_ADJ1 0x122c + +#define MT_DACCLK_EN_DLY_CFG 0x1264 + +#define MT_EDCA_CFG_BASE 0x1300 +#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2)) +#define MT_EDCA_CFG_TXOP GENMASK(7, 0) +#define MT_EDCA_CFG_AIFSN GENMASK(11, 8) +#define MT_EDCA_CFG_CWMIN GENMASK(15, 12) +#define MT_EDCA_CFG_CWMAX GENMASK(19, 16) + +#define MT_TX_PWR_CFG_0 0x1314 +#define MT_TX_PWR_CFG_1 0x1318 +#define MT_TX_PWR_CFG_2 0x131c +#define MT_TX_PWR_CFG_3 0x1320 +#define MT_TX_PWR_CFG_4 0x1324 + +#define MT_TX_BAND_CFG 0x132c +#define MT_TX_BAND_CFG_UPPER_40M BIT(0) +#define MT_TX_BAND_CFG_5G BIT(1) +#define MT_TX_BAND_CFG_2G BIT(2) + +#define MT_HT_FBK_TO_LEGACY 0x1384 +#define MT_TX_MPDU_ADJ_INT 0x1388 + +#define MT_TX_PWR_CFG_7 0x13d4 +#define MT_TX_PWR_CFG_8 0x13d8 +#define MT_TX_PWR_CFG_9 0x13dc + +#define MT_TX_SW_CFG0 0x1330 +#define MT_TX_SW_CFG1 0x1334 +#define MT_TX_SW_CFG2 0x1338 + +#define MT_TXOP_CTRL_CFG 0x1340 + +#define MT_TX_RTS_CFG 0x1344 +#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) +#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8) +#define MT_TX_RTS_FALLBACK BIT(24) + +#define MT_TX_TIMEOUT_CFG 0x1348 +#define MT_TX_TIMEOUT_CFG_ACKTO GENMASK(15, 8) + +#define MT_TX_RETRY_CFG 0x134c +#define MT_VHT_HT_FBK_CFG1 0x1358 + +#define MT_PROT_CFG_RATE GENMASK(15, 0) +#define MT_PROT_CFG_CTRL GENMASK(17, 16) +#define MT_PROT_CFG_NAV GENMASK(19, 18) +#define MT_PROT_CFG_TXOP_ALLOW GENMASK(25, 20) +#define MT_PROT_CFG_RTS_THRESH BIT(26) + +#define MT_CCK_PROT_CFG 0x1364 +#define MT_OFDM_PROT_CFG 0x1368 +#define MT_MM20_PROT_CFG 0x136c +#define MT_MM40_PROT_CFG 0x1370 +#define MT_GF20_PROT_CFG 0x1374 +#define MT_GF40_PROT_CFG 0x1378 + +#define MT_EXP_ACK_TIME 0x1380 + +#define MT_TX_PWR_CFG_0_EXT 0x1390 +#define MT_TX_PWR_CFG_1_EXT 0x1394 + +#define MT_TX_FBK_LIMIT 0x1398 +#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0) +#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8) +#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16) +#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17) +#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18) + +#define MT_TX0_RF_GAIN_CORR 0x13a0 +#define MT_TX1_RF_GAIN_CORR 0x13a4 + +#define MT_TX_ALC_CFG_0 0x13b0 +#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0) +#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8) +#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16) +#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24) + +#define MT_TX_ALC_CFG_1 0x13b4 +#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0) + +#define MT_TX_ALC_CFG_2 0x13a8 +#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0) + +#define MT_TX_ALC_CFG_3 0x13ac +#define MT_TX_ALC_CFG_4 0x13c0 +#define MT_TX_ALC_CFG_4_LOWGAIN_CH_EN BIT(31) + +#define MT_TX_ALC_VGA3 0x13c8 + +#define MT_TX_PROT_CFG6 0x13e0 +#define MT_TX_PROT_CFG7 0x13e4 +#define MT_TX_PROT_CFG8 0x13e8 + +#define MT_PIFS_TX_CFG 0x13ec + +#define MT_RX_FILTR_CFG 0x1400 + +#define MT_RX_FILTR_CFG_CRC_ERR BIT(0) +#define MT_RX_FILTR_CFG_PHY_ERR BIT(1) +#define MT_RX_FILTR_CFG_PROMISC BIT(2) +#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3) +#define MT_RX_FILTR_CFG_VER_ERR BIT(4) +#define MT_RX_FILTR_CFG_MCAST BIT(5) +#define MT_RX_FILTR_CFG_BCAST BIT(6) +#define MT_RX_FILTR_CFG_DUP BIT(7) +#define MT_RX_FILTR_CFG_CFACK BIT(8) +#define MT_RX_FILTR_CFG_CFEND BIT(9) +#define MT_RX_FILTR_CFG_ACK BIT(10) +#define MT_RX_FILTR_CFG_CTS BIT(11) +#define MT_RX_FILTR_CFG_RTS BIT(12) +#define MT_RX_FILTR_CFG_PSPOLL BIT(13) +#define MT_RX_FILTR_CFG_BA BIT(14) +#define MT_RX_FILTR_CFG_BAR BIT(15) +#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) + +#define MT_LEGACY_BASIC_RATE 0x1408 +#define MT_HT_BASIC_RATE 0x140c + +#define MT_HT_CTRL_CFG 0x1410 + +#define MT_EXT_CCA_CFG 0x141c +#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0) +#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2) +#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4) +#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6) +#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8) +#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12) + +#define MT_TX_SW_CFG3 0x1478 + +#define MT_PN_PAD_MODE 0x150c + +#define MT_TXOP_HLDR_ET 0x1608 + +#define MT_PROT_AUTO_TX_CFG 0x1648 +#define MT_PROT_AUTO_TX_CFG_PROT_PADJ GENMASK(11, 8) +#define MT_PROT_AUTO_TX_CFG_AUTO_PADJ GENMASK(27, 24) + +#define MT_RX_STAT_0 0x1700 +#define MT_RX_STAT_0_CRC_ERRORS GENMASK(15, 0) +#define MT_RX_STAT_0_PHY_ERRORS GENMASK(31, 16) + +#define MT_RX_STAT_1 0x1704 +#define MT_RX_STAT_1_CCA_ERRORS GENMASK(15, 0) +#define MT_RX_STAT_1_PLCP_ERRORS GENMASK(31, 16) + +#define MT_RX_STAT_2 0x1708 +#define MT_RX_STAT_2_DUP_ERRORS GENMASK(15, 0) +#define MT_RX_STAT_2_OVERFLOW_ERRORS GENMASK(31, 16) + +#define MT_TX_STAT_FIFO 0x1718 +#define MT_TX_STAT_FIFO_VALID BIT(0) +#define MT_TX_STAT_FIFO_SUCCESS BIT(5) +#define MT_TX_STAT_FIFO_AGGR BIT(6) +#define MT_TX_STAT_FIFO_ACKREQ BIT(7) +#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8) +#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16) + +#define MT_TX_AGG_CNT_BASE0 0x1720 +#define MT_TX_AGG_CNT_BASE1 0x174c + +#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ + MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \ + MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2)) + +#define MT_TX_STAT_FIFO_EXT 0x1798 +#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0) +#define MT_TX_STAT_FIFO_EXT_PKTID GENMASK(15, 8) + +#define MT_WCID_TX_RATE_BASE 0x1c00 +#define MT_WCID_TX_RATE(_i) (MT_WCID_TX_RATE_BASE + ((_i) << 3)) + +#define MT_BBP_CORE_BASE 0x2000 +#define MT_BBP_IBI_BASE 0x2100 +#define MT_BBP_AGC_BASE 0x2300 +#define MT_BBP_TXC_BASE 0x2400 +#define MT_BBP_RXC_BASE 0x2500 +#define MT_BBP_TXO_BASE 0x2600 +#define MT_BBP_TXBE_BASE 0x2700 +#define MT_BBP_RXFE_BASE 0x2800 +#define MT_BBP_RXO_BASE 0x2900 +#define MT_BBP_DFS_BASE 0x2a00 +#define MT_BBP_TR_BASE 0x2b00 +#define MT_BBP_CAL_BASE 0x2c00 +#define MT_BBP_DSC_BASE 0x2e00 +#define MT_BBP_PFMU_BASE 0x2f00 + +#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2)) + +#define MT_BBP_CORE_R1_BW GENMASK(4, 3) + +#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8) +#define MT_BBP_AGC_R0_BW GENMASK(14, 12) + +/* AGC, R4/R5 */ +#define MT_BBP_AGC_LNA_HIGH_GAIN GENMASK(21, 16) +#define MT_BBP_AGC_LNA_MID_GAIN GENMASK(13, 8) +#define MT_BBP_AGC_LNA_LOW_GAIN GENMASK(5, 0) + +/* AGC, R6/R7 */ +#define MT_BBP_AGC_LNA_ULOW_GAIN GENMASK(5, 0) + +/* AGC, R8/R9 */ +#define MT_BBP_AGC_LNA_GAIN_MODE GENMASK(7, 6) +#define MT_BBP_AGC_GAIN GENMASK(14, 8) + +#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0) +#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8) + +#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0) + +#define MT_WCID_ADDR_BASE 0x1800 +#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8) + +#define MT_SRAM_BASE 0x4000 + +#define MT_WCID_KEY_BASE 0x8000 +#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32) + +#define MT_WCID_IV_BASE 0xa000 +#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8) + +#define MT_WCID_ATTR_BASE 0xa800 +#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4) + +#define MT_WCID_ATTR_PAIRWISE BIT(0) +#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1) +#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4) +#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7) +#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10) +#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11) +#define MT_WCID_ATTR_WAPI_MCBC BIT(15) +#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24) + +#define MT_SKEY_BASE_0 0xac00 +#define MT_SKEY_BASE_1 0xb400 +#define MT_SKEY_0(_bss, _idx) (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32) +#define MT_SKEY_1(_bss, _idx) (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32) +#define MT_SKEY(_bss, _idx) ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) + +#define MT_SKEY_MODE_BASE_0 0xb000 +#define MT_SKEY_MODE_BASE_1 0xb3f0 +#define MT_SKEY_MODE_0(_bss) (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2)) +#define MT_SKEY_MODE_1(_bss) (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2)) +#define MT_SKEY_MODE(_bss) ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) +#define MT_SKEY_MODE_MASK GENMASK(3, 0) +#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1))) + +#define MT_BEACON_BASE 0xc000 + +#define MT_TEMP_SENSOR 0x1d000 +#define MT_TEMP_SENSOR_VAL GENMASK(6, 0) + +struct mt76_wcid_addr { + u8 macaddr[6]; + __le16 ba_mask; +} __packed __aligned(4); + +struct mt76_wcid_key { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __packed __aligned(4); + +enum mt76x2_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_WEP104, + MT_CIPHER_TKIP, + MT_CIPHER_AES_CCMP, + MT_CIPHER_CKIP40, + MT_CIPHER_CKIP104, + MT_CIPHER_CKIP128, + MT_CIPHER_WAPI, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c new file mode 100644 index 0000000000000..a09f117848d66 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "mt76x2_trace.h" + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h new file mode 100644 index 0000000000000..4cd424148d4b3 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__MT76x2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MT76x2_TRACE_H + +#include +#include "mt76x2.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mt76x2 + +#define MAXNAME 32 +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) +#define DEV_PR_FMT "%s" +#define DEV_PR_ARG __entry->wiphy_name + +#define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) +#define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid +#define TXID_PR_FMT " [%d:%d]" +#define TXID_PR_ARG __entry->wcid, __entry->pktid + +DECLARE_EVENT_CLASS(dev_evt, + TP_PROTO(struct mt76x2_dev *dev), + TP_ARGS(dev), + TP_STRUCT__entry( + DEV_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + ), + TP_printk(DEV_PR_FMT, DEV_PR_ARG) +); + +DECLARE_EVENT_CLASS(dev_txid_evt, + TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid), + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + TXID_ASSIGN; + ), + TP_printk( + DEV_PR_FMT TXID_PR_FMT, + DEV_PR_ARG, TXID_PR_ARG + ) +); + +DEFINE_EVENT(dev_evt, mac_txstat_poll, + TP_PROTO(struct mt76x2_dev *dev), + TP_ARGS(dev) +); + +DEFINE_EVENT(dev_txid_evt, mac_txdone_add, + TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid) +); + +TRACE_EVENT(mac_txstat_fetch, + TP_PROTO(struct mt76x2_dev *dev, + struct mt76x2_tx_status *stat), + + TP_ARGS(dev, stat), + + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + __field(bool, success) + __field(bool, aggr) + __field(bool, ack_req) + __field(u16, rate) + __field(u8, retry) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->success = stat->success; + __entry->aggr = stat->aggr; + __entry->ack_req = stat->ack_req; + __entry->wcid = stat->wcid; + __entry->pktid = stat->pktid; + __entry->rate = stat->rate; + __entry->retry = stat->retry; + ), + + TP_printk( + DEV_PR_FMT TXID_PR_FMT + " success:%d aggr:%d ack_req:%d" + " rate:%04x retry:%d", + DEV_PR_ARG, TXID_PR_ARG, + __entry->success, __entry->aggr, __entry->ack_req, + __entry->rate, __entry->retry + ) +); + + +TRACE_EVENT(dev_irq, + TP_PROTO(struct mt76x2_dev *dev, u32 val, u32 mask), + + TP_ARGS(dev, val, mask), + + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, val) + __field(u32, mask) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->val = val; + __entry->mask = mask; + ), + + TP_printk( + DEV_PR_FMT " %08x & %08x", + DEV_PR_ARG, __entry->val, __entry->mask + ) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE mt76x2_trace + +#include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c new file mode 100644 index 0000000000000..1a32e1fb8743f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76x2.h" +#include "mt76x2_dma.h" + +struct beacon_bc_data { + struct mt76x2_dev *dev; + struct sk_buff_head q; + struct sk_buff *tail[8]; +}; + +void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76x2_dev *dev = hw->priv; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->global_wcid; + + if (control->sta) { + struct mt76x2_sta *msta; + + msta = (struct mt76x2_sta *) control->sta->drv_priv; + wcid = &msta->wcid; + } else if (vif) { + struct mt76x2_vif *mvif; + + mvif = (struct mt76x2_vif *) vif->drv_priv; + wcid = &mvif->group_wcid; + } + + mt76_tx(&dev->mt76, control->sta, wcid, skb); +} + +void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + ieee80211_free_txskb(mt76_hw(dev), skb); + } else { + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status(mt76_hw(dev), skb); + } +} + +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, + const struct ieee80211_tx_rate *rate) +{ + s8 max_txpwr; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + + if (mcs == 8 || mcs == 9) { + max_txpwr = dev->rate_power.vht[8]; + } else { + u8 nss, idx; + + nss = ieee80211_rate_get_vht_nss(rate); + idx = ((nss - 1) << 3) + mcs; + max_txpwr = dev->rate_power.ht[idx & 0xf]; + } + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + } else { + enum nl80211_band band = dev->mt76.chandef.chan->band; + + if (band == NL80211_BAND_2GHZ) { + const struct ieee80211_rate *r; + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + struct mt76_rate_power *rp = &dev->rate_power; + + r = &wiphy->bands[band]->bitrates[rate->idx]; + if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) + max_txpwr = rp->cck[r->hw_value & 0x3]; + else + max_txpwr = rp->ofdm[r->hw_value & 0x7]; + } else { + max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + } + } + + return max_txpwr; +} + +s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) +{ + txpwr = min_t(s8, txpwr, dev->txpower_conf); + txpwr -= (dev->target_power + dev->target_power_delta[0]); + txpwr = min_t(s8, txpwr, max_txpwr_adj); + + if (!dev->enable_tpc) + return 0; + else if (txpwr >= 0) + return min_t(s8, txpwr, 7); + else + return (txpwr < -16) ? 8 : (txpwr + 32) / 2; +} + +void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) +{ + s8 txpwr_adj; + + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, + dev->rate_power.ofdm[4]); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); +} + +static int mt76x2_insert_hdr_pad(struct sk_buff *skb) +{ + int len = ieee80211_get_hdrlen_from_skb(skb); + + if (len % 4 == 0) + return 0; + + skb_push(skb, 2); + memmove(skb->data, skb->data + 2, len); + + skb->data[len] = 0; + skb->data[len + 1] = 0; + return 2; +} + +int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int qsel = MT_QSEL_EDCA; + int ret; + + if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) + mt76x2_mac_wcid_set_drop(dev, wcid->idx, false); + + mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta); + + ret = mt76x2_insert_hdr_pad(skb); + if (ret < 0) + return ret; + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + qsel = MT_QSEL_MGMT; + + *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | + MT_TXD_INFO_80211; + + if (!wcid || wcid->hw_key_idx == 0xff) + *tx_info |= MT_TXD_INFO_WIV; + + return 0; +} + +static void +mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct sk_buff *skb = NULL; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_beacon_get(mt76_hw(dev), vif); + if (!skb) + return; + + mt76x2_mac_set_beacon(dev, mvif->idx, skb); +} + +static void +mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct beacon_bc_data *data = priv; + struct mt76x2_dev *dev = data->dev; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct ieee80211_tx_info *info; + struct sk_buff *skb; + + if (!(dev->beacon_mask & BIT(mvif->idx))) + return; + + skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->control.vif = vif; + info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + mt76_skb_set_moredata(skb, true); + __skb_queue_tail(&data->q, skb); + data->tail[mvif->idx] = skb; +} + +void mt76x2_pre_tbtt_tasklet(unsigned long arg) +{ + struct mt76x2_dev *dev = (struct mt76x2_dev *) arg; + struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD]; + struct beacon_bc_data data = {}; + struct sk_buff *skb; + int i, nframes; + + data.dev = dev; + __skb_queue_head_init(&data.q); + + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76x2_update_beacon_iter, dev); + + do { + nframes = skb_queue_len(&data.q); + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76x2_add_buffered_bc, &data); + } while (nframes != skb_queue_len(&data.q)); + + if (!nframes) + return; + + for (i = 0; i < ARRAY_SIZE(data.tail); i++) { + if (!data.tail[i]) + continue; + + mt76_skb_set_moredata(data.tail[i], false); + } + + spin_lock_bh(&q->lock); + while ((skb = __skb_dequeue(&data.q)) != NULL) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + + mt76_tx_queue_skb(&dev->mt76, q, skb, &mvif->group_wcid, NULL); + } + spin_unlock_bh(&q->lock); +} + diff --git a/drivers/net/wireless/mediatek/mt76/trace.c b/drivers/net/wireless/mediatek/mt76/trace.c new file mode 100644 index 0000000000000..ea4ab8729ae48 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/trace.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/trace.h b/drivers/net/wireless/mediatek/mt76/trace.h new file mode 100644 index 0000000000000..ea30895933c5b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/trace.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__MT76_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MT76_TRACE_H + +#include +#include "mt76.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mt76 + +#define MAXNAME 32 +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(dev->hw->wiphy), MAXNAME) +#define DEV_PR_FMT "%s" +#define DEV_PR_ARG __entry->wiphy_name + +#define REG_ENTRY __field(u32, reg) __field(u32, val) +#define REG_ASSIGN __entry->reg = reg; __entry->val = val +#define REG_PR_FMT " %04x=%08x" +#define REG_PR_ARG __entry->reg, __entry->val + +DECLARE_EVENT_CLASS(dev_reg_evt, + TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val), + TP_STRUCT__entry( + DEV_ENTRY + REG_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + REG_ASSIGN; + ), + TP_printk( + DEV_PR_FMT REG_PR_FMT, + DEV_PR_ARG, REG_PR_ARG + ) +); + +DEFINE_EVENT(dev_reg_evt, reg_rr, + TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val) +); + +DEFINE_EVENT(dev_reg_evt, reg_wr, + TP_PROTO(struct mt76_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c new file mode 100644 index 0000000000000..4eef69bd8a9ea --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76.h" + +static struct mt76_txwi_cache * +mt76_alloc_txwi(struct mt76_dev *dev) +{ + struct mt76_txwi_cache *t; + dma_addr_t addr; + int size; + + size = (sizeof(*t) + L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1); + t = devm_kzalloc(dev->dev, size, GFP_ATOMIC); + if (!t) + return NULL; + + addr = dma_map_single(dev->dev, &t->txwi, sizeof(t->txwi), + DMA_TO_DEVICE); + t->dma_addr = addr; + + return t; +} + +static struct mt76_txwi_cache * +__mt76_get_txwi(struct mt76_dev *dev) +{ + struct mt76_txwi_cache *t = NULL; + + spin_lock_bh(&dev->lock); + if (!list_empty(&dev->txwi_cache)) { + t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache, + list); + list_del(&t->list); + } + spin_unlock_bh(&dev->lock); + + return t; +} + +static struct mt76_txwi_cache * +mt76_get_txwi(struct mt76_dev *dev) +{ + struct mt76_txwi_cache *t = __mt76_get_txwi(dev); + + if (t) + return t; + + return mt76_alloc_txwi(dev); +} + +void +mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + if (!t) + return; + + spin_lock_bh(&dev->lock); + list_add(&t->list, &dev->txwi_cache); + spin_unlock_bh(&dev->lock); +} + +void mt76_tx_free(struct mt76_dev *dev) +{ + struct mt76_txwi_cache *t; + + while ((t = __mt76_get_txwi(dev)) != NULL) + dma_unmap_single(dev->dev, t->dma_addr, sizeof(t->txwi), + DMA_TO_DEVICE); +} + +static int +mt76_txq_get_qid(struct ieee80211_txq *txq) +{ + if (!txq->sta) + return MT_TXQ_BE; + + return txq->ac; +} + +int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta) +{ + struct mt76_queue_entry e; + struct mt76_txwi_cache *t; + struct mt76_queue_buf buf[32]; + struct sk_buff *iter; + dma_addr_t addr; + int len; + u32 tx_info = 0; + int n, ret; + + t = mt76_get_txwi(dev); + if (!t) { + ieee80211_free_txskb(dev->hw, skb); + return -ENOMEM; + } + + dma_sync_single_for_cpu(dev->dev, t->dma_addr, sizeof(t->txwi), + DMA_TO_DEVICE); + ret = dev->drv->tx_prepare_skb(dev, &t->txwi, skb, q, wcid, sta, + &tx_info); + dma_sync_single_for_device(dev->dev, t->dma_addr, sizeof(t->txwi), + DMA_TO_DEVICE); + if (ret < 0) + goto free; + + len = skb->len - skb->data_len; + addr = dma_map_single(dev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, addr)) { + ret = -ENOMEM; + goto free; + } + + n = 0; + buf[n].addr = t->dma_addr; + buf[n++].len = dev->drv->txwi_size; + buf[n].addr = addr; + buf[n++].len = len; + + skb_walk_frags(skb, iter) { + if (n == ARRAY_SIZE(buf)) + goto unmap; + + addr = dma_map_single(dev->dev, iter->data, iter->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, addr)) + goto unmap; + + buf[n].addr = addr; + buf[n++].len = iter->len; + } + + if (q->queued + (n + 1) / 2 >= q->ndesc - 1) + goto unmap; + + return dev->queue_ops->add_buf(dev, q, buf, n, tx_info, skb, t); + +unmap: + ret = -ENOMEM; + for (n--; n > 0; n--) + dma_unmap_single(dev->dev, buf[n].addr, buf[n].len, + DMA_TO_DEVICE); + +free: + e.skb = skb; + e.txwi = t; + dev->drv->tx_complete_skb(dev, q, &e, true); + mt76_put_txwi(dev, t); + return ret; +} +EXPORT_SYMBOL_GPL(mt76_tx_queue_skb); + +void +mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, + struct mt76_wcid *wcid, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76_queue *q; + int qid = skb_get_queue_mapping(skb); + + if (WARN_ON(qid >= MT_TXQ_PSD)) { + qid = MT_TXQ_BE; + skb_set_queue_mapping(skb, qid); + } + + if (!wcid->tx_rate_set) + ieee80211_get_tx_rates(info->control.vif, sta, skb, + info->control.rates, 1); + + q = &dev->q_tx[qid]; + + spin_lock_bh(&q->lock); + mt76_tx_queue_skb(dev, q, skb, wcid, sta); + dev->queue_ops->kick(dev, q); + + if (q->queued > q->ndesc - 8) + ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb)); + spin_unlock_bh(&q->lock); +} +EXPORT_SYMBOL_GPL(mt76_tx); + +static struct sk_buff * +mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps) +{ + struct ieee80211_txq *txq = mtxq_to_txq(mtxq); + struct sk_buff *skb; + + skb = skb_dequeue(&mtxq->retry_q); + if (skb) { + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + + if (ps && skb_queue_empty(&mtxq->retry_q)) + ieee80211_sta_set_buffered(txq->sta, tid, false); + + return skb; + } + + skb = ieee80211_tx_dequeue(dev->hw, txq); + if (!skb) + return NULL; + + return skb; +} + +static void +mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (!ieee80211_is_data_qos(hdr->frame_control)) + return; + + mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; +} + +static void +mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, + struct sk_buff *skb, bool last) +{ + struct mt76_wcid *wcid = (struct mt76_wcid *) sta->drv_priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76_queue *hwq = &dev->q_tx[MT_TXQ_PSD]; + + info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; + if (last) + info->flags |= IEEE80211_TX_STATUS_EOSP; + + mt76_skb_set_moredata(skb, !last); + mt76_tx_queue_skb(dev, hwq, skb, wcid, sta); +} + +void +mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tids, int nframes, + enum ieee80211_frame_release_type reason, + bool more_data) +{ + struct mt76_dev *dev = hw->priv; + struct sk_buff *last_skb = NULL; + struct mt76_queue *hwq = &dev->q_tx[MT_TXQ_PSD]; + int i; + + spin_lock_bh(&hwq->lock); + for (i = 0; tids && nframes; i++, tids >>= 1) { + struct ieee80211_txq *txq = sta->txq[i]; + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + struct sk_buff *skb; + + if (!(tids & 1)) + continue; + + do { + skb = mt76_txq_dequeue(dev, mtxq, true); + if (!skb) + break; + + if (mtxq->aggr) + mt76_check_agg_ssn(mtxq, skb); + + nframes--; + if (last_skb) + mt76_queue_ps_skb(dev, sta, last_skb, false); + + last_skb = skb; + } while (nframes); + } + + if (last_skb) { + mt76_queue_ps_skb(dev, sta, last_skb, true); + dev->queue_ops->kick(dev, hwq); + } + spin_unlock_bh(&hwq->lock); +} +EXPORT_SYMBOL_GPL(mt76_release_buffered_frames); + +static int +mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_queue *hwq, + struct mt76_txq *mtxq, bool *empty) +{ + struct ieee80211_txq *txq = mtxq_to_txq(mtxq); + struct ieee80211_tx_info *info; + struct mt76_wcid *wcid = mtxq->wcid; + struct sk_buff *skb; + int n_frames = 1, limit; + struct ieee80211_tx_rate tx_rate; + bool ampdu; + bool probe; + int idx; + + skb = mt76_txq_dequeue(dev, mtxq, false); + if (!skb) { + *empty = true; + return 0; + } + + info = IEEE80211_SKB_CB(skb); + if (!wcid->tx_rate_set) + ieee80211_get_tx_rates(txq->vif, txq->sta, skb, + info->control.rates, 1); + tx_rate = info->control.rates[0]; + + probe = (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); + ampdu = IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU; + limit = ampdu ? 16 : 3; + + if (ampdu) + mt76_check_agg_ssn(mtxq, skb); + + idx = mt76_tx_queue_skb(dev, hwq, skb, wcid, txq->sta); + + if (idx < 0) + return idx; + + do { + bool cur_ampdu; + + if (probe) + break; + + if (test_bit(MT76_SCANNING, &dev->state) || + test_bit(MT76_RESET, &dev->state)) + return -EBUSY; + + skb = mt76_txq_dequeue(dev, mtxq, false); + if (!skb) { + *empty = true; + break; + } + + info = IEEE80211_SKB_CB(skb); + cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; + + if (ampdu != cur_ampdu || + (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { + skb_queue_tail(&mtxq->retry_q, skb); + break; + } + + info->control.rates[0] = tx_rate; + + if (cur_ampdu) + mt76_check_agg_ssn(mtxq, skb); + + idx = mt76_tx_queue_skb(dev, hwq, skb, wcid, txq->sta); + if (idx < 0) + return idx; + + n_frames++; + } while (n_frames < limit); + + if (!probe) { + hwq->swq_queued++; + hwq->entry[idx].schedule = true; + } + + dev->queue_ops->kick(dev, hwq); + + return n_frames; +} + +static int +mt76_txq_schedule_list(struct mt76_dev *dev, struct mt76_queue *hwq) +{ + struct mt76_txq *mtxq, *mtxq_last; + int len = 0; + +restart: + mtxq_last = list_last_entry(&hwq->swq, struct mt76_txq, list); + while (!list_empty(&hwq->swq)) { + bool empty = false; + int cur; + + mtxq = list_first_entry(&hwq->swq, struct mt76_txq, list); + if (mtxq->send_bar && mtxq->aggr) { + struct ieee80211_txq *txq = mtxq_to_txq(mtxq); + struct ieee80211_sta *sta = txq->sta; + struct ieee80211_vif *vif = txq->vif; + u16 agg_ssn = mtxq->agg_ssn; + u8 tid = txq->tid; + + mtxq->send_bar = false; + spin_unlock_bh(&hwq->lock); + ieee80211_send_bar(vif, sta->addr, tid, agg_ssn); + spin_lock_bh(&hwq->lock); + goto restart; + } + + list_del_init(&mtxq->list); + + cur = mt76_txq_send_burst(dev, hwq, mtxq, &empty); + if (!empty) + list_add_tail(&mtxq->list, &hwq->swq); + + if (cur < 0) + return cur; + + len += cur; + + if (mtxq == mtxq_last) + break; + } + + return len; +} + +void mt76_txq_schedule(struct mt76_dev *dev, struct mt76_queue *hwq) +{ + int len; + + do { + if (hwq->swq_queued >= 4 || list_empty(&hwq->swq)) + break; + + len = mt76_txq_schedule_list(dev, hwq); + } while (len > 0); +} +EXPORT_SYMBOL_GPL(mt76_txq_schedule); + +void mt76_txq_schedule_all(struct mt76_dev *dev) +{ + int i; + + for (i = 0; i <= MT_TXQ_BK; i++) { + struct mt76_queue *q = &dev->q_tx[i]; + + spin_lock_bh(&q->lock); + mt76_txq_schedule(dev, q); + spin_unlock_bh(&q->lock); + } +} +EXPORT_SYMBOL_GPL(mt76_txq_schedule_all); + +void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, + bool send_bar) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + struct ieee80211_txq *txq = sta->txq[i]; + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + + spin_lock_bh(&mtxq->hwq->lock); + mtxq->send_bar = mtxq->aggr && send_bar; + if (!list_empty(&mtxq->list)) + list_del_init(&mtxq->list); + spin_unlock_bh(&mtxq->hwq->lock); + } +} +EXPORT_SYMBOL_GPL(mt76_stop_tx_queues); + +void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ + struct mt76_dev *dev = hw->priv; + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + struct mt76_queue *hwq = mtxq->hwq; + + spin_lock_bh(&hwq->lock); + if (list_empty(&mtxq->list)) + list_add_tail(&mtxq->list, &hwq->swq); + mt76_txq_schedule(dev, hwq); + spin_unlock_bh(&hwq->lock); +} +EXPORT_SYMBOL_GPL(mt76_wake_tx_queue); + +void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq) +{ + struct mt76_txq *mtxq; + struct mt76_queue *hwq; + struct sk_buff *skb; + + if (!txq) + return; + + mtxq = (struct mt76_txq *) txq->drv_priv; + hwq = mtxq->hwq; + + spin_lock_bh(&hwq->lock); + if (!list_empty(&mtxq->list)) + list_del(&mtxq->list); + spin_unlock_bh(&hwq->lock); + + while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL) + ieee80211_free_txskb(dev->hw, skb); +} +EXPORT_SYMBOL_GPL(mt76_txq_remove); + +void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) +{ + struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + + INIT_LIST_HEAD(&mtxq->list); + skb_queue_head_init(&mtxq->retry_q); + + mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)]; +} +EXPORT_SYMBOL_GPL(mt76_txq_init); diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c new file mode 100644 index 0000000000000..0c35b8db58cde --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "mt76.h" + +bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, + int timeout) +{ + u32 cur; + + timeout /= 10; + do { + cur = dev->bus->rr(dev, offset) & mask; + if (cur == val) + return true; + + udelay(10); + } while (timeout-- > 0); + + return false; +} +EXPORT_SYMBOL_GPL(__mt76_poll); + +bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, + int timeout) +{ + u32 cur; + + timeout /= 10; + do { + cur = dev->bus->rr(dev, offset) & mask; + if (cur == val) + return true; + + usleep_range(10000, 20000); + } while (timeout-- > 0); + + return false; +} +EXPORT_SYMBOL_GPL(__mt76_poll_msec); + +int mt76_wcid_alloc(unsigned long *mask, int size) +{ + int i, idx = 0, cur; + + for (i = 0; i < size / BITS_PER_LONG; i++) { + idx = ffs(~mask[i]); + if (!idx) + continue; + + idx--; + cur = i * BITS_PER_LONG + idx; + if (cur >= size) + break; + + mask[i] |= BIT(idx); + return cur; + } + + return -1; +} +EXPORT_SYMBOL_GPL(mt76_wcid_alloc); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h new file mode 100644 index 0000000000000..018d475504a25 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/util.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2004 - 2009 Ivo van Doorn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT76_UTIL_H +#define __MT76_UTIL_H + +#include +#include +#include + +#define MT76_INCR(_var, _size) \ + _var = (((_var) + 1) % _size) + +int mt76_wcid_alloc(unsigned long *mask, int size); + +static inline void +mt76_wcid_free(unsigned long *mask, int idx) +{ + mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); +} + +static inline void +mt76_skb_set_moredata(struct sk_buff *skb, bool enable) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (enable) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + else + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); +} + +#endif diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 69131965a298f..146e42a132e72 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -643,11 +643,11 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) { if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { - pr_err_ratelimited("reclaim full Tx queue\n"); qtnf_pcie_data_tx_reclaim(priv); if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { + pr_warn_ratelimited("reclaim full Tx queue\n"); priv->tx_full_count++; return 0; } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index e2f4f5778267b..086aad22743dc 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -57,7 +57,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, if (status >= 0) return 0; - if (status == -ENODEV) { + if (status == -ENODEV || status == -ENOENT) { /* Device has disappeared. */ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); break; @@ -321,7 +321,7 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void *data) status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC); if (status) { - if (status == -ENODEV) + if (status == -ENODEV || status == -ENOENT) clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); @@ -410,7 +410,7 @@ static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void *data) status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC); if (status) { - if (status == -ENODEV) + if (status == -ENODEV || status == -ENOENT) clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 7eae27f8e173f..f9563ae301ad2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -682,7 +682,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct sk_buff *skb = NULL; - + bool rtstatus; u32 totalpacketlen; u8 u1rsvdpageloc[5] = { 0 }; bool b_dlok = false; @@ -768,7 +768,9 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) skb = dev_alloc_skb(totalpacketlen); skb_put_data(skb, &reserved_page_packet, totalpacketlen); - b_dlok = true; + rtstatus = rtl_cmd_send_packet(hw, skb); + if (rtstatus) + b_dlok = true; if (b_dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 1d431d4bf6d26..9ac1511de7ba2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -1372,6 +1372,7 @@ static void _rtl8821ae_get_wakeup_reason(struct ieee80211_hw *hw) ppsc->wakeup_reason = 0; + do_gettimeofday(&ts); rtlhal->last_suspend_sec = ts.tv_sec; switch (fw_reason) { diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 81df09dd2636a..f90c10b3c9211 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -162,13 +162,13 @@ static int rsi_usb_reg_read(struct usb_device *usbdev, u8 *buf; int status = -ENOMEM; + if (len > RSI_USB_CTRL_BUF_SIZE) + return -EINVAL; + buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); if (!buf) return status; - if (len > RSI_USB_CTRL_BUF_SIZE) - return -EINVAL; - status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, @@ -207,13 +207,13 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, u8 *usb_reg_buf; int status = -ENOMEM; + if (len > RSI_USB_CTRL_BUF_SIZE) + return -EINVAL; + usb_reg_buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); if (!usb_reg_buf) return status; - if (len > RSI_USB_CTRL_BUF_SIZE) - return -EINVAL; - usb_reg_buf[0] = (value & 0x00ff); usb_reg_buf[1] = (value & 0xff00) >> 8; usb_reg_buf[2] = 0x0; diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index d5612bd1cc81c..09428ebd315b2 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -210,12 +210,12 @@ static int btt_map_read(struct arena_info *arena, u32 lba, u32 *mapping, return ret; } -static int btt_log_read_pair(struct arena_info *arena, u32 lane, - struct log_entry *ent) +static int btt_log_group_read(struct arena_info *arena, u32 lane, + struct log_group *log) { return arena_read_bytes(arena, - arena->logoff + (2 * lane * LOG_ENT_SIZE), ent, - 2 * LOG_ENT_SIZE, 0); + arena->logoff + (lane * LOG_GRP_SIZE), log, + LOG_GRP_SIZE, 0); } static struct dentry *debugfs_root; @@ -255,6 +255,8 @@ static void arena_debugfs_init(struct arena_info *a, struct dentry *parent, debugfs_create_x64("logoff", S_IRUGO, d, &a->logoff); debugfs_create_x64("info2off", S_IRUGO, d, &a->info2off); debugfs_create_x32("flags", S_IRUGO, d, &a->flags); + debugfs_create_u32("log_index_0", S_IRUGO, d, &a->log_index[0]); + debugfs_create_u32("log_index_1", S_IRUGO, d, &a->log_index[1]); } static void btt_debugfs_init(struct btt *btt) @@ -273,6 +275,11 @@ static void btt_debugfs_init(struct btt *btt) } } +static u32 log_seq(struct log_group *log, int log_idx) +{ + return le32_to_cpu(log->ent[log_idx].seq); +} + /* * This function accepts two log entries, and uses the * sequence number to find the 'older' entry. @@ -282,8 +289,10 @@ static void btt_debugfs_init(struct btt *btt) * * TODO The logic feels a bit kludge-y. make it better.. */ -static int btt_log_get_old(struct log_entry *ent) +static int btt_log_get_old(struct arena_info *a, struct log_group *log) { + int idx0 = a->log_index[0]; + int idx1 = a->log_index[1]; int old; /* @@ -291,23 +300,23 @@ static int btt_log_get_old(struct log_entry *ent) * the next time, the following logic works out to put this * (next) entry into [1] */ - if (ent[0].seq == 0) { - ent[0].seq = cpu_to_le32(1); + if (log_seq(log, idx0) == 0) { + log->ent[idx0].seq = cpu_to_le32(1); return 0; } - if (ent[0].seq == ent[1].seq) + if (log_seq(log, idx0) == log_seq(log, idx1)) return -EINVAL; - if (le32_to_cpu(ent[0].seq) + le32_to_cpu(ent[1].seq) > 5) + if (log_seq(log, idx0) + log_seq(log, idx1) > 5) return -EINVAL; - if (le32_to_cpu(ent[0].seq) < le32_to_cpu(ent[1].seq)) { - if (le32_to_cpu(ent[1].seq) - le32_to_cpu(ent[0].seq) == 1) + if (log_seq(log, idx0) < log_seq(log, idx1)) { + if ((log_seq(log, idx1) - log_seq(log, idx0)) == 1) old = 0; else old = 1; } else { - if (le32_to_cpu(ent[0].seq) - le32_to_cpu(ent[1].seq) == 1) + if ((log_seq(log, idx0) - log_seq(log, idx1)) == 1) old = 1; else old = 0; @@ -327,17 +336,18 @@ static int btt_log_read(struct arena_info *arena, u32 lane, { int ret; int old_ent, ret_ent; - struct log_entry log[2]; + struct log_group log; - ret = btt_log_read_pair(arena, lane, log); + ret = btt_log_group_read(arena, lane, &log); if (ret) return -EIO; - old_ent = btt_log_get_old(log); + old_ent = btt_log_get_old(arena, &log); if (old_ent < 0 || old_ent > 1) { dev_err(to_dev(arena), "log corruption (%d): lane %d seq [%d, %d]\n", - old_ent, lane, log[0].seq, log[1].seq); + old_ent, lane, log.ent[arena->log_index[0]].seq, + log.ent[arena->log_index[1]].seq); /* TODO set error state? */ return -EIO; } @@ -345,7 +355,7 @@ static int btt_log_read(struct arena_info *arena, u32 lane, ret_ent = (old_flag ? old_ent : (1 - old_ent)); if (ent != NULL) - memcpy(ent, &log[ret_ent], LOG_ENT_SIZE); + memcpy(ent, &log.ent[arena->log_index[ret_ent]], LOG_ENT_SIZE); return ret_ent; } @@ -359,17 +369,13 @@ static int __btt_log_write(struct arena_info *arena, u32 lane, u32 sub, struct log_entry *ent, unsigned long flags) { int ret; - /* - * Ignore the padding in log_entry for calculating log_half. - * The entry is 'committed' when we write the sequence number, - * and we want to ensure that that is the last thing written. - * We don't bother writing the padding as that would be extra - * media wear and write amplification - */ - unsigned int log_half = (LOG_ENT_SIZE - 2 * sizeof(u64)) / 2; - u64 ns_off = arena->logoff + (((2 * lane) + sub) * LOG_ENT_SIZE); + u32 group_slot = arena->log_index[sub]; + unsigned int log_half = LOG_ENT_SIZE / 2; void *src = ent; + u64 ns_off; + ns_off = arena->logoff + (lane * LOG_GRP_SIZE) + + (group_slot * LOG_ENT_SIZE); /* split the 16B write into atomic, durable halves */ ret = arena_write_bytes(arena, ns_off, src, log_half, flags); if (ret) @@ -452,7 +458,7 @@ static int btt_log_init(struct arena_info *arena) { size_t logsize = arena->info2off - arena->logoff; size_t chunk_size = SZ_4K, offset = 0; - struct log_entry log; + struct log_entry ent; void *zerobuf; int ret; u32 i; @@ -484,11 +490,11 @@ static int btt_log_init(struct arena_info *arena) } for (i = 0; i < arena->nfree; i++) { - log.lba = cpu_to_le32(i); - log.old_map = cpu_to_le32(arena->external_nlba + i); - log.new_map = cpu_to_le32(arena->external_nlba + i); - log.seq = cpu_to_le32(LOG_SEQ_INIT); - ret = __btt_log_write(arena, i, 0, &log, 0); + ent.lba = cpu_to_le32(i); + ent.old_map = cpu_to_le32(arena->external_nlba + i); + ent.new_map = cpu_to_le32(arena->external_nlba + i); + ent.seq = cpu_to_le32(LOG_SEQ_INIT); + ret = __btt_log_write(arena, i, 0, &ent, 0); if (ret) goto free; } @@ -593,6 +599,123 @@ static int btt_freelist_init(struct arena_info *arena) return 0; } +static bool ent_is_padding(struct log_entry *ent) +{ + return (ent->lba == 0) && (ent->old_map == 0) && (ent->new_map == 0) + && (ent->seq == 0); +} + +/* + * Detecting valid log indices: We read a log group (see the comments in btt.h + * for a description of a 'log_group' and its 'slots'), and iterate over its + * four slots. We expect that a padding slot will be all-zeroes, and use this + * to detect a padding slot vs. an actual entry. + * + * If a log_group is in the initial state, i.e. hasn't been used since the + * creation of this BTT layout, it will have three of the four slots with + * zeroes. We skip over these log_groups for the detection of log_index. If + * all log_groups are in the initial state (i.e. the BTT has never been + * written to), it is safe to assume the 'new format' of log entries in slots + * (0, 1). + */ +static int log_set_indices(struct arena_info *arena) +{ + bool idx_set = false, initial_state = true; + int ret, log_index[2] = {-1, -1}; + u32 i, j, next_idx = 0; + struct log_group log; + u32 pad_count = 0; + + for (i = 0; i < arena->nfree; i++) { + ret = btt_log_group_read(arena, i, &log); + if (ret < 0) + return ret; + + for (j = 0; j < 4; j++) { + if (!idx_set) { + if (ent_is_padding(&log.ent[j])) { + pad_count++; + continue; + } else { + /* Skip if index has been recorded */ + if ((next_idx == 1) && + (j == log_index[0])) + continue; + /* valid entry, record index */ + log_index[next_idx] = j; + next_idx++; + } + if (next_idx == 2) { + /* two valid entries found */ + idx_set = true; + } else if (next_idx > 2) { + /* too many valid indices */ + return -ENXIO; + } + } else { + /* + * once the indices have been set, just verify + * that all subsequent log groups are either in + * their initial state or follow the same + * indices. + */ + if (j == log_index[0]) { + /* entry must be 'valid' */ + if (ent_is_padding(&log.ent[j])) + return -ENXIO; + } else if (j == log_index[1]) { + ; + /* + * log_index[1] can be padding if the + * lane never got used and it is still + * in the initial state (three 'padding' + * entries) + */ + } else { + /* entry must be invalid (padding) */ + if (!ent_is_padding(&log.ent[j])) + return -ENXIO; + } + } + } + /* + * If any of the log_groups have more than one valid, + * non-padding entry, then the we are no longer in the + * initial_state + */ + if (pad_count < 3) + initial_state = false; + pad_count = 0; + } + + if (!initial_state && !idx_set) + return -ENXIO; + + /* + * If all the entries in the log were in the initial state, + * assume new padding scheme + */ + if (initial_state) + log_index[1] = 1; + + /* + * Only allow the known permutations of log/padding indices, + * i.e. (0, 1), and (0, 2) + */ + if ((log_index[0] == 0) && ((log_index[1] == 1) || (log_index[1] == 2))) + ; /* known index possibilities */ + else { + dev_err(to_dev(arena), "Found an unknown padding scheme\n"); + return -ENXIO; + } + + arena->log_index[0] = log_index[0]; + arena->log_index[1] = log_index[1]; + dev_dbg(to_dev(arena), "log_index_0 = %d\n", log_index[0]); + dev_dbg(to_dev(arena), "log_index_1 = %d\n", log_index[1]); + return 0; +} + static int btt_rtt_init(struct arena_info *arena) { arena->rtt = kcalloc(arena->nfree, sizeof(u32), GFP_KERNEL); @@ -649,8 +772,7 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size, available -= 2 * BTT_PG_SIZE; /* The log takes a fixed amount of space based on nfree */ - logsize = roundup(2 * arena->nfree * sizeof(struct log_entry), - BTT_PG_SIZE); + logsize = roundup(arena->nfree * LOG_GRP_SIZE, BTT_PG_SIZE); available -= logsize; /* Calculate optimal split between map and data area */ @@ -667,6 +789,10 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size, arena->mapoff = arena->dataoff + datasize; arena->logoff = arena->mapoff + mapsize; arena->info2off = arena->logoff + logsize; + + /* Default log indices are (0,1) */ + arena->log_index[0] = 0; + arena->log_index[1] = 1; return arena; } @@ -757,6 +883,13 @@ static int discover_arenas(struct btt *btt) arena->external_lba_start = cur_nlba; parse_arena_meta(arena, super, cur_off); + ret = log_set_indices(arena); + if (ret) { + dev_err(to_dev(arena), + "Unable to deduce log/padding indices\n"); + goto out; + } + mutex_init(&arena->err_lock); ret = btt_freelist_init(arena); if (ret) diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h index 578c2057524d3..2609683c41679 100644 --- a/drivers/nvdimm/btt.h +++ b/drivers/nvdimm/btt.h @@ -27,6 +27,7 @@ #define MAP_ERR_MASK (1 << MAP_ERR_SHIFT) #define MAP_LBA_MASK (~((1 << MAP_TRIM_SHIFT) | (1 << MAP_ERR_SHIFT))) #define MAP_ENT_NORMAL 0xC0000000 +#define LOG_GRP_SIZE sizeof(struct log_group) #define LOG_ENT_SIZE sizeof(struct log_entry) #define ARENA_MIN_SIZE (1UL << 24) /* 16 MB */ #define ARENA_MAX_SIZE (1ULL << 39) /* 512 GB */ @@ -50,12 +51,52 @@ enum btt_init_state { INIT_READY }; +/* + * A log group represents one log 'lane', and consists of four log entries. + * Two of the four entries are valid entries, and the remaining two are + * padding. Due to an old bug in the padding location, we need to perform a + * test to determine the padding scheme being used, and use that scheme + * thereafter. + * + * In kernels prior to 4.15, 'log group' would have actual log entries at + * indices (0, 2) and padding at indices (1, 3), where as the correct/updated + * format has log entries at indices (0, 1) and padding at indices (2, 3). + * + * Old (pre 4.15) format: + * +-----------------+-----------------+ + * | ent[0] | ent[1] | + * | 16B | 16B | + * | lba/old/new/seq | pad | + * +-----------------------------------+ + * | ent[2] | ent[3] | + * | 16B | 16B | + * | lba/old/new/seq | pad | + * +-----------------+-----------------+ + * + * New format: + * +-----------------+-----------------+ + * | ent[0] | ent[1] | + * | 16B | 16B | + * | lba/old/new/seq | lba/old/new/seq | + * +-----------------------------------+ + * | ent[2] | ent[3] | + * | 16B | 16B | + * | pad | pad | + * +-----------------+-----------------+ + * + * We detect during start-up which format is in use, and set + * arena->log_index[(0, 1)] with the detected format. + */ + struct log_entry { __le32 lba; __le32 old_map; __le32 new_map; __le32 seq; - __le64 padding[2]; +}; + +struct log_group { + struct log_entry ent[4]; }; struct btt_sb { @@ -125,6 +166,7 @@ struct aligned_lock { * @list: List head for list of arenas * @debugfs_dir: Debugfs dentry * @flags: Arena flags - may signify error states. + * @log_index: Indices of the valid log entries in a log_group * * arena_info is a per-arena handle. Once an arena is narrowed down for an * IO, this struct is passed around for the duration of the IO. @@ -157,6 +199,7 @@ struct arena_info { /* Arena flags */ u32 flags; struct mutex err_lock; + int log_index[2]; }; /** diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index e0f0e3ce1a32e..98466d762c8fa 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -68,6 +68,7 @@ static int nvdimm_probe(struct device *dev) rc = nd_label_reserve_dpa(ndd); if (ndd->ns_current >= 0) nvdimm_set_aliasing(dev); + nvdimm_clear_locked(dev); nvdimm_bus_unlock(dev); if (rc) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index f0d1b7e5de01d..5f1385b96b131 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -200,6 +200,13 @@ void nvdimm_set_locked(struct device *dev) set_bit(NDD_LOCKED, &nvdimm->flags); } +void nvdimm_clear_locked(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + clear_bit(NDD_LOCKED, &nvdimm->flags); +} + static void nvdimm_release(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 9c5f108910e33..de66c02f61409 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -1050,7 +1050,7 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels) nsindex = to_namespace_index(ndd, 0); memset(nsindex, 0, ndd->nsarea.config_size); for (i = 0; i < 2; i++) { - int rc = nd_label_write_index(ndd, i, i*2, ND_NSINDEX_INIT); + int rc = nd_label_write_index(ndd, i, 3 - i, ND_NSINDEX_INIT); if (rc) return rc; diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 3e4d1e7998dac..0af988739a06c 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1620,7 +1620,7 @@ static umode_t namespace_visible(struct kobject *kobj, if (a == &dev_attr_resource.attr) { if (is_namespace_blk(dev)) return 0; - return a->mode; + return 0400; } if (is_namespace_pmem(dev) || is_namespace_blk(dev)) { diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 9c758a91372bb..156be00e1f760 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -254,6 +254,7 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys, unsigned int len); void nvdimm_set_aliasing(struct device *dev); void nvdimm_set_locked(struct device *dev); +void nvdimm_clear_locked(struct device *dev); struct nd_btt *to_nd_btt(struct device *dev); struct nd_gen_sb { diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 9576c444f0ab5..2adada1a58551 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -282,8 +282,16 @@ static struct attribute *nd_pfn_attributes[] = { NULL, }; +static umode_t pfn_visible(struct kobject *kobj, struct attribute *a, int n) +{ + if (a == &dev_attr_resource.attr) + return 0400; + return a->mode; +} + struct attribute_group nd_pfn_attribute_group = { .attrs = nd_pfn_attributes, + .is_visible = pfn_visible, }; static const struct attribute_group *nd_pfn_attribute_groups[] = { @@ -356,9 +364,9 @@ struct device *nd_pfn_create(struct nd_region *nd_region) int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) { u64 checksum, offset; - unsigned long align; enum nd_pfn_mode mode; struct nd_namespace_io *nsio; + unsigned long align, start_pad; struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; struct nd_namespace_common *ndns = nd_pfn->ndns; const u8 *parent_uuid = nd_dev_to_uuid(&ndns->dev); @@ -402,6 +410,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) align = le32_to_cpu(pfn_sb->align); offset = le64_to_cpu(pfn_sb->dataoff); + start_pad = le32_to_cpu(pfn_sb->start_pad); if (align == 0) align = 1UL << ilog2(offset); mode = le32_to_cpu(pfn_sb->mode); @@ -460,7 +469,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) return -EBUSY; } - if ((align && !IS_ALIGNED(offset, align)) + if ((align && !IS_ALIGNED(nsio->res.start + offset + start_pad, align)) || !IS_ALIGNED(offset, PAGE_SIZE)) { dev_err(&nd_pfn->dev, "bad offset: %#llx dax disabled align: %#lx\n", @@ -574,6 +583,12 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn, return altmap; } +static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys) +{ + return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys), + ALIGN_DOWN(phys, nd_pfn->align)); +} + static int nd_pfn_init(struct nd_pfn *nd_pfn) { u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0; @@ -629,13 +644,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) start = nsio->res.start; size = PHYS_SECTION_ALIGN_UP(start + size) - start; if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM, - IORES_DESC_NONE) == REGION_MIXED) { + IORES_DESC_NONE) == REGION_MIXED + || !IS_ALIGNED(start + resource_size(&nsio->res), + nd_pfn->align)) { size = resource_size(&nsio->res); - end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size); + end_trunc = start + size - phys_pmem_align_down(nd_pfn, + start + size); } if (start_pad + end_trunc) - dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n", + dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n", dev_name(&ndns->dev), start_pad + end_trunc); /* diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 829d760f651c7..abaf38c612206 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -562,8 +562,12 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n) if (!is_nd_pmem(dev) && a == &dev_attr_badblocks.attr) return 0; - if (!is_nd_pmem(dev) && a == &dev_attr_resource.attr) - return 0; + if (a == &dev_attr_resource.attr) { + if (is_nd_pmem(dev)) + return 0400; + else + return 0; + } if (a == &dev_attr_deep_flush.attr) { int has_flush = nvdimm_has_flush(nd_region); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 37f9039bb9cab..0655f45643d90 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2299,7 +2299,8 @@ static struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid) mutex_lock(&ctrl->namespaces_mutex); list_for_each_entry(ns, &ctrl->namespaces, list) { if (ns->ns_id == nsid) { - kref_get(&ns->kref); + if (!kref_get_unless_zero(&ns->kref)) + continue; ret = ns; break; } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index d3f3c44475157..044af553204ca 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -108,7 +108,7 @@ static inline struct nvme_request *nvme_req(struct request *req) * NVME_QUIRK_DELAY_BEFORE_CHK_RDY quirk enabled. The value (in ms) was * found empirically. */ -#define NVME_QUIRK_DELAY_AMOUNT 2000 +#define NVME_QUIRK_DELAY_AMOUNT 2300 enum nvme_ctrl_state { NVME_CTRL_NEW, diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 3f5a04c586cef..75539f7c58b9a 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2519,6 +2519,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_IDENTIFY_CNS, }, { PCI_DEVICE(0x1c58, 0x0003), /* HGST adapter */ .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x1c58, 0x0023), /* WDC SN200 adapter */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, { PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */ .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, { PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */ diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 76d2bb793afe5..3333d417b248b 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -1512,15 +1512,17 @@ static struct nvmet_fabrics_ops nvmet_rdma_ops = { static void nvmet_rdma_remove_one(struct ib_device *ib_device, void *client_data) { - struct nvmet_rdma_queue *queue; + struct nvmet_rdma_queue *queue, *tmp; /* Device is being removed, delete all queues using this device */ mutex_lock(&nvmet_rdma_queue_mutex); - list_for_each_entry(queue, &nvmet_rdma_queue_list, queue_list) { + list_for_each_entry_safe(queue, tmp, &nvmet_rdma_queue_list, + queue_list) { if (queue->dev->device != ib_device) continue; pr_info("Removing queue %d\n", queue->idx); + list_del_init(&queue->queue_list); __nvmet_rdma_queue_disconnect(queue); } mutex_unlock(&nvmet_rdma_queue_mutex); diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index a25fed52f7e94..41b740aed3a34 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1692,3 +1692,36 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) iounmap(base_addr); } + +/* + * The design of the Diva management card in rp34x0 machines (rp3410, rp3440) + * seems rushed, so that many built-in components simply don't work. + * The following quirks disable the serial AUX port and the built-in ATI RV100 + * Radeon 7000 graphics card which both don't have any external connectors and + * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as + * such makes those machines the only PARISC machines on which we can't use + * ttyS0 as boot console. + */ +static void quirk_diva_ati_card(struct pci_dev *dev) +{ + if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || + dev->subsystem_device != 0x1292) + return; + + dev_info(&dev->dev, "Hiding Diva built-in ATI card"); + dev->device = 0; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, + quirk_diva_ati_card); + +static void quirk_diva_aux_disable(struct pci_dev *dev) +{ + if (dev->subsystem_vendor != PCI_VENDOR_ID_HP || + dev->subsystem_device != 0x1291) + return; + + dev_info(&dev->dev, "Hiding Diva built-in AUX serial device"); + dev->device = 0; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, + quirk_diva_aux_disable); diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c index 34427a6a15afa..362607f727ee6 100644 --- a/drivers/pci/dwc/pci-dra7xx.c +++ b/drivers/pci/dwc/pci-dra7xx.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -594,6 +595,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) int i; int phy_count; struct phy **phy; + struct device_link **link; void __iomem *base; struct resource *res; struct dw_pcie *pci; @@ -649,11 +651,21 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) if (!phy) return -ENOMEM; + link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); + if (!link) + return -ENOMEM; + for (i = 0; i < phy_count; i++) { snprintf(name, sizeof(name), "pcie-phy%d", i); phy[i] = devm_phy_get(dev, name); if (IS_ERR(phy[i])) return PTR_ERR(phy[i]); + + link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); + if (!link[i]) { + ret = -EINVAL; + goto err_link; + } } dra7xx->base = base; @@ -732,6 +744,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) pm_runtime_disable(dev); dra7xx_pcie_disable_phy(dra7xx); +err_link: + while (--i >= 0) + device_link_del(link[i]); + return ret; } diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 0fe3ea164ee53..04dac6a42c9f2 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -879,7 +879,7 @@ static void hv_irq_unmask(struct irq_data *data) int cpu; u64 res; - dest = irq_data_get_affinity_mask(data); + dest = irq_data_get_effective_affinity_mask(data); pdev = msi_desc_to_pci_dev(msi_desc); pbus = pdev->bus; hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata); @@ -1042,6 +1042,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) struct hv_pci_dev *hpdev; struct pci_bus *pbus; struct pci_dev *pdev; + struct cpumask *dest; struct compose_comp_ctxt comp; struct tran_int_desc *int_desc; struct { @@ -1056,6 +1057,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) int ret; pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data)); + dest = irq_data_get_effective_affinity_mask(data); pbus = pdev->bus; hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata); hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn)); @@ -1081,14 +1083,14 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) switch (pci_protocol_version) { case PCI_PROTOCOL_VERSION_1_1: size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1, - irq_data_get_affinity_mask(data), + dest, hpdev->desc.win_slot.slot, cfg->vector); break; case PCI_PROTOCOL_VERSION_1_2: size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2, - irq_data_get_affinity_mask(data), + dest, hpdev->desc.win_slot.slot, cfg->vector); break; diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c index db93efdf1d635..a4ffab883ab6f 100644 --- a/drivers/pci/host/pcie-mediatek.c +++ b/drivers/pci/host/pcie-mediatek.c @@ -333,10 +333,23 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus, { struct mtk_pcie *pcie = bus->sysdata; struct mtk_pcie_port *port; + struct pci_dev *dev; + struct pci_bus *pbus; - list_for_each_entry(port, &pcie->ports, list) - if (port->slot == PCI_SLOT(devfn)) + list_for_each_entry(port, &pcie->ports, list) { + if (bus->number == 0 && port->slot == PCI_SLOT(devfn)) { return port; + } else if (bus->number != 0) { + pbus = bus; + do { + dev = pbus->self; + if (port->slot == PCI_SLOT(dev->devfn)) + return port; + + pbus = dev->bus; + } while (dev->bus->number != 0); + } + } return NULL; } @@ -663,6 +676,9 @@ static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, { struct mtk_pcie *pcie = bus->sysdata; + if (!mtk_pcie_find_port(bus, devfn)) + return 0; + writel(PCIE_CONF_ADDR(where, PCI_FUNC(devfn), PCI_SLOT(devfn), bus->number), pcie->base + PCIE_CFG_ADDR); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index ac41c8be9200a..0fd8e164339c3 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -162,7 +162,6 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); - pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) @@ -173,6 +172,8 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset) kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); + pci_bus_add_device(virtfn); + return 0; failed2: diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 11bd267fc1371..bb0927de79dd7 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -968,7 +968,12 @@ static int pci_pm_thaw_noirq(struct device *dev) if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_resume_early(dev); - pci_update_current_state(pci_dev, PCI_D0); + /* + * pci_restore_state() requires the device to be in D0 (because of MSI + * restoration among other things), so force it into D0 in case the + * driver's "freeze" callbacks put it into a low-power state directly. + */ + pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); if (drv && drv->pm && drv->pm->thaw_noirq) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6078dfc11b112..74f1c57ab93b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4356,6 +4356,10 @@ static bool pci_bus_resetable(struct pci_bus *bus) { struct pci_dev *dev; + + if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) + return false; + list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || (dev->subordinate && !pci_bus_resetable(dev->subordinate))) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 890efcc574cbb..744805232155c 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -390,7 +390,14 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, * If the error is reported by an end point, we think this * error is related to the upstream link of the end point. */ - pci_walk_bus(dev->bus, cb, &result_data); + if (state == pci_channel_io_normal) + /* + * the error is non fatal so the bus is ok, just invoke + * the callback for the function that logged the error. + */ + cb(dev, &result_data); + else + pci_walk_bus(dev->bus, cb, &result_data); } return result_data.result; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 83e4a892b14be..cae54f8320be4 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -453,7 +453,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, /* Choose the greater of the two T_cmn_mode_rstr_time */ val1 = (upreg->l1ss_cap >> 8) & 0xFF; - val2 = (upreg->l1ss_cap >> 8) & 0xFF; + val2 = (dwreg->l1ss_cap >> 8) & 0xFF; if (val1 > val2) link->l1ss.ctl1 |= val1 << 8; else @@ -658,7 +658,7 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) 0xFF00, link->l1ss.ctl1); /* Program LTR L1.2 threshold in both ports */ - pci_clear_and_set_dword(parent, dw_cap_ptr + PCI_L1SS_CTL1, + pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1, 0xE3FF0000, link->l1ss.ctl1); pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1, 0xE3FF0000, link->l1ss.ctl1); diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index fafdb165dd2ed..df290aa58dce9 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -226,6 +226,9 @@ static void pcie_pme_work_fn(struct work_struct *work) break; pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); + if (rtsta == (u32) ~0) + break; + if (rtsta & PCI_EXP_RTSTA_PME) { /* * Clear PME status of the port. If there are other @@ -273,7 +276,7 @@ static irqreturn_t pcie_pme_irq(int irq, void *context) spin_lock_irqsave(&data->lock, flags); pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); - if (!(rtsta & PCI_EXP_RTSTA_PME)) { + if (rtsta == (u32) ~0 || !(rtsta & PCI_EXP_RTSTA_PME)) { spin_unlock_irqrestore(&data->lock, flags); return IRQ_NONE; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ff94b69738a87..f285cd74088ec 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1076,7 +1076,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) child = pci_add_new_bus(bus, dev, max+1); if (!child) goto out; - pci_bus_insert_busn_res(child, max+1, 0xff); + pci_bus_insert_busn_res(child, max+1, + bus->busn_res.end); } max++; buses = (buses & 0xff000000) @@ -2433,6 +2434,10 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) { if (max - bus->busn_res.start < pci_hotplug_bus_size - 1) max = bus->busn_res.start + pci_hotplug_bus_size - 1; + + /* Do not allocate more buses than we have room left */ + if (max > bus->busn_res.end) + max = bus->busn_res.end; } /* diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 911b3b65c8b2d..f66f9375177c8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4212,17 +4212,32 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags) #endif } +static bool pci_quirk_cavium_acs_match(struct pci_dev *dev) +{ + /* + * Effectively selects all downstream ports for whole ThunderX 1 + * family by 0xf800 mask (which represents 8 SoCs), while the lower + * bits of device ID are used to indicate which subdevice is used + * within the SoC. + */ + return (pci_is_pcie(dev) && + (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) && + ((dev->device & 0xf800) == 0xa000)); +} + static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags) { /* - * Cavium devices matching this quirk do not perform peer-to-peer - * with other functions, allowing masking out these bits as if they - * were unimplemented in the ACS capability. + * Cavium root ports don't advertise an ACS capability. However, + * the RTL internally implements similar protection as if ACS had + * Request Redirection, Completion Redirection, Source Validation, + * and Upstream Forwarding features enabled. Assert that the + * hardware implements and enables equivalent ACS functionality for + * these flags. */ - acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | - PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT); + acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF); - if (!((dev->device >= 0xa000) && (dev->device <= 0xa0ff))) + if (!pci_quirk_cavium_acs_match(dev)) return -ENOTTY; return acs_flags ? 0 : 1; diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 73a03d3825903..2fa0dbde36b7a 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -19,9 +19,9 @@ static void pci_stop_dev(struct pci_dev *dev) pci_pme_active(dev, false); if (dev->is_added) { + device_release_driver(&dev->dev); pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); - device_release_driver(&dev->dev); dev->is_added = 0; } diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index a268f4d6f3e90..48a365e303e5a 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -395,6 +395,10 @@ static struct phy *_of_phy_get(struct device_node *np, int index) if (ret) return ERR_PTR(-ENODEV); + /* This phy type handled by the usb-phy subsystem for now */ + if (of_device_is_compatible(args.np, "usb-nop-xceiv")) + return ERR_PTR(-ENODEV); + mutex_lock(&phy_provider_mutex); phy_provider = of_phy_provider_lookup(args.np); if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) { diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 4307bf0013e18..63e916d4d0696 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -75,14 +75,14 @@ MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); static struct device_node * tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name) { - /* - * of_find_node_by_name() drops a reference, so make sure to grab one. - */ - struct device_node *np = of_node_get(padctl->dev->of_node); + struct device_node *pads, *np; + + pads = of_get_child_by_name(padctl->dev->of_node, "pads"); + if (!pads) + return NULL; - np = of_find_node_by_name(np, "pads"); - if (np) - np = of_find_node_by_name(np, name); + np = of_get_child_by_name(pads, name); + of_node_put(pads); return np; } @@ -90,16 +90,16 @@ tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name) static struct device_node * tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index) { - /* - * of_find_node_by_name() drops a reference, so make sure to grab one. - */ - struct device_node *np = of_node_get(pad->dev.of_node); + struct device_node *np, *lanes; - np = of_find_node_by_name(np, "lanes"); - if (!np) + lanes = of_get_child_by_name(pad->dev.of_node, "lanes"); + if (!lanes) return NULL; - return of_find_node_by_name(np, pad->soc->lanes[index].name); + np = of_get_child_by_name(lanes, pad->soc->lanes[index].name); + of_node_put(lanes); + + return np; } static int @@ -195,7 +195,7 @@ int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, unsigned int i; int err; - children = of_find_node_by_name(pad->dev.of_node, "lanes"); + children = of_get_child_by_name(pad->dev.of_node, "lanes"); if (!children) return -ENODEV; @@ -444,21 +444,21 @@ static struct device_node * tegra_xusb_find_port_node(struct tegra_xusb_padctl *padctl, const char *type, unsigned int index) { - /* - * of_find_node_by_name() drops a reference, so make sure to grab one. - */ - struct device_node *np = of_node_get(padctl->dev->of_node); + struct device_node *ports, *np; + char *name; - np = of_find_node_by_name(np, "ports"); - if (np) { - char *name; + ports = of_get_child_by_name(padctl->dev->of_node, "ports"); + if (!ports) + return NULL; - name = kasprintf(GFP_KERNEL, "%s-%u", type, index); - if (!name) - return ERR_PTR(-ENOMEM); - np = of_find_node_by_name(np, name); - kfree(name); + name = kasprintf(GFP_KERNEL, "%s-%u", type, index); + if (!name) { + of_node_put(ports); + return ERR_PTR(-ENOMEM); } + np = of_get_child_by_name(ports, name); + kfree(name); + of_node_put(ports); return np; } @@ -847,7 +847,7 @@ static void tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) static int tegra_xusb_padctl_probe(struct platform_device *pdev) { - struct device_node *np = of_node_get(pdev->dev.of_node); + struct device_node *np = pdev->dev.of_node; const struct tegra_xusb_padctl_soc *soc; struct tegra_xusb_padctl *padctl; const struct of_device_id *match; @@ -855,7 +855,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) int err; /* for backwards compatibility with old device trees */ - np = of_find_node_by_name(np, "pads"); + np = of_get_child_by_name(np, "pads"); if (!np) { dev_warn(&pdev->dev, "deprecated DT, using legacy driver\n"); return tegra_xusb_padctl_legacy_probe(pdev); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 82cd8b08d71f5..a73c794bed035 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -33,7 +33,8 @@ config DEBUG_PINCTRL config PINCTRL_ADI2 bool "ADI pin controller driver" - depends on BLACKFIN + depends on (BF54x || BF60x) + depends on !GPIO_ADI select PINMUX select IRQ_DOMAIN help diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index fadbca907c7c7..0907531a02caa 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1620,6 +1620,22 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) clear_bit(i, chip->irq_valid_mask); } + /* + * The same set of machines in chv_no_valid_mask[] have incorrectly + * configured GPIOs that generate spurious interrupts so we use + * this same list to apply another quirk for them. + * + * See also https://bugzilla.kernel.org/show_bug.cgi?id=197953. + */ + if (!need_valid_mask) { + /* + * Mask all interrupts the community is able to generate + * but leave the ones that can only generate GPEs unmasked. + */ + chv_writel(GENMASK(31, pctrl->community->nirqs), + pctrl->regs + CHV_INTMASK); + } + /* Clear all interrupts */ chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 71b944748304e..c5fe7d4a90659 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -408,12 +408,21 @@ static int armada_37xx_gpio_direction_output(struct gpio_chip *chip, { struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); unsigned int reg = OUTPUT_EN; - unsigned int mask; + unsigned int mask, val, ret; armada_37xx_update_reg(®, offset); mask = BIT(offset); - return regmap_update_bits(info->regmap, reg, mask, mask); + ret = regmap_update_bits(info->regmap, reg, mask, mask); + + if (ret) + return ret; + + reg = OUTPUT_VAL; + val = value ? mask : 0; + regmap_update_bits(info->regmap, reg, mask, val); + + return 0; } static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index f3796164329ef..d4aeac3477f55 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -118,6 +118,7 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event) return; } input_report_key(data->idev, KEY_RFKILL, 1); + input_sync(data->idev); input_report_key(data->idev, KEY_RFKILL, 0); input_sync(data->idev); } diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index b4ed3dc983d52..b4224389febeb 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -297,7 +297,7 @@ static int hp_wmi_hw_state(int mask) if (state < 0) return state; - return state & 0x1; + return !!(state & mask); } static int __init hp_wmi_bios_2008_later(void) diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index 493d8910a74e2..7b12abe86b94f 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -240,6 +240,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd), + AXIS_DMI_MATCH("HPB440G4", "HP ProBook 440 G4", x_inverted), AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c index a47a41fc10ad7..b5b890127479f 100644 --- a/drivers/platform/x86/intel_punit_ipc.c +++ b/drivers/platform/x86/intel_punit_ipc.c @@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev) * - GTDRIVER_IPC BASE_IFACE */ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (res) { + if (res && resource_size(res) > 1) { addr = devm_ioremap_resource(&pdev->dev, res); if (!IS_ERR(addr)) punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; } res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - if (res) { + if (res && resource_size(res) > 1) { addr = devm_ioremap_resource(&pdev->dev, res); if (!IS_ERR(addr)) punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; } res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - if (res) { + if (res && resource_size(res) > 1) { addr = devm_ioremap_resource(&pdev->dev, res); if (!IS_ERR(addr)) punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; } res = platform_get_resource(pdev, IORESOURCE_MEM, 5); - if (res) { + if (res && resource_size(res) > 1) { addr = devm_ioremap_resource(&pdev->dev, res); if (!IS_ERR(addr)) punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c index bc98ef95514a1..2da48ecc90c12 100644 --- a/drivers/platform/x86/peaq-wmi.c +++ b/drivers/platform/x86/peaq-wmi.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -64,8 +65,23 @@ static void peaq_wmi_poll(struct input_polled_dev *dev) } } +/* Some other devices (Shuttle XS35) use the same WMI GUID for other purposes */ +static const struct dmi_system_id peaq_dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"), + DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"), + }, + }, + {} +}; + static int __init peaq_wmi_init(void) { + /* WMI GUID is not unique, also check for a DMI match */ + if (!dmi_check_system(peaq_dmi_table)) + return -ENODEV; + if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) return -ENODEV; @@ -86,6 +102,9 @@ static int __init peaq_wmi_init(void) static void __exit peaq_wmi_exit(void) { + if (!dmi_check_system(peaq_dmi_table)) + return; + if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) return; diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 0765b1797d4c0..7f8fa42a10840 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1268,5 +1268,5 @@ static void __exit acpi_wmi_exit(void) bus_unregister(&wmi_bus_type); } -subsys_initcall(acpi_wmi_init); +subsys_initcall_sync(acpi_wmi_init); module_exit(acpi_wmi_exit); diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index b52f3afb2ba1f..1cc2f6870f577 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -29,6 +29,8 @@ #define PWMWAVENUM 0x28 #define PWMDWIDTH 0x2c #define PWMTHRES 0x30 +#define PWM45DWIDTH 0x30 +#define PWM45THRES 0x34 #define PWM_CLK_DIV_MAX 7 @@ -138,10 +140,17 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return -EINVAL; } - mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); - mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); - mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); + printk(KERN_NOTICE "[mtk_pwm_config] period_ns: %d, duty_ns: %d",period_ns,duty_ns); + printk(KERN_NOTICE "[mtk_pwm_config] resolution: %d, clkdiv: %d",resolution,clkdiv); + mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); + if (pwm->hwpwm > 2) { //for PWM4 and PWM5 + mtk_pwm_writel(pc, pwm->hwpwm, PWM45DWIDTH, period_ns / resolution); + mtk_pwm_writel(pc, pwm->hwpwm, PWM45THRES, duty_ns / resolution); + }else{ + mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); + mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); + } mtk_pwm_clk_disable(chip, pwm); return 0; diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 5beb0c361076b..76afe1449cab1 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -963,7 +963,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode, req->sgt.sgl, req->sgt.nents, dir); if (nents == -EFAULT) { rmcd_error("Failed to map SG list"); - return -EFAULT; + ret = -EFAULT; + goto err_pg; } ret = do_dma_request(req, xfer, sync, nents); diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 5dcc9bf1c5bc5..e8e12c2b1d0e0 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->open_req); init_completion(&channel->open_ack); + init_completion(&channel->intent_req_comp); INIT_LIST_HEAD(&channel->done_intents); INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work); @@ -1616,3 +1617,6 @@ void qcom_glink_native_unregister(struct qcom_glink *glink) device_unregister(glink->dev); } EXPORT_SYMBOL_GPL(qcom_glink_native_unregister); + +MODULE_DESCRIPTION("Qualcomm GLINK driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8cec9a02c0b89..9eb32ead63dbe 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -779,7 +779,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) } timerqueue_add(&rtc->timerqueue, &timer->node); - if (!next) { + if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; int err; alarm.time = rtc_ktime_to_tm(timer->node.expires); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index f4c070ea83849..c90fba3ed8618 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -154,6 +154,8 @@ struct m41t80_data { struct rtc_device *rtc; #ifdef CONFIG_COMMON_CLK struct clk_hw sqw; + unsigned long freq; + unsigned int sqwe; #endif }; @@ -443,43 +445,40 @@ static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume); #ifdef CONFIG_COMMON_CLK #define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw) -static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static unsigned long m41t80_decode_freq(int setting) +{ + return (setting == 0) ? 0 : (setting == 1) ? M41T80_SQW_MAX_FREQ : + M41T80_SQW_MAX_FREQ >> setting; +} + +static unsigned long m41t80_get_freq(struct m41t80_data *m41t80) { - struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); struct i2c_client *client = m41t80->client; int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ? M41T80_REG_WDAY : M41T80_REG_SQW; int ret = i2c_smbus_read_byte_data(client, reg_sqw); - unsigned long val = M41T80_SQW_MAX_FREQ; if (ret < 0) return 0; + return m41t80_decode_freq(ret >> 4); +} - ret >>= 4; - if (ret == 0) - val = 0; - else if (ret > 1) - val = val / (1 << ret); - - return val; +static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return sqw_to_m41t80_data(hw)->freq; } static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { - int i, freq = M41T80_SQW_MAX_FREQ; - - if (freq <= rate) - return freq; - - for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) { - freq /= 1 << i; - if (freq <= rate) - return freq; - } - - return 0; + if (rate >= M41T80_SQW_MAX_FREQ) + return M41T80_SQW_MAX_FREQ; + if (rate >= M41T80_SQW_MAX_FREQ / 4) + return M41T80_SQW_MAX_FREQ / 4; + if (!rate) + return 0; + return 1 << ilog2(rate); } static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate, @@ -491,17 +490,12 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate, M41T80_REG_WDAY : M41T80_REG_SQW; int reg, ret, val = 0; - if (rate) { - if (!is_power_of_2(rate)) - return -EINVAL; - val = ilog2(rate); - if (val == ilog2(M41T80_SQW_MAX_FREQ)) - val = 1; - else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1)) - val = ilog2(M41T80_SQW_MAX_FREQ) - val; - else - return -EINVAL; - } + if (rate >= M41T80_SQW_MAX_FREQ) + val = 1; + else if (rate >= M41T80_SQW_MAX_FREQ / 4) + val = 2; + else if (rate) + val = 15 - ilog2(rate); reg = i2c_smbus_read_byte_data(client, reg_sqw); if (reg < 0) @@ -510,10 +504,9 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate, reg = (reg & 0x0f) | (val << 4); ret = i2c_smbus_write_byte_data(client, reg_sqw, reg); - if (ret < 0) - return ret; - - return -EINVAL; + if (!ret) + m41t80->freq = m41t80_decode_freq(val); + return ret; } static int m41t80_sqw_control(struct clk_hw *hw, bool enable) @@ -530,7 +523,10 @@ static int m41t80_sqw_control(struct clk_hw *hw, bool enable) else ret &= ~M41T80_ALMON_SQWE; - return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret); + ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret); + if (!ret) + m41t80->sqwe = enable; + return ret; } static int m41t80_sqw_prepare(struct clk_hw *hw) @@ -545,14 +541,7 @@ static void m41t80_sqw_unprepare(struct clk_hw *hw) static int m41t80_sqw_is_prepared(struct clk_hw *hw) { - struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); - struct i2c_client *client = m41t80->client; - int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); - - if (ret < 0) - return ret; - - return !!(ret & M41T80_ALMON_SQWE); + return sqw_to_m41t80_data(hw)->sqwe; } static const struct clk_ops m41t80_sqw_ops = { @@ -587,6 +576,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) init.parent_names = NULL; init.num_parents = 0; m41t80->sqw.init = &init; + m41t80->freq = m41t80_get_freq(m41t80); /* optional override of the clockname */ of_property_read_string(node, "clock-output-names", &init.name); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index cea6ea4df970f..8c836c51a508f 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -422,7 +422,7 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw, return 0; buf &= PCF8563_REG_CLKO_F_MASK; - return clkout_rates[ret]; + return clkout_rates[buf]; } static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index e1687e19c59f4..a30f24cb6c83c 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -308,7 +308,8 @@ static int pl031_remove(struct amba_device *adev) dev_pm_clear_wake_irq(&adev->dev); device_init_wakeup(&adev->dev, false); - free_irq(adev->irq[0], ldata); + if (adev->irq[0]) + free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); kfree(ldata); @@ -381,12 +382,13 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_rtc; } - if (request_irq(adev->irq[0], pl031_interrupt, - vendor->irqflags, "rtc-pl031", ldata)) { - ret = -EIO; - goto out_no_irq; + if (adev->irq[0]) { + ret = request_irq(adev->irq[0], pl031_interrupt, + vendor->irqflags, "rtc-pl031", ldata); + if (ret) + goto out_no_irq; + dev_pm_set_wake_irq(&adev->dev, adev->irq[0]); } - dev_pm_set_wake_irq(&adev->dev, adev->irq[0]); return 0; out_no_irq: diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index f20b4d66c75f7..4a39b54732d03 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -330,6 +330,8 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) { struct ccw1 *ccw = chain->ch_ccw + idx; + if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw)) + return; if (!ccw->count) return; diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 47a13c5723c6a..92dd4aef21a3b 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -564,9 +564,9 @@ enum qeth_cq { }; struct qeth_ipato { - int enabled; - int invert4; - int invert6; + bool enabled; + bool invert4; + bool invert6; struct list_head entries; }; @@ -985,6 +985,9 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *, int qeth_set_features(struct net_device *, netdev_features_t); int qeth_recover_features(struct net_device *); netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t); +netdev_features_t qeth_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features); int qeth_vm_request_mac(struct qeth_card *card); int qeth_push_hdr(struct sk_buff *skb, struct qeth_hdr **hdr, unsigned int len); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index bae7440abc01e..7c7a244b6684e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include + #include #include @@ -1474,9 +1479,9 @@ static int qeth_setup_card(struct qeth_card *card) qeth_set_intial_options(card); /* IP address takeover */ INIT_LIST_HEAD(&card->ipato.entries); - card->ipato.enabled = 0; - card->ipato.invert4 = 0; - card->ipato.invert6 = 0; + card->ipato.enabled = false; + card->ipato.invert4 = false; + card->ipato.invert6 = false; /* init QDIO stuff */ qeth_init_qdio_info(card); INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work); @@ -5440,6 +5445,13 @@ int qeth_poll(struct napi_struct *napi, int budget) } EXPORT_SYMBOL_GPL(qeth_poll); +static int qeth_setassparms_inspect_rc(struct qeth_ipa_cmd *cmd) +{ + if (!cmd->hdr.return_code) + cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; + return cmd->hdr.return_code; +} + int qeth_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { @@ -6299,7 +6311,7 @@ static int qeth_ipa_checksum_run_cmd_cb(struct qeth_card *card, (struct qeth_checksum_cmd *)reply->param; QETH_CARD_TEXT(card, 4, "chkdoccb"); - if (cmd->hdr.return_code) + if (qeth_setassparms_inspect_rc(cmd)) return 0; memset(chksum_cb, 0, sizeof(*chksum_cb)); @@ -6505,6 +6517,32 @@ netdev_features_t qeth_fix_features(struct net_device *dev, } EXPORT_SYMBOL_GPL(qeth_fix_features); +netdev_features_t qeth_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + /* GSO segmentation builds skbs with + * a (small) linear part for the headers, and + * page frags for the data. + * Compared to a linear skb, the header-only part consumes an + * additional buffer element. This reduces buffer utilization, and + * hurts throughput. So compress small segments into one element. + */ + if (netif_needs_gso(skb, features)) { + /* match skb_segment(): */ + unsigned int doffset = skb->data - skb_mac_header(skb); + unsigned int hsize = skb_shinfo(skb)->gso_size; + unsigned int hroom = skb_headroom(skb); + + /* linearize only if resulting skb allocations are order-0: */ + if (SKB_DATA_ALIGN(hroom + doffset + hsize) <= SKB_MAX_HEAD(0)) + features &= ~NETIF_F_SG; + } + + return vlan_features_check(skb, features); +} +EXPORT_SYMBOL_GPL(qeth_features_check); + static int __init qeth_core_init(void) { int rc; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 760b023eae956..5a973ebcb13c6 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -963,6 +963,7 @@ static const struct net_device_ops qeth_l2_netdev_ops = { .ndo_stop = qeth_l2_stop, .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l2_hard_start_xmit, + .ndo_features_check = qeth_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = qeth_l2_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, @@ -1009,6 +1010,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) { card->dev->hw_features = NETIF_F_SG; card->dev->vlan_features = NETIF_F_SG; + card->dev->features |= NETIF_F_SG; /* OSA 3S and earlier has no RX/TX support */ if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) { card->dev->hw_features |= NETIF_F_IP_CSUM; @@ -1027,8 +1029,6 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) card->info.broadcast_capable = 1; qeth_l2_request_initial_mac(card); - card->dev->gso_max_size = (QETH_MAX_BUFFER_ELEMENTS(card) - 1) * - PAGE_SIZE; SET_NETDEV_DEV(card->dev, &card->gdev->dev); netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); netif_carrier_off(card->dev); diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 194ae9b577cca..e5833837b799e 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -82,7 +82,7 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, const u8 *); -int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *); +void qeth_l3_update_ipato(struct qeth_card *card); struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions); int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *); int qeth_l3_delete_ip(struct qeth_card *, struct qeth_ipaddr *); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ab661a431f7c6..36dee176f8e2c 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -163,8 +163,8 @@ static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) } } -int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, - struct qeth_ipaddr *addr) +static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, + struct qeth_ipaddr *addr) { struct qeth_ipato_entry *ipatoe; u8 addr_bits[128] = {0, }; @@ -173,6 +173,8 @@ int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, if (!card->ipato.enabled) return 0; + if (addr->type != QETH_IP_TYPE_NORMAL) + return 0; qeth_l3_convert_addr_to_bits((u8 *) &addr->u, addr_bits, (addr->proto == QETH_PROT_IPV4)? 4:16); @@ -289,8 +291,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) memcpy(addr, tmp_addr, sizeof(struct qeth_ipaddr)); addr->ref_counter = 1; - if (addr->type == QETH_IP_TYPE_NORMAL && - qeth_l3_is_addr_covered_by_ipato(card, addr)) { + if (qeth_l3_is_addr_covered_by_ipato(card, addr)) { QETH_CARD_TEXT(card, 2, "tkovaddr"); addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; } @@ -604,6 +605,27 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) /* * IP address takeover related functions */ + +/** + * qeth_l3_update_ipato() - Update 'takeover' property, for all NORMAL IPs. + * + * Caller must hold ip_lock. + */ +void qeth_l3_update_ipato(struct qeth_card *card) +{ + struct qeth_ipaddr *addr; + unsigned int i; + + hash_for_each(card->ip_htable, i, addr, hnode) { + if (addr->type != QETH_IP_TYPE_NORMAL) + continue; + if (qeth_l3_is_addr_covered_by_ipato(card, addr)) + addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; + else + addr->set_flags &= ~QETH_IPA_SETIP_TAKEOVER_FLAG; + } +} + static void qeth_l3_clear_ipato_list(struct qeth_card *card) { struct qeth_ipato_entry *ipatoe, *tmp; @@ -615,6 +637,7 @@ static void qeth_l3_clear_ipato_list(struct qeth_card *card) kfree(ipatoe); } + qeth_l3_update_ipato(card); spin_unlock_bh(&card->ip_lock); } @@ -639,8 +662,10 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, } } - if (!rc) + if (!rc) { list_add_tail(&new->entry, &card->ipato.entries); + qeth_l3_update_ipato(card); + } spin_unlock_bh(&card->ip_lock); @@ -663,6 +688,7 @@ void qeth_l3_del_ipato_entry(struct qeth_card *card, (proto == QETH_PROT_IPV4)? 4:16) && (ipatoe->mask_bits == mask_bits)) { list_del(&ipatoe->entry); + qeth_l3_update_ipato(card); kfree(ipatoe); } } @@ -1376,6 +1402,7 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); memcpy(tmp->mac, buf, sizeof(tmp->mac)); + tmp->is_multicast = 1; ipm = qeth_l3_ip_from_hash(card, tmp); if (ipm) { @@ -1553,7 +1580,7 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); if (!addr) - return; + goto out; spin_lock_bh(&card->ip_lock); @@ -1567,6 +1594,7 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, spin_unlock_bh(&card->ip_lock); kfree(addr); +out: in_dev_put(in_dev); } @@ -1591,7 +1619,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); if (!addr) - return; + goto out; spin_lock_bh(&card->ip_lock); @@ -1606,6 +1634,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, spin_unlock_bh(&card->ip_lock); kfree(addr); +out: in6_dev_put(in6_dev); #endif /* CONFIG_QETH_IPV6 */ } @@ -2920,6 +2949,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_stop = qeth_l3_stop, .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_features_check = qeth_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_do_ioctl, @@ -2960,6 +2990,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->vlan_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO; + card->dev->features |= NETIF_F_SG; } } } else if (card->info.type == QETH_CARD_TYPE_IQD) { @@ -2987,8 +3018,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; netif_keep_dst(card->dev); - card->dev->gso_max_size = (QETH_MAX_BUFFER_ELEMENTS(card) - 1) * - PAGE_SIZE; + netif_set_gso_max_size(card->dev, (QETH_MAX_BUFFER_ELEMENTS(card) - 1) * + PAGE_SIZE); SET_NETDEV_DEV(card->dev, &card->gdev->dev); netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 7a829ad777836..1295dd8ec849d 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -370,8 +370,8 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); - struct qeth_ipaddr *addr; - int i, rc = 0; + bool enable; + int rc = 0; if (!card) return -EINVAL; @@ -384,25 +384,18 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, } if (sysfs_streq(buf, "toggle")) { - card->ipato.enabled = (card->ipato.enabled)? 0 : 1; - } else if (sysfs_streq(buf, "1")) { - card->ipato.enabled = 1; - hash_for_each(card->ip_htable, i, addr, hnode) { - if ((addr->type == QETH_IP_TYPE_NORMAL) && - qeth_l3_is_addr_covered_by_ipato(card, addr)) - addr->set_flags |= - QETH_IPA_SETIP_TAKEOVER_FLAG; - } - } else if (sysfs_streq(buf, "0")) { - card->ipato.enabled = 0; - hash_for_each(card->ip_htable, i, addr, hnode) { - if (addr->set_flags & - QETH_IPA_SETIP_TAKEOVER_FLAG) - addr->set_flags &= - ~QETH_IPA_SETIP_TAKEOVER_FLAG; - } - } else + enable = !card->ipato.enabled; + } else if (kstrtobool(buf, &enable)) { rc = -EINVAL; + goto out; + } + + if (card->ipato.enabled != enable) { + card->ipato.enabled = enable; + spin_lock_bh(&card->ip_lock); + qeth_l3_update_ipato(card); + spin_unlock_bh(&card->ip_lock); + } out: mutex_unlock(&card->conf_mutex); return rc ? rc : count; @@ -428,20 +421,27 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); + bool invert; int rc = 0; if (!card) return -EINVAL; mutex_lock(&card->conf_mutex); - if (sysfs_streq(buf, "toggle")) - card->ipato.invert4 = (card->ipato.invert4)? 0 : 1; - else if (sysfs_streq(buf, "1")) - card->ipato.invert4 = 1; - else if (sysfs_streq(buf, "0")) - card->ipato.invert4 = 0; - else + if (sysfs_streq(buf, "toggle")) { + invert = !card->ipato.invert4; + } else if (kstrtobool(buf, &invert)) { rc = -EINVAL; + goto out; + } + + if (card->ipato.invert4 != invert) { + card->ipato.invert4 = invert; + spin_lock_bh(&card->ip_lock); + qeth_l3_update_ipato(card); + spin_unlock_bh(&card->ip_lock); + } +out: mutex_unlock(&card->conf_mutex); return rc ? rc : count; } @@ -607,20 +607,27 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); + bool invert; int rc = 0; if (!card) return -EINVAL; mutex_lock(&card->conf_mutex); - if (sysfs_streq(buf, "toggle")) - card->ipato.invert6 = (card->ipato.invert6)? 0 : 1; - else if (sysfs_streq(buf, "1")) - card->ipato.invert6 = 1; - else if (sysfs_streq(buf, "0")) - card->ipato.invert6 = 0; - else + if (sysfs_streq(buf, "toggle")) { + invert = !card->ipato.invert6; + } else if (kstrtobool(buf, &invert)) { rc = -EINVAL; + goto out; + } + + if (card->ipato.invert6 != invert) { + card->ipato.invert6 = invert; + spin_lock_bh(&card->ip_lock); + qeth_l3_update_ipato(card); + spin_unlock_bh(&card->ip_lock); + } +out: mutex_unlock(&card->conf_mutex); return rc ? rc : count; } diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index dfe8e70f8d996..525a652dab48e 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -2383,19 +2383,19 @@ static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, goto out; } -int aac_send_safw_hostttime(struct aac_dev *dev, struct timeval *now) +int aac_send_safw_hostttime(struct aac_dev *dev, struct timespec64 *now) { struct tm cur_tm; char wellness_str[] = "TD\010\0\0\0\0\0\0\0\0\0DW\0\0ZZ"; u32 datasize = sizeof(wellness_str); - unsigned long local_time; + time64_t local_time; int ret = -ENODEV; if (!dev->sa_firmware) goto out; - local_time = (u32)(now->tv_sec - (sys_tz.tz_minuteswest * 60)); - time_to_tm(local_time, 0, &cur_tm); + local_time = (now->tv_sec - (sys_tz.tz_minuteswest * 60)); + time64_to_tm(local_time, 0, &cur_tm); cur_tm.tm_mon += 1; cur_tm.tm_year += 1900; wellness_str[8] = bin2bcd(cur_tm.tm_hour); @@ -2412,7 +2412,7 @@ int aac_send_safw_hostttime(struct aac_dev *dev, struct timeval *now) return ret; } -int aac_send_hosttime(struct aac_dev *dev, struct timeval *now) +int aac_send_hosttime(struct aac_dev *dev, struct timespec64 *now) { int ret = -ENOMEM; struct fib *fibptr; @@ -2424,7 +2424,7 @@ int aac_send_hosttime(struct aac_dev *dev, struct timeval *now) aac_fib_init(fibptr); info = (__le32 *)fib_data(fibptr); - *info = cpu_to_le32(now->tv_sec); + *info = cpu_to_le32(now->tv_sec); /* overflow in y2106 */ ret = aac_fib_send(SendHostTime, fibptr, sizeof(*info), FsaNormal, 1, 1, NULL, NULL); @@ -2496,7 +2496,7 @@ int aac_command_thread(void *data) } if (!time_before(next_check_jiffies,next_jiffies) && ((difference = next_jiffies - jiffies) <= 0)) { - struct timeval now; + struct timespec64 now; int ret; /* Don't even try to talk to adapter if its sick */ @@ -2506,15 +2506,15 @@ int aac_command_thread(void *data) next_check_jiffies = jiffies + ((long)(unsigned)check_interval) * HZ; - do_gettimeofday(&now); + ktime_get_real_ts64(&now); /* Synchronize our watches */ - if (((1000000 - (1000000 / HZ)) > now.tv_usec) - && (now.tv_usec > (1000000 / HZ))) - difference = (((1000000 - now.tv_usec) * HZ) - + 500000) / 1000000; + if (((NSEC_PER_SEC - (NSEC_PER_SEC / HZ)) > now.tv_nsec) + && (now.tv_nsec > (NSEC_PER_SEC / HZ))) + difference = (((NSEC_PER_SEC - now.tv_nsec) * HZ) + + NSEC_PER_SEC / 2) / NSEC_PER_SEC; else { - if (now.tv_usec > 500000) + if (now.tv_nsec > NSEC_PER_SEC / 2) ++now.tv_sec; if (dev->sa_firmware) diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index 8dcd8c70c7ee0..05f523971348a 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -255,7 +255,8 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, struct bfad_s *bfad = port->bfad; struct bfa_s *bfa = &bfad->bfa; struct bfa_ioc_s *ioc = &bfa->ioc; - int addr, len, rc, i; + int addr, rc, i; + u32 len; u32 *regbuf; void __iomem *rb, *reg_addr; unsigned long flags; @@ -266,7 +267,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf, return PTR_ERR(kern_buf); rc = sscanf(kern_buf, "%x:%x", &addr, &len); - if (rc < 2) { + if (rc < 2 || len > (UINT_MAX >> 2)) { printk(KERN_INFO "bfad[%d]: %s failed to read user buf\n", bfad->inst_no, __func__); diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 1d02cf9fe06c5..30d5f0ef29bbf 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1575,6 +1575,7 @@ static void release_offload_resources(struct cxgbi_sock *csk) csk, csk->state, csk->flags, csk->tid); cxgbi_sock_free_cpl_skbs(csk); + cxgbi_sock_purge_write_queue(csk); if (csk->wr_cred != csk->wr_max_cred) { cxgbi_sock_purge_wr_queue(csk); cxgbi_sock_reset_wr_list(csk); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 16664f2e15fba..8fa9bb336ad4a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -185,13 +185,16 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; + if (!task->lldd_task) + return; + + task->lldd_task = NULL; + if (!sas_protocol_ata(task->task_proto)) if (slot->n_elem) dma_unmap_sg(dev, task->scatter, slot->n_elem, task->data_dir); - task->lldd_task = NULL; - if (sas_dev) atomic64_dec(&sas_dev->running_req); } @@ -199,8 +202,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, if (slot->buf) dma_pool_free(hisi_hba->buffer_pool, slot->buf, slot->buf_dma); - list_del_init(&slot->entry); + slot->buf = NULL; slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4ed3d26ffdde8..5fbaf13781b6c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8684,6 +8684,8 @@ static void hpsa_remove_one(struct pci_dev *pdev) destroy_workqueue(h->rescan_ctlr_wq); destroy_workqueue(h->resubmit_wq); + hpsa_delete_sas_host(h); + /* * Call before disabling interrupts. * scsi_remove_host can trigger I/O operations especially @@ -8718,8 +8720,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) h->lockup_detected = NULL; /* init_one 2 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ - hpsa_delete_sas_host(h); - kfree(h); /* init_one 1 */ } @@ -9207,9 +9207,9 @@ static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy) struct sas_phy *phy = hpsa_sas_phy->phy; sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy); - sas_phy_free(phy); if (hpsa_sas_phy->added_to_port) list_del(&hpsa_sas_phy->phy_list_entry); + sas_phy_delete(phy); kfree(hpsa_sas_phy); } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 6b4fd23751785..324d8d8c62dec 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2145,7 +2145,7 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, struct sas_rphy *rphy) { struct domain_device *dev; - unsigned int reslen = 0; + unsigned int rcvlen = 0; int ret = -EINVAL; /* no rphy means no smp target support (ie aic94xx host) */ @@ -2179,12 +2179,12 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, ret = smp_execute_task_sg(dev, job->request_payload.sg_list, job->reply_payload.sg_list); - if (ret > 0) { - /* positive number is the untransferred residual */ - reslen = ret; + if (ret >= 0) { + /* bsg_job_done() requires the length received */ + rcvlen = job->reply_payload.payload_len - ret; ret = 0; } out: - bsg_job_done(job, ret, reslen); + bsg_job_done(job, ret, rcvlen); } diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ea8ad06ff582e..10b17da20176d 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -486,15 +486,28 @@ static int sas_queue_reset(struct domain_device *dev, int reset_type, int sas_eh_abort_handler(struct scsi_cmnd *cmd) { - int res; + int res = TMF_RESP_FUNC_FAILED; struct sas_task *task = TO_SAS_TASK(cmd); struct Scsi_Host *host = cmd->device->host; + struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_internal *i = to_sas_internal(host->transportt); + unsigned long flags; if (!i->dft->lldd_abort_task) return FAILED; - res = i->dft->lldd_abort_task(task); + spin_lock_irqsave(host->host_lock, flags); + /* We cannot do async aborts for SATA devices */ + if (dev_is_sata(dev) && !host->host_eh_scheduled) { + spin_unlock_irqrestore(host->host_lock, flags); + return FAILED; + } + spin_unlock_irqrestore(host->host_lock, flags); + + if (task) + res = i->dft->lldd_abort_task(task); + else + SAS_DPRINTK("no task to abort\n"); if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) return SUCCESS; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c17677f494afe..dc6519b2c53ad 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3134,7 +3134,8 @@ lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf) struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", pring->txq_max); + return snprintf(buf, PAGE_SIZE, "%d\n", + pring ? pring->txq_max : 0); } static DEVICE_ATTR(txq_hw, S_IRUGO, @@ -3147,7 +3148,8 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", pring->txcmplq_max); + return snprintf(buf, PAGE_SIZE, "%d\n", + pring ? pring->txcmplq_max : 0); } static DEVICE_ATTR(txcmplq_hw, S_IRUGO, diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index fe9e1c079c20f..d89816222b230 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2911,7 +2911,7 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, } } - if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { + if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer || !pring) { ret_val = -ENOMEM; goto err_post_rxbufs_exit; } @@ -5421,6 +5421,8 @@ lpfc_bsg_timeout(struct bsg_job *job) struct lpfc_iocbq *check_iocb, *next_iocb; pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return -EIO; /* if job's driver data is NULL, the command completed or is in the * the process of completing. In this case, return status to request diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 468a66371de9d..3ebf6ccba6e63 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -7430,6 +7430,8 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) timeout = (uint32_t)(phba->fc_ratov << 1); pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return; if ((phba->pport->load_flag & FC_UNLOADING)) return; @@ -9310,6 +9312,9 @@ void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return; + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list, list) { @@ -9416,7 +9421,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, rxid, 1); /* Check if TXQ queue needs to be serviced */ - if (!(list_empty(&pring->txq))) + if (pring && !list_empty(&pring->txq)) lpfc_worker_wake_up(phba); return; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 20808349a80e9..d9a03beb76a4b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3324,7 +3324,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Unblock ELS traffic */ pring = lpfc_phba_elsring(phba); - pring->flag &= ~LPFC_STOP_IOCB_EVENT; + if (pring) + pring->flag &= ~LPFC_STOP_IOCB_EVENT; /* Check for error */ if (mb->mbxStatus) { @@ -4982,7 +4983,8 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(vport, ndlp); if ((ndlp->nlp_flag & NLP_DEFER_RM) && !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && - !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { + !(ndlp->nlp_flag & NLP_RPI_REGISTERED) && + phba->sli_rev != LPFC_SLI_REV4) { /* For this case we need to cleanup the default rpi * allocated by the firmware. */ @@ -5430,6 +5432,8 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) psli = &phba->sli; pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return; /* Error matching iocb on txq or txcmplq * First check the txq. diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 1db0a38683f43..2b145966c73f4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -3636,7 +3636,7 @@ struct lpfc_mbx_get_port_name { #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 #define MB_CQE_STATUS_DMA_FAILED 0x5 -#define LPFC_MBX_WR_CONFIG_MAX_BDE 8 +#define LPFC_MBX_WR_CONFIG_MAX_BDE 1 struct lpfc_mbx_wr_object { struct mbox_header header; union { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 100bc4c8798d7..6acf1bb1d3200 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11404,6 +11404,13 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /* Remove FC host and then SCSI host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); + /* + * Bring down the SLI Layer. This step disables all interrupts, + * clears the rings, discards all mailbox commands, and resets + * the HBA FCoE function. + */ + lpfc_debugfs_terminate(vport); + lpfc_sli4_hba_unset(phba); /* Perform ndlp cleanup on the physical port. The nvme and nvmet * localports are destroyed after to cleanup all transport memory. @@ -11412,14 +11419,8 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) lpfc_nvmet_destroy_targetport(phba); lpfc_nvme_destroy_localport(vport); - /* - * Bring down the SLI Layer. This step disables all interrupts, - * clears the rings, discards all mailbox commands, and resets - * the HBA FCoE function. - */ - lpfc_debugfs_terminate(vport); - lpfc_sli4_hba_unset(phba); + lpfc_stop_hba_timers(phba); spin_lock_irq(&phba->hbalock); list_del_init(&vport->listentry); spin_unlock_irq(&phba->hbalock); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index f3ad7cac355d3..b6957d944b9ac 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -216,7 +216,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) pring = lpfc_phba_elsring(phba); /* In case of error recovery path, we might have a NULL pring here */ - if (!pring) + if (unlikely(!pring)) return; /* Abort outstanding I/O on NPort */ diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 0b7c1a49e203f..7ac1a067d7801 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1138,9 +1138,14 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) #endif if (error) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, - "6025 Cannot register NVME targetport " - "x%x\n", error); + "6025 Cannot register NVME targetport x%x: " + "portnm %llx nodenm %llx segs %d qs %d\n", + error, + pinfo.port_name, pinfo.node_name, + lpfc_tgttemplate.max_sgl_segments, + lpfc_tgttemplate.max_hw_queues); phba->targetport = NULL; + phba->nvmet_support = 0; lpfc_nvmet_cleanup_io_context(phba); @@ -1152,9 +1157,11 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, "6026 Registered NVME " "targetport: %p, private %p " - "portnm %llx nodenm %llx\n", + "portnm %llx nodenm %llx segs %d qs %d\n", phba->targetport, tgtp, - pinfo.port_name, pinfo.node_name); + pinfo.port_name, pinfo.node_name, + lpfc_tgttemplate.max_sgl_segments, + lpfc_tgttemplate.max_hw_queues); atomic_set(&tgtp->rcv_ls_req_in, 0); atomic_set(&tgtp->rcv_ls_req_out, 0); @@ -1457,6 +1464,7 @@ static struct lpfc_nvmet_ctxbuf * lpfc_nvmet_replenish_context(struct lpfc_hba *phba, struct lpfc_nvmet_ctx_info *current_infop) { +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_nvmet_ctxbuf *ctx_buf = NULL; struct lpfc_nvmet_ctx_info *get_infop; int i; @@ -1504,6 +1512,7 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba, get_infop = get_infop->nvmet_ctx_next_cpu; } +#endif /* Nothing found, all contexts for the MRQ are in-flight */ return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 8b119f87b51d6..455f3ce9fda94 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9396,10 +9396,13 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) * for abort iocb hba_wqidx should already * be setup based on what work queue we used. */ - if (!(piocb->iocb_flag & LPFC_USE_FCPWQIDX)) + if (!(piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { piocb->hba_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb->context1); + piocb->hba_wqidx = piocb->hba_wqidx % + phba->cfg_fcp_io_channel; + } return phba->sli4_hba.fcp_wq[piocb->hba_wqidx]->pring; } else { if (unlikely(!phba->sli4_hba.oas_wq)) @@ -10632,6 +10635,14 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) return 0; + if (!pring) { + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; + goto abort_iotag_exit; + } + /* * If we're unloading, don't abort iocb on the ELS ring, but change * the callback so that nothing happens when it finishes. @@ -12500,6 +12511,8 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, unsigned long iflags; pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return NULL; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; spin_lock_irqsave(&pring->ring_lock, iflags); @@ -12507,19 +12520,21 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - /* Put the iocb back on the txcmplq */ - lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq); - spin_unlock_irqrestore(&pring->ring_lock, iflags); - if (unlikely(!cmdiocbq)) { + spin_unlock_irqrestore(&pring->ring_lock, iflags); lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0386 ELS complete with no corresponding " - "cmdiocb: iotag (%d)\n", - bf_get(lpfc_wcqe_c_request_tag, wcqe)); + "cmdiocb: 0x%x 0x%x 0x%x 0x%x\n", + wcqe->word0, wcqe->total_data_placed, + wcqe->parameter, wcqe->word3); lpfc_sli_release_iocbq(phba, irspiocbq); return NULL; } + /* Put the iocb back on the txcmplq */ + lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + /* Fake the irspiocbq and copy necessary response information */ lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); @@ -17137,7 +17152,8 @@ lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport, if (pcmd && pcmd->virt) dma_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys); kfree(pcmd); - lpfc_sli_release_iocbq(phba, iocbq); + if (iocbq) + lpfc_sli_release_iocbq(phba, iocbq); lpfc_in_buf_free(phba, &dmabuf->dbuf); } @@ -18691,6 +18707,8 @@ lpfc_drain_txq(struct lpfc_hba *phba) uint32_t txq_cnt = 0; pring = lpfc_phba_elsring(phba); + if (unlikely(!pring)) + return 0; spin_lock_irqsave(&pring->ring_lock, iflags); list_for_each_entry(piocbq, &pring->txq, list) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 22998cbd538f9..33ff691878e28 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4804,6 +4804,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } else if (log_info == VIRTUAL_IO_FAILED_RETRY) { scmd->result = DID_RESET << 16; break; + } else if ((scmd->device->channel == RAID_CHANNEL) && + (scsi_state == (MPI2_SCSI_STATE_TERMINATED | + MPI2_SCSI_STATE_NO_SCSI_STATUS))) { + scmd->result = DID_RESET << 16; + break; } scmd->result = DID_SOFT_ERROR << 16; break; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index a4f28b7e4c65d..e18877177f1b5 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1576,7 +1576,9 @@ static struct request *_make_request(struct request_queue *q, bool has_write, return req; for_each_bio(bio) { - ret = blk_rq_append_bio(req, bio); + struct bio *bounce_bio = bio; + + ret = blk_rq_append_bio(req, &bounce_bio); if (ret) return ERR_PTR(ret); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index dce42a4168765..6eaaa326e508f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -388,7 +388,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, INIT_LIST_HEAD(&ha->base_qpair->nvme_done_list); ha->base_qpair->enable_class_2 = ql2xenableclass2; /* init qpair to this cpu. Will adjust at run time. */ - qla_cpu_update(rsp->qpair, smp_processor_id()); + qla_cpu_update(rsp->qpair, raw_smp_processor_id()); ha->base_qpair->pdev = ha->pdev; if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 09ba494f88967..92bc5b2d24ae9 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -3001,11 +3001,11 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, if (-1 == ret) { write_unlock_irqrestore(&atomic_rw, iflags); return DID_ERROR << 16; - } else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) + } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size)) sdev_printk(KERN_INFO, scp->device, - "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", + "%s: %s: lb size=%u, IO sent=%d bytes\n", my_name, "write same", - num * sdebug_sector_size, ret); + sdebug_sector_size, ret); /* Copy first sector to remaining blocks */ for (i = 1 ; i < num ; i++) diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c index 01f08c03f2c18..c3765d29fd3ff 100644 --- a/drivers/scsi/scsi_debugfs.c +++ b/drivers/scsi/scsi_debugfs.c @@ -8,9 +8,11 @@ void scsi_show_rq(struct seq_file *m, struct request *rq) { struct scsi_cmnd *cmd = container_of(scsi_req(rq), typeof(*cmd), req); int msecs = jiffies_to_msecs(jiffies - cmd->jiffies_at_alloc); - char buf[80]; + const u8 *const cdb = READ_ONCE(cmd->cmnd); + char buf[80] = "(?)"; - __scsi_format_command(buf, sizeof(buf), cmd->cmnd, cmd->cmd_len); + if (cdb) + __scsi_format_command(buf, sizeof(buf), cdb, cmd->cmd_len); seq_printf(m, ", .cmd=%s, .retries=%d, allocated %d.%03d s ago", buf, cmd->retries, msecs / 1000, msecs % 1000); } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 6bf43d94cdc0c..b19b00adacb24 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -161,7 +161,7 @@ static struct { {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_REPORTLUN2}, {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN}, {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN}, diff --git a/drivers/scsi/scsi_devinfo_tbl.c b/drivers/scsi/scsi_devinfo_tbl.c new file mode 100644 index 0000000000000..6a7f155b1f13c --- /dev/null +++ b/drivers/scsi/scsi_devinfo_tbl.c @@ -0,0 +1,25 @@ +BLIST_FLAG_NAME(NOLUN), +BLIST_FLAG_NAME(FORCELUN), +BLIST_FLAG_NAME(BORKEN), +BLIST_FLAG_NAME(KEY), +BLIST_FLAG_NAME(SINGLELUN), +BLIST_FLAG_NAME(NOTQ), +BLIST_FLAG_NAME(SPARSELUN), +BLIST_FLAG_NAME(MAX5LUN), +BLIST_FLAG_NAME(ISROM), +BLIST_FLAG_NAME(LARGELUN), +BLIST_FLAG_NAME(INQUIRY_36), +BLIST_FLAG_NAME(NOSTARTONADD), +BLIST_FLAG_NAME(REPORTLUN2), +BLIST_FLAG_NAME(NOREPORTLUN), +BLIST_FLAG_NAME(NOT_LOCKABLE), +BLIST_FLAG_NAME(NO_ULD_ATTACH), +BLIST_FLAG_NAME(SELECT_NO_ATN), +BLIST_FLAG_NAME(RETRY_HWERROR), +BLIST_FLAG_NAME(MAX_512), +BLIST_FLAG_NAME(NO_DIF), +BLIST_FLAG_NAME(SKIP_VPD_PAGES), +BLIST_FLAG_NAME(TRY_VPD_PAGES), +BLIST_FLAG_NAME(NO_RSOC), +BLIST_FLAG_NAME(MAX_1024), +BLIST_FLAG_NAME(UNMAP_LIMIT_WS), diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bcc1694cebcd3..635cfa1f2aced 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2126,11 +2126,13 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) q->limits.cluster = 0; /* - * set a reasonable default alignment on word boundaries: the - * host and device may alter it using - * blk_queue_update_dma_alignment() later. + * Set a reasonable default alignment: The larger of 32-byte (dword), + * which is a common minimum for HBAs, and the minimum DMA alignment, + * which is set by the platform. + * + * Devices that require a bigger alignment can increase it later. */ - blk_queue_dma_alignment(q, 0x03); + blk_queue_dma_alignment(q, max(4, dma_get_cache_alignment()) - 1); } EXPORT_SYMBOL_GPL(__scsi_init_queue); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d175c5c5ccf87..72db0f7d221a7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -231,11 +231,15 @@ manage_start_stop_store(struct device *dev, struct device_attribute *attr, { struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_device *sdp = sdkp->device; + bool v; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - sdp->manage_start_stop = simple_strtoul(buf, NULL, 10); + if (kstrtobool(buf, &v)) + return -EINVAL; + + sdp->manage_start_stop = v; return count; } @@ -253,6 +257,7 @@ static ssize_t allow_restart_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + bool v; struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_device *sdp = sdkp->device; @@ -262,7 +267,10 @@ allow_restart_store(struct device *dev, struct device_attribute *attr, if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC) return -EINVAL; - sdp->allow_restart = simple_strtoul(buf, NULL, 10); + if (kstrtobool(buf, &v)) + return -EINVAL; + + sdp->allow_restart = v; return count; } @@ -1284,6 +1292,7 @@ static int sd_init_command(struct scsi_cmnd *cmd) static void sd_uninit_command(struct scsi_cmnd *SCpnt) { struct request *rq = SCpnt->request; + u8 *cmnd; if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK) sd_zbc_write_unlock_zone(SCpnt); @@ -1292,9 +1301,10 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt) __free_page(rq->special_vec.bv_page); if (SCpnt->cmnd != scsi_req(rq)->cmd) { - mempool_free(SCpnt->cmnd, sd_cdb_pool); + cmnd = SCpnt->cmnd; SCpnt->cmnd = NULL; SCpnt->cmd_len = 0; + mempool_free(cmnd, sd_cdb_pool); } } diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 8aa54779aac1b..2eb61d54bbb48 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -375,15 +375,15 @@ static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp, if (sdkp->device->type != TYPE_ZBC) { /* Host-aware */ sdkp->urswrz = 1; - sdkp->zones_optimal_open = get_unaligned_be64(&buf[8]); - sdkp->zones_optimal_nonseq = get_unaligned_be64(&buf[12]); + sdkp->zones_optimal_open = get_unaligned_be32(&buf[8]); + sdkp->zones_optimal_nonseq = get_unaligned_be32(&buf[12]); sdkp->zones_max_open = 0; } else { /* Host-managed */ sdkp->urswrz = buf[4] & 1; sdkp->zones_optimal_open = 0; sdkp->zones_optimal_nonseq = 0; - sdkp->zones_max_open = get_unaligned_be64(&buf[16]); + sdkp->zones_max_open = get_unaligned_be32(&buf[16]); } return 0; diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index c2048382830f7..086c9ea8d7cb6 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -522,7 +522,7 @@ struct pmic_wrapper_type { u32 int_en_all; u32 spi_w; u32 wdt_src; - int has_bridge:1; + unsigned int has_bridge:1; int (*init_reg_clock)(struct pmic_wrapper *wrp); int (*init_soc_specific)(struct pmic_wrapper *wrp); }; @@ -1107,6 +1107,22 @@ static const struct of_device_id of_pwrap_match_tbl[] = { }; MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); +struct regmap *pwrap_node_to_regmap(struct device_node *np) +{ + struct platform_device *pdev; + struct pmic_wrapper *wrp; + + pdev = of_find_device_by_node(np); + + if (!pdev) + return ERR_PTR(-ENODEV); + + wrp = platform_get_drvdata(pdev); + + return wrp->regmap; +} +EXPORT_SYMBOL_GPL(pwrap_node_to_regmap); + static int pwrap_probe(struct platform_device *pdev) { int ret, irq; diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 568e1c65aa82c..fe3fa1e8517a1 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -79,6 +79,7 @@ #define A3700_SPI_BYTE_LEN BIT(5) #define A3700_SPI_CLK_PRESCALE BIT(0) #define A3700_SPI_CLK_PRESCALE_MASK (0x1f) +#define A3700_SPI_CLK_EVEN_OFFS (0x10) #define A3700_SPI_WFIFO_THRS_BIT 28 #define A3700_SPI_RFIFO_THRS_BIT 24 @@ -220,6 +221,13 @@ static void a3700_spi_clock_set(struct a3700_spi *a3700_spi, prescale = DIV_ROUND_UP(clk_get_rate(a3700_spi->clk), speed_hz); + /* For prescaler values over 15, we can only set it by steps of 2. + * Starting from A3700_SPI_CLK_EVEN_OFFS, we set values from 0 up to + * 30. We only use this range from 16 to 30. + */ + if (prescale > 15) + prescale = A3700_SPI_CLK_EVEN_OFFS + DIV_ROUND_UP(prescale, 2); + val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); val = val & ~A3700_SPI_CLK_PRESCALE_MASK; diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 6ab4c77002288..68cfc351b47f6 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -553,7 +553,7 @@ static int spi_engine_probe(struct platform_device *pdev) static int spi_engine_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct spi_engine *spi_engine = spi_master_get_devdata(master); int irq = platform_get_irq(pdev, 0); @@ -561,6 +561,8 @@ static int spi_engine_remove(struct platform_device *pdev) free_irq(irq, master); + spi_master_put(master); + writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING); writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0eb1e95834854..837bb95eea623 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -900,7 +900,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, break; copy32 = copy_bswap32; } else if (bits <= 16) { - if (l & 1) + if (l & 3) break; copy32 = copy_wswap32; } else { diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index bc7100b93dfcf..e0b9fe1d0e37d 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -271,6 +271,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) while (remaining_words) { int n_words, tx_words, rx_words; u32 sr; + int stalled; n_words = min(remaining_words, xspi->buffer_size); @@ -299,7 +300,17 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) /* Read out all the data from the Rx FIFO */ rx_words = n_words; + stalled = 10; while (rx_words) { + if (rx_words == n_words && !(stalled--) && + !(sr & XSPI_SR_TX_EMPTY_MASK) && + (sr & XSPI_SR_RX_EMPTY_MASK)) { + dev_err(&spi->dev, + "Detected stall. Check C_SPI_MODE and C_SPI_MEMORY\n"); + xspi_init_hw(xspi); + return -EIO; + } + if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) { xilinx_spi_rx(xspi); rx_words--; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e8b5a5e21b2e6..3ff0ee88c467a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2245,11 +2245,12 @@ static int __unregister(struct device *dev, void *null) void spi_unregister_controller(struct spi_controller *ctlr) { struct spi_controller *found; + int id = ctlr->bus_num; int dummy; /* First make sure that this controller was ever added */ mutex_lock(&board_lock); - found = idr_find(&spi_master_idr, ctlr->bus_num); + found = idr_find(&spi_master_idr, id); mutex_unlock(&board_lock); if (found != ctlr) { dev_dbg(&ctlr->dev, @@ -2269,7 +2270,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) device_unregister(&ctlr->dev); /* free bus id */ mutex_lock(&board_lock); - idr_remove(&spi_master_idr, ctlr->bus_num); + idr_remove(&spi_master_idr, id); mutex_unlock(&board_lock); } EXPORT_SYMBOL_GPL(spi_unregister_controller); diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 0f695df14c9d8..372ce9913e6de 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -765,10 +765,12 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case ASHMEM_SET_SIZE: ret = -EINVAL; + mutex_lock(&ashmem_mutex); if (!asma->file) { ret = 0; asma->size = (size_t)arg; } + mutex_unlock(&ashmem_mutex); break; case ASHMEM_GET_SIZE: ret = asma->size; diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 93e2c90fa77d5..83dc3292e9ab1 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -348,7 +348,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents, - DMA_BIDIRECTIONAL); + direction); } mutex_unlock(&buffer->lock); @@ -370,7 +370,7 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents, - DMA_BIDIRECTIONAL); + direction); } mutex_unlock(&buffer->lock); diff --git a/drivers/staging/ccree/cc_lli_defs.h b/drivers/staging/ccree/cc_lli_defs.h index 851d3907167ea..a9c417b07b042 100644 --- a/drivers/staging/ccree/cc_lli_defs.h +++ b/drivers/staging/ccree/cc_lli_defs.h @@ -59,7 +59,7 @@ static inline void cc_lli_set_addr(u32 *lli_p, dma_addr_t addr) lli_p[LLI_WORD0_OFFSET] = (addr & U32_MAX); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT lli_p[LLI_WORD1_OFFSET] &= ~LLI_HADDR_MASK; - lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_HADDR_MASK, (addr >> 16)); + lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_HADDR_MASK, (addr >> 32)); #endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */ } diff --git a/drivers/staging/ccree/ssi_hash.c b/drivers/staging/ccree/ssi_hash.c index 13291aeaf350b..f72ca485c86f6 100644 --- a/drivers/staging/ccree/ssi_hash.c +++ b/drivers/staging/ccree/ssi_hash.c @@ -1790,9 +1790,12 @@ static int ssi_ahash_import(struct ahash_request *req, const void *in) } in += sizeof(u32); - rc = ssi_hash_init(state, ctx); - if (rc) - goto out; + /* call init() to allocate bufs if the user hasn't */ + if (!state->digest_buff) { + rc = ssi_hash_init(state, ctx); + if (rc) + goto out; + } dma_sync_single_for_cpu(dev, state->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL); diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index 26017fe9df936..8e84b2e7f5bda 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -131,6 +131,8 @@ static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv, u16 fd_offset = dpaa2_fd_get_offset(fd); u32 fd_length = dpaa2_fd_get_len(fd); + ch->buf_count--; + skb = build_skb(fd_vaddr, DPAA2_ETH_RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); if (unlikely(!skb)) @@ -139,8 +141,6 @@ static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv, skb_reserve(skb, fd_offset); skb_put(skb, fd_length); - ch->buf_count--; - return skb; } @@ -178,8 +178,15 @@ static struct sk_buff *build_frag_skb(struct dpaa2_eth_priv *priv, /* We build the skb around the first data buffer */ skb = build_skb(sg_vaddr, DPAA2_ETH_RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - if (unlikely(!skb)) - return NULL; + if (unlikely(!skb)) { + /* We still need to subtract the buffers used + * by this FD from our software counter + */ + while (!dpaa2_sg_is_final(&sgt[i]) && + i < DPAA2_ETH_MAX_SG_ENTRIES) + i++; + break; + } sg_offset = dpaa2_sg_get_offset(sge); skb_reserve(skb, sg_offset); diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c index f8096828f5b71..a609ec82daf34 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c @@ -76,7 +76,7 @@ static inline struct dpaa2_io *service_select_by_cpu(struct dpaa2_io *d, if (d) return d; - if (unlikely(cpu >= num_possible_cpus())) + if (cpu != DPAA2_IO_ANY_CPU && cpu >= num_possible_cpus()) return NULL; /* @@ -121,7 +121,7 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) return NULL; /* check if CPU is out of range (-1 means any cpu) */ - if (desc->cpu >= num_possible_cpus()) { + if (desc->cpu != DPAA2_IO_ANY_CPU && desc->cpu >= num_possible_cpus()) { kfree(obj); return NULL; } diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h index c5646096c5d4c..afc2d060d077c 100644 --- a/drivers/staging/fsl-mc/include/dpaa2-io.h +++ b/drivers/staging/fsl-mc/include/dpaa2-io.h @@ -54,6 +54,8 @@ struct device; * for dequeue. */ +#define DPAA2_IO_ANY_CPU -1 + /** * struct dpaa2_io_desc - The DPIO descriptor * @receives_notifications: Use notificaton mode. Non-zero if the DPIO @@ -91,8 +93,8 @@ irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj); * @cb: The callback to be invoked when the notification arrives * @is_cdan: Zero for FQDAN, non-zero for CDAN * @id: FQID or channel ID, needed for rearm - * @desired_cpu: The cpu on which the notifications will show up. -1 means - * any CPU. + * @desired_cpu: The cpu on which the notifications will show up. Use + * DPAA2_IO_ANY_CPU if don't care * @dpio_id: The dpio index * @qman64: The 64-bit context value shows up in the FQDAN/CDAN. * @node: The list node diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c index 3f4148c92308e..0f538b8c3a076 100644 --- a/drivers/staging/greybus/light.c +++ b/drivers/staging/greybus/light.c @@ -925,6 +925,8 @@ static void __gb_lights_led_unregister(struct gb_channel *channel) return; led_classdev_unregister(cdev); + kfree(cdev->name); + cdev->name = NULL; channel->led = NULL; } diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 08e2558842061..93e86798ec1c2 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -1042,8 +1042,10 @@ static int gb_loopback_fn(void *data) else if (type == GB_LOOPBACK_TYPE_SINK) error = gb_loopback_async_sink(gb, size); - if (error) + if (error) { gb->error++; + gb->iteration_count++; + } } else { /* We are effectively single threaded here */ if (type == GB_LOOPBACK_TYPE_PING) diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c index e97b191484971..1e7321a1404cc 100644 --- a/drivers/staging/greybus/spilib.c +++ b/drivers/staging/greybus/spilib.c @@ -544,11 +544,14 @@ int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, return 0; -exit_spi_unregister: - spi_unregister_master(master); exit_spi_put: spi_master_put(master); + return ret; + +exit_spi_unregister: + spi_unregister_master(master); + return ret; } EXPORT_SYMBOL_GPL(gb_spilib_master_init); @@ -558,7 +561,6 @@ void gb_spilib_master_exit(struct gb_connection *connection) struct spi_master *master = gb_connection_get_data(connection); spi_unregister_master(master); - spi_master_put(master); } EXPORT_SYMBOL_GPL(gb_spilib_master_exit); diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 32a483769975b..fa611455109ae 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -754,7 +754,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf) } /* setting only at first time */ - if (!(pmlmepriv->cur_network.join_res)) { + if (pmlmepriv->cur_network.join_res != true) { /* WEP Key will be set before this function, do not * clear CAM. */ diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index 9461bce883ea9..be8542676adf9 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c @@ -333,7 +333,7 @@ u8 rtw_createbss_cmd(struct adapter *padapter) else RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); - pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); if (!pcmd) { res = _FAIL; goto exit; @@ -508,7 +508,7 @@ u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueu if (enqueue) { /* need enqueue, prepare cmd_obj and enqueue */ - cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL); + cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC); if (!cmdobj) { res = _FAIL; kfree(param); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index f663e6c41f8ae..f6d71587b803b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -106,10 +106,10 @@ void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) { - rtw_free_mlme_priv_ie_data(pmlmepriv); - - if (pmlmepriv) + if (pmlmepriv) { + rtw_free_mlme_priv_ie_data(pmlmepriv); vfree(pmlmepriv->free_bss_buf); + } } struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv) diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 3fd5f4102b360..afb9dadc1cfe9 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -259,10 +259,12 @@ static int recvframe_chkmic(struct adapter *adapter, } /* icv_len included the mic code */ - datalen = precvframe->pkt->len-prxattrib->hdrlen - 8; + datalen = precvframe->pkt->len-prxattrib->hdrlen - + prxattrib->iv_len-prxattrib->icv_len-8; pframe = precvframe->pkt->data; - payload = pframe+prxattrib->hdrlen; + payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len)); rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */ @@ -407,15 +409,9 @@ static struct recv_frame *decryptor(struct adapter *padapter, default: break; } - if (res != _FAIL) { - memmove(precv_frame->pkt->data + precv_frame->attrib.iv_len, precv_frame->pkt->data, precv_frame->attrib.hdrlen); - skb_pull(precv_frame->pkt, precv_frame->attrib.iv_len); - skb_trim(precv_frame->pkt, precv_frame->pkt->len - precv_frame->attrib.icv_len); - } } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && - (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)) { - psecuritypriv->hw_decrypted = true; - } + (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)) + psecuritypriv->hw_decrypted = true; if (res == _FAIL) { rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue); @@ -456,7 +452,7 @@ static struct recv_frame *portctrl(struct adapter *adapter, if (auth_alg == 2) { /* get ether_type */ - ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; + ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE + pfhdr->attrib.iv_len; memcpy(&be_tmp, ptr, 2); ether_type = ntohs(be_tmp); @@ -1138,8 +1134,6 @@ static int validate_recv_data_frame(struct adapter *adapter, } if (pattrib->privacy) { - struct sk_buff *skb = precv_frame->pkt; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy)); RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); @@ -1148,13 +1142,6 @@ static int validate_recv_data_frame(struct adapter *adapter, RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt)); SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); - - if (pattrib->bdecrypted == 1 && pattrib->encrypt > 0) { - memmove(skb->data + pattrib->iv_len, - skb->data, pattrib->hdrlen); - skb_pull(skb, pattrib->iv_len); - skb_trim(skb, skb->len - pattrib->icv_len); - } } else { pattrib->encrypt = 0; pattrib->iv_len = 0; @@ -1274,7 +1261,6 @@ static int validate_recv_frame(struct adapter *adapter, * Hence forward the frame to the monitor anyway to preserve the order * in which frames were received. */ - rtl88eu_mon_recv_hook(adapter->pmondev, precv_frame); exit: @@ -1296,8 +1282,11 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe) u8 *ptr = precvframe->pkt->data; struct rx_pkt_attrib *pattrib = &precvframe->attrib; - psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen); - psnap_type = ptr+pattrib->hdrlen + SNAP_SIZE; + if (pattrib->encrypt) + skb_trim(precvframe->pkt, precvframe->pkt->len - pattrib->icv_len); + + psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); + psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; /* convert hdr + possible LLC headers into Ethernet header */ if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && (!memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) && @@ -1310,9 +1299,12 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe) bsnaphdr = false; } - rmv_len = pattrib->hdrlen + (bsnaphdr ? SNAP_SIZE : 0); + rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); len = precvframe->pkt->len - rmv_len; + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len)); + memcpy(&be_tmp, ptr+rmv_len, 2); eth_type = ntohs(be_tmp); /* pattrib->ether_type */ pattrib->eth_type = eth_type; @@ -1337,6 +1329,7 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) { struct list_head *plist, *phead; + u8 wlanhdr_offset; u8 curfragnum; struct recv_frame *pfhdr, *pnfhdr; struct recv_frame *prframe, *pnextrframe; @@ -1385,7 +1378,12 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter, /* copy the 2nd~n fragment frame's payload to the first fragment */ /* get the 2nd~last fragment frame's payload */ - skb_pull(pnextrframe->pkt, pnfhdr->attrib.hdrlen); + wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; + + skb_pull(pnextrframe->pkt, wlanhdr_offset); + + /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ + skb_trim(prframe->pkt, prframe->pkt->len - pfhdr->attrib.icv_len); /* memcpy */ memcpy(skb_tail_pointer(pfhdr->pkt), pnfhdr->pkt->data, @@ -1393,7 +1391,7 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter, skb_put(prframe->pkt, pnfhdr->pkt->len); - pfhdr->attrib.icv_len = 0; + pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; plist = plist->next; } @@ -1519,6 +1517,11 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) nr_subframes = 0; pattrib = &prframe->attrib; + skb_pull(prframe->pkt, prframe->attrib.hdrlen); + + if (prframe->attrib.iv_len > 0) + skb_pull(prframe->pkt, prframe->attrib.iv_len); + a_len = prframe->pkt->len; pdata = prframe->pkt->data; @@ -1887,6 +1890,24 @@ static int process_recv_indicatepkts(struct adapter *padapter, return retval; } +static int recv_func_prehandle(struct adapter *padapter, + struct recv_frame *rframe) +{ + int ret = _SUCCESS; + struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + /* check the frame crtl field and decache */ + ret = validate_recv_frame(padapter, rframe); + if (ret != _SUCCESS) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + goto exit; + } + +exit: + return ret; +} + static int recv_func_posthandle(struct adapter *padapter, struct recv_frame *prframe) { @@ -1939,7 +1960,6 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe) struct rx_pkt_attrib *prxattrib = &rframe->attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; struct mlme_priv *mlmepriv = &padapter->mlmepriv; - struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; /* check if need to handle uc_swdec_pending_queue*/ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) { @@ -1951,12 +1971,9 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe) } } - /* check the frame crtl field and decache */ - ret = validate_recv_frame(padapter, rframe); - if (ret != _SUCCESS) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); - rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ - } else { + ret = recv_func_prehandle(padapter, rframe); + + if (ret == _SUCCESS) { /* check if need to enqueue into uc_swdec_pending_queue*/ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 && diff --git a/drivers/staging/rtl8188eu/os_dep/mon.c b/drivers/staging/rtl8188eu/os_dep/mon.c index 37fd52d7364f5..225c23fc69dce 100644 --- a/drivers/staging/rtl8188eu/os_dep/mon.c +++ b/drivers/staging/rtl8188eu/os_dep/mon.c @@ -66,34 +66,6 @@ static void mon_recv_decrypted(struct net_device *dev, const u8 *data, netif_rx(skb); } -static void mon_recv_decrypted_recv(struct net_device *dev, const u8 *data, - int data_len) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - int hdr_len; - - skb = netdev_alloc_skb(dev, data_len); - if (!skb) - return; - memcpy(skb_put(skb, data_len), data, data_len); - - /* - * Frame data is not encrypted. Strip off protection so - * userspace doesn't think that it is. - */ - - hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); - - if (ieee80211_has_protected(hdr->frame_control)) - hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -} - static void mon_recv_encrypted(struct net_device *dev, const u8 *data, int data_len) { @@ -110,6 +82,7 @@ static void mon_recv_encrypted(struct net_device *dev, const u8 *data, void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame) { struct rx_pkt_attrib *attr; + int iv_len, icv_len; int data_len; u8 *data; @@ -122,8 +95,11 @@ void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame) data = frame->pkt->data; data_len = frame->pkt->len; + /* Broadcast and multicast frames don't have attr->{iv,icv}_len set */ + SET_ICE_IV_LEN(iv_len, icv_len, attr->encrypt); + if (attr->bdecrypted) - mon_recv_decrypted_recv(dev, data, data_len); + mon_recv_decrypted(dev, data, data_len, iv_len, icv_len); else mon_recv_encrypted(dev, data, data_len); } diff --git a/drivers/staging/rtlwifi/phydm/phydm_dig.c b/drivers/staging/rtlwifi/phydm/phydm_dig.c index 31a4f3fcad193..c88b9788363a7 100644 --- a/drivers/staging/rtlwifi/phydm/phydm_dig.c +++ b/drivers/staging/rtlwifi/phydm/phydm_dig.c @@ -490,6 +490,8 @@ void odm_pause_dig(void *dm_void, enum phydm_pause_type pause_type, break; } + /* pin max_level to be >= 0 */ + max_level = max_t(s8, 0, max_level); /* write IGI of lower level */ odm_write_dig(dm, dig_tab->pause_dig_value[max_level]); ODM_RT_TRACE(dm, ODM_COMP_DIG, diff --git a/drivers/staging/rtlwifi/rtl8822be/fw.c b/drivers/staging/rtlwifi/rtl8822be/fw.c index 8e24da16752c2..a2cc54866e79c 100644 --- a/drivers/staging/rtlwifi/rtl8822be/fw.c +++ b/drivers/staging/rtlwifi/rtl8822be/fw.c @@ -419,7 +419,7 @@ static bool _rtl8822be_send_bcn_or_cmd_packet(struct ieee80211_hw *hw, dma_addr = rtlpriv->cfg->ops->get_desc( hw, (u8 *)pbd_desc, true, HW_DESC_TXBUFF_ADDR); - pci_unmap_single(rtlpci->pdev, dma_addr, skb->len, + pci_unmap_single(rtlpci->pdev, dma_addr, pskb->len, PCI_DMA_TODEVICE); kfree_skb(pskb); diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h index 09c223f815def..aee82fcaf6693 100644 --- a/drivers/staging/sm750fb/ddk750_chip.h +++ b/drivers/staging/sm750fb/ddk750_chip.h @@ -18,7 +18,7 @@ static inline u32 peek32(u32 addr) return readl(addr + mmio750); } -static inline void poke32(u32 data, u32 addr) +static inline void poke32(u32 addr, u32 data) { writel(data, addr + mmio750); } diff --git a/drivers/staging/vboxvideo/vbox_drv.h b/drivers/staging/vboxvideo/vbox_drv.h index 4b9302703b362..eeac4f0cb2c65 100644 --- a/drivers/staging/vboxvideo/vbox_drv.h +++ b/drivers/staging/vboxvideo/vbox_drv.h @@ -137,8 +137,8 @@ struct vbox_connector { char name[32]; struct vbox_crtc *vbox_crtc; struct { - u16 width; - u16 height; + u32 width; + u32 height; bool disconnected; } mode_hint; }; @@ -150,8 +150,8 @@ struct vbox_crtc { unsigned int crtc_id; u32 fb_offset; bool cursor_enabled; - u16 x_hint; - u16 y_hint; + u32 x_hint; + u32 y_hint; }; struct vbox_encoder { diff --git a/drivers/staging/vboxvideo/vbox_irq.c b/drivers/staging/vboxvideo/vbox_irq.c index 3ca8bec62ac41..74abdf02d9fdd 100644 --- a/drivers/staging/vboxvideo/vbox_irq.c +++ b/drivers/staging/vboxvideo/vbox_irq.c @@ -150,8 +150,8 @@ static void vbox_update_mode_hints(struct vbox_private *vbox) disconnected = !(hints->enabled); crtc_id = vbox_conn->vbox_crtc->crtc_id; - vbox_conn->mode_hint.width = hints->cx & 0x8fff; - vbox_conn->mode_hint.height = hints->cy & 0x8fff; + vbox_conn->mode_hint.width = hints->cx; + vbox_conn->mode_hint.height = hints->cy; vbox_conn->vbox_crtc->x_hint = hints->dx; vbox_conn->vbox_crtc->y_hint = hints->dy; vbox_conn->mode_hint.disconnected = disconnected; diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c index 257a778304107..6f08dc9667193 100644 --- a/drivers/staging/vboxvideo/vbox_mode.c +++ b/drivers/staging/vboxvideo/vbox_mode.c @@ -553,12 +553,22 @@ static int vbox_get_modes(struct drm_connector *connector) ++num_modes; } vbox_set_edid(connector, preferred_width, preferred_height); - drm_object_property_set_value( - &connector->base, vbox->dev->mode_config.suggested_x_property, - vbox_connector->vbox_crtc->x_hint); - drm_object_property_set_value( - &connector->base, vbox->dev->mode_config.suggested_y_property, - vbox_connector->vbox_crtc->y_hint); + + if (vbox_connector->vbox_crtc->x_hint != -1) + drm_object_property_set_value(&connector->base, + vbox->dev->mode_config.suggested_x_property, + vbox_connector->vbox_crtc->x_hint); + else + drm_object_property_set_value(&connector->base, + vbox->dev->mode_config.suggested_x_property, 0); + + if (vbox_connector->vbox_crtc->y_hint != -1) + drm_object_property_set_value(&connector->base, + vbox->dev->mode_config.suggested_y_property, + vbox_connector->vbox_crtc->y_hint); + else + drm_object_property_set_value(&connector->base, + vbox->dev->mode_config.suggested_y_property, 0); return num_modes; } @@ -640,9 +650,9 @@ static int vbox_connector_init(struct drm_device *dev, drm_mode_create_suggested_offset_properties(dev); drm_object_attach_property(&connector->base, - dev->mode_config.suggested_x_property, -1); + dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, - dev->mode_config.suggested_y_property, -1); + dev->mode_config.suggested_y_property, 0); drm_connector_register(connector); drm_mode_connector_attach_encoder(connector, encoder); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 9fcf2e223f719..1123b4f1e1d66 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1693,10 +1693,11 @@ static int vt6655_suspend(struct pci_dev *pcid, pm_message_t state) MACbShutdown(priv); pci_disable_device(pcid); - pci_set_power_state(pcid, pci_choose_state(pcid, state)); spin_unlock_irqrestore(&priv->lock, flags); + pci_set_power_state(pcid, pci_choose_state(pcid, state)); + return 0; } diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 9addef1f1e128..f49dfa82f1b8a 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -714,7 +714,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) char *bssid = ((struct tx_complete_data *)(tqe->priv))->bssid; buffer_offset = ETH_ETHERNET_HDR_OFFSET; - memcpy(&txb[offset + 4], bssid, 6); + memcpy(&txb[offset + 8], bssid, 6); } else { buffer_offset = HOST_HDR_OFFSET; } diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 5001261f5d69d..52fa52c20be05 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -834,6 +834,7 @@ static int iscsit_add_reject_from_cmd( unsigned char *buf) { struct iscsi_conn *conn; + const bool do_put = cmd->se_cmd.se_tfo != NULL; if (!cmd->conn) { pr_err("cmd->conn is NULL for ITT: 0x%08x\n", @@ -864,7 +865,7 @@ static int iscsit_add_reject_from_cmd( * Perform the kref_put now if se_cmd has already been setup by * scsit_setup_scsi_cmd() */ - if (cmd->se_cmd.se_tfo != NULL) { + if (do_put) { pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n"); target_put_sess_cmd(&cmd->se_cmd); } @@ -1960,7 +1961,6 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, struct iscsi_tmr_req *tmr_req; struct iscsi_tm *hdr; int out_of_order_cmdsn = 0, ret; - bool sess_ref = false; u8 function, tcm_function = TMR_UNKNOWN; hdr = (struct iscsi_tm *) buf; @@ -1993,22 +1993,23 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, cmd->data_direction = DMA_NONE; cmd->tmr_req = kzalloc(sizeof(*cmd->tmr_req), GFP_KERNEL); - if (!cmd->tmr_req) + if (!cmd->tmr_req) { return iscsit_add_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); + } + + transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, + conn->sess->se_sess, 0, DMA_NONE, + TCM_SIMPLE_TAG, cmd->sense_buffer + 2); + + target_get_sess_cmd(&cmd->se_cmd, true); /* * TASK_REASSIGN for ERL=2 / connection stays inside of * LIO-Target $FABRIC_MOD */ if (function != ISCSI_TM_FUNC_TASK_REASSIGN) { - transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, - conn->sess->se_sess, 0, DMA_NONE, - TCM_SIMPLE_TAG, cmd->sense_buffer + 2); - - target_get_sess_cmd(&cmd->se_cmd, true); - sess_ref = true; tcm_function = iscsit_convert_tmf(function); if (tcm_function == TMR_UNKNOWN) { pr_err("Unknown iSCSI TMR Function:" @@ -2099,12 +2100,14 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); - if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) + if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) { out_of_order_cmdsn = 1; - else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) + } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { + target_put_sess_cmd(&cmd->se_cmd); return 0; - else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) + } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { return -1; + } } iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); @@ -2124,12 +2127,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, * For connection recovery, this is also the default action for * TMR TASK_REASSIGN. */ - if (sess_ref) { - pr_debug("Handle TMR, using sess_ref=true check\n"); - target_put_sess_cmd(&cmd->se_cmd); - } - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); + target_put_sess_cmd(&cmd->se_cmd); return 0; } EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0dd4c45f7575a..0ebc4818e132a 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1123,7 +1123,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( ret = core_tpg_register(wwn, &tpg->tpg_se_tpg, SCSI_PROTOCOL_ISCSI); if (ret < 0) - return NULL; + goto free_out; ret = iscsit_tpg_add_portal_group(tiqn, tpg); if (ret != 0) @@ -1135,6 +1135,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( return &tpg->tpg_se_tpg; out: core_tpg_deregister(&tpg->tpg_se_tpg); +free_out: kfree(tpg); return NULL; } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1e36f83b59616..70c6b9bfc04ee 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -694,6 +694,8 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) struct iscsi_session *sess; struct se_cmd *se_cmd = &cmd->se_cmd; + WARN_ON(!list_empty(&cmd->i_conn_node)); + if (cmd->conn) sess = cmd->conn->sess; else @@ -716,6 +718,8 @@ void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues) { struct iscsi_conn *conn = cmd->conn; + WARN_ON(!list_empty(&cmd->i_conn_node)); + if (cmd->data_direction == DMA_TO_DEVICE) { iscsit_stop_dataout_timer(cmd); iscsit_free_r2ts_from_list(cmd); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index c629817a8854b..9b2c0c773022c 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -482,6 +482,10 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) struct inode *inode = file->f_mapping->host; int ret; + if (!nolb) { + return 0; + } + if (cmd->se_dev->dev_attrib.pi_prot_type) { ret = fd_do_prot_unmap(cmd, lba, nolb); if (ret) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index dd2cd8048582c..4ba5004a069e9 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -58,8 +58,10 @@ void core_pr_dump_initiator_port( char *buf, u32 size) { - if (!pr_reg->isid_present_at_reg) + if (!pr_reg->isid_present_at_reg) { buf[0] = '\0'; + return; + } snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid); } @@ -4011,6 +4013,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * Set the ADDITIONAL DESCRIPTOR LENGTH */ put_unaligned_be32(desc_len, &buf[off]); + off += 4; /* * Size of full desctipor header minus TransportID * containing $FABRIC_MOD specific) initiator device/port diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 7c69b4a9694d2..0d99b242e82e3 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -920,7 +920,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, " %d i: %d bio: %p, allocating another" " bio\n", bio->bi_vcnt, i, bio); - rc = blk_rq_append_bio(req, bio); + rc = blk_rq_append_bio(req, &bio); if (rc) { pr_err("pSCSI: failed to append bio\n"); goto fail; @@ -938,7 +938,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } if (bio) { - rc = blk_rq_append_bio(req, bio); + rc = blk_rq_append_bio(req, &bio); if (rc) { pr_err("pSCSI: failed to append bio\n"); goto fail; diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index e22847bd79b95..9c7bc1ca341a6 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -133,6 +133,15 @@ static bool __target_check_io_state(struct se_cmd *se_cmd, spin_unlock(&se_cmd->t_state_lock); return false; } + if (se_cmd->transport_state & CMD_T_PRE_EXECUTE) { + if (se_cmd->scsi_status) { + pr_debug("Attempted to abort io tag: %llu early failure" + " status: 0x%02x\n", se_cmd->tag, + se_cmd->scsi_status); + spin_unlock(&se_cmd->t_state_lock); + return false; + } + } if (sess->sess_tearing_down || se_cmd->cmd_wait_set) { pr_debug("Attempted to abort io tag: %llu already shutdown," " skipping\n", se_cmd->tag); @@ -217,7 +226,8 @@ static void core_tmr_drain_tmr_list( * LUN_RESET tmr.. */ spin_lock_irqsave(&dev->se_tmr_lock, flags); - list_del_init(&tmr->tmr_list); + if (tmr) + list_del_init(&tmr->tmr_list); list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) { cmd = tmr_p->task_cmd; if (!cmd) { diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 836d552b0385e..e6d51135d1055 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1730,9 +1730,6 @@ void transport_generic_request_failure(struct se_cmd *cmd, { int ret = 0, post_ret = 0; - if (transport_check_aborted_status(cmd, 1)) - return; - pr_debug("-----[ Storage Engine Exception; sense_reason %d\n", sense_reason); target_show_cmd("-----[ ", cmd); @@ -1741,6 +1738,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, * For SAM Task Attribute emulation for failed struct se_cmd */ transport_complete_task_attr(cmd); + /* * Handle special case for COMPARE_AND_WRITE failure, where the * callback is expected to drop the per device ->caw_sem. @@ -1749,6 +1747,9 @@ void transport_generic_request_failure(struct se_cmd *cmd, cmd->transport_complete_callback) cmd->transport_complete_callback(cmd, false, &post_ret); + if (transport_check_aborted_status(cmd, 1)) + return; + switch (sense_reason) { case TCM_NON_EXISTENT_LUN: case TCM_UNSUPPORTED_SCSI_OPCODE: @@ -1973,6 +1974,7 @@ void target_execute_cmd(struct se_cmd *cmd) } cmd->t_state = TRANSPORT_PROCESSING; + cmd->transport_state &= ~CMD_T_PRE_EXECUTE; cmd->transport_state |= CMD_T_ACTIVE | CMD_T_SENT; spin_unlock_irq(&cmd->t_state_lock); @@ -2010,6 +2012,8 @@ static void target_restart_delayed_cmds(struct se_device *dev) list_del(&cmd->se_delayed_node); spin_unlock(&dev->delayed_cmd_lock); + cmd->transport_state |= CMD_T_SENT; + __target_execute_cmd(cmd, true); if (cmd->sam_task_attr == TCM_ORDERED_TAG) @@ -2045,6 +2049,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd) pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n", dev->dev_cur_ordered_id); } + cmd->se_cmd_flags &= ~SCF_TASK_ATTR_SET; + restart: target_restart_delayed_cmds(dev); } @@ -2570,7 +2576,20 @@ EXPORT_SYMBOL(transport_generic_new_cmd); static void transport_write_pending_qf(struct se_cmd *cmd) { + unsigned long flags; int ret; + bool stop; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + stop = (cmd->transport_state & (CMD_T_STOP | CMD_T_ABORTED)); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + if (stop) { + pr_debug("%s:%d CMD_T_STOP|CMD_T_ABORTED for ITT: 0x%08llx\n", + __func__, __LINE__, cmd->tag); + complete_all(&cmd->t_transport_stop_comp); + return; + } ret = cmd->se_tfo->write_pending(cmd); if (ret) { @@ -2664,6 +2683,7 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) ret = -ESHUTDOWN; goto out; } + se_cmd->transport_state |= CMD_T_PRE_EXECUTE; list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 7952357df9c86..edb6e4e9ef3ac 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -590,7 +590,6 @@ static int __init optee_driver_init(void) return -ENODEV; np = of_find_matching_node(fw_np, optee_match); - of_node_put(fw_np); if (!np) return -ENODEV; diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index bd3572c41585c..6d8906d654763 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -35,8 +35,9 @@ #define TEMP0_RST_MSK (0x1C) #define TEMP0_VALUE (0x28) -#define HISI_TEMP_BASE (-60) +#define HISI_TEMP_BASE (-60000) #define HISI_TEMP_RESET (100000) +#define HISI_TEMP_STEP (784) #define HISI_MAX_SENSORS 4 @@ -61,19 +62,38 @@ struct hisi_thermal_data { void __iomem *regs; }; -/* in millicelsius */ -static inline int _step_to_temp(int step) +/* + * The temperature computation on the tsensor is as follow: + * Unit: millidegree Celsius + * Step: 255/200 (0.7843) + * Temperature base: -60°C + * + * The register is programmed in temperature steps, every step is 784 + * millidegree and begins at -60 000 m°C + * + * The temperature from the steps: + * + * Temp = TempBase + (steps x 784) + * + * and the steps from the temperature: + * + * steps = (Temp - TempBase) / 784 + * + */ +static inline int hisi_thermal_step_to_temp(int step) { - /* - * Every step equals (1 * 200) / 255 celsius, and finally - * need convert to millicelsius. - */ - return (HISI_TEMP_BASE * 1000 + (step * 200000 / 255)); + return HISI_TEMP_BASE + (step * HISI_TEMP_STEP); +} + +static inline long hisi_thermal_temp_to_step(long temp) +{ + return (temp - HISI_TEMP_BASE) / HISI_TEMP_STEP; } -static inline long _temp_to_step(long temp) +static inline long hisi_thermal_round_temp(int temp) { - return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000; + return hisi_thermal_step_to_temp( + hisi_thermal_temp_to_step(temp)); } static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data, @@ -99,7 +119,7 @@ static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data, usleep_range(3000, 5000); val = readl(data->regs + TEMP0_VALUE); - val = _step_to_temp(val); + val = hisi_thermal_step_to_temp(val); mutex_unlock(&data->thermal_lock); @@ -126,10 +146,11 @@ static void hisi_thermal_enable_bind_irq_sensor writel((sensor->id << 12), data->regs + TEMP0_CFG); /* enable for interrupt */ - writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00, + writel(hisi_thermal_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00, data->regs + TEMP0_TH); - writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH); + writel(hisi_thermal_temp_to_step(HISI_TEMP_RESET), + data->regs + TEMP0_RST_TH); /* enable module */ writel(0x1, data->regs + TEMP0_RST_MSK); @@ -230,7 +251,7 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) sensor = &data->sensors[data->irq_bind_sensor]; dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n", - sensor->thres_temp / 1000); + sensor->thres_temp); mutex_unlock(&data->thermal_lock); for (i = 0; i < HISI_MAX_SENSORS; i++) { @@ -269,7 +290,7 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev, for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) { if (trip[i].type == THERMAL_TRIP_PASSIVE) { - sensor->thres_temp = trip[i].temperature; + sensor->thres_temp = hisi_thermal_round_temp(trip[i].temperature); break; } } @@ -317,15 +338,6 @@ static int hisi_thermal_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; - ret = devm_request_threaded_irq(&pdev->dev, data->irq, - hisi_thermal_alarm_irq, - hisi_thermal_alarm_irq_thread, - 0, "hisi_thermal", data); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); - return ret; - } - platform_set_drvdata(pdev, data); data->clk = devm_clk_get(&pdev->dev, "thermal_clk"); @@ -345,8 +357,7 @@ static int hisi_thermal_probe(struct platform_device *pdev) } hisi_thermal_enable_bind_irq_sensor(data); - irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED, - &data->irq_enabled); + data->irq_enabled = true; for (i = 0; i < HISI_MAX_SENSORS; ++i) { ret = hisi_thermal_register_sensor(pdev, data, @@ -358,6 +369,17 @@ static int hisi_thermal_probe(struct platform_device *pdev) hisi_thermal_toggle_sensor(&data->sensors[i], true); } + ret = devm_request_threaded_irq(&pdev->dev, data->irq, + hisi_thermal_alarm_irq, + hisi_thermal_alarm_irq_thread, + 0, "hisi_thermal", data); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); + return ret; + } + + enable_irq(data->irq); + return 0; } diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index be95826631b72..ee047ca43084d 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -31,8 +31,7 @@ * If the temperature is higher than a trip point, * a. if the trend is THERMAL_TREND_RAISING, use higher cooling * state for this trip point - * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling - * state for this trip point + * b. if the trend is THERMAL_TREND_DROPPING, do nothing * c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit * for this trip point * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit @@ -94,9 +93,11 @@ static unsigned long get_target_state(struct thermal_instance *instance, if (!throttle) next_target = THERMAL_NO_TARGET; } else { - next_target = cur_state - 1; - if (next_target > instance->upper) - next_target = instance->upper; + if (!throttle) { + next_target = cur_state - 1; + if (next_target > instance->upper) + next_target = instance->upper; + } } break; case THERMAL_TREND_DROP_FULL: diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index d674e06767a56..1424581fd9af5 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -225,6 +225,7 @@ static void tb_activate_pcie_devices(struct tb *tb) tb_port_info(up_port, "PCIe tunnel activation failed, aborting\n"); tb_pci_free(tunnel); + continue; } list_add(&tunnel->list, &tcm->tunnel_list); diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index bdf0e6e899914..faf50df816224 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1764,7 +1764,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { struct n_tty_data *ldata = tty->disc_data; - if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) { + if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) { bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); ldata->line_start = ldata->read_tail; if (!L_ICANON(tty) || !read_cnt(ldata)) { @@ -2427,7 +2427,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, return put_user(tty_chars_in_buffer(tty), (int __user *) arg); case TIOCINQ: down_write(&tty->termios_rwsem); - if (L_ICANON(tty)) + if (L_ICANON(tty) && !L_EXTPROC(tty)) retval = inq_canon(ldata); else retval = read_cnt(ldata); diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index c68fb3a8ea1c3..97db76afced2e 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -65,21 +65,32 @@ static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) */ int serdev_device_add(struct serdev_device *serdev) { + struct serdev_controller *ctrl = serdev->ctrl; struct device *parent = serdev->dev.parent; int err; dev_set_name(&serdev->dev, "%s-%d", dev_name(parent), serdev->nr); + /* Only a single slave device is currently supported. */ + if (ctrl->serdev) { + dev_err(&serdev->dev, "controller busy\n"); + return -EBUSY; + } + ctrl->serdev = serdev; + err = device_add(&serdev->dev); if (err < 0) { dev_err(&serdev->dev, "Can't add %s, status %d\n", dev_name(&serdev->dev), err); - goto err_device_add; + goto err_clear_serdev; } dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev)); -err_device_add: + return 0; + +err_clear_serdev: + ctrl->serdev = NULL; return err; } EXPORT_SYMBOL_GPL(serdev_device_add); @@ -90,7 +101,10 @@ EXPORT_SYMBOL_GPL(serdev_device_add); */ void serdev_device_remove(struct serdev_device *serdev) { + struct serdev_controller *ctrl = serdev->ctrl; + device_unregister(&serdev->dev); + ctrl->serdev = NULL; } EXPORT_SYMBOL_GPL(serdev_device_remove); @@ -295,7 +309,6 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) return NULL; serdev->ctrl = ctrl; - ctrl->serdev = serdev; device_initialize(&serdev->dev); serdev->dev.parent = &ctrl->dev; serdev->dev.bus = &serdev_bus_type; diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index 302018d67efa9..69fc6d9ab490f 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -35,23 +35,41 @@ static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp, { struct serdev_controller *ctrl = port->client_data; struct serport *serport = serdev_controller_get_drvdata(ctrl); + int ret; if (!test_bit(SERPORT_ACTIVE, &serport->flags)) return 0; - return serdev_controller_receive_buf(ctrl, cp, count); + ret = serdev_controller_receive_buf(ctrl, cp, count); + + dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count, + "receive_buf returns %d (count = %zu)\n", + ret, count); + if (ret < 0) + return 0; + else if (ret > count) + return count; + + return ret; } static void ttyport_write_wakeup(struct tty_port *port) { struct serdev_controller *ctrl = port->client_data; struct serport *serport = serdev_controller_get_drvdata(ctrl); + struct tty_struct *tty; + + tty = tty_port_tty_get(port); + if (!tty) + return; - if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) && + if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && test_bit(SERPORT_ACTIVE, &serport->flags)) serdev_controller_write_wakeup(ctrl); - wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT); + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); + + tty_kref_put(tty); } static const struct tty_port_client_operations client_ops = { @@ -102,10 +120,10 @@ static int ttyport_open(struct serdev_controller *ctrl) return PTR_ERR(tty); serport->tty = tty; - if (tty->ops->open) - tty->ops->open(serport->tty, NULL); - else - tty_port_open(serport->port, tty, NULL); + if (!tty->ops->open) + goto err_unlock; + + tty->ops->open(serport->tty, NULL); /* Bring the UART into a known 8 bits no parity hw fc state */ ktermios = tty->termios; @@ -122,6 +140,12 @@ static int ttyport_open(struct serdev_controller *ctrl) tty_unlock(serport->tty); return 0; + +err_unlock: + tty_unlock(tty); + tty_release_struct(tty, serport->tty_idx); + + return -ENODEV; } static void ttyport_close(struct serdev_controller *ctrl) @@ -131,8 +155,10 @@ static void ttyport_close(struct serdev_controller *ctrl) clear_bit(SERPORT_ACTIVE, &serport->flags); + tty_lock(tty); if (tty->ops->close) tty->ops->close(tty, NULL); + tty_unlock(tty); tty_release_struct(tty, serport->tty_idx); } diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index af72ec32e4047..f135c1846477e 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -125,12 +125,14 @@ static void __init init_port(struct earlycon_device *device) serial8250_early_out(port, UART_FCR, 0); /* no fifo */ serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ - divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); - c = serial8250_early_in(port, UART_LCR); - serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); - serial8250_early_out(port, UART_DLL, divisor & 0xff); - serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); - serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); + if (port->uartclk && device->baud) { + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); + c = serial8250_early_in(port, UART_LCR); + serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); + serial8250_early_out(port, UART_DLL, divisor & 0xff); + serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff); + serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); + } } int __init early_serial8250_setup(struct earlycon_device *device, diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index e500f7dd2470a..ba4af5434b917 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -118,6 +118,9 @@ static int fintek_8250_enter_key(u16 base_port, u8 key) if (!request_muxed_region(base_port, 2, "8250_fintek")) return -EBUSY; + /* Force to deactive all SuperIO in this base_port */ + outb(EXIT_KEY, base_port + ADDR_PORT); + outb(key, base_port + ADDR_PORT); outb(key, base_port + ADDR_PORT); return 0; @@ -208,7 +211,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) == (!!(rs485->flags & SER_RS485_RTS_AFTER_SEND))) - rs485->flags &= SER_RS485_ENABLED; + rs485->flags &= ~SER_RS485_ENABLED; else config |= RS485_URA; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 0c101a7470b0e..d4e7be88e0da3 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5137,6 +5137,9 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 }, + /* Amazon PCI serial device */ + { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index f0cc04f62b676..8dcfd4978a036 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2586,8 +2586,11 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, serial_dl_write(up, quot); /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ - if (up->port.type == PORT_XR17V35X) + if (up->port.type == PORT_XR17V35X) { + /* Preserve bits not related to baudrate; DLD[7:4]. */ + quot_frac |= serial_port_in(port, 0x2) & 0xf0; serial_port_out(port, 0x2, quot_frac); + } } static unsigned int serial8250_get_baud_rate(struct uart_port *port, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dfeff3951f934..3657d745e90f0 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -334,7 +334,8 @@ static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); - mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); + sport->port.mctrl |= TIOCM_RTS; + mctrl_gpio_set(sport->gpios, sport->port.mctrl); } static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) @@ -342,7 +343,8 @@ static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); + sport->port.mctrl &= ~TIOCM_RTS; + mctrl_gpio_set(sport->gpios, sport->port.mctrl); } static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 7754053deedac..26a22b100df10 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -693,7 +693,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) up->efr |= UART_EFR_RTS; else - up->efr &= UART_EFR_RTS; + up->efr &= ~UART_EFR_RTS; serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, lcr); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 784dd42002ead..761b9f5f14915 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1491,6 +1491,14 @@ static void sci_request_dma(struct uart_port *port) return; s->cookie_tx = -EINVAL; + + /* + * Don't request a dma channel if no channel was specified + * in the device tree. + */ + if (!of_find_property(port->dev->of_node, "dmas", NULL)) + return; + chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV); dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); if (chan) { diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index d008f5a751971..377b3592384e0 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -246,8 +246,10 @@ static void sysrq_handle_showallcpus(int key) * architecture has no support for it: */ if (!trigger_all_cpu_backtrace()) { - struct pt_regs *regs = get_irq_regs(); + struct pt_regs *regs = NULL; + if (in_irq()) + regs = get_irq_regs(); if (regs) { pr_info("CPU%d:\n", smp_processor_id()); show_regs(regs); @@ -266,7 +268,10 @@ static struct sysrq_key_op sysrq_showallcpus_op = { static void sysrq_handle_showregs(int key) { - struct pt_regs *regs = get_irq_regs(); + struct pt_regs *regs = NULL; + + if (in_irq()) + regs = get_irq_regs(); if (regs) show_regs(regs); perf_event_print_debug(); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index f8eba1c5412f9..677fa99b77478 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -446,7 +446,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * Callers other than flush_to_ldisc() need to exclude the kworker * from concurrent use of the line discipline, see paste_selection(). * - * Returns the number of bytes not processed + * Returns the number of bytes processed */ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, char *f, int count) diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index bb626120296ff..53f3bf459dd1b 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -251,7 +251,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev) if (ret) goto err_mux; - ulpi_node = of_find_node_by_name(of_node_get(pdev->dev.of_node), "ulpi"); + ulpi_node = of_get_child_by_name(pdev->dev.of_node, "ulpi"); if (ulpi_node) { phy_node = of_get_next_available_child(ulpi_node, NULL); ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy"); diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 4aa5195db8ea5..e02acfb1ca95f 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -183,9 +183,9 @@ static int ulpi_of_register(struct ulpi *ulpi) /* Find a ulpi bus underneath the parent or the grandparent */ parent = ulpi->dev.parent; if (parent->of_node) - np = of_find_node_by_name(parent->of_node, "ulpi"); + np = of_get_child_by_name(parent->of_node, "ulpi"); else if (parent->parent && parent->parent->of_node) - np = of_find_node_by_name(parent->parent->of_node, "ulpi"); + np = of_get_child_by_name(parent->parent->of_node, "ulpi"); if (!np) return 0; diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 883549ee946cb..9e3355b973961 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -555,6 +555,9 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, unsigned iad_num = 0; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); + nintf = nintf_orig = config->desc.bNumInterfaces; + config->desc.bNumInterfaces = 0; // Adjusted later + if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE || config->desc.bLength > size) { @@ -568,7 +571,6 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, buffer += config->desc.bLength; size -= config->desc.bLength; - nintf = nintf_orig = config->desc.bNumInterfaces; if (nintf > USB_MAXINTERFACES) { dev_warn(ddev, "config %d has too many interfaces: %d, " "using maximum allowed: %d\n", @@ -905,14 +907,25 @@ void usb_release_bos_descriptor(struct usb_device *dev) } } +static const __u8 bos_desc_len[256] = { + [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE, + [USB_CAP_TYPE_EXT] = USB_DT_USB_EXT_CAP_SIZE, + [USB_SS_CAP_TYPE] = USB_DT_USB_SS_CAP_SIZE, + [USB_SSP_CAP_TYPE] = USB_DT_USB_SSP_CAP_SIZE(1), + [CONTAINER_ID_TYPE] = USB_DT_USB_SS_CONTN_ID_SIZE, + [USB_PTM_CAP_TYPE] = USB_DT_USB_PTM_ID_SIZE, +}; + /* Get BOS descriptor set */ int usb_get_bos_descriptor(struct usb_device *dev) { struct device *ddev = &dev->dev; struct usb_bos_descriptor *bos; struct usb_dev_cap_header *cap; + struct usb_ssp_cap_descriptor *ssp_cap; unsigned char *buffer; - int length, total_len, num, i; + int length, total_len, num, i, ssac; + __u8 cap_type; int ret; bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); @@ -965,7 +978,13 @@ int usb_get_bos_descriptor(struct usb_device *dev) dev->bos->desc->bNumDeviceCaps = i; break; } + cap_type = cap->bDevCapabilityType; length = cap->bLength; + if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) { + dev->bos->desc->bNumDeviceCaps = i; + break; + } + total_len -= length; if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { @@ -973,7 +992,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) continue; } - switch (cap->bDevCapabilityType) { + switch (cap_type) { case USB_CAP_TYPE_WIRELESS_USB: /* Wireless USB cap descriptor is handled by wusb */ break; @@ -986,8 +1005,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) (struct usb_ss_cap_descriptor *)buffer; break; case USB_SSP_CAP_TYPE: - dev->bos->ssp_cap = - (struct usb_ssp_cap_descriptor *)buffer; + ssp_cap = (struct usb_ssp_cap_descriptor *)buffer; + ssac = (le32_to_cpu(ssp_cap->bmAttributes) & + USB_SSP_SUBLINK_SPEED_ATTRIBS); + if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac)) + dev->bos->ssp_cap = ssp_cap; break; case CONTAINER_ID_TYPE: dev->bos->ss_id = diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e9326f31db8d4..ab245352f102a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1455,14 +1455,18 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb int number_of_packets = 0; unsigned int stream_id = 0; void *buf; - - if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | - USBDEVFS_URB_SHORT_NOT_OK | + unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | USBDEVFS_URB_BULK_CONTINUATION | USBDEVFS_URB_NO_FSBR | USBDEVFS_URB_ZERO_PACKET | - USBDEVFS_URB_NO_INTERRUPT)) - return -EINVAL; + USBDEVFS_URB_NO_INTERRUPT; + /* USBDEVFS_URB_ISO_ASAP is a special case */ + if (uurb->type == USBDEVFS_URB_TYPE_ISO) + mask |= USBDEVFS_URB_ISO_ASAP; + + if (uurb->flags & ~mask) + return -EINVAL; + if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX) return -EINVAL; if (uurb->buffer_length > 0 && !uurb->buffer) @@ -1833,6 +1837,18 @@ static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) return 0; } +static void compute_isochronous_actual_length(struct urb *urb) +{ + unsigned int i; + + if (urb->number_of_packets > 0) { + urb->actual_length = 0; + for (i = 0; i < urb->number_of_packets; i++) + urb->actual_length += + urb->iso_frame_desc[i].actual_length; + } +} + static int processcompl(struct async *as, void __user * __user *arg) { struct urb *urb = as->urb; @@ -1840,6 +1856,7 @@ static int processcompl(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; + compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) goto err_out; @@ -2008,6 +2025,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) void __user *addr = as->userurb; unsigned int i; + compute_isochronous_actual_length(urb); if (as->userbuffer && urb->actual_length) { if (copy_urb_data_to_user(as->userbuffer, urb)) return -EFAULT; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e9ce6bb0b22d1..8f7d94239ee3e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4935,6 +4935,15 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, usb_put_dev(udev); if ((status == -ENOTCONN) || (status == -ENOTSUPP)) break; + + /* When halfway through our retry count, power-cycle the port */ + if (i == (SET_CONFIG_TRIES / 2) - 1) { + dev_info(&port_dev->dev, "attempt power cycle\n"); + usb_hub_set_port_power(hdev, hub, port1, false); + msleep(2 * hub_power_on_good_delay(hub)); + usb_hub_set_port_power(hdev, hub, port1, true); + msleep(hub_power_on_good_delay(hub)); + } } if (hub->hdev->parent || !hcd->driver->port_handed_over || diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index a6aaf2f193a46..c05c4f8777504 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -57,10 +57,11 @@ static const struct usb_device_id usb_quirk_list[] = { /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Logitech HD Pro Webcams C920, C920-C and C930e */ + /* Logitech HD Pro Webcams C920, C920-C, C925e and C930e */ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x046d, 0x085b), .driver_info = USB_QUIRK_DELAY_INIT }, /* Logitech ConferenceCam CC3000e */ { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -151,6 +152,12 @@ static const struct usb_device_id usb_quirk_list[] = { /* appletouch */ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Genesys Logic hub, internally used by KY-688 USB 3.1 Type-C Hub */ + { USB_DEVICE(0x05e3, 0x0612), .driver_info = USB_QUIRK_NO_LPM }, + + /* ELSA MicroLink 56K */ + { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */ { USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM }, @@ -221,6 +228,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Corsair Strafe RGB */ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair K70 LUX */ + { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, + /* MIDI keyboard WORLDE MINI */ { USB_DEVICE(0x1c75, 0x0204), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, diff --git a/drivers/usb/early/xhci-dbc.h b/drivers/usb/early/xhci-dbc.h index 2df0f6e613fed..a516cab0bf4a5 100644 --- a/drivers/usb/early/xhci-dbc.h +++ b/drivers/usb/early/xhci-dbc.h @@ -90,8 +90,8 @@ struct xdbc_context { #define XDBC_INFO_CONTEXT_SIZE 48 #define XDBC_MAX_STRING_LENGTH 64 -#define XDBC_STRING_MANUFACTURER "Linux" -#define XDBC_STRING_PRODUCT "Remote GDB" +#define XDBC_STRING_MANUFACTURER "Linux Foundation" +#define XDBC_STRING_PRODUCT "Linux USB GDB Target" #define XDBC_STRING_SERIAL "0001" struct xdbc_strings { @@ -103,7 +103,7 @@ struct xdbc_strings { #define XDBC_PROTOCOL 1 /* GNU Remote Debug Command Set */ #define XDBC_VENDOR_ID 0x1d6b /* Linux Foundation 0x1d6b */ -#define XDBC_PRODUCT_ID 0x0004 /* __le16 idProduct; device 0004 */ +#define XDBC_PRODUCT_ID 0x0011 /* __le16 idProduct; device 0011 */ #define XDBC_DEVICE_REV 0x0010 /* 0.10 */ /* diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 8b342587f8ad6..876cdbec13074 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1016,7 +1016,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) else ret = ep->status; goto error_mutex; - } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) { + } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { ret = -ENOMEM; } else { req->buf = data; @@ -2286,9 +2286,18 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, int i; if (len < sizeof(*d) || - d->bFirstInterfaceNumber >= ffs->interfaces_count || - !d->Reserved1) + d->bFirstInterfaceNumber >= ffs->interfaces_count) return -EINVAL; + if (d->Reserved1 != 1) { + /* + * According to the spec, Reserved1 must be set to 1 + * but older kernels incorrectly rejected non-zero + * values. We fix it here to avoid returning EINVAL + * in response to values we used to accept. + */ + pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n"); + d->Reserved1 = 1; + } for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) if (d->Reserved2[i]) return -EINVAL; @@ -3677,6 +3686,7 @@ static void ffs_closed(struct ffs_data *ffs) goto done; ffs_obj->desc_ready = false; + ffs_obj->ffs_data = NULL; if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) && ffs_obj->ffs_closed_callback) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index d41d07aae0cec..284bd1a7b5703 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1080,8 +1080,12 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc) static inline void usb_gadget_udc_set_speed(struct usb_udc *udc, enum usb_device_speed speed) { - if (udc->gadget->ops->udc_set_speed) - udc->gadget->ops->udc_set_speed(udc->gadget, speed); + if (udc->gadget->ops->udc_set_speed) { + enum usb_device_speed s; + + s = min(speed, udc->gadget->max_speed); + udc->gadget->ops->udc_set_speed(udc->gadget, s); + } } /** @@ -1154,11 +1158,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, udc = kzalloc(sizeof(*udc), GFP_KERNEL); if (!udc) - goto err1; - - ret = device_add(&gadget->dev); - if (ret) - goto err2; + goto err_put_gadget; device_initialize(&udc->dev); udc->dev.release = usb_udc_release; @@ -1167,7 +1167,11 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, udc->dev.parent = parent; ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); if (ret) - goto err3; + goto err_put_udc; + + ret = device_add(&gadget->dev); + if (ret) + goto err_put_udc; udc->gadget = gadget; gadget->udc = udc; @@ -1177,7 +1181,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, ret = device_add(&udc->dev); if (ret) - goto err4; + goto err_unlist_udc; usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); udc->vbus = true; @@ -1185,27 +1189,25 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, /* pick up one of pending gadget drivers */ ret = check_pending_gadget_drivers(udc); if (ret) - goto err5; + goto err_del_udc; mutex_unlock(&udc_lock); return 0; -err5: + err_del_udc: device_del(&udc->dev); -err4: + err_unlist_udc: list_del(&udc->list); mutex_unlock(&udc_lock); -err3: - put_device(&udc->dev); device_del(&gadget->dev); -err2: - kfree(udc); + err_put_udc: + put_device(&udc->dev); -err1: + err_put_gadget: put_device(&gadget->dev); return ret; } diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 63a2061220589..6b3e8adb64e68 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -254,7 +254,7 @@ #define USB3_EP0_SS_MAX_PACKET_SIZE 512 #define USB3_EP0_HSFS_MAX_PACKET_SIZE 64 #define USB3_EP0_BUF_SIZE 8 -#define USB3_MAX_NUM_PIPES 30 +#define USB3_MAX_NUM_PIPES 6 /* This includes PIPE 0 */ #define USB3_WAIT_US 3 #define USB3_DMA_NUM_SETTING_AREA 4 /* diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index cbb9b8e12c3ce..8c5a6fee4dfdf 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -837,7 +837,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) default: /* unknown */ break; } - temp = (cap >> 8) & 0xff; + offset = (cap >> 8) & 0xff; } } #endif diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 2a82c927ded21..ccdc971283d09 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -947,6 +947,12 @@ void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) if (!vdev) return; + if (vdev->real_port == 0 || + vdev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) { + xhci_dbg(xhci, "Bad vdev->real_port.\n"); + goto out; + } + tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts); list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) { /* is this a hub device that added a tt_info to the tts list */ @@ -960,6 +966,7 @@ void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) } } } +out: /* we are now at a leaf device */ xhci_free_virt_device(xhci, slot_id); } @@ -976,10 +983,9 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, return 0; } - xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags); - if (!xhci->devs[slot_id]) + dev = kzalloc(sizeof(*dev), flags); + if (!dev) return 0; - dev = xhci->devs[slot_id]; /* Allocate the (output) device context that will be used in the HC. */ dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); @@ -1020,9 +1026,17 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, trace_xhci_alloc_virt_device(dev); + xhci->devs[slot_id] = dev; + return 1; fail: - xhci_free_virt_device(xhci, slot_id); + + if (dev->in_ctx) + xhci_free_container_ctx(xhci, dev->in_ctx); + if (dev->out_ctx) + xhci_free_container_ctx(xhci, dev->out_ctx); + kfree(dev); + return 0; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 76f3929547336..abb8f19ae40f2 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -189,6 +189,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_BROKEN_STREAMS; } + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + pdev->device == 0x0014) + xhci->quirks |= XHCI_TRUST_TX_LENGTH; if (pdev->vendor == PCI_VENDOR_ID_RENESAS && pdev->device == 0x0015) xhci->quirks |= XHCI_RESET_ON_RESUME; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 82c746e2d85c0..6996235e34a95 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2486,12 +2486,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ if (list_empty(&ep_ring->td_list)) { /* - * A stopped endpoint may generate an extra completion - * event if the device was suspended. Don't print - * warnings. + * Don't print wanings if it's due to a stopped endpoint + * generating an extra completion event if the device + * was suspended. Or, a event for the last TRB of a + * short TD we already got a short event for. + * The short TD is already removed from the TD list. */ + if (!(trb_comp_code == COMP_STOPPED || - trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { + trb_comp_code == COMP_STOPPED_LENGTH_INVALID || + ep_ring->last_td_was_short)) { xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); @@ -3117,7 +3121,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, { u32 maxp, total_packet_count; - /* MTK xHCI is mostly 0.97 but contains some features from 1.0 */ + /* MTK xHCI 0.96 contains some features from 1.0 */ if (xhci->hci_version < 0x100 && !(xhci->quirks & XHCI_MTK_HOST)) return ((td_total_len - transferred) >> 10); @@ -3126,8 +3130,8 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, trb_buff_len == td_total_len) return 0; - /* for MTK xHCI, TD size doesn't include this TRB */ - if (xhci->quirks & XHCI_MTK_HOST) + /* for MTK xHCI 0.96, TD size include this TRB, but not in 1.x */ + if ((xhci->quirks & XHCI_MTK_HOST) && (xhci->hci_version < 0x100)) trb_buff_len = 0; maxp = usb_endpoint_maxp(&urb->ep->desc); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 51535ba2bcd42..e5677700dea4d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3583,10 +3583,9 @@ int xhci_disable_slot(struct xhci_hcd *xhci, struct xhci_command *command, state = readl(&xhci->op_regs->status); if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_free_virt_device(xhci, slot_id); spin_unlock_irqrestore(&xhci->lock, flags); kfree(command); - return ret; + return -ENODEV; } ret = xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 8e7737d7ac0a3..03be5d574f234 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -292,6 +292,8 @@ static int usb3503_probe(struct usb3503 *hub) if (gpio_is_valid(hub->gpio_reset)) { err = devm_gpio_request_one(dev, hub->gpio_reset, GPIOF_OUT_INIT_LOW, "usb3503 reset"); + /* Datasheet defines a hardware reset to be at least 100us */ + usleep_range(100, 10000); if (err) { dev_err(dev, "unable to request GPIO %d as reset pin (%d)\n", diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f6ae753ab99b0..f932f40302df9 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1004,7 +1004,9 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg break; case MON_IOCQ_RING_SIZE: + mutex_lock(&rp->fetch_lock); ret = rp->b_size; + mutex_unlock(&rp->fetch_lock); break; case MON_IOCT_RING_SIZE: @@ -1231,12 +1233,16 @@ static int mon_bin_vma_fault(struct vm_fault *vmf) unsigned long offset, chunk_idx; struct page *pageptr; + mutex_lock(&rp->fetch_lock); offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rp->b_size) + if (offset >= rp->b_size) { + mutex_unlock(&rp->fetch_lock); return VM_FAULT_SIGBUS; + } chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); + mutex_unlock(&rp->fetch_lock); vmf->page = pageptr; return 0; } diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 99c65b0788ff9..947579842ad78 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -774,9 +774,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) return -ENOMEM; mtu->irq = platform_get_irq(pdev, 0); - if (mtu->irq <= 0) { + if (mtu->irq < 0) { dev_err(dev, "fail to get irq number\n"); - return -ENODEV; + return mtu->irq; } dev_info(dev, "irq %d\n", mtu->irq); diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index df88123274ca7..972bf42101893 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -305,7 +305,15 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); - } else { + } else if (!(musb->int_usb & MUSB_INTR_BABBLE)){ + /* + * When babble condition happens, drvvbus interrupt + * is also generated. Ignore this drvvbus interrupt + * and let babble interrupt handler recovers the + * controller; otherwise, the host-mode flag is lost + * due to the MUSB_DEV_MODE() call below and babble + * recovery logic will not called. + */ musb->is_active = 0; MUSB_DEV_MODE(musb); otg->default_a = 0; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index 8babd318c0ed3..1ec00eae339a2 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -368,7 +368,8 @@ static int tahvo_usb_probe(struct platform_device *pdev) tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable); if (IS_ERR(tu->extcon)) { dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); - return -ENOMEM; + ret = PTR_ERR(tu->extcon); + goto err_disable_clk; } ret = devm_extcon_dev_register(&pdev->dev, tu->extcon); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 412f812522ee0..aed182d24d234 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -127,6 +127,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ + { USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ @@ -177,6 +178,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */ + { USB_DEVICE(0x18EF, 0xE030) }, /* ELV ALC 8xxx Battery Charger */ { USB_DEVICE(0x18EF, 0xE032) }, /* ELV TFD500 Data Logger */ { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 49d1b2d4606d3..d038e543c2462 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1017,6 +1017,7 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, + { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 4faa09fe308ca..8b4ecd2bd297b 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -914,6 +914,12 @@ #define ICPDAS_I7561U_PID 0x0104 #define ICPDAS_I7563U_PID 0x0105 +/* + * Airbus Defence and Space + */ +#define AIRBUS_DS_VID 0x1e8e /* Vendor ID */ +#define AIRBUS_DS_P8GR 0x6001 /* Tetra P8GR */ + /* * RT Systems programming cables for various ham radios */ diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index b2f2e87aed945..91e7e3a166a5c 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -138,6 +138,7 @@ struct garmin_data { __u8 privpkt[4*6]; spinlock_t lock; struct list_head pktlist; + struct usb_anchor write_urbs; }; @@ -905,13 +906,19 @@ static int garmin_init_session(struct usb_serial_port *port) sizeof(GARMIN_START_SESSION_REQ), 0); if (status < 0) - break; + goto err_kill_urbs; } if (status > 0) status = 0; } + return status; + +err_kill_urbs: + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); + usb_kill_urb(port->interrupt_in_urb); + return status; } @@ -930,7 +937,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&garmin_data_p->lock, flags); /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); if (garmin_data_p->state == STATE_RESET) @@ -953,7 +959,7 @@ static void garmin_close(struct usb_serial_port *port) /* shutdown our urbs */ usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); /* keep reset state so we know that we must start a new session */ if (garmin_data_p->state != STATE_RESET) @@ -1037,12 +1043,14 @@ static int garmin_write_bulk(struct usb_serial_port *port, } /* send it down the pipe */ + usb_anchor_urb(urb, &garmin_data_p->write_urbs); status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status); count = status; + usb_unanchor_urb(urb); kfree(buffer); } @@ -1401,9 +1409,16 @@ static int garmin_port_probe(struct usb_serial_port *port) garmin_data_p->state = 0; garmin_data_p->flags = 0; garmin_data_p->count = 0; + init_usb_anchor(&garmin_data_p->write_urbs); usb_set_serial_port_data(port, garmin_data_p); status = garmin_init_session(port); + if (status) + goto err_free; + + return 0; +err_free: + kfree(garmin_data_p); return status; } @@ -1413,6 +1428,7 @@ static int garmin_port_remove(struct usb_serial_port *port) { struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); kfree(garmin_data_p); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 14511d6a7d44d..3950d44b80f1c 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -189,7 +189,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); - goto exit; + return result; } /* Send activate cmd to device */ @@ -198,9 +198,14 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - failed to configure device, error code=%d\n", __func__, result); - goto exit; + goto err_kill_urb; } -exit: + + return 0; + +err_kill_urb: + usb_kill_urb(port->interrupt_in_urb); + return result; } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ba672cf4e888c..a9400458cceaa 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -236,11 +236,14 @@ static void option_instat_callback(struct urb *urb); /* These Quectel products use Qualcomm's vendor ID */ #define QUECTEL_PRODUCT_UC20 0x9003 #define QUECTEL_PRODUCT_UC15 0x9090 +/* These Yuga products use Qualcomm's vendor ID */ +#define YUGA_PRODUCT_CLM920_NC5 0x9625 #define QUECTEL_VENDOR_ID 0x2c7c /* These Quectel products use Quectel's vendor ID */ #define QUECTEL_PRODUCT_EC21 0x0121 #define QUECTEL_PRODUCT_EC25 0x0125 +#define QUECTEL_PRODUCT_BG96 0x0296 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -282,6 +285,7 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_LE922_USBCFG3 0x1043 #define TELIT_PRODUCT_LE922_USBCFG5 0x1045 #define TELIT_PRODUCT_ME910 0x1100 +#define TELIT_PRODUCT_ME910_DUAL_MODEM 0x1101 #define TELIT_PRODUCT_LE920 0x1200 #define TELIT_PRODUCT_LE910 0x1201 #define TELIT_PRODUCT_LE910_USBCFG4 0x1206 @@ -647,6 +651,11 @@ static const struct option_blacklist_info telit_me910_blacklist = { .reserved = BIT(1) | BIT(3), }; +static const struct option_blacklist_info telit_me910_dual_modem_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(3), +}; + static const struct option_blacklist_info telit_le910_blacklist = { .sendsetup = BIT(0), .reserved = BIT(1) | BIT(2), @@ -676,6 +685,10 @@ static const struct option_blacklist_info cinterion_rmnet2_blacklist = { .reserved = BIT(4) | BIT(5), }; +static const struct option_blacklist_info yuga_clm920_nc5_blacklist = { + .reserved = BIT(1) | BIT(4), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1180,11 +1193,16 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + /* Yuga products use Qualcomm vendor ID */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5), + .driver_info = (kernel_ulong_t)&yuga_clm920_nc5_blacklist }, /* Quectel products using Quectel vendor ID */ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), @@ -1244,6 +1262,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = (kernel_ulong_t)&telit_me910_blacklist }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), + .driver_info = (kernel_ulong_t)&telit_me910_dual_modem_blacklist }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index eb9928963a53c..55a8fb25ce2be 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -148,6 +148,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC7304/MC7354 */ {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ + {DEVICE_SWI(0x1199, 0x901e)}, /* Sierra Wireless EM7355 QDL */ {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ @@ -165,6 +166,8 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x9079)}, /* Sierra Wireless EM74xx */ {DEVICE_SWI(0x1199, 0x907a)}, /* Sierra Wireless EM74xx QDL */ {DEVICE_SWI(0x1199, 0x907b)}, /* Sierra Wireless EM74xx */ + {DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */ + {DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */ {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ @@ -345,6 +348,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; case 2: dev_dbg(dev, "NMEA GPS interface found\n"); + sendsetup = true; break; case 3: dev_dbg(dev, "Modem port found\n"); diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 12f4c5a91e628..c593ca8800e59 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -34,13 +34,15 @@ static const struct usb_device_id id_table[] = { }; static const struct usb_device_id dbc_id_table[] = { - { USB_DEVICE(0x1d6b, 0x0004) }, + { USB_DEVICE(0x1d6b, 0x0010) }, + { USB_DEVICE(0x1d6b, 0x0011) }, { }, }; static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(0x0525, 0x127a) }, - { USB_DEVICE(0x1d6b, 0x0004) }, + { USB_DEVICE(0x1d6b, 0x0010) }, + { USB_DEVICE(0x1d6b, 0x0011) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table_combined); diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h index 1fcd758a961f5..3734a25e09e53 100644 --- a/drivers/usb/storage/uas-detect.h +++ b/drivers/usb/storage/uas-detect.h @@ -112,6 +112,10 @@ static int uas_use_uas_driver(struct usb_interface *intf, } } + /* All Seagate disk enclosures have broken ATA pass-through support */ + if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2) + flags |= US_FL_NO_ATA_1X; + usb_stor_adjust_quirks(udev, &flags); if (flags & US_FL_IGNORE_UAS) { diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index eb06d88b41d69..9af39644561f0 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2113,6 +2113,13 @@ UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0116, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA ), +/* Reported by David Kozub */ +UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999, + "JMicron", + "JMS567", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BROKEN_FUA), + /* * Reported by Alexandre Oliva * JMicron responds to USN and several other SCSI ioctls with a diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index cde1153597930..719ec68ae3099 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -142,6 +142,13 @@ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES), +/* Reported-by: David Kozub */ +UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999, + "JMicron", + "JMS567", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BROKEN_FUA), + /* Reported-by: Hans de Goede */ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, "VIA", @@ -149,6 +156,13 @@ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_ATA_1X), +/* Reported-by: Icenowy Zheng */ +UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999, + "Norelsys", + "NS1068X", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_UAS), + /* Reported-by: Takeo Nakayama */ UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999, "JMicron", diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index c653ce533430a..720408d39f113 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -163,8 +163,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) * step 1? */ if (ud->tcp_socket) { - dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n", - ud->tcp_socket); + dev_dbg(&sdev->udev->dev, "shutdown sockfd %d\n", ud->sockfd); kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); } diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 7170404e89798..6968c906fa291 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -251,11 +251,12 @@ void stub_device_cleanup_urbs(struct stub_device *sdev) struct stub_priv *priv; struct urb *urb; - dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev); + dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n"); while ((priv = stub_priv_pop(sdev))) { urb = priv->urb; - dev_dbg(&sdev->udev->dev, "free urb %p\n", urb); + dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n", + priv->seqnum); usb_kill_urb(urb); kmem_cache_free(stub_priv_cache, priv); diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 191b176ffedfd..5b807185f79ec 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -225,9 +225,6 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev, if (priv->seqnum != pdu->u.cmd_unlink.seqnum) continue; - dev_info(&priv->urb->dev->dev, "unlink urb %p\n", - priv->urb); - /* * This matched urb is not completed yet (i.e., be in * flight in usb hcd hardware/driver). Now we are @@ -266,8 +263,8 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev, ret = usb_unlink_urb(priv->urb); if (ret != -EINPROGRESS) dev_err(&priv->urb->dev->dev, - "failed to unlink a urb %p, ret %d\n", - priv->urb, ret); + "failed to unlink a urb # %lu, ret %d\n", + priv->seqnum, ret); return 0; } @@ -336,23 +333,34 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, return priv; } -static int get_pipe(struct stub_device *sdev, int epnum, int dir) +static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu) { struct usb_device *udev = sdev->udev; struct usb_host_endpoint *ep; struct usb_endpoint_descriptor *epd = NULL; + int epnum = pdu->base.ep; + int dir = pdu->base.direction; + + if (epnum < 0 || epnum > 15) + goto err_ret; if (dir == USBIP_DIR_IN) ep = udev->ep_in[epnum & 0x7f]; else ep = udev->ep_out[epnum & 0x7f]; - if (!ep) { - dev_err(&sdev->udev->dev, "no such endpoint?, %d\n", - epnum); - BUG(); - } + if (!ep) + goto err_ret; epd = &ep->desc; + + /* validate transfer_buffer_length */ + if (pdu->u.cmd_submit.transfer_buffer_length > INT_MAX) { + dev_err(&sdev->udev->dev, + "CMD_SUBMIT: -EMSGSIZE transfer_buffer_length %d\n", + pdu->u.cmd_submit.transfer_buffer_length); + return -1; + } + if (usb_endpoint_xfer_control(epd)) { if (dir == USBIP_DIR_OUT) return usb_sndctrlpipe(udev, epnum); @@ -375,15 +383,31 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) } if (usb_endpoint_xfer_isoc(epd)) { + /* validate packet size and number of packets */ + unsigned int maxp, packets, bytes; + + maxp = usb_endpoint_maxp(epd); + maxp *= usb_endpoint_maxp_mult(epd); + bytes = pdu->u.cmd_submit.transfer_buffer_length; + packets = DIV_ROUND_UP(bytes, maxp); + + if (pdu->u.cmd_submit.number_of_packets < 0 || + pdu->u.cmd_submit.number_of_packets > packets) { + dev_err(&sdev->udev->dev, + "CMD_SUBMIT: isoc invalid num packets %d\n", + pdu->u.cmd_submit.number_of_packets); + return -1; + } if (dir == USBIP_DIR_OUT) return usb_sndisocpipe(udev, epnum); else return usb_rcvisocpipe(udev, epnum); } +err_ret: /* NOT REACHED */ - dev_err(&sdev->udev->dev, "get pipe, epnum %d\n", epnum); - return 0; + dev_err(&sdev->udev->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum); + return -1; } static void masking_bogus_flags(struct urb *urb) @@ -447,7 +471,10 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, struct stub_priv *priv; struct usbip_device *ud = &sdev->ud; struct usb_device *udev = sdev->udev; - int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); + int pipe = get_pipe(sdev, pdu); + + if (pipe == -1) + return; priv = stub_priv_alloc(sdev, pdu); if (!priv) @@ -466,7 +493,8 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, } /* allocate urb transfer buffer, if needed */ - if (pdu->u.cmd_submit.transfer_buffer_length > 0) { + if (pdu->u.cmd_submit.transfer_buffer_length > 0 && + pdu->u.cmd_submit.transfer_buffer_length <= INT_MAX) { priv->urb->transfer_buffer = kzalloc(pdu->u.cmd_submit.transfer_buffer_length, GFP_KERNEL); diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c index be50cef645d8a..96aa375b80d9c 100644 --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c @@ -102,7 +102,7 @@ void stub_complete(struct urb *urb) /* link a urb to the queue of tx. */ spin_lock_irqsave(&sdev->priv_lock, flags); if (sdev->ud.tcp_socket == NULL) { - usbip_dbg_stub_tx("ignore urb for closed connection %p", urb); + usbip_dbg_stub_tx("ignore urb for closed connection\n"); /* It will be freed in stub_device_cleanup_urbs(). */ } else if (priv->unlinking) { stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status); @@ -181,6 +181,13 @@ static int stub_send_ret_submit(struct stub_device *sdev) memset(&pdu_header, 0, sizeof(pdu_header)); memset(&msg, 0, sizeof(msg)); + if (urb->actual_length > 0 && !urb->transfer_buffer) { + dev_err(&sdev->udev->dev, + "urb: actual_length %d transfer_buffer null\n", + urb->actual_length); + return -1; + } + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) iovnum = 2 + urb->number_of_packets; else @@ -197,8 +204,8 @@ static int stub_send_ret_submit(struct stub_device *sdev) /* 1. setup usbip_header */ setup_ret_submit_pdu(&pdu_header, urb); - usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", - pdu_header.base.seqnum, urb); + usbip_dbg_stub_tx("setup txdata seqnum: %d\n", + pdu_header.base.seqnum); usbip_header_correct_endian(&pdu_header, 1); iov[iovnum].iov_base = &pdu_header; diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index 2281f3562870a..7f0d221311211 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -105,7 +105,7 @@ static void usbip_dump_usb_device(struct usb_device *udev) dev_dbg(dev, " devnum(%d) devpath(%s) usb speed(%s)", udev->devnum, udev->devpath, usb_speed_string(udev->speed)); - pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport); + pr_debug("tt hub ttport %d\n", udev->ttport); dev_dbg(dev, " "); for (i = 0; i < 16; i++) @@ -138,12 +138,8 @@ static void usbip_dump_usb_device(struct usb_device *udev) } pr_debug("\n"); - dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus); - - dev_dbg(dev, - "descriptor %p, config %p, actconfig %p, rawdescriptors %p\n", - &udev->descriptor, udev->config, - udev->actconfig, udev->rawdescriptors); + dev_dbg(dev, "parent %s, bus %s\n", dev_name(&udev->parent->dev), + udev->bus->bus_name); dev_dbg(dev, "have_langid %d, string_langid %d\n", udev->have_langid, udev->string_langid); @@ -251,9 +247,6 @@ void usbip_dump_urb(struct urb *urb) dev = &urb->dev->dev; - dev_dbg(dev, " urb :%p\n", urb); - dev_dbg(dev, " dev :%p\n", urb->dev); - usbip_dump_usb_device(urb->dev); dev_dbg(dev, " pipe :%08x ", urb->pipe); @@ -262,11 +255,9 @@ void usbip_dump_urb(struct urb *urb) dev_dbg(dev, " status :%d\n", urb->status); dev_dbg(dev, " transfer_flags :%08X\n", urb->transfer_flags); - dev_dbg(dev, " transfer_buffer :%p\n", urb->transfer_buffer); dev_dbg(dev, " transfer_buffer_length:%d\n", urb->transfer_buffer_length); dev_dbg(dev, " actual_length :%d\n", urb->actual_length); - dev_dbg(dev, " setup_packet :%p\n", urb->setup_packet); if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL) usbip_dump_usb_ctrlrequest( @@ -276,8 +267,6 @@ void usbip_dump_urb(struct urb *urb) dev_dbg(dev, " number_of_packets :%d\n", urb->number_of_packets); dev_dbg(dev, " interval :%d\n", urb->interval); dev_dbg(dev, " error_count :%d\n", urb->error_count); - dev_dbg(dev, " context :%p\n", urb->context); - dev_dbg(dev, " complete :%p\n", urb->complete); } EXPORT_SYMBOL_GPL(usbip_dump_urb); @@ -331,26 +320,20 @@ int usbip_recv(struct socket *sock, void *buf, int size) struct msghdr msg = {.msg_flags = MSG_NOSIGNAL}; int total = 0; + if (!sock || !buf || !size) + return -EINVAL; + iov_iter_kvec(&msg.msg_iter, READ|ITER_KVEC, &iov, 1, size); usbip_dbg_xmit("enter\n"); - if (!sock || !buf || !size) { - pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf, - size); - return -EINVAL; - } - do { - int sz = msg_data_left(&msg); + msg_data_left(&msg); sock->sk->sk_allocation = GFP_NOIO; result = sock_recvmsg(sock, &msg, MSG_WAITALL); - if (result <= 0) { - pr_debug("receive sock %p buf %p size %u ret %d total %d\n", - sock, buf + total, sz, result, total); + if (result <= 0) goto err; - } total += result; } while (msg_data_left(&msg)); diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index 3050fc99a417b..33737b612b1fd 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -270,6 +270,7 @@ struct usbip_device { /* lock for status */ spinlock_t lock; + int sockfd; struct socket *tcp_socket; struct task_struct *tcp_rx; diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 11b9a22799ccb..692cfdef667e7 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -670,9 +670,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag struct vhci_device *vdev; unsigned long flags; - usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", - hcd, urb, mem_flags); - if (portnum > VHCI_HC_PORTS) { pr_err("invalid port number %d\n", portnum); return -ENODEV; @@ -836,8 +833,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct vhci_device *vdev; unsigned long flags; - pr_info("dequeue a urb %p\n", urb); - spin_lock_irqsave(&vhci->lock, flags); priv = urb->hcpriv; @@ -865,7 +860,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* tcp connection is closed */ spin_lock(&vdev->priv_lock); - pr_info("device %p seems to be disconnected\n", vdev); list_del(&priv->list); kfree(priv); urb->hcpriv = NULL; @@ -877,8 +871,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) * vhci_rx will receive RET_UNLINK and give back the URB. * Otherwise, we give back it here. */ - pr_info("gives back urb %p\n", urb); - usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock_irqrestore(&vhci->lock, flags); @@ -906,8 +898,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unlink->unlink_seqnum = priv->seqnum; - pr_info("device %p seems to be still connected\n", vdev); - /* send cmd_unlink and try to cancel the pending URB in the * peer */ list_add_tail(&unlink->list, &vdev->unlink_tx); @@ -989,7 +979,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) /* need this? see stub_dev.c */ if (ud->tcp_socket) { - pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket); + pr_debug("shutdown tcp_socket %d\n", ud->sockfd); kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); } @@ -1112,7 +1102,6 @@ static int hcd_name_to_id(const char *name) static int vhci_setup(struct usb_hcd *hcd) { struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller)); - hcd->self.sg_tablesize = ~0; if (usb_hcd_is_primary_hcd(hcd)) { vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd); vhci->vhci_hcd_hs->vhci = vhci; diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index ef2f2d5ca6b2f..1343037d00f9a 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -37,24 +37,23 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) urb = priv->urb; status = urb->status; - usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n", - urb, priv, seqnum); + usbip_dbg_vhci_rx("find urb seqnum %u\n", seqnum); switch (status) { case -ENOENT: /* fall through */ case -ECONNRESET: - dev_info(&urb->dev->dev, - "urb %p was unlinked %ssynchronuously.\n", urb, - status == -ENOENT ? "" : "a"); + dev_dbg(&urb->dev->dev, + "urb seq# %u was unlinked %ssynchronuously\n", + seqnum, status == -ENOENT ? "" : "a"); break; case -EINPROGRESS: /* no info output */ break; default: - dev_info(&urb->dev->dev, - "urb %p may be in a error, status %d\n", urb, - status); + dev_dbg(&urb->dev->dev, + "urb seq# %u may be in a error, status %d\n", + seqnum, status); } list_del(&priv->list); @@ -81,8 +80,8 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, spin_unlock_irqrestore(&vdev->priv_lock, flags); if (!urb) { - pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum); - pr_info("max seqnum %d\n", + pr_err("cannot find a urb of seqnum %u max seqnum %d\n", + pdu->base.seqnum, atomic_read(&vhci_hcd->seqnum)); usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return; @@ -105,7 +104,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, if (usbip_dbg_flag_vhci_rx) usbip_dump_urb(urb); - usbip_dbg_vhci_rx("now giveback urb %p\n", urb); + usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum); spin_lock_irqsave(&vhci->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb); @@ -172,7 +171,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, pr_info("the urb (seqnum %d) was already given back\n", pdu->base.seqnum); } else { - usbip_dbg_vhci_rx("now giveback urb %p\n", urb); + usbip_dbg_vhci_rx("now giveback urb %d\n", pdu->base.seqnum); /* If unlink is successful, status is -ECONNRESET */ urb->status = pdu->u.ret_unlink.status; diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 1b9f60a22e0b4..84df63e3130d2 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -31,15 +31,20 @@ /* * output example: - * hub port sta spd dev socket local_busid - * hs 0000 004 000 00000000 c5a7bb80 1-2.3 + * hub port sta spd dev sockfd local_busid + * hs 0000 004 000 00000000 3 1-2.3 * ................................................ - * ss 0008 004 000 00000000 d8cee980 2-3.4 + * ss 0008 004 000 00000000 4 2-3.4 * ................................................ * - * IP address can be retrieved from a socket pointer address by looking - * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a - * port number and its peer IP address. + * Output includes socket fd instead of socket pointer address to avoid + * leaking kernel memory address in: + * /sys/devices/platform/vhci_hcd.0/status and in debug output. + * The socket pointer address is not used at the moment and it was made + * visible as a convenient way to find IP address from socket pointer + * address by looking up /proc/net/{tcp,tcp6}. As this opens a security + * hole, the change is made to use sockfd instead. + * */ static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev) { @@ -53,8 +58,8 @@ static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vd if (vdev->ud.status == VDEV_ST_USED) { *out += sprintf(*out, "%03u %08x ", vdev->speed, vdev->devid); - *out += sprintf(*out, "%16p %s", - vdev->ud.tcp_socket, + *out += sprintf(*out, "%u %s", + vdev->ud.sockfd, dev_name(&vdev->udev->dev)); } else { @@ -174,7 +179,8 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr, char *s = out; /* - * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2. + * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, + * thus the * 2. */ out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers); return out - s; @@ -380,6 +386,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->devid = devid; vdev->speed = speed; + vdev->ud.sockfd = sockfd; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c index 3e7878fe2fd46..a9a663a578b62 100644 --- a/drivers/usb/usbip/vhci_tx.c +++ b/drivers/usb/usbip/vhci_tx.c @@ -83,7 +83,8 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev) memset(&msg, 0, sizeof(msg)); memset(&iov, 0, sizeof(iov)); - usbip_dbg_vhci_tx("setup txdata urb %p\n", urb); + usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n", + priv->seqnum); /* 1. setup usbip_header */ setup_cmd_submit_pdu(&pdu_header, urb); diff --git a/drivers/usb/usbip/vudc_rx.c b/drivers/usb/usbip/vudc_rx.c index e429b59f6f8a6..d020e72b31225 100644 --- a/drivers/usb/usbip/vudc_rx.c +++ b/drivers/usb/usbip/vudc_rx.c @@ -132,6 +132,25 @@ static int v_recv_cmd_submit(struct vudc *udc, urb_p->new = 1; urb_p->seqnum = pdu->base.seqnum; + if (urb_p->ep->type == USB_ENDPOINT_XFER_ISOC) { + /* validate packet size and number of packets */ + unsigned int maxp, packets, bytes; + + maxp = usb_endpoint_maxp(urb_p->ep->desc); + maxp *= usb_endpoint_maxp_mult(urb_p->ep->desc); + bytes = pdu->u.cmd_submit.transfer_buffer_length; + packets = DIV_ROUND_UP(bytes, maxp); + + if (pdu->u.cmd_submit.number_of_packets < 0 || + pdu->u.cmd_submit.number_of_packets > packets) { + dev_err(&udc->gadget.dev, + "CMD_SUBMIT: isoc invalid num packets %d\n", + pdu->u.cmd_submit.number_of_packets); + ret = -EMSGSIZE; + goto free_urbp; + } + } + ret = alloc_urb_from_cmd(&urb_p->urb, pdu, urb_p->ep->type); if (ret) { usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); diff --git a/drivers/usb/usbip/vudc_tx.c b/drivers/usb/usbip/vudc_tx.c index 234661782fa07..3ab4c86486a74 100644 --- a/drivers/usb/usbip/vudc_tx.c +++ b/drivers/usb/usbip/vudc_tx.c @@ -97,6 +97,13 @@ static int v_send_ret_submit(struct vudc *udc, struct urbp *urb_p) memset(&pdu_header, 0, sizeof(pdu_header)); memset(&msg, 0, sizeof(msg)); + if (urb->actual_length > 0 && !urb->transfer_buffer) { + dev_err(&udc->gadget.dev, + "urb: actual_length %d transfer_buffer null\n", + urb->actual_length); + return -1; + } + if (urb_p->type == USB_ENDPOINT_XFER_ISOC) iovnum = 2 + urb->number_of_packets; else @@ -112,8 +119,8 @@ static int v_send_ret_submit(struct vudc *udc, struct urbp *urb_p) /* 1. setup usbip_header */ setup_ret_submit_pdu(&pdu_header, urb_p); - usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", - pdu_header.base.seqnum, urb); + usbip_dbg_stub_tx("setup txdata seqnum: %d\n", + pdu_header.base.seqnum); usbip_header_correct_endian(&pdu_header, 1); iov[iovnum].iov_base = &pdu_header; diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 5628fe114347a..91335e6de88a2 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -849,11 +849,13 @@ static int __init init_pci_cap_exp_perm(struct perm_bits *perm) /* * Allow writes to device control fields, except devctl_phantom, - * which could confuse IOMMU, and the ARI bit in devctl2, which + * which could confuse IOMMU, MPS, which can break communication + * with other physical devices, and the ARI bit in devctl2, which * is set at probe time. FLR gets virtualized via our writefn. */ p_setw(perm, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR, ~PCI_EXP_DEVCTL_PHANTOM); + PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD, + ~PCI_EXP_DEVCTL_PHANTOM); p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI); return 0; } diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 58585ec8699e8..bd15309ac5f16 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -782,16 +782,6 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out; - if (nvq->rx_array) - msg.msg_control = vhost_net_buf_consume(&nvq->rxq); - /* On overrun, truncate and discard */ - if (unlikely(headcount > UIO_MAXIOV)) { - iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); - err = sock->ops->recvmsg(sock, &msg, - 1, MSG_DONTWAIT | MSG_TRUNC); - pr_debug("Discarded rx packet: len %zd\n", sock_len); - continue; - } /* OK, now we need to know about added descriptors. */ if (!headcount) { if (unlikely(vhost_enable_notify(&net->dev, vq))) { @@ -804,6 +794,16 @@ static void handle_rx(struct vhost_net *net) * they refilled. */ goto out; } + if (nvq->rx_array) + msg.msg_control = vhost_net_buf_consume(&nvq->rxq); + /* On overrun, truncate and discard */ + if (unlikely(headcount > UIO_MAXIOV)) { + iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); + err = sock->ops->recvmsg(sock, &msg, + 1, MSG_DONTWAIT | MSG_TRUNC); + pr_debug("Discarded rx packet: len %zd\n", sock_len); + continue; + } /* We don't need to be notified again. */ iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len); fixup = msg.msg_iter; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 046f6d280af57..e47c5bc3ddcad 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -688,6 +688,7 @@ vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, struct scatterlist *sg, int sg_count) { size_t off = iter->iov_offset; + struct scatterlist *p = sg; int i, ret; for (i = 0; i < iter->nr_segs; i++) { @@ -696,8 +697,8 @@ vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write, ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write); if (ret < 0) { - for (i = 0; i < sg_count; i++) { - struct page *page = sg_page(&sg[i]); + while (p < sg) { + struct page *page = sg_page(p++); if (page) put_page(page); } diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 9bd17682655a5..1c2289ddd555a 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -79,14 +79,17 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) { unsigned int lth = pb->lth_brightness; - int duty_cycle; + u64 duty_cycle; if (pb->levels) duty_cycle = pb->levels[brightness]; else duty_cycle = brightness; - return (duty_cycle * (pb->period - lth) / pb->scale) + lth; + duty_cycle *= pb->period - lth; + do_div(duty_cycle, pb->scale); + + return duty_cycle + lth; } static int pwm_backlight_update_status(struct backlight_device *bl) diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 5f04b4096c428..6c542d0ca076e 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1681,8 +1681,10 @@ static int au1200fb_drv_probe(struct platform_device *dev) fbi = framebuffer_alloc(sizeof(struct au1200fb_device), &dev->dev); - if (!fbi) + if (!fbi) { + ret = -ENOMEM; goto failed; + } _au1200fb_infos[plane] = fbi; fbdev = fbi->par; @@ -1701,7 +1703,8 @@ static int au1200fb_drv_probe(struct platform_device *dev) if (!fbdev->fb_mem) { print_err("fail to allocate frambuffer (size: %dK))", fbdev->fb_len / 1024); - return -ENOMEM; + ret = -ENOMEM; + goto failed; } /* diff --git a/drivers/video/fbdev/controlfb.h b/drivers/video/fbdev/controlfb.h index 6026c60fc1007..261522fabdac8 100644 --- a/drivers/video/fbdev/controlfb.h +++ b/drivers/video/fbdev/controlfb.h @@ -141,5 +141,7 @@ static struct max_cmodes control_mac_modes[] = { {{ 1, 2}}, /* 1152x870, 75Hz */ {{ 0, 1}}, /* 1280x960, 75Hz */ {{ 0, 1}}, /* 1280x1024, 75Hz */ + {{ 1, 2}}, /* 1152x768, 60Hz */ + {{ 0, 1}}, /* 1600x1024, 60Hz */ }; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index ef08a104fb42c..d44f14242016e 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -769,11 +769,11 @@ static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len) for (i = 0; i < len; i++) { ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), (0x02), - (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2, - HZ); - if (ret < 1) { - pr_err("Read EDID byte %d failed err %x\n", i, ret); + usb_rcvctrlpipe(dev->udev, 0), 0x02, + (0x80 | (0x02 << 5)), i << 8, 0xA1, + rbuf, 2, USB_CTRL_GET_TIMEOUT); + if (ret < 2) { + pr_err("Read EDID byte %d failed: %d\n", i, ret); i--; break; } diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 48230a5e12f26..bf7ff3934d7ff 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -333,6 +333,8 @@ int register_virtio_device(struct virtio_device *dev) /* device_register() causes the bus infrastructure to look for a * matching driver. */ err = device_register(&dev->dev); + if (err) + ida_simple_remove(&virtio_index_ida, dev->index); out: if (err) virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 7ed417a765c70..43676313f32ba 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -21,14 +21,34 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include +#include #include +#ifdef CONFIG_FIQ_GLUE +#include +#include +#endif #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MT6397_MISC +#include +#endif #define WDT_MAX_TIMEOUT 31 #define WDT_MIN_TIMEOUT 1 @@ -47,37 +67,167 @@ #define WDT_MODE_EXRST_EN (1 << 2) #define WDT_MODE_IRQ_EN (1 << 3) #define WDT_MODE_AUTO_START (1 << 4) +#define WDT_MODE_IRQ_LVL (1 << 5) #define WDT_MODE_DUAL_EN (1 << 6) #define WDT_MODE_KEY 0x22000000 +#define WDT_STATUS 0x0c +#define WDT_NONRST_REG 0x20 +#define WDT_NONRST_REG2 0x24 + #define WDT_SWRST 0x14 #define WDT_SWRST_KEY 0x1209 +#define WDT_SWSYSRST 0x18 +#define WDT_SWSYSRST_KEY 0x88000000 + +#define WDT_REQ_MODE 0x30 +#define WDT_REQ_MODE_KEY 0x33000000 +#define WDT_REQ_IRQ_EN 0x34 +#define WDT_REQ_IRQ_KEY 0x44000000 +#define WDT_REQ_MODE_DEBUG_EN 0x80000 + + #define DRV_NAME "mtk-wdt" -#define DRV_VERSION "1.0" +#define DRV_VERSION "2.0" static bool nowayout = WATCHDOG_NOWAYOUT; static unsigned int timeout = WDT_MAX_TIMEOUT; +struct toprgu_reset { + spinlock_t lock; + void __iomem *toprgu_swrst_base; + int regofs; + struct reset_controller_dev rcdev; +}; + struct mtk_wdt_dev { struct watchdog_device wdt_dev; void __iomem *wdt_base; + int wdt_irq_id; + struct notifier_block restart_handler; + struct toprgu_reset reset_controller; }; -static int mtk_wdt_restart(struct watchdog_device *wdt_dev, - unsigned long action, void *data) +static void __iomem *toprgu_base; +static struct watchdog_device *wdt_dev; + +static int toprgu_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) { - struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); + unsigned int tmp; + unsigned long flags; + struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); + + spin_lock_irqsave(&data->lock, flags); + + tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); + tmp |= BIT(id); + tmp |= WDT_SWSYSRST_KEY; + writel(tmp, data->toprgu_swrst_base + data->regofs); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int toprgu_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + unsigned int tmp; + unsigned long flags; + struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev); + + spin_lock_irqsave(&data->lock, flags); + + tmp = __raw_readl(data->toprgu_swrst_base + data->regofs); + tmp &= ~BIT(id); + tmp |= WDT_SWSYSRST_KEY; + writel(tmp, data->toprgu_swrst_base + data->regofs); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int toprgu_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = toprgu_reset_assert(rcdev, id); + if (ret) + return ret; + + return toprgu_reset_deassert(rcdev, id); +} + +static struct reset_control_ops toprgu_reset_ops = { + .assert = toprgu_reset_assert, + .deassert = toprgu_reset_deassert, + .reset = toprgu_reset, +}; + +static void toprgu_register_reset_controller(struct platform_device *pdev, int regofs) +{ + int ret; + struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); + + spin_lock_init(&mtk_wdt->reset_controller.lock); + + mtk_wdt->reset_controller.toprgu_swrst_base = mtk_wdt->wdt_base; + mtk_wdt->reset_controller.regofs = regofs; + mtk_wdt->reset_controller.rcdev.owner = THIS_MODULE; + mtk_wdt->reset_controller.rcdev.nr_resets = 15; + mtk_wdt->reset_controller.rcdev.ops = &toprgu_reset_ops; + mtk_wdt->reset_controller.rcdev.of_node = pdev->dev.of_node; + + ret = reset_controller_register(&mtk_wdt->reset_controller.rcdev); + if (ret) + pr_err("could not register toprgu reset controller: %d\n", ret); +} + +static int mtk_reset_handler(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + struct mtk_wdt_dev *mtk_wdt; void __iomem *wdt_base; + u32 reg; + mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler); wdt_base = mtk_wdt->wdt_base; - while (1) { - writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); - mdelay(5); + /* WDT_STATUS will be cleared to zero after writing to WDT_MODE, so we backup it in WDT_NONRST_REG, + * and then print it out in mtk_wdt_probe() after reset + */ + writel(__raw_readl(wdt_base + WDT_STATUS), wdt_base + WDT_NONRST_REG); + + reg = ioread32(wdt_base + WDT_MODE); + reg &= ~(WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EN); + reg |= WDT_MODE_KEY; + iowrite32(reg, wdt_base + WDT_MODE); + + if (cmd && !strcmp(cmd, "rpmbpk")) { + iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 0), wdt_base + WDT_NONRST_REG2); + } else if (cmd && !strcmp(cmd, "recovery")) { + iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 1), wdt_base + WDT_NONRST_REG2); + #ifdef CONFIG_MT6397_MISC + mtk_misc_mark_recovery(); + #endif + } else if (cmd && !strcmp(cmd, "bootloader")) { + iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 2), wdt_base + WDT_NONRST_REG2); + #ifdef CONFIG_MT6397_MISC + mtk_misc_mark_fast(); + #endif } - return 0; + if (!arm_pm_restart) { + while (1) { + writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); + mdelay(5); + } + } + return NOTIFY_DONE; } static int mtk_wdt_ping(struct watchdog_device *wdt_dev) @@ -86,6 +236,7 @@ static int mtk_wdt_ping(struct watchdog_device *wdt_dev) void __iomem *wdt_base = mtk_wdt->wdt_base; iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); + printk_deferred("[WDK]: kick Ex WDT\n"); return 0; } @@ -137,7 +288,8 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev) return ret; reg = ioread32(wdt_base + WDT_MODE); - reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); + reg |= (WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EXRST_EN); + reg &= ~(WDT_MODE_IRQ_LVL | WDT_MODE_EXT_POL_HIGH); reg |= (WDT_MODE_EN | WDT_MODE_KEY); iowrite32(reg, wdt_base + WDT_MODE); @@ -157,13 +309,56 @@ static const struct watchdog_ops mtk_wdt_ops = { .stop = mtk_wdt_stop, .ping = mtk_wdt_ping, .set_timeout = mtk_wdt_set_timeout, - .restart = mtk_wdt_restart, }; +#ifdef CONFIG_FIQ_GLUE +static void wdt_fiq(void *arg, void *regs, void *svc_sp) +{ + unsigned int wdt_mode_val; + void __iomem *wdt_base = ((struct mtk_wdt_dev *)arg)->wdt_base; + + wdt_mode_val = __raw_readl(wdt_base + WDT_STATUS); + writel(wdt_mode_val, wdt_base + WDT_NONRST_REG); + + aee_wdt_fiq_info(arg, regs, svc_sp); +} +#else +static void wdt_report_info(void) +{ + struct task_struct *task; + + task = &init_task; + pr_debug("Qwdt: -- watchdog time out\n"); + + for_each_process(task) { + if (task->state == 0) { + pr_debug("PID: %d, name: %s\n backtrace:\n", task->pid, task->comm); + show_stack(task, NULL); + pr_debug("\n"); + } + } + + pr_debug("backtrace of current task:\n"); + show_stack(NULL, NULL); + pr_debug("Qwdt: -- watchdog time out\n"); +} + +static irqreturn_t mtk_wdt_isr(int irq, void *dev_id) +{ + pr_err("fwq mtk_wdt_isr\n"); + + wdt_report_info(); + BUG(); + + return IRQ_HANDLED; +} +#endif + static int mtk_wdt_probe(struct platform_device *pdev) { struct mtk_wdt_dev *mtk_wdt; struct resource *res; + unsigned int tmp; int err; mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL); @@ -174,9 +369,32 @@ static int mtk_wdt_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mtk_wdt->wdt_base)) return PTR_ERR(mtk_wdt->wdt_base); + pr_err("MTK_WDT_NONRST_REG(%x)\n", __raw_readl(mtk_wdt->wdt_base + WDT_NONRST_REG)); + + mtk_wdt->wdt_irq_id = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!mtk_wdt->wdt_irq_id) { + pr_err("RGU get IRQ ID failed\n"); + return -ENODEV; + } + +#ifndef CONFIG_FIQ_GLUE + err = request_irq(mtk_wdt->wdt_irq_id, (irq_handler_t)mtk_wdt_isr, IRQF_TRIGGER_NONE, DRV_NAME, mtk_wdt); +#else + mtk_wdt->wdt_irq_id = get_hardware_irq(mtk_wdt->wdt_irq_id); + err = request_fiq(mtk_wdt->wdt_irq_id, wdt_fiq, IRQF_TRIGGER_FALLING, mtk_wdt); +#endif + if (err != 0) { + pr_err("mtk_wdt_probe : failed to request irq (%d)\n", err); + return err; + } + + toprgu_base = mtk_wdt->wdt_base; + wdt_dev = &mtk_wdt->wdt_dev; + mtk_wdt->wdt_dev.info = &mtk_wdt_info; mtk_wdt->wdt_dev.ops = &mtk_wdt_ops; mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT; @@ -186,7 +404,6 @@ static int mtk_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev); watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout); - watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128); watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt); @@ -196,9 +413,40 @@ static int mtk_wdt_probe(struct platform_device *pdev) if (unlikely(err)) return err; + mtk_wdt->restart_handler.notifier_call = mtk_reset_handler; + mtk_wdt->restart_handler.priority = 128; + + if (arm_pm_restart) { + dev_info(&pdev->dev, "register restart_handler on reboot_notifier_list for psci reset\n"); + err = register_reboot_notifier(&mtk_wdt->restart_handler); + if (err != 0) + dev_warn(&pdev->dev, + "cannot register reboot notifier (err=%d)\n", err); + } else { + err = register_restart_handler(&mtk_wdt->restart_handler); + if (err) + dev_warn(&pdev->dev, + "cannot register restart handler (err=%d)\n", err); + } + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n", mtk_wdt->wdt_dev.timeout, nowayout); + writel(WDT_REQ_MODE_KEY | (__raw_readl(mtk_wdt->wdt_base + WDT_REQ_MODE) & + (~WDT_REQ_MODE_DEBUG_EN)), mtk_wdt->wdt_base + WDT_REQ_MODE); + + toprgu_register_reset_controller(pdev, WDT_SWSYSRST); + + /* enable scpsys thermal and thermal_controller request, and set to reset directly mode */ + tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_MODE) | (1 << 18) | (1 << 0); + tmp |= WDT_REQ_MODE_KEY; + iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_MODE); + + tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); + tmp &= ~((1 << 18) | (1 << 0)); + tmp |= WDT_REQ_IRQ_KEY; + iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_IRQ_EN); + return 0; } @@ -214,8 +462,12 @@ static int mtk_wdt_remove(struct platform_device *pdev) { struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); + unregister_restart_handler(&mtk_wdt->restart_handler); + watchdog_unregister_device(&mtk_wdt->wdt_dev); + reset_controller_unregister(&mtk_wdt->reset_controller.rcdev); + return 0; } @@ -267,6 +519,95 @@ static struct platform_driver mtk_wdt_driver = { module_platform_driver(mtk_wdt_driver); +static int wk_proc_cmd_read(struct seq_file *s, void *v) +{ + unsigned int enabled = 1; + + if (!(ioread32(toprgu_base + WDT_MODE) & WDT_MODE_EN)) + enabled = 0; + + seq_printf(s, "enabled timeout\n%-4d %-8d\n", enabled, wdt_dev->timeout); + + return 0; +} + +static int wk_proc_cmd_open(struct inode *inode, struct file *file) +{ + return single_open(file, wk_proc_cmd_read, NULL); +} + +static ssize_t wk_proc_cmd_write(struct file *file, const char *buf, size_t count, loff_t *data) +{ + int ret; + int enable; + int timeout; + char wk_cmd_buf[256]; + + if (count == 0) + return -1; + + if (count > 255) + count = 255; + + ret = copy_from_user(wk_cmd_buf, buf, count); + if (ret < 0) + return -1; + + wk_cmd_buf[count] = '\0'; + + pr_debug("Write %s\n", wk_cmd_buf); + + ret = sscanf(wk_cmd_buf, "%d %d", &enable, &timeout); + if (ret != 2) + pr_debug("%s: expect 2 numbers\n", __func__); + + pr_debug("[WDK] enable=%d timeout=%d\n", enable, timeout); + + if (timeout > 20 && timeout <= WDT_MAX_TIMEOUT) { + wdt_dev->timeout = timeout; + mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout); + } else { + pr_err("[WDK] The timeout(%d) should bigger than 20 and not bigger than %d\n", + timeout, WDT_MAX_TIMEOUT); + + } + + if (enable == 1) { + mtk_wdt_start(wdt_dev); + set_bit(WDOG_ACTIVE, &wdt_dev->status); + pr_err("[WDK] enable wdt\n"); + } else if (enable == 0) { + mtk_wdt_stop(wdt_dev); + clear_bit(WDOG_ACTIVE, &wdt_dev->status); + pr_err("[WDK] disable wdt\n"); + } + + return count; +} + +static const struct file_operations wk_proc_cmd_fops = { + .owner = THIS_MODULE, + .open = wk_proc_cmd_open, + .read = seq_read, + .write = wk_proc_cmd_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init wk_proc_init(void) +{ + struct proc_dir_entry *de = proc_create("wdk", 0660, NULL, &wk_proc_cmd_fops); + + if (!de) + pr_err("[wk_proc_init]: create /proc/wdk failed\n"); + + pr_debug("[WDK] Initialize proc\n"); + + return 0; +} + +late_initcall(wk_proc_init); + module_param(timeout, uint, 0); MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 2a5de610dd8fd..bdabb2765d1b3 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -483,6 +483,9 @@ static int v9fs_test_inode(struct inode *inode, void *data) if (v9inode->qid.type != st->qid.type) return 0; + + if (v9inode->qid.path != st->qid.path) + return 0; return 1; } diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 70f9887c59a90..7f6ae21a27b3c 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -87,6 +87,9 @@ static int v9fs_test_inode_dotl(struct inode *inode, void *data) if (v9inode->qid.type != st->qid.type) return 0; + + if (v9inode->qid.path != st->qid.path) + return 0; return 1; } diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 782d4d05a53ba..c7475867a52b3 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -127,6 +127,9 @@ bool afs_cm_incoming_call(struct afs_call *call) case CBProbe: call->type = &afs_SRXCBProbe; return true; + case CBProbeUuid: + call->type = &afs_SRXCBProbeUuid; + return true; case CBTellMeAboutYourself: call->type = &afs_SRXCBTellMeAboutYourself; return true; diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 0bf191f0dbafa..9f715c3edcf96 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -377,8 +377,17 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, */ tx_total_len = call->request_size; if (call->send_pages) { - tx_total_len += call->last_to - call->first_offset; - tx_total_len += (call->last - call->first) * PAGE_SIZE; + if (call->last == call->first) { + tx_total_len += call->last_to - call->first_offset; + } else { + /* It looks mathematically like you should be able to + * combine the following lines with the ones above, but + * unsigned arithmetic is fun when it wraps... + */ + tx_total_len += PAGE_SIZE - call->first_offset; + tx_total_len += call->last_to; + tx_total_len += (call->last - call->first - 1) * PAGE_SIZE; + } } /* create a call */ diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index d79ced9258614..82e8f6edfb48d 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -281,8 +281,8 @@ static int autofs4_mount_wait(const struct path *path, bool rcu_walk) pr_debug("waiting for mount name=%pd\n", path->dentry); status = autofs4_wait(sbi, path, NFY_MOUNT); pr_debug("mount wait done status=%d\n", status); - ino->last_used = jiffies; } + ino->last_used = jiffies; return status; } @@ -321,21 +321,16 @@ static struct dentry *autofs4_mountpoint_changed(struct path *path) */ if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { struct dentry *parent = dentry->d_parent; + struct autofs_info *ino; struct dentry *new; new = d_lookup(parent, &dentry->d_name); if (!new) return NULL; - if (new == dentry) - dput(new); - else { - struct autofs_info *ino; - - ino = autofs4_dentry_ino(new); - ino->last_used = jiffies; - dput(path->dentry); - path->dentry = new; - } + ino = autofs4_dentry_ino(new); + ino->last_used = jiffies; + dput(path->dentry); + path->dentry = new; } return path->dentry; } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 4ac49d038bf38..961a12dc6dc81 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -81,7 +81,8 @@ static int autofs4_write(struct autofs_sb_info *sbi, spin_unlock_irqrestore(¤t->sighand->siglock, flags); } - return (bytes > 0); + /* if 'wr' returned 0 (impossible) we assume -EIO (safe) */ + return bytes == 0 ? 0 : wr < 0 ? wr : -EIO; } static void autofs4_notify_daemon(struct autofs_sb_info *sbi, @@ -95,6 +96,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, } pkt; struct file *pipe = NULL; size_t pktsz; + int ret; pr_debug("wait id = 0x%08lx, name = %.*s, type=%d\n", (unsigned long) wq->wait_queue_token, @@ -168,8 +170,18 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, mutex_unlock(&sbi->wq_mutex); - if (autofs4_write(sbi, pipe, &pkt, pktsz)) + switch (ret = autofs4_write(sbi, pipe, &pkt, pktsz)) { + case 0: + break; + case -ENOMEM: + case -ERESTARTSYS: + /* Just fail this one */ + autofs4_wait_release(sbi, wq->wait_queue_token, ret); + break; + default: autofs4_catatonic_mode(sbi); + break; + } fput(pipe); } diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 6d49db7d86be2..e2bb2a0657419 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1032,14 +1032,17 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { ret = btrfs_inc_ref(trans, root, buf, 1); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { ret = btrfs_dec_ref(trans, root, buf, 0); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; ret = btrfs_inc_ref(trans, root, cow, 1); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; } new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; } else { @@ -1049,7 +1052,8 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; } if (new_flags != 0) { int level = btrfs_header_level(buf); @@ -1068,9 +1072,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; ret = btrfs_dec_ref(trans, root, buf, 1); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + return ret; } clean_tree_block(fs_info, buf); *last_ref = 1; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 19e4ad2f3f2e4..04f39111fafb4 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -87,6 +87,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node( spin_lock(&root->inode_lock); node = radix_tree_lookup(&root->delayed_nodes_tree, ino); + if (node) { if (btrfs_inode->delayed_node) { refcount_inc(&node->refs); /* can be accessed */ @@ -94,9 +95,30 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node( spin_unlock(&root->inode_lock); return node; } - btrfs_inode->delayed_node = node; - /* can be accessed and cached in the inode */ - refcount_add(2, &node->refs); + + /* + * It's possible that we're racing into the middle of removing + * this node from the radix tree. In this case, the refcount + * was zero and it should never go back to one. Just return + * NULL like it was never in the radix at all; our release + * function is in the process of removing it. + * + * Some implementations of refcount_inc refuse to bump the + * refcount once it has hit zero. If we don't do this dance + * here, refcount_inc() may decide to just WARN_ONCE() instead + * of actually bumping the refcount. + * + * If this node is properly in the radix, we want to bump the + * refcount twice, once for the inode and once for this get + * operation. + */ + if (refcount_inc_not_zero(&node->refs)) { + refcount_inc(&node->refs); + btrfs_inode->delayed_node = node; + } else { + node = NULL; + } + spin_unlock(&root->inode_lock); return node; } @@ -254,17 +276,18 @@ static void __btrfs_release_delayed_node( mutex_unlock(&delayed_node->mutex); if (refcount_dec_and_test(&delayed_node->refs)) { - bool free = false; struct btrfs_root *root = delayed_node->root; + spin_lock(&root->inode_lock); - if (refcount_read(&delayed_node->refs) == 0) { - radix_tree_delete(&root->delayed_nodes_tree, - delayed_node->inode_id); - free = true; - } + /* + * Once our refcount goes to zero, nobody is allowed to bump it + * back up. We can delete it now. + */ + ASSERT(refcount_read(&delayed_node->refs) == 0); + radix_tree_delete(&root->delayed_nodes_tree, + delayed_node->inode_id); spin_unlock(&root->inode_lock); - if (free) - kmem_cache_free(delayed_node_cache, delayed_node); + kmem_cache_free(delayed_node_cache, delayed_node); } } @@ -1654,28 +1677,18 @@ void btrfs_readdir_put_delayed_items(struct inode *inode, int btrfs_should_delete_dir_index(struct list_head *del_list, u64 index) { - struct btrfs_delayed_item *curr, *next; - int ret; - - if (list_empty(del_list)) - return 0; + struct btrfs_delayed_item *curr; + int ret = 0; - list_for_each_entry_safe(curr, next, del_list, readdir_list) { + list_for_each_entry(curr, del_list, readdir_list) { if (curr->key.offset > index) break; - - list_del(&curr->readdir_list); - ret = (curr->key.offset == index); - - if (refcount_dec_and_test(&curr->refs)) - kfree(curr); - - if (ret) - return 1; - else - continue; + if (curr->key.offset == index) { + ret = 1; + break; + } } - return 0; + return ret; } /* diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e2d7e86b51d1b..d227d8514b256 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3526,13 +3526,6 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, goto again; } - /* We've already setup this transaction, go ahead and exit */ - if (block_group->cache_generation == trans->transid && - i_size_read(inode)) { - dcs = BTRFS_DC_SETUP; - goto out_put; - } - /* * We want to set the generation to 0, that way if anything goes wrong * from here on out we know not to trust this cache when we load up next @@ -3556,6 +3549,13 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, } WARN_ON(ret); + /* We've already setup this transaction, go ahead and exit */ + if (block_group->cache_generation == trans->transid && + i_size_read(inode)) { + dcs = BTRFS_DC_SETUP; + goto out_put; + } + if (i_size_read(inode) > 0) { ret = btrfs_check_trunc_cache_free_space(fs_info, &fs_info->global_block_rsv); @@ -4919,6 +4919,13 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim, } } +struct reserve_ticket { + u64 bytes; + int error; + struct list_head list; + wait_queue_head_t wait; +}; + /** * maybe_commit_transaction - possibly commit the transaction if its ok to * @root - the root we're allocating for @@ -4930,18 +4937,29 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim, * will return -ENOSPC. */ static int may_commit_transaction(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - u64 bytes, int force) + struct btrfs_space_info *space_info) { + struct reserve_ticket *ticket = NULL; struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_block_rsv; struct btrfs_trans_handle *trans; + u64 bytes; trans = (struct btrfs_trans_handle *)current->journal_info; if (trans) return -EAGAIN; - if (force) - goto commit; + spin_lock(&space_info->lock); + if (!list_empty(&space_info->priority_tickets)) + ticket = list_first_entry(&space_info->priority_tickets, + struct reserve_ticket, list); + else if (!list_empty(&space_info->tickets)) + ticket = list_first_entry(&space_info->tickets, + struct reserve_ticket, list); + bytes = (ticket) ? ticket->bytes : 0; + spin_unlock(&space_info->lock); + + if (!bytes) + return 0; /* See if there is enough pinned space to make this reservation */ if (percpu_counter_compare(&space_info->total_bytes_pinned, @@ -4956,8 +4974,12 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info, return -ENOSPC; spin_lock(&delayed_rsv->lock); + if (delayed_rsv->size > bytes) + bytes = 0; + else + bytes -= delayed_rsv->size; if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes - delayed_rsv->size) < 0) { + bytes) < 0) { spin_unlock(&delayed_rsv->lock); return -ENOSPC; } @@ -4971,13 +4993,6 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info, return btrfs_commit_transaction(trans); } -struct reserve_ticket { - u64 bytes; - int error; - struct list_head list; - wait_queue_head_t wait; -}; - /* * Try to flush some data based on policy set by @state. This is only advisory * and may fail for various reasons. The caller is supposed to examine the @@ -5027,8 +5042,7 @@ static void flush_space(struct btrfs_fs_info *fs_info, ret = 0; break; case COMMIT_TRANS: - ret = may_commit_transaction(fs_info, space_info, - num_bytes, 0); + ret = may_commit_transaction(fs_info, space_info); break; default: ret = -ENOSPC; @@ -9269,6 +9283,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, ret = btrfs_del_root(trans, fs_info, &root->root_key); if (ret) { btrfs_abort_transaction(trans, ret); + err = ret; goto out_end_trans; } diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 6c7a49faf4e06..1f1338d523038 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1842,8 +1842,13 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); + if (ret < 0) { + btrfs_end_transaction(trans); + goto out_reset; + } + + ret = btrfs_commit_transaction(trans); - btrfs_commit_transaction(trans); out_reset: if (ret) btrfs_set_root_flags(&root->root_item, root_flags); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 161694b660385..e8f5e24325f33 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -202,7 +202,6 @@ static struct ratelimit_state printk_limits[] = { void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) { - struct super_block *sb = fs_info->sb; char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0"; struct va_format vaf; va_list args; @@ -228,7 +227,8 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) vaf.va = &args; if (__ratelimit(ratelimit)) - printk("%sBTRFS %s (device %s): %pV\n", lvl, type, sb->s_id, &vaf); + printk("%sBTRFS %s (device %s): %pV\n", lvl, type, + fs_info ? fs_info->sb->s_id : "", &vaf); va_end(args); } diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index 1458bb0ea124a..8444a018cca29 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c @@ -500,7 +500,8 @@ static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, path = btrfs_alloc_path(); if (!path) { test_msg("Couldn't allocate path\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } ret = add_block_group_free_space(&trans, root->fs_info, cache); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b39737568c223..0c11121a8ace7 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2501,6 +2501,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path return ret; error_trans: + if (seeding_dev) + sb->s_flags |= MS_RDONLY; btrfs_end_transaction(trans); rcu_string_free(device->name); btrfs_sysfs_rm_device_link(fs_info->fs_devices, device); @@ -6144,7 +6146,10 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; bio->bi_iter.bi_sector = logical >> 9; - bio->bi_status = BLK_STS_IOERR; + if (atomic_read(&bbio->error) > bbio->max_errors) + bio->bi_status = BLK_STS_IOERR; + else + bio->bi_status = BLK_STS_OK; btrfs_end_bbio(bbio, bio); } } diff --git a/fs/buffer.c b/fs/buffer.c index 170df856bdb99..b96f3b98a6ef9 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3055,8 +3055,16 @@ void guard_bio_eod(int op, struct bio *bio) sector_t maxsector; struct bio_vec *bvec = &bio->bi_io_vec[bio->bi_vcnt - 1]; unsigned truncated_bytes; + struct hd_struct *part; + + rcu_read_lock(); + part = __disk_get_part(bio->bi_disk, bio->bi_partno); + if (part) + maxsector = part_nr_sects_read(part); + else + maxsector = get_capacity(bio->bi_disk); + rcu_read_unlock(); - maxsector = get_capacity(bio->bi_disk); if (!maxsector) return; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 0687ab3c32674..bf378ddca4dba 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1428,6 +1428,29 @@ static int __close_session(struct ceph_mds_client *mdsc, return request_close_session(mdsc, session); } +static bool drop_negative_children(struct dentry *dentry) +{ + struct dentry *child; + bool all_negative = true; + + if (!d_is_dir(dentry)) + goto out; + + spin_lock(&dentry->d_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + if (d_really_is_positive(child)) { + all_negative = false; + break; + } + } + spin_unlock(&dentry->d_lock); + + if (all_negative) + shrink_dcache_parent(dentry); +out: + return all_negative; +} + /* * Trim old(er) caps. * @@ -1473,16 +1496,27 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) if ((used | wanted) & ~oissued & mine) goto out; /* we need these caps */ - session->s_trim_caps--; if (oissued) { /* we aren't the only cap.. just remove us */ __ceph_remove_cap(cap, true); + session->s_trim_caps--; } else { + struct dentry *dentry; /* try dropping referring dentries */ spin_unlock(&ci->i_ceph_lock); - d_prune_aliases(inode); - dout("trim_caps_cb %p cap %p pruned, count now %d\n", - inode, cap, atomic_read(&inode->i_count)); + dentry = d_find_any_alias(inode); + if (dentry && drop_negative_children(dentry)) { + int count; + dput(dentry); + d_prune_aliases(inode); + count = atomic_read(&inode->i_count); + if (count == 1) + session->s_trim_caps--; + dout("trim_caps_cb %p cap %p pruned, count now %d\n", + inode, cap, count); + } else { + dput(dentry); + } return 0; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 5331631386a23..01346b8b6edb3 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2678,27 +2678,27 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, cifs_small_buf_release(req); rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; - shdr = get_sync_hdr(rsp); - if (shdr->Status == STATUS_END_OF_FILE) { + if (rc) { + if (rc != -ENODATA) { + cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); + cifs_dbg(VFS, "Send error in read = %d\n", rc); + } free_rsp_buf(resp_buftype, rsp_iov.iov_base); - return 0; + return rc == -ENODATA ? 0 : rc; } - if (rc) { - cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); - cifs_dbg(VFS, "Send error in read = %d\n", rc); - } else { - *nbytes = le32_to_cpu(rsp->DataLength); - if ((*nbytes > CIFS_MAX_MSGSIZE) || - (*nbytes > io_parms->length)) { - cifs_dbg(FYI, "bad length %d for count %d\n", - *nbytes, io_parms->length); - rc = -EIO; - *nbytes = 0; - } + *nbytes = le32_to_cpu(rsp->DataLength); + if ((*nbytes > CIFS_MAX_MSGSIZE) || + (*nbytes > io_parms->length)) { + cifs_dbg(FYI, "bad length %d for count %d\n", + *nbytes, io_parms->length); + rc = -EIO; + *nbytes = 0; } + shdr = get_sync_hdr(rsp); + if (*buf) { memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes); free_rsp_buf(resp_buftype, rsp_iov.iov_base); diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index a37f003530d73..1175a1722411d 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -447,8 +447,7 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid) UPARG(CODA_FSYNC); inp->coda_fsync.VFid = *fid; - error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs), - &outsize, inp); + error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error; diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index c7835df7e7b84..d262a93d9b31c 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -410,11 +410,8 @@ int fscrypt_initialize(unsigned int cop_flags) { int i, res = -ENOMEM; - /* - * No need to allocate a bounce page pool if there already is one or - * this FS won't use it. - */ - if (cop_flags & FS_CFLG_OWN_PAGES || fscrypt_bounce_page_pool) + /* No need to allocate a bounce page pool if this FS won't use it. */ + if (cop_flags & FS_CFLG_OWN_PAGES) return 0; mutex_lock(&fscrypt_init_mutex); diff --git a/fs/dax.c b/fs/dax.c index f001d8c72a065..191306cd8b6b5 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -1327,7 +1327,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, * this is a reliable test. */ pgoff = linear_page_index(vma, pmd_addr); - max_pgoff = (i_size_read(inode) - 1) >> PAGE_SHIFT; + max_pgoff = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); trace_dax_pmd_fault(inode, vmf, max_pgoff, 0); @@ -1351,13 +1351,13 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, if ((pmd_addr + PMD_SIZE) > vma->vm_end) goto fallback; - if (pgoff > max_pgoff) { + if (pgoff >= max_pgoff) { result = VM_FAULT_SIGBUS; goto out; } /* If the PMD would extend beyond the file size */ - if ((pgoff | PG_PMD_COLOUR) > max_pgoff) + if ((pgoff | PG_PMD_COLOUR) >= max_pgoff) goto fallback; /* diff --git a/fs/dcache.c b/fs/dcache.c index f90141387f01e..34c852af215c0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -231,7 +231,7 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c { /* * Be careful about RCU walk racing with rename: - * use 'lockless_dereference' to fetch the name pointer. + * use 'READ_ONCE' to fetch the name pointer. * * NOTE! Even if a rename will mean that the length * was not loaded atomically, we don't care. The @@ -245,7 +245,7 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c * early because the data cannot match (there can * be no NUL in the ct/tcount data) */ - const unsigned char *cs = lockless_dereference(dentry->d_name.name); + const unsigned char *cs = READ_ONCE(dentry->d_name.name); return dentry_string_cmp(cs, ct, tcount); } diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 286f10b0363b1..4f457d5c49331 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -442,15 +442,16 @@ void ecryptfs_release_messaging(void) } if (ecryptfs_daemon_hash) { struct ecryptfs_daemon *daemon; + struct hlist_node *n; int i; mutex_lock(&ecryptfs_daemon_hash_mux); for (i = 0; i < (1 << ecryptfs_hash_bits); i++) { int rc; - hlist_for_each_entry(daemon, - &ecryptfs_daemon_hash[i], - euid_chain) { + hlist_for_each_entry_safe(daemon, n, + &ecryptfs_daemon_hash[i], + euid_chain) { rc = ecryptfs_exorcise_daemon(daemon); if (rc) printk(KERN_ERR "%s: Error whilst " diff --git a/fs/exec.c b/fs/exec.c index 3e14ba25f678b..acec119fcc314 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1350,9 +1350,14 @@ void setup_new_exec(struct linux_binprm * bprm) current->sas_ss_sp = current->sas_ss_size = 0; - /* Figure out dumpability. */ + /* + * Figure out dumpability. Note that this checking only of current + * is wrong, but userspace depends on it. This should be testing + * bprm->secureexec instead. + */ if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || - bprm->secureexec) + !(uid_eq(current_euid(), current_uid()) && + gid_eq(current_egid(), current_gid()))) set_dumpable(current->mm, suid_dumpable); else set_dumpable(current->mm, SUID_DUMP_USER); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 97f0fd06728d7..c941251ac0c00 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4722,6 +4722,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, EXT4_INODE_EOFBLOCKS); } ext4_mark_inode_dirty(handle, inode); + ext4_update_inode_fsync_trans(handle, inode, 1); ret2 = ext4_journal_stop(handle); if (ret2) break; @@ -4794,7 +4795,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, } if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { + (offset + len > i_size_read(inode) || + offset + len > EXT4_I(inode)->i_disksize)) { new_size = offset + len; ret = inode_newsize_ok(inode, new_size); if (ret) @@ -4965,7 +4967,8 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) } if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { + (offset + len > i_size_read(inode) || + offset + len > EXT4_I(inode)->i_disksize)) { new_size = offset + len; ret = inode_newsize_ok(inode, new_size); if (ret) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index c5f697a3fad43..207588dc803e0 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -816,6 +816,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, #ifdef CONFIG_EXT4_FS_POSIX_ACL struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(p)) + return ERR_CAST(p); if (p) { int acl_size = p->a_count * sizeof(ext4_acl_entry); diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 28c5c3abddb30..fd9501977f1c7 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -302,11 +302,6 @@ static int ext4_create_inline_data(handle_t *handle, EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE; ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA); - /* - * Propagate changes to inode->i_flags as well - e.g. S_DAX may - * get cleared - */ - ext4_set_inode_flags(inode); get_bh(is.iloc.bh); error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); @@ -451,11 +446,6 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, } } ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA); - /* - * Propagate changes to inode->i_flags as well - e.g. S_DAX may - * get set. - */ - ext4_set_inode_flags(inode); get_bh(is.iloc.bh); error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 90afeb7293a6b..ea2ccc524bd98 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -149,6 +149,15 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, */ int ext4_inode_is_fast_symlink(struct inode *inode) { + if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { + int ea_blocks = EXT4_I(inode)->i_file_acl ? + EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; + + if (ext4_has_inline_data(inode)) + return 0; + + return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); + } return S_ISLNK(inode->i_mode) && inode->i_size && (inode->i_size < EXT4_N_BLOCKS * 4); } @@ -5967,11 +5976,6 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); } ext4_set_aops(inode); - /* - * Update inode->i_flags after EXT4_INODE_JOURNAL_DATA was updated. - * E.g. S_DAX may get cleared / set. - */ - ext4_set_inode_flags(inode); jbd2_journal_unlock_updates(journal); percpu_up_write(&sbi->s_journal_flag_rwsem); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 75d83471f65c4..d97f40396765f 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -291,10 +291,20 @@ static int ext4_ioctl_setflags(struct inode *inode, if (err) goto flags_out; - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { + /* + * Changes to the journaling mode can cause unsafe changes to + * S_DAX if we are using the DAX mount option. + */ + if (test_opt(inode->i_sb, DAX)) { + err = -EBUSY; + goto flags_out; + } + err = ext4_change_inode_journal_flag(inode, jflag); - if (err) - goto flags_out; + if (err) + goto flags_out; + } if (migrate) { if (flags & EXT4_EXTENTS_FL) err = ext4_ext_migrate(inode); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index bd48a8d83961b..fccf295fcb03a 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1399,6 +1399,10 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, "falling back\n")); } nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); + if (!nblocks) { + ret = NULL; + goto cleanup_and_exit; + } start = EXT4_I(dir)->i_dir_start_lookup; if (start >= nblocks) start = 0; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b0915b734a381..f29351c666109 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3708,6 +3708,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } if (sbi->s_mount_opt & EXT4_MOUNT_DAX) { + if (ext4_has_feature_inline_data(sb)) { + ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem" + " that may contain inline data"); + goto failed_mount; + } err = bdev_dax_supported(sb, blocksize); if (err) goto failed_mount; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 517e112c8a9a9..b8372095ba0a6 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -683,6 +683,12 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, STATX_ATTR_NODUMP); generic_fillattr(inode, stat); + + /* we need to show initial sectors used for inline_data/dentries */ + if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) || + f2fs_has_inline_dentry(inode)) + stat->blocks += (stat->size + 511) >> 9; + return 0; } @@ -2691,6 +2697,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) err = f2fs_preallocate_blocks(iocb, from); if (err) { + clear_inode_flag(inode, FI_NO_PREALLOC); inode_unlock(inode); return err; } diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 30c52394a7adb..c7a4dee206b90 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -779,7 +779,7 @@ static void __exit fat_destroy_inodecache(void) static int fat_remount(struct super_block *sb, int *flags, char *data) { - int new_rdonly; + bool new_rdonly; struct msdos_sb_info *sbi = MSDOS_SB(sb); *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); diff --git a/fs/fcntl.c b/fs/fcntl.c index 8d78ffd7b399d..0345a46b88565 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -563,6 +563,9 @@ static int put_compat_flock64(const struct flock *kfl, struct compat_flock64 __u { struct compat_flock64 fl; + BUILD_BUG_ON(sizeof(kfl->l_start) > sizeof(ufl->l_start)); + BUILD_BUG_ON(sizeof(kfl->l_len) > sizeof(ufl->l_len)); + memset(&fl, 0, sizeof(struct compat_flock64)); copy_flock_fields(&fl, kfl); if (copy_to_user(ufl, &fl, sizeof(struct compat_flock64))) @@ -632,9 +635,8 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, if (err) break; err = fixup_compat_flock(&flock); - if (err) - return err; - err = put_compat_flock(&flock, compat_ptr(arg)); + if (!err) + err = put_compat_flock(&flock, compat_ptr(arg)); break; case F_GETLK64: case F_OFD_GETLK: @@ -642,12 +644,8 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, if (err) break; err = fcntl_getlk(f.file, convert_fcntl_cmd(cmd), &flock); - if (err) - break; - err = fixup_compat_flock(&flock); - if (err) - return err; - err = put_compat_flock64(&flock, compat_ptr(arg)); + if (!err) + err = put_compat_flock64(&flock, compat_ptr(arg)); break; case F_SETLK: case F_SETLKW: diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 33a0cb5701a33..2a29cf3371f69 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -256,7 +256,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) goto out; } if ((flags ^ new_flags) & GFS2_DIF_JDATA) { - if (flags & GFS2_DIF_JDATA) + if (new_flags & GFS2_DIF_JDATA) gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); error = filemap_fdatawrite(inode->i_mapping); if (error) @@ -264,6 +264,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) error = filemap_fdatawait(inode->i_mapping); if (error) goto out; + if (new_flags & GFS2_DIF_JDATA) + gfs2_ordered_del_inode(ip); } error = gfs2_trans_begin(sdp, RES_DINODE, 0); if (error) diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 57d4c3e2e94a4..8e42b4fbefdc3 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -107,7 +107,7 @@ static inline unsigned int isonum_733(char *p) /* Ignore bigendian datum due to broken mastering programs */ return get_unaligned_le32(p); } -extern int iso_date(char *, int); +extern int iso_date(u8 *, int); struct inode; /* To make gcc happy */ diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h index ef03625431bbf..ac5cc587d718f 100644 --- a/fs/isofs/rock.h +++ b/fs/isofs/rock.h @@ -66,7 +66,7 @@ struct RR_PL_s { }; struct stamp { - char time[7]; + __u8 time[7]; /* actually 6 unsigned, 1 signed */ } __attribute__ ((packed)); struct RR_TF_s { diff --git a/fs/isofs/util.c b/fs/isofs/util.c index 42544bf0e2223..e88dba7216618 100644 --- a/fs/isofs/util.c +++ b/fs/isofs/util.c @@ -16,7 +16,7 @@ * to GMT. Thus we should always be correct. */ -int iso_date(char * p, int flag) +int iso_date(u8 *p, int flag) { int year, month, day, hour, minute, second, tz; int crtime; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index b995bdc139768..45e96549ebd2a 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -274,6 +274,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) if (ln->nlmsvc_users) { if (--ln->nlmsvc_users == 0) { nlm_shutdown_hosts_net(net); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); svc_shutdown_net(serv, net); dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); } @@ -369,6 +371,7 @@ static int lockd_start_svc(struct svc_serv *serv) printk(KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n", error); + lockd_unregister_notifiers(); goto out_rqst; } @@ -459,13 +462,16 @@ int lockd_up(struct net *net) } error = lockd_up_net(serv, net); - if (error < 0) - goto err_net; + if (error < 0) { + lockd_unregister_notifiers(); + goto err_put; + } error = lockd_start_svc(serv); - if (error < 0) - goto err_start; - + if (error < 0) { + lockd_down_net(serv, net); + goto err_put; + } nlmsvc_users++; /* * Note: svc_serv structures have an initial use count of 1, @@ -476,12 +482,6 @@ int lockd_up(struct net *net) err_create: mutex_unlock(&nlmsvc_mutex); return error; - -err_start: - lockd_down_net(serv, net); -err_net: - lockd_unregister_notifiers(); - goto err_put; } EXPORT_SYMBOL_GPL(lockd_up); diff --git a/fs/namei.c b/fs/namei.c index ed8b9488a890c..62a0db6e6725e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1129,18 +1129,9 @@ static int follow_automount(struct path *path, struct nameidata *nd, * of the daemon to instantiate them before they can be used. */ if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE | - LOOKUP_AUTOMOUNT))) { - /* Positive dentry that isn't meant to trigger an - * automount, EISDIR will allow it to be used, - * otherwise there's no mount here "now" so return - * ENOENT. - */ - if (path->dentry->d_inode) - return -EISDIR; - else - return -ENOENT; - } + LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) && + path->dentry->d_inode) + return -EISDIR; if (path->dentry->d_sb->s_user_ns != &init_user_ns) return -EACCES; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5ceaeb1f6fb69..bf2c43635062b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1241,8 +1241,7 @@ static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags) return 0; } - if (nfs_mapping_need_revalidate_inode(inode)) - error = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + error = nfs_lookup_verify_inode(inode, flags); dfprintk(LOOKUPCACHE, "NFS: %s: inode %lu is %s\n", __func__, inode->i_ino, error ? "invalid" : "valid"); return !error; @@ -1393,6 +1392,7 @@ static int nfs4_lookup_revalidate(struct dentry *, unsigned int); const struct dentry_operations nfs4_dentry_operations = { .d_revalidate = nfs4_lookup_revalidate, + .d_weak_revalidate = nfs_weak_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, .d_automount = nfs_d_automount, @@ -2064,7 +2064,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, * should mark the directories for revalidation. */ d_move(old_dentry, new_dentry); - nfs_set_verifier(new_dentry, + nfs_set_verifier(old_dentry, nfs_save_change_attribute(new_dir)); } else if (error == -ENOENT) nfs_dentry_handle_enoent(old_dentry); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0214dd1e10602..81cca49a83750 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -829,23 +829,9 @@ int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK) is_local = 1; - /* - * VFS doesn't require the open mode to match a flock() lock's type. - * NFS, however, may simulate flock() locking with posix locking which - * requires the open mode to match the lock type. - */ - switch (fl->fl_type) { - case F_UNLCK: + /* We're simulating flock() locks using posix locks on the server */ + if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - return -EBADF; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) - return -EBADF; - } - return do_setlk(filp, cmd, fl, is_local); } EXPORT_SYMBOL_GPL(nfs_flock); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f90090e8c959b..2241d52710f7b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -254,15 +254,12 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE }; const u32 nfs4_fs_locations_bitmap[3] = { - FATTR4_WORD0_TYPE - | FATTR4_WORD0_CHANGE + FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID | FATTR4_WORD0_FS_LOCATIONS, - FATTR4_WORD1_MODE - | FATTR4_WORD1_NUMLINKS - | FATTR4_WORD1_OWNER + FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV | FATTR4_WORD1_SPACE_USED @@ -6568,6 +6565,20 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags)) return -ENOLCK; + /* + * Don't rely on the VFS having checked the file open mode, + * since it won't do this for flock() locks. + */ + switch (request->fl_type) { + case F_RDLCK: + if (!(filp->f_mode & FMODE_READ)) + return -EBADF; + break; + case F_WRLCK: + if (!(filp->f_mode & FMODE_WRITE)) + return -EBADF; + } + status = nfs4_set_lock_state(state, request); if (status != 0) return status; @@ -6763,9 +6774,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, struct page *page) { struct nfs_server *server = NFS_SERVER(dir); - u32 bitmask[3] = { - [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, - }; + u32 bitmask[3]; struct nfs4_fs_locations_arg args = { .dir_fh = NFS_FH(dir), .name = name, @@ -6784,12 +6793,15 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, dprintk("%s: start\n", __func__); + bitmask[0] = nfs4_fattr_bitmap[0] | FATTR4_WORD0_FS_LOCATIONS; + bitmask[1] = nfs4_fattr_bitmap[1]; + /* Ask for the fileid of the absent filesystem if mounted_on_fileid * is not supported */ if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) - bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; + bitmask[0] &= ~FATTR4_WORD0_FILEID; else - bitmask[0] |= FATTR4_WORD0_FILEID; + bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; nfs_fattr_init(&fs_locations->fattr); fs_locations->server = server; diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index e7c6275519b09..71d2ca04a9f87 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -202,17 +202,13 @@ DECLARE_EVENT_CLASS(nfs4_clientid_event, TP_ARGS(clp, error), TP_STRUCT__entry( - __string(dstaddr, - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR)) + __string(dstaddr, clp->cl_hostname) __field(int, error) ), TP_fast_assign( __entry->error = error; - __assign_str(dstaddr, - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR)); + __assign_str(dstaddr, clp->cl_hostname); ), TP_printk( @@ -1133,9 +1129,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event, __field(dev_t, dev) __field(u32, fhandle) __field(u64, fileid) - __string(dstaddr, clp ? - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR) : "unknown") + __string(dstaddr, clp ? clp->cl_hostname : "unknown") ), TP_fast_assign( @@ -1148,9 +1142,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event, __entry->fileid = 0; __entry->dev = 0; } - __assign_str(dstaddr, clp ? - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR) : "unknown") + __assign_str(dstaddr, clp ? clp->cl_hostname : "unknown") ), TP_printk( @@ -1192,9 +1184,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event, __field(dev_t, dev) __field(u32, fhandle) __field(u64, fileid) - __string(dstaddr, clp ? - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR) : "unknown") + __string(dstaddr, clp ? clp->cl_hostname : "unknown") __field(int, stateid_seq) __field(u32, stateid_hash) ), @@ -1209,9 +1199,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event, __entry->fileid = 0; __entry->dev = 0; } - __assign_str(dstaddr, clp ? - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR) : "unknown") + __assign_str(dstaddr, clp ? clp->cl_hostname : "unknown") __entry->stateid_seq = be32_to_cpu(stateid->seqid); __entry->stateid_hash = diff --git a/fs/nfs/super.c b/fs/nfs/super.c index c9d24bae30251..216f67d628b3c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1332,7 +1332,7 @@ static int nfs_parse_mount_options(char *raw, mnt->options |= NFS_OPTION_MIGRATION; break; case Opt_nomigration: - mnt->options &= NFS_OPTION_MIGRATION; + mnt->options &= ~NFS_OPTION_MIGRATION; break; /* diff --git a/fs/nfs/write.c b/fs/nfs/write.c index babebbccae2a0..de325804941d1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1889,6 +1889,8 @@ int nfs_commit_inode(struct inode *inode, int how) if (res) error = nfs_generic_commit_list(inode, &head, how, &cinfo); nfs_commit_end(cinfo.mds); + if (res == 0) + return res; if (error < 0) goto out_error; if (!may_wait) diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 697f8ae7792d1..fdf2aad734709 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -61,6 +61,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) else gi->gid[i] = rqgi->gid[i]; } + + /* Each thread allocates its own gi, no race */ + groups_sort(gi); } else { gi = get_group_info(rqgi); } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0c04f81aa63b2..a439a70177a46 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3512,7 +3512,9 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) /* ignore lock owners */ if (local->st_stateowner->so_is_open_owner == 0) continue; - if (local->st_stateowner == &oo->oo_owner) { + if (local->st_stateowner != &oo->oo_owner) + continue; + if (local->st_stid.sc_type == NFS4_OPEN_STID) { ret = local; atomic_inc(&ret->st_stid.sc_count); break; @@ -3521,6 +3523,52 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) return ret; } +static __be32 +nfsd4_verify_open_stid(struct nfs4_stid *s) +{ + __be32 ret = nfs_ok; + + switch (s->sc_type) { + default: + break; + case NFS4_CLOSED_STID: + case NFS4_CLOSED_DELEG_STID: + ret = nfserr_bad_stateid; + break; + case NFS4_REVOKED_DELEG_STID: + ret = nfserr_deleg_revoked; + } + return ret; +} + +/* Lock the stateid st_mutex, and deal with races with CLOSE */ +static __be32 +nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) +{ + __be32 ret; + + mutex_lock(&stp->st_mutex); + ret = nfsd4_verify_open_stid(&stp->st_stid); + if (ret != nfs_ok) + mutex_unlock(&stp->st_mutex); + return ret; +} + +static struct nfs4_ol_stateid * +nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) +{ + struct nfs4_ol_stateid *stp; + for (;;) { + spin_lock(&fp->fi_lock); + stp = nfsd4_find_existing_open(fp, open); + spin_unlock(&fp->fi_lock); + if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) + break; + nfs4_put_stid(&stp->st_stid); + } + return stp; +} + static struct nfs4_openowner * alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, struct nfsd4_compound_state *cstate) @@ -3565,6 +3613,7 @@ init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) mutex_init(&stp->st_mutex); mutex_lock(&stp->st_mutex); +retry: spin_lock(&oo->oo_owner.so_client->cl_lock); spin_lock(&fp->fi_lock); @@ -3589,7 +3638,11 @@ init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) spin_unlock(&fp->fi_lock); spin_unlock(&oo->oo_owner.so_client->cl_lock); if (retstp) { - mutex_lock(&retstp->st_mutex); + /* Handle races with CLOSE */ + if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { + nfs4_put_stid(&retstp->st_stid); + goto retry; + } /* To keep mutex tracking happy */ mutex_unlock(&stp->st_mutex); stp = retstp; @@ -3966,7 +4019,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei { struct nfs4_stid *ret; - ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); + ret = find_stateid_by_type(cl, s, + NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); if (!ret) return NULL; return delegstateid(ret); @@ -3989,6 +4043,12 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); if (deleg == NULL) goto out; + if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { + nfs4_put_stid(&deleg->dl_stid); + if (cl->cl_minorversion) + status = nfserr_deleg_revoked; + goto out; + } flags = share_access_to_flags(open->op_share_access); status = nfs4_check_delegmode(deleg, flags); if (status) { @@ -4392,6 +4452,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf struct nfs4_ol_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; __be32 status; + bool new_stp = false; /* * Lookup file; if found, lookup stateid and check open request, @@ -4403,9 +4464,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf status = nfs4_check_deleg(cl, open, &dp); if (status) goto out; - spin_lock(&fp->fi_lock); - stp = nfsd4_find_existing_open(fp, open); - spin_unlock(&fp->fi_lock); + stp = nfsd4_find_and_lock_existing_open(fp, open); } else { open->op_file = NULL; status = nfserr_bad_stateid; @@ -4413,35 +4472,31 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf goto out; } + if (!stp) { + stp = init_open_stateid(fp, open); + if (!open->op_stp) + new_stp = true; + } + /* * OPEN the file, or upgrade an existing OPEN. * If truncate fails, the OPEN fails. + * + * stp is already locked. */ - if (stp) { + if (!new_stp) { /* Stateid was found, this is an OPEN upgrade */ - mutex_lock(&stp->st_mutex); status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); if (status) { mutex_unlock(&stp->st_mutex); goto out; } } else { - /* stp is returned locked. */ - stp = init_open_stateid(fp, open); - /* See if we lost the race to some other thread */ - if (stp->st_access_bmap != 0) { - status = nfs4_upgrade_open(rqstp, fp, current_fh, - stp, open); - if (status) { - mutex_unlock(&stp->st_mutex); - goto out; - } - goto upgrade_out; - } status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); if (status) { - mutex_unlock(&stp->st_mutex); + stp->st_stid.sc_type = NFS4_CLOSED_STID; release_open_stateid(stp); + mutex_unlock(&stp->st_mutex); goto out; } @@ -4450,7 +4505,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf if (stp->st_clnt_odstate == open->op_odstate) open->op_odstate = NULL; } -upgrade_out: + nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); mutex_unlock(&stp->st_mutex); @@ -4677,7 +4732,7 @@ nfs4_laundromat(struct nfsd_net *nn) spin_unlock(&nn->blocked_locks_lock); while (!list_empty(&reaplist)) { - nbl = list_first_entry(&nn->blocked_locks_lru, + nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, nbl_lru); list_del_init(&nbl->nbl_lru); posix_unblock_lock(&nbl->nbl_lock); @@ -4858,6 +4913,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, struct nfs4_stid **s, struct nfsd_net *nn) { __be32 status; + bool return_revoked = false; + + /* + * only return revoked delegations if explicitly asked. + * otherwise we report revoked or bad_stateid status. + */ + if (typemask & NFS4_REVOKED_DELEG_STID) + return_revoked = true; + else if (typemask & NFS4_DELEG_STID) + typemask |= NFS4_REVOKED_DELEG_STID; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return nfserr_bad_stateid; @@ -4872,6 +4937,12 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, *s = find_stateid_by_type(cstate->clp, stateid, typemask); if (!*s) return nfserr_bad_stateid; + if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { + nfs4_put_stid(*s); + if (cstate->minorversion) + return nfserr_deleg_revoked; + return nfserr_bad_stateid; + } return nfs_ok; } @@ -5294,7 +5365,6 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) bool unhashed; LIST_HEAD(reaplist); - s->st_stid.sc_type = NFS4_CLOSED_STID; spin_lock(&clp->cl_lock); unhashed = unhash_open_stateid(s, &reaplist); @@ -5334,10 +5404,12 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_bump_seqid(cstate, status); if (status) goto out; + + stp->st_stid.sc_type = NFS4_CLOSED_STID; nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); - mutex_unlock(&stp->st_mutex); nfsd4_close_open_stateid(stp); + mutex_unlock(&stp->st_mutex); /* put reference from nfs4_preprocess_seqid_op */ nfs4_put_stid(&stp->st_stid); @@ -7080,7 +7152,7 @@ nfs4_state_shutdown_net(struct net *net) spin_unlock(&nn->blocked_locks_lock); while (!list_empty(&reaplist)) { - nbl = list_first_entry(&nn->blocked_locks_lru, + nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, nbl_lru); list_del_init(&nbl->nbl_lru); posix_unblock_lock(&nbl->nbl_lock); diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 70ded52dc1dd0..50e12956c7377 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1958,8 +1958,6 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci, err, ii->vfs_inode.i_ino); return err; } - mark_buffer_dirty(ibh); - nilfs_mdt_mark_dirty(ifile); spin_lock(&nilfs->ns_inode_lock); if (likely(!ii->i_bh)) ii->i_bh = ibh; @@ -1968,6 +1966,10 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci, goto retry; } + // Always redirty the buffer to avoid race condition + mark_buffer_dirty(ii->i_bh); + nilfs_mdt_mark_dirty(ifile); + clear_bit(NILFS_I_QUEUED, &ii->i_state); set_bit(NILFS_I_BUSY, &ii->i_state); list_move_tail(&ii->i_dirty, &sci->sc_dirty_files); diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 09640b5463638..3c7053207297f 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -65,19 +65,8 @@ static int fanotify_get_response(struct fsnotify_group *group, pr_debug("%s: group=%p event=%p\n", __func__, group, event); - /* - * fsnotify_prepare_user_wait() fails if we race with mark deletion. - * Just let the operation pass in that case. - */ - if (!fsnotify_prepare_user_wait(iter_info)) { - event->response = FAN_ALLOW; - goto out; - } - wait_event(group->fanotify_data.access_waitq, event->response); - fsnotify_finish_user_wait(iter_info); -out: /* userspace responded, convert to something usable */ switch (event->response) { case FAN_ALLOW: @@ -212,9 +201,21 @@ static int fanotify_handle_event(struct fsnotify_group *group, pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, mask); +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + if (mask & FAN_ALL_PERM_EVENTS) { + /* + * fsnotify_prepare_user_wait() fails if we race with mark + * deletion. Just let the operation pass in that case. + */ + if (!fsnotify_prepare_user_wait(iter_info)) + return 0; + } +#endif + event = fanotify_alloc_event(inode, mask, data); + ret = -ENOMEM; if (unlikely(!event)) - return -ENOMEM; + goto finish; fsn_event = &event->fse; ret = fsnotify_add_event(group, fsn_event, fanotify_merge); @@ -224,7 +225,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, /* Our event wasn't used in the end. Free it. */ fsnotify_destroy_event(group, fsn_event); - return 0; + ret = 0; + goto finish; } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS @@ -233,6 +235,11 @@ static int fanotify_handle_event(struct fsnotify_group *group, iter_info); fsnotify_destroy_event(group, fsn_event); } +finish: + if (mask & FAN_ALL_PERM_EVENTS) + fsnotify_finish_user_wait(iter_info); +#else +finish: #endif return ret; } diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 0c4583b617176..0747162938296 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -335,6 +335,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, struct fsnotify_mark, obj_list); vfsmount_group = vfsmount_mark->group; } + /* + * Need to protect both marks against freeing so that we can + * continue iteration from this place, regardless of which mark + * we actually happen to send an event for. + */ + iter_info.inode_mark = inode_mark; + iter_info.vfsmount_mark = vfsmount_mark; if (inode_group && vfsmount_group) { int cmp = fsnotify_compare_groups(inode_group, @@ -348,9 +355,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is, } } - iter_info.inode_mark = inode_mark; - iter_info.vfsmount_mark = vfsmount_mark; - ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask, data, data_is, cookie, file_name, &iter_info); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 9991f88267342..258d99087183d 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -109,16 +109,6 @@ void fsnotify_get_mark(struct fsnotify_mark *mark) atomic_inc(&mark->refcnt); } -/* - * Get mark reference when we found the mark via lockless traversal of object - * list. Mark can be already removed from the list by now and on its way to be - * destroyed once SRCU period ends. - */ -static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) -{ - return atomic_inc_not_zero(&mark->refcnt); -} - static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) { u32 new_mask = 0; @@ -256,32 +246,60 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) FSNOTIFY_REAPER_DELAY); } -bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) +/* + * Get mark reference when we found the mark via lockless traversal of object + * list. Mark can be already removed from the list by now and on its way to be + * destroyed once SRCU period ends. + * + * Also pin the group so it doesn't disappear under us. + */ +static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) { - struct fsnotify_group *group; - - if (WARN_ON_ONCE(!iter_info->inode_mark && !iter_info->vfsmount_mark)) - return false; - - if (iter_info->inode_mark) - group = iter_info->inode_mark->group; - else - group = iter_info->vfsmount_mark->group; + if (!mark) + return true; + + if (atomic_inc_not_zero(&mark->refcnt)) { + spin_lock(&mark->lock); + if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) { + /* mark is attached, group is still alive then */ + atomic_inc(&mark->group->user_waits); + spin_unlock(&mark->lock); + return true; + } + spin_unlock(&mark->lock); + fsnotify_put_mark(mark); + } + return false; +} - /* - * Since acquisition of mark reference is an atomic op as well, we can - * be sure this inc is seen before any effect of refcount increment. - */ - atomic_inc(&group->user_waits); +/* + * Puts marks and wakes up group destruction if necessary. + * + * Pairs with fsnotify_get_mark_safe() + */ +static void fsnotify_put_mark_wake(struct fsnotify_mark *mark) +{ + if (mark) { + struct fsnotify_group *group = mark->group; - if (iter_info->inode_mark) { - /* This can fail if mark is being removed */ - if (!fsnotify_get_mark_safe(iter_info->inode_mark)) - goto out_wait; + fsnotify_put_mark(mark); + /* + * We abuse notification_waitq on group shutdown for waiting for + * all marks pinned when waiting for userspace. + */ + if (atomic_dec_and_test(&group->user_waits) && group->shutdown) + wake_up(&group->notification_waitq); } - if (iter_info->vfsmount_mark) { - if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) - goto out_inode; +} + +bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) +{ + /* This can fail if mark is being removed */ + if (!fsnotify_get_mark_safe(iter_info->inode_mark)) + return false; + if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) { + fsnotify_put_mark_wake(iter_info->inode_mark); + return false; } /* @@ -292,34 +310,13 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx); return true; -out_inode: - if (iter_info->inode_mark) - fsnotify_put_mark(iter_info->inode_mark); -out_wait: - if (atomic_dec_and_test(&group->user_waits) && group->shutdown) - wake_up(&group->notification_waitq); - return false; } void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) { - struct fsnotify_group *group = NULL; - iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); - if (iter_info->inode_mark) { - group = iter_info->inode_mark->group; - fsnotify_put_mark(iter_info->inode_mark); - } - if (iter_info->vfsmount_mark) { - group = iter_info->vfsmount_mark->group; - fsnotify_put_mark(iter_info->vfsmount_mark); - } - /* - * We abuse notification_waitq on group shutdown for waiting for all - * marks pinned when waiting for userspace. - */ - if (atomic_dec_and_test(&group->user_waits) && group->shutdown) - wake_up(&group->notification_waitq); + fsnotify_put_mark_wake(iter_info->inode_mark); + fsnotify_put_mark_wake(iter_info->vfsmount_mark); } /* diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 74407c6dd592a..ec8f75813beb4 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -2419,6 +2419,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) dlm_lockres_put(res); continue; } + dlm_move_lockres_to_recovery_list(dlm, res); } else if (res->owner == dlm->node_num) { dlm_free_dead_locks(dlm, res, dead_node); __dlm_lockres_calc_usage(dlm, res); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 6e41fc8fabbe7..dc455d45a66ae 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1161,6 +1161,13 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) } size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE; if (size_change) { + /* + * Here we should wait dio to finish before inode lock + * to avoid a deadlock between ocfs2_setattr() and + * ocfs2_dio_end_io_write() + */ + inode_dio_wait(inode); + status = ocfs2_rw_lock(inode, 1); if (status < 0) { mlog_errno(status); @@ -1200,8 +1207,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (status) goto bail_unlock; - inode_dio_wait(inode); - if (i_size_read(inode) >= attr->ia_size) { if (ocfs2_should_order_data(inode)) { status = ocfs2_begin_ordered_truncate(inode, diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index ded456f17de61..c584ad8d023cd 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c @@ -162,7 +162,7 @@ static ssize_t orangefs_devreq_read(struct file *file, struct orangefs_kernel_op_s *op, *temp; __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION; static __s32 magic = ORANGEFS_DEVREQ_MAGIC; - struct orangefs_kernel_op_s *cur_op = NULL; + struct orangefs_kernel_op_s *cur_op; unsigned long ret; /* We do not support blocking IO. */ @@ -186,6 +186,7 @@ static ssize_t orangefs_devreq_read(struct file *file, return -EAGAIN; restart: + cur_op = NULL; /* Get next op (if any) from top of list. */ spin_lock(&orangefs_request_list_lock); list_for_each_entry_safe(op, temp, &orangefs_request_list, list) { diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index e4a8e6a7eb17b..962bf4824283d 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -446,7 +446,7 @@ ssize_t orangefs_inode_read(struct inode *inode, static ssize_t orangefs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; - loff_t pos = *(&iocb->ki_pos); + loff_t pos = iocb->ki_pos; ssize_t rc = 0; BUG_ON(iocb->private); @@ -486,9 +486,6 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *ite } } - if (file->f_pos > i_size_read(file->f_mapping->host)) - orangefs_i_size_write(file->f_mapping->host, file->f_pos); - rc = generic_write_checks(iocb, iter); if (rc <= 0) { @@ -502,7 +499,7 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *ite * pos to the end of the file, so we will wait till now to set * pos... */ - pos = *(&iocb->ki_pos); + pos = iocb->ki_pos; rc = do_readv_writev(ORANGEFS_IO_WRITE, file, diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index 004af348fb80e..c244bbf494bc5 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h @@ -566,17 +566,6 @@ do { \ sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE; \ } while (0) -static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size) -{ -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) - inode_lock(inode); -#endif - i_size_write(inode, i_size); -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) - inode_unlock(inode); -#endif -} - static inline void orangefs_set_timeout(struct dentry *dentry) { unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000; diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c index 835c6e148afcc..0577d6dba8c81 100644 --- a/fs/orangefs/waitqueue.c +++ b/fs/orangefs/waitqueue.c @@ -29,10 +29,10 @@ static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s */ void purge_waiting_ops(void) { - struct orangefs_kernel_op_s *op; + struct orangefs_kernel_op_s *op, *tmp; spin_lock(&orangefs_request_list_lock); - list_for_each_entry(op, &orangefs_request_list, list) { + list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) { gossip_debug(GOSSIP_WAIT_DEBUG, "pvfs2-client-core: purging op tag %llu %s\n", llu(op->tag), diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index a12dc10bf7263..4bb7e4f53ea6d 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -437,7 +437,7 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack, /* Check if index is orphan and don't warn before cleaning it */ if (d_inode(index)->i_nlink == 1 && - ovl_get_nlink(index, origin.dentry, 0) == 0) + ovl_get_nlink(origin.dentry, index, 0) == 0) err = -ENOENT; dput(origin.dentry); @@ -630,7 +630,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, err = ovl_check_origin(upperdentry, roe->lowerstack, roe->numlower, &stack, &ctr); if (err) - goto out; + goto out_put_upper; } if (d.redirect) { diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 25d9b5adcd429..36b49bd09264a 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -77,5 +77,5 @@ static inline struct ovl_inode *OVL_I(struct inode *inode) static inline struct dentry *ovl_upperdentry_dereference(struct ovl_inode *oi) { - return lockless_dereference(oi->__upperdentry); + return READ_ONCE(oi->__upperdentry); } diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 698b74dd750ee..d94a51dc4e32d 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -645,7 +645,10 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) return PTR_ERR(rdt.cache); } - return iterate_dir(od->realfile, &rdt.ctx); + err = iterate_dir(od->realfile, &rdt.ctx); + ctx->pos = rdt.ctx.pos; + + return err; } @@ -754,7 +757,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) { struct inode *inode = file_inode(file); - realfile = lockless_dereference(od->upperfile); + realfile = READ_ONCE(od->upperfile); if (!realfile) { struct path upperpath; diff --git a/fs/pipe.c b/fs/pipe.c index 349c9d56d4b34..f0f4ab36c444d 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1018,13 +1018,19 @@ const struct file_operations pipefifo_fops = { /* * Currently we rely on the pipe array holding a power-of-2 number - * of pages. + * of pages. Returns 0 on error. */ static inline unsigned int round_pipe_size(unsigned int size) { unsigned long nr_pages; + if (size < pipe_min_size) + size = pipe_min_size; + nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (nr_pages == 0) + return 0; + return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; } @@ -1040,6 +1046,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) long ret = 0; size = round_pipe_size(arg); + if (size == 0) + return -EINVAL; nr_pages = size >> PAGE_SHIFT; if (!nr_pages) @@ -1123,13 +1131,18 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, size_t *lenp, loff_t *ppos) { + unsigned int rounded_pipe_max_size; int ret; - ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); + ret = proc_douintvec_minmax(table, write, buf, lenp, ppos); if (ret < 0 || !write) return ret; - pipe_max_size = round_pipe_size(pipe_max_size); + rounded_pipe_max_size = round_pipe_size(pipe_max_size); + if (rounded_pipe_max_size == 0) + return -EINVAL; + + pipe_max_size = rounded_pipe_max_size; return ret; } diff --git a/fs/proc/array.c b/fs/proc/array.c index 9390032a11e13..e6094a15ef307 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -424,8 +424,11 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, * safe because the task has stopped executing permanently. */ if (permitted && (task->flags & PF_DUMPCORE)) { - eip = KSTK_EIP(task); - esp = KSTK_ESP(task); + if (try_get_task_stack(task)) { + eip = KSTK_EIP(task); + esp = KSTK_ESP(task); + put_task_stack(task); + } } } diff --git a/fs/proc/cpuinfo.c b/fs/proc/cpuinfo.c index e0f867cd85537..96f1087e372c1 100644 --- a/fs/proc/cpuinfo.c +++ b/fs/proc/cpuinfo.c @@ -1,12 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include #include +__weak void arch_freq_prepare_all(void) +{ +} + extern const struct seq_operations cpuinfo_op; static int cpuinfo_open(struct inode *inode, struct file *file) { + arch_freq_prepare_all(); return seq_open(file, &cpuinfo_op); } diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 2da657848cfc6..d0cf1c50bb6c2 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -15,6 +15,7 @@ #include #include #include +#include "internal.h" /* * The /proc/tty directory inodes... @@ -165,7 +166,7 @@ void proc_tty_unregister_driver(struct tty_driver *driver) if (!ent) return; - remove_proc_entry(driver->driver_name, proc_tty_driver); + remove_proc_entry(ent->name, proc_tty_driver); driver->proc_entry = NULL; } diff --git a/fs/udf/super.c b/fs/udf/super.c index 99cb81d0077f9..08bf097507f6d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -703,7 +703,7 @@ static loff_t udf_check_vsd(struct super_block *sb) else sectorsize = sb->s_blocksize; - sector += (sbi->s_session << sb->s_blocksize_bits); + sector += (((loff_t)sbi->s_session) << sb->s_blocksize_bits); udf_debug("Starting at sector %u (%ld byte sectors)\n", (unsigned int)(sector >> sb->s_blocksize_bits), diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 1c713fd5b3e67..5aa392eae1c3c 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -570,11 +570,14 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason) static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, struct userfaultfd_wait_queue *ewq) { + struct userfaultfd_ctx *release_new_ctx; + if (WARN_ON_ONCE(current->flags & PF_EXITING)) goto out; ewq->ctx = ctx; init_waitqueue_entry(&ewq->wq, current); + release_new_ctx = NULL; spin_lock(&ctx->event_wqh.lock); /* @@ -601,8 +604,7 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, new = (struct userfaultfd_ctx *) (unsigned long) ewq->msg.arg.reserved.reserved1; - - userfaultfd_ctx_put(new); + release_new_ctx = new; } break; } @@ -617,6 +619,20 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, __set_current_state(TASK_RUNNING); spin_unlock(&ctx->event_wqh.lock); + if (release_new_ctx) { + struct vm_area_struct *vma; + struct mm_struct *mm = release_new_ctx->mm; + + /* the various vma->vm_userfaultfd_ctx still points to it */ + down_write(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) + if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) + vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; + up_write(&mm->mmap_sem); + + userfaultfd_ctx_put(release_new_ctx); + } + /* * ctx may go away after this if the userfault pseudo fd is * already released. diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 89263797cf325..a3cc8afed367c 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -2560,7 +2560,7 @@ xfs_bmap_add_extent_unwritten_real( &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - cur->bc_rec.b.br_state = XFS_EXT_NORM; + cur->bc_rec.b.br_state = new->br_state; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 34227115a5d6e..43005fbe8b1ee 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -610,7 +610,7 @@ xfs_iget( } else { rcu_read_unlock(); if (flags & XFS_IGET_INCORE) { - error = -ENOENT; + error = -ENODATA; goto out_error_or_again; } XFS_STATS_INC(mp, xs_ig_missed); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 4ec5b7f454013..63350906961ad 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2378,6 +2378,7 @@ xfs_ifree_cluster( */ if (ip->i_ino != inum + i) { xfs_iunlock(ip, XFS_ILOCK_EXCL); + rcu_read_unlock(); continue; } } diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 17081c77ef86e..f24e5b6cfc867 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -885,22 +885,6 @@ xfs_setattr_size( if (error) return error; - /* - * We are going to log the inode size change in this transaction so - * any previous writes that are beyond the on disk EOF and the new - * EOF that have not been written out need to be written here. If we - * do not write the data out, we expose ourselves to the null files - * problem. Note that this includes any block zeroing we did above; - * otherwise those blocks may not be zeroed after a crash. - */ - if (did_zeroing || - (newsize > ip->i_d.di_size && oldsize != ip->i_d.di_size)) { - error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, - ip->i_d.di_size, newsize); - if (error) - return error; - } - /* * We've already locked out new page faults, so now we can safely remove * pages from the page cache knowing they won't get refaulted until we @@ -917,9 +901,29 @@ xfs_setattr_size( * user visible changes). There's not much we can do about this, except * to hope that the caller sees ENOMEM and retries the truncate * operation. + * + * And we update in-core i_size and truncate page cache beyond newsize + * before writeback the [di_size, newsize] range, so we're guaranteed + * not to write stale data past the new EOF on truncate down. */ truncate_setsize(inode, newsize); + /* + * We are going to log the inode size change in this transaction so + * any previous writes that are beyond the on disk EOF and the new + * EOF that have not been written out need to be written here. If we + * do not write the data out, we expose ourselves to the null files + * problem. Note that this includes any block zeroing we did above; + * otherwise those blocks may not be zeroed after a crash. + */ + if (did_zeroing || + (newsize > ip->i_d.di_size && oldsize != ip->i_d.di_size)) { + error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, + ip->i_d.di_size, newsize - 1); + if (error) + return error; + } + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); if (error) return error; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index ee34899396b26..d6e049fdd977d 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -753,7 +753,7 @@ xlog_find_head( * in the in-core log. The following number can be made tighter if * we actually look at the block size of the filesystem. */ - num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); + num_scan_bblks = min_t(int, log_bbnum, XLOG_TOTAL_REC_SHIFT(log)); if (head_blk >= num_scan_bblks) { /* * We are guaranteed that the entire check can be performed diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index fa1505292f6cd..324a04df3785b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -105,6 +105,7 @@ enum acpi_bus_device_type { ACPI_BUS_TYPE_THERMAL, ACPI_BUS_TYPE_POWER_BUTTON, ACPI_BUS_TYPE_SLEEP_BUTTON, + ACPI_BUS_TYPE_ECDT_EC, ACPI_BUS_DEVICE_TYPE_COUNT }; diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 29c691265b493..14499757338f6 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -58,6 +58,7 @@ #define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_BAY_HID "LNXIOBAY" #define ACPI_DOCK_HID "LNXDOCK" +#define ACPI_ECDT_HID "LNXEC" /* Quirk for broken IBM BIOSes */ #define ACPI_SMBUS_IBM_HID "SMBUSIBM" diff --git a/include/asm-generic/mm_hooks.h b/include/asm-generic/mm_hooks.h index ea189d88a3cc7..8ac4e68a12f08 100644 --- a/include/asm-generic/mm_hooks.h +++ b/include/asm-generic/mm_hooks.h @@ -7,9 +7,10 @@ #ifndef _ASM_GENERIC_MM_HOOKS_H #define _ASM_GENERIC_MM_HOOKS_H -static inline void arch_dup_mmap(struct mm_struct *oldmm, - struct mm_struct *mm) +static inline int arch_dup_mmap(struct mm_struct *oldmm, + struct mm_struct *mm) { + return 0; } static inline void arch_exit_mmap(struct mm_struct *mm) diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 757dc6ffc7ba5..045a7f52ab3a5 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -814,6 +814,14 @@ static inline int pmd_write(pmd_t pmd) #endif /* __HAVE_ARCH_PMD_WRITE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#ifndef pud_write +static inline int pud_write(pud_t pud) +{ + BUG(); + return 0; +} +#endif /* pud_write */ + #if !defined(CONFIG_TRANSPARENT_HUGEPAGE) || \ (defined(CONFIG_TRANSPARENT_HUGEPAGE) && \ !defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) @@ -1017,6 +1025,11 @@ static inline int pmd_clear_huge(pmd_t *pmd) struct file; int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, unsigned long size, pgprot_t *vma_prot); + +#ifndef CONFIG_X86_ESPFIX64 +static inline void init_espfix_bsp(void) { } +#endif + #endif /* !__ASSEMBLY__ */ #ifndef io_remap_pfn_range diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8acfc1e099e11..353f52fdc35eb 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -459,6 +459,7 @@ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ + *(.text..refcount) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ @@ -687,7 +688,7 @@ #define BUG_TABLE #endif -#ifdef CONFIG_ORC_UNWINDER +#ifdef CONFIG_UNWINDER_ORC #define ORC_UNWIND_TABLE \ . = ALIGN(4); \ .orc_unwind_ip : AT(ADDR(.orc_unwind_ip) - LOAD_OFFSET) { \ diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 75ec9c662268b..aeec003a566b5 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -255,6 +255,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, unsigned int ivsize); ssize_t af_alg_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); +void af_alg_free_resources(struct af_alg_async_req *areq); void af_alg_async_cb(struct crypto_async_request *_req, int err); unsigned int af_alg_poll(struct file *file, struct socket *sock, poll_table *wait); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index f0b44c16e88f2..c2bae8da642cb 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -82,6 +82,14 @@ int ahash_register_instance(struct crypto_template *tmpl, struct ahash_instance *inst); void ahash_free_instance(struct crypto_instance *inst); +int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen); + +static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg) +{ + return alg->setkey != shash_no_setkey; +} + int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, struct hash_alg_common *alg, struct crypto_instance *inst); diff --git a/include/crypto/mcryptd.h b/include/crypto/mcryptd.h index cceafa01f9073..b67404fc4b34b 100644 --- a/include/crypto/mcryptd.h +++ b/include/crypto/mcryptd.h @@ -27,6 +27,7 @@ static inline struct mcryptd_ahash *__mcryptd_ahash_cast( struct mcryptd_cpu_queue { struct crypto_queue queue; + spinlock_t q_lock; struct work_struct work; }; diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 1e1908a6b1d66..a992434ded999 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -360,7 +360,8 @@ void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, const struct drm_display_mode *mode, enum hdmi_quantization_range rgb_quant_range, - bool rgb_quant_range_selectable); + bool rgb_quant_range_selectable, + bool is_hdmi2_sink); /** * drm_eld_mnl - Get ELD monitor name length in bytes. diff --git a/include/linux/bio.h b/include/linux/bio.h index 275c91c995163..45f00dd6323c9 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -504,6 +504,8 @@ extern unsigned int bvec_nr_vecs(unsigned short idx); #define bio_set_dev(bio, bdev) \ do { \ + if ((bio)->bi_disk != (bdev)->bd_disk) \ + bio_clear_flag(bio, BIO_THROTTLED);\ (bio)->bi_disk = (bdev)->bd_disk; \ (bio)->bi_partno = (bdev)->bd_partno; \ } while (0) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 96ac3815542c1..1c8a8a2aedf71 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -50,8 +50,6 @@ struct blk_issue_stat { struct bio { struct bio *bi_next; /* request queue link */ struct gendisk *bi_disk; - u8 bi_partno; - blk_status_t bi_status; unsigned int bi_opf; /* bottom bits req flags, * top bits REQ_OP. Use * accessors. @@ -59,8 +57,8 @@ struct bio { unsigned short bi_flags; /* status, etc and bvec pool number */ unsigned short bi_ioprio; unsigned short bi_write_hint; - - struct bvec_iter bi_iter; + blk_status_t bi_status; + u8 bi_partno; /* Number of segments in this BIO after * physical address coalescing is performed. @@ -74,8 +72,9 @@ struct bio { unsigned int bi_seg_front_size; unsigned int bi_seg_back_size; - atomic_t __bi_remaining; + struct bvec_iter bi_iter; + atomic_t __bi_remaining; bio_end_io_t *bi_end_io; void *bi_private; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8da66379f7ea7..6362e3606aa50 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -135,7 +135,7 @@ typedef __u32 __bitwise req_flags_t; struct request { struct list_head queuelist; union { - call_single_data_t csd; + struct __call_single_data csd; u64 fifo_time; }; @@ -241,14 +241,24 @@ struct request { struct request *next_rq; }; +static inline bool blk_op_is_scsi(unsigned int op) +{ + return op == REQ_OP_SCSI_IN || op == REQ_OP_SCSI_OUT; +} + +static inline bool blk_op_is_private(unsigned int op) +{ + return op == REQ_OP_DRV_IN || op == REQ_OP_DRV_OUT; +} + static inline bool blk_rq_is_scsi(struct request *rq) { - return req_op(rq) == REQ_OP_SCSI_IN || req_op(rq) == REQ_OP_SCSI_OUT; + return blk_op_is_scsi(req_op(rq)); } static inline bool blk_rq_is_private(struct request *rq) { - return req_op(rq) == REQ_OP_DRV_IN || req_op(rq) == REQ_OP_DRV_OUT; + return blk_op_is_private(req_op(rq)); } static inline bool blk_rq_is_passthrough(struct request *rq) @@ -256,6 +266,13 @@ static inline bool blk_rq_is_passthrough(struct request *rq) return blk_rq_is_scsi(rq) || blk_rq_is_private(rq); } +static inline bool bio_is_passthrough(struct bio *bio) +{ + unsigned op = bio_op(bio); + + return blk_op_is_scsi(op) || blk_op_is_private(op); +} + static inline unsigned short req_get_ioprio(struct request *req) { return req->ioprio; @@ -952,7 +969,7 @@ extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, extern void blk_rq_unprep_clone(struct request *rq); extern blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *rq); -extern int blk_rq_append_bio(struct request *rq, struct bio *bio); +extern int blk_rq_append_bio(struct request *rq, struct bio **bio); extern void blk_delay_queue(struct request_queue *, unsigned long); extern void blk_queue_split(struct request_queue *, struct bio **); extern void blk_recount_segments(struct request_queue *, struct bio *); diff --git a/include/linux/bpf.h b/include/linux/bpf.h index f1af7d63d6786..5c5be80ce802c 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -42,7 +42,14 @@ struct bpf_map_ops { }; struct bpf_map { - atomic_t refcnt; + /* 1st cacheline with read-mostly members of which some + * are also accessed in fast-path (e.g. ops, max_entries). + */ + const struct bpf_map_ops *ops ____cacheline_aligned; + struct bpf_map *inner_map_meta; +#ifdef CONFIG_SECURITY + void *security; +#endif enum bpf_map_type map_type; u32 key_size; u32 value_size; @@ -51,11 +58,16 @@ struct bpf_map { u32 pages; u32 id; int numa_node; - struct user_struct *user; - const struct bpf_map_ops *ops; - struct work_struct work; + bool unpriv_array; + /* 7 bytes hole */ + + /* 2nd cacheline with misc members to avoid false sharing + * particularly with refcounting. + */ + struct user_struct *user ____cacheline_aligned; + atomic_t refcnt; atomic_t usercnt; - struct bpf_map *inner_map_meta; + struct work_struct work; }; /* function argument constraints */ @@ -195,6 +207,7 @@ struct bpf_prog_aux { struct bpf_array { struct bpf_map map; u32 elem_size; + u32 index_mask; /* 'ownership' of prog_array is claimed by the first program that * is going to use this map or by the first program which FD is stored * in the map to make sure that all callers and callees have the same diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index b8d200f60a409..73bec75b74c80 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -15,11 +15,11 @@ * In practice this is far bigger than any realistic pointer offset; this limit * ensures that umax_value + (int)off + (int)size cannot overflow a u64. */ -#define BPF_MAX_VAR_OFF (1ULL << 31) +#define BPF_MAX_VAR_OFF (1 << 29) /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures * that converting umax_value to int cannot overflow. */ -#define BPF_MAX_VAR_SIZ INT_MAX +#define BPF_MAX_VAR_SIZ (1 << 29) /* Liveness marks, used for registers and spilled-regs (in stack slots). * Read marks propagate upwards until they find a write mark; they record that @@ -110,7 +110,7 @@ struct bpf_insn_aux_data { struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */ }; int ctx_field_size; /* the ctx field size for load insn, maybe 0 */ - int converted_op_size; /* the valid value width after perceived conversion */ + bool seen; /* this insn was processed by the verifier */ }; #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 54dfef70a0727..3b609edffa8fb 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_COMPILER_H +#ifndef __LINUX_COMPILER_TYPES_H #error "Please don't include directly, include instead." #endif @@ -16,3 +16,6 @@ * with any version that can compile the kernel */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +#define randomized_struct_fields_start struct { +#define randomized_struct_fields_end }; diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index bb78e5bdff263..2272ded07496d 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_COMPILER_H +#ifndef __LINUX_COMPILER_TYPES_H #error "Please don't include directly, include instead." #endif diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index 523d1b74550f2..bfa08160db3a4 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_COMPILER_H +#ifndef __LINUX_COMPILER_TYPES_H #error "Please don't include directly, include instead." #endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 202710420d6de..fab5dc250c61a 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -2,111 +2,12 @@ #ifndef __LINUX_COMPILER_H #define __LINUX_COMPILER_H -#ifndef __ASSEMBLY__ +#include -#ifdef __CHECKER__ -# define __user __attribute__((noderef, address_space(1))) -# define __kernel __attribute__((address_space(0))) -# define __safe __attribute__((safe)) -# define __force __attribute__((force)) -# define __nocast __attribute__((nocast)) -# define __iomem __attribute__((noderef, address_space(2))) -# define __must_hold(x) __attribute__((context(x,1,1))) -# define __acquires(x) __attribute__((context(x,0,1))) -# define __releases(x) __attribute__((context(x,1,0))) -# define __acquire(x) __context__(x,1) -# define __release(x) __context__(x,-1) -# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) -# define __percpu __attribute__((noderef, address_space(3))) -# define __rcu __attribute__((noderef, address_space(4))) -# define __private __attribute__((noderef)) -extern void __chk_user_ptr(const volatile void __user *); -extern void __chk_io_ptr(const volatile void __iomem *); -# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member)) -#else /* __CHECKER__ */ -# ifdef STRUCTLEAK_PLUGIN -# define __user __attribute__((user)) -# else -# define __user -# endif -# define __kernel -# define __safe -# define __force -# define __nocast -# define __iomem -# define __chk_user_ptr(x) (void)0 -# define __chk_io_ptr(x) (void)0 -# define __builtin_warning(x, y...) (1) -# define __must_hold(x) -# define __acquires(x) -# define __releases(x) -# define __acquire(x) (void)0 -# define __release(x) (void)0 -# define __cond_lock(x,c) (c) -# define __percpu -# define __rcu -# define __private -# define ACCESS_PRIVATE(p, member) ((p)->member) -#endif /* __CHECKER__ */ - -/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ -#define ___PASTE(a,b) a##b -#define __PASTE(a,b) ___PASTE(a,b) +#ifndef __ASSEMBLY__ #ifdef __KERNEL__ -#ifdef __GNUC__ -#include -#endif - -#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__) -#define notrace __attribute__((hotpatch(0,0))) -#else -#define notrace __attribute__((no_instrument_function)) -#endif - -/* Intel compiler defines __GNUC__. So we will overwrite implementations - * coming from above header files here - */ -#ifdef __INTEL_COMPILER -# include -#endif - -/* Clang compiler defines __GNUC__. So we will overwrite implementations - * coming from above header files here - */ -#ifdef __clang__ -#include -#endif - -/* - * Generic compiler-dependent macros required for kernel - * build go below this comment. Actual compiler/compiler version - * specific implementations come from the above header files - */ - -struct ftrace_branch_data { - const char *func; - const char *file; - unsigned line; - union { - struct { - unsigned long correct; - unsigned long incorrect; - }; - struct { - unsigned long miss; - unsigned long hit; - }; - unsigned long miss_hit[2]; - }; -}; - -struct ftrace_likely_data { - struct ftrace_branch_data data; - unsigned long constant; -}; - /* * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code * to disable branch tracing on a per file basis. @@ -333,6 +234,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s * with an explicit memory barrier or atomic instruction that provides the * required ordering. */ +#include #define __READ_ONCE(x, check) \ ({ \ @@ -341,6 +243,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __read_once_size(&(x), __u.__c, sizeof(x)); \ else \ __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \ + smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \ __u.__val; \ }) #define READ_ONCE(x) __READ_ONCE(x, 1) @@ -363,167 +266,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #endif /* __ASSEMBLY__ */ -#ifdef __KERNEL__ -/* - * Allow us to mark functions as 'deprecated' and have gcc emit a nice - * warning for each use, in hopes of speeding the functions removal. - * Usage is: - * int __deprecated foo(void) - */ -#ifndef __deprecated -# define __deprecated /* unimplemented */ -#endif - -#ifdef MODULE -#define __deprecated_for_modules __deprecated -#else -#define __deprecated_for_modules -#endif - -#ifndef __must_check -#define __must_check -#endif - -#ifndef CONFIG_ENABLE_MUST_CHECK -#undef __must_check -#define __must_check -#endif -#ifndef CONFIG_ENABLE_WARN_DEPRECATED -#undef __deprecated -#undef __deprecated_for_modules -#define __deprecated -#define __deprecated_for_modules -#endif - -#ifndef __malloc -#define __malloc -#endif - -/* - * Allow us to avoid 'defined but not used' warnings on functions and data, - * as well as force them to be emitted to the assembly file. - * - * As of gcc 3.4, static functions that are not marked with attribute((used)) - * may be elided from the assembly file. As of gcc 3.4, static data not so - * marked will not be elided, but this may change in a future gcc version. - * - * NOTE: Because distributions shipped with a backported unit-at-a-time - * compiler in gcc 3.3, we must define __used to be __attribute__((used)) - * for gcc >=3.3 instead of 3.4. - * - * In prior versions of gcc, such functions and data would be emitted, but - * would be warned about except with attribute((unused)). - * - * Mark functions that are referenced only in inline assembly as __used so - * the code is emitted even though it appears to be unreferenced. - */ -#ifndef __used -# define __used /* unimplemented */ -#endif - -#ifndef __maybe_unused -# define __maybe_unused /* unimplemented */ -#endif - -#ifndef __always_unused -# define __always_unused /* unimplemented */ -#endif - -#ifndef noinline -#define noinline -#endif - -/* - * Rather then using noinline to prevent stack consumption, use - * noinline_for_stack instead. For documentation reasons. - */ -#define noinline_for_stack noinline - -#ifndef __always_inline -#define __always_inline inline -#endif - -#endif /* __KERNEL__ */ - -/* - * From the GCC manual: - * - * Many functions do not examine any values except their arguments, - * and have no effects except the return value. Basically this is - * just slightly more strict class than the `pure' attribute above, - * since function is not allowed to read global memory. - * - * Note that a function that has pointer arguments and examines the - * data pointed to must _not_ be declared `const'. Likewise, a - * function that calls a non-`const' function usually must not be - * `const'. It does not make sense for a `const' function to return - * `void'. - */ -#ifndef __attribute_const__ -# define __attribute_const__ /* unimplemented */ -#endif - -#ifndef __designated_init -# define __designated_init -#endif - -#ifndef __latent_entropy -# define __latent_entropy -#endif - -#ifndef __randomize_layout -# define __randomize_layout __designated_init -#endif - -#ifndef __no_randomize_layout -# define __no_randomize_layout -#endif - -#ifndef randomized_struct_fields_start -# define randomized_struct_fields_start -# define randomized_struct_fields_end -#endif - -/* - * Tell gcc if a function is cold. The compiler will assume any path - * directly leading to the call is unlikely. - */ - -#ifndef __cold -#define __cold -#endif - -/* Simple shorthand for a section definition */ -#ifndef __section -# define __section(S) __attribute__ ((__section__(#S))) -#endif - -#ifndef __visible -#define __visible -#endif - -#ifndef __nostackprotector -# define __nostackprotector -#endif - -/* - * Assume alignment of return value. - */ -#ifndef __assume_aligned -#define __assume_aligned(a, ...) -#endif - - -/* Are two types/vars the same type (ignoring qualifiers)? */ -#ifndef __same_type -# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) -#endif - -/* Is this type a native word size -- useful for atomic operations */ -#ifndef __native_word -# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) -#endif - /* Compile time object size, -1 for unknown */ #ifndef __compiletime_object_size # define __compiletime_object_size(obj) -1 diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h new file mode 100644 index 0000000000000..6b79a9bba9a76 --- /dev/null +++ b/include/linux/compiler_types.h @@ -0,0 +1,274 @@ +#ifndef __LINUX_COMPILER_TYPES_H +#define __LINUX_COMPILER_TYPES_H + +#ifndef __ASSEMBLY__ + +#ifdef __CHECKER__ +# define __user __attribute__((noderef, address_space(1))) +# define __kernel __attribute__((address_space(0))) +# define __safe __attribute__((safe)) +# define __force __attribute__((force)) +# define __nocast __attribute__((nocast)) +# define __iomem __attribute__((noderef, address_space(2))) +# define __must_hold(x) __attribute__((context(x,1,1))) +# define __acquires(x) __attribute__((context(x,0,1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) +# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) +# define __percpu __attribute__((noderef, address_space(3))) +# define __rcu __attribute__((noderef, address_space(4))) +# define __private __attribute__((noderef)) +extern void __chk_user_ptr(const volatile void __user *); +extern void __chk_io_ptr(const volatile void __iomem *); +# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member)) +#else /* __CHECKER__ */ +# ifdef STRUCTLEAK_PLUGIN +# define __user __attribute__((user)) +# else +# define __user +# endif +# define __kernel +# define __safe +# define __force +# define __nocast +# define __iomem +# define __chk_user_ptr(x) (void)0 +# define __chk_io_ptr(x) (void)0 +# define __builtin_warning(x, y...) (1) +# define __must_hold(x) +# define __acquires(x) +# define __releases(x) +# define __acquire(x) (void)0 +# define __release(x) (void)0 +# define __cond_lock(x,c) (c) +# define __percpu +# define __rcu +# define __private +# define ACCESS_PRIVATE(p, member) ((p)->member) +#endif /* __CHECKER__ */ + +/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ +#define ___PASTE(a,b) a##b +#define __PASTE(a,b) ___PASTE(a,b) + +#ifdef __KERNEL__ + +#ifdef __GNUC__ +#include +#endif + +#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__) +#define notrace __attribute__((hotpatch(0,0))) +#else +#define notrace __attribute__((no_instrument_function)) +#endif + +/* Intel compiler defines __GNUC__. So we will overwrite implementations + * coming from above header files here + */ +#ifdef __INTEL_COMPILER +# include +#endif + +/* Clang compiler defines __GNUC__. So we will overwrite implementations + * coming from above header files here + */ +#ifdef __clang__ +#include +#endif + +/* + * Generic compiler-dependent macros required for kernel + * build go below this comment. Actual compiler/compiler version + * specific implementations come from the above header files + */ + +struct ftrace_branch_data { + const char *func; + const char *file; + unsigned line; + union { + struct { + unsigned long correct; + unsigned long incorrect; + }; + struct { + unsigned long miss; + unsigned long hit; + }; + unsigned long miss_hit[2]; + }; +}; + +struct ftrace_likely_data { + struct ftrace_branch_data data; + unsigned long constant; +}; + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#ifdef __KERNEL__ +/* + * Allow us to mark functions as 'deprecated' and have gcc emit a nice + * warning for each use, in hopes of speeding the functions removal. + * Usage is: + * int __deprecated foo(void) + */ +#ifndef __deprecated +# define __deprecated /* unimplemented */ +#endif + +#ifdef MODULE +#define __deprecated_for_modules __deprecated +#else +#define __deprecated_for_modules +#endif + +#ifndef __must_check +#define __must_check +#endif + +#ifndef CONFIG_ENABLE_MUST_CHECK +#undef __must_check +#define __must_check +#endif +#ifndef CONFIG_ENABLE_WARN_DEPRECATED +#undef __deprecated +#undef __deprecated_for_modules +#define __deprecated +#define __deprecated_for_modules +#endif + +#ifndef __malloc +#define __malloc +#endif + +/* + * Allow us to avoid 'defined but not used' warnings on functions and data, + * as well as force them to be emitted to the assembly file. + * + * As of gcc 3.4, static functions that are not marked with attribute((used)) + * may be elided from the assembly file. As of gcc 3.4, static data not so + * marked will not be elided, but this may change in a future gcc version. + * + * NOTE: Because distributions shipped with a backported unit-at-a-time + * compiler in gcc 3.3, we must define __used to be __attribute__((used)) + * for gcc >=3.3 instead of 3.4. + * + * In prior versions of gcc, such functions and data would be emitted, but + * would be warned about except with attribute((unused)). + * + * Mark functions that are referenced only in inline assembly as __used so + * the code is emitted even though it appears to be unreferenced. + */ +#ifndef __used +# define __used /* unimplemented */ +#endif + +#ifndef __maybe_unused +# define __maybe_unused /* unimplemented */ +#endif + +#ifndef __always_unused +# define __always_unused /* unimplemented */ +#endif + +#ifndef noinline +#define noinline +#endif + +/* + * Rather then using noinline to prevent stack consumption, use + * noinline_for_stack instead. For documentation reasons. + */ +#define noinline_for_stack noinline + +#ifndef __always_inline +#define __always_inline inline +#endif + +#endif /* __KERNEL__ */ + +/* + * From the GCC manual: + * + * Many functions do not examine any values except their arguments, + * and have no effects except the return value. Basically this is + * just slightly more strict class than the `pure' attribute above, + * since function is not allowed to read global memory. + * + * Note that a function that has pointer arguments and examines the + * data pointed to must _not_ be declared `const'. Likewise, a + * function that calls a non-`const' function usually must not be + * `const'. It does not make sense for a `const' function to return + * `void'. + */ +#ifndef __attribute_const__ +# define __attribute_const__ /* unimplemented */ +#endif + +#ifndef __designated_init +# define __designated_init +#endif + +#ifndef __latent_entropy +# define __latent_entropy +#endif + +#ifndef __randomize_layout +# define __randomize_layout __designated_init +#endif + +#ifndef __no_randomize_layout +# define __no_randomize_layout +#endif + +#ifndef randomized_struct_fields_start +# define randomized_struct_fields_start +# define randomized_struct_fields_end +#endif + +/* + * Tell gcc if a function is cold. The compiler will assume any path + * directly leading to the call is unlikely. + */ + +#ifndef __cold +#define __cold +#endif + +/* Simple shorthand for a section definition */ +#ifndef __section +# define __section(S) __attribute__ ((__section__(#S))) +#endif + +#ifndef __visible +#define __visible +#endif + +#ifndef __nostackprotector +# define __nostackprotector +#endif + +/* + * Assume alignment of return value. + */ +#ifndef __assume_aligned +#define __assume_aligned(a, ...) +#endif + + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#ifndef __same_type +# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) +#endif + +/* Is this type a native word size -- useful for atomic operations */ +#ifndef __native_word +# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) +#endif + +#endif /* __LINUX_COMPILER_TYPES_H */ diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 938ea8ae0ba42..c816e6f2730cd 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -47,6 +47,13 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr); extern int cpu_add_dev_attr_group(struct attribute_group *attrs); extern void cpu_remove_dev_attr_group(struct attribute_group *attrs); +extern ssize_t cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf); + extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, const struct attribute_group **groups, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 537ff842ff733..cbf85c4c745f8 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -917,6 +917,7 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) } #endif +extern void arch_freq_prepare_all(void); extern unsigned int arch_freq_get_on_cpu(int cpu); /* the following are really really optional */ diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 2477a5cb5bd54..fb83dee528a1c 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -86,7 +86,7 @@ enum cpuhp_state { CPUHP_MM_ZSWP_POOL_PREPARE, CPUHP_KVM_PPC_BOOK3S_PREPARE, CPUHP_ZCOMP_PREPARE, - CPUHP_TIMERS_DEAD, + CPUHP_TIMERS_PREPARE, CPUHP_MIPS_SOC_PREPARE, CPUHP_BP_PREPARE_DYN, CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20, diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h index 06097ef304491..b511f6d24b42b 100644 --- a/include/linux/crash_core.h +++ b/include/linux/crash_core.h @@ -42,6 +42,8 @@ phys_addr_t paddr_vmcoreinfo_note(void); vmcoreinfo_append_str("PAGESIZE=%ld\n", value) #define VMCOREINFO_SYMBOL(name) \ vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)&name) +#define VMCOREINFO_SYMBOL_ARRAY(name) \ + vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)name) #define VMCOREINFO_SIZE(name) \ vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \ (unsigned long)sizeof(name)) diff --git a/include/linux/cred.h b/include/linux/cred.h index 099058e1178b4..631286535d0f1 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -83,6 +83,7 @@ extern int set_current_groups(struct group_info *); extern void set_groups(struct cred *, struct group_info *); extern int groups_search(const struct group_info *, kgid_t); extern bool may_setgroups(void); +extern void groups_sort(struct group_info *); /* * The security context of a task diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 4178d24935477..5e335b6203f49 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -71,7 +71,7 @@ extern void delayacct_init(void); extern void __delayacct_tsk_init(struct task_struct *); extern void __delayacct_tsk_exit(struct task_struct *); extern void __delayacct_blkio_start(void); -extern void __delayacct_blkio_end(void); +extern void __delayacct_blkio_end(struct task_struct *); extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *); extern __u64 __delayacct_blkio_ticks(struct task_struct *); extern void __delayacct_freepages_start(void); @@ -122,10 +122,10 @@ static inline void delayacct_blkio_start(void) __delayacct_blkio_start(); } -static inline void delayacct_blkio_end(void) +static inline void delayacct_blkio_end(struct task_struct *p) { if (current->delays) - __delayacct_blkio_end(); + __delayacct_blkio_end(p); delayacct_clear_flag(DELAYACCT_PF_BLKIO); } @@ -169,7 +169,7 @@ static inline void delayacct_tsk_free(struct task_struct *tsk) {} static inline void delayacct_blkio_start(void) {} -static inline void delayacct_blkio_end(void) +static inline void delayacct_blkio_end(struct task_struct *p) {} static inline int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 7653ea66874dd..46930f82a9888 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -697,7 +697,6 @@ static inline void *dma_zalloc_coherent(struct device *dev, size_t size, return ret; } -#ifdef CONFIG_HAS_DMA static inline int dma_get_cache_alignment(void) { #ifdef ARCH_DMA_MINALIGN @@ -705,7 +704,6 @@ static inline int dma_get_cache_alignment(void) #endif return 1; } -#endif /* flags for the coherent memory api */ #define DMA_MEMORY_EXCLUSIVE 0x01 diff --git a/include/linux/efi.h b/include/linux/efi.h index d813f7b04da7a..29fdf8029cf6f 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -140,11 +140,13 @@ struct efi_boot_memmap { struct capsule_info { efi_capsule_header_t header; + efi_capsule_header_t *capsule; int reset_type; long index; size_t count; size_t total_size; - phys_addr_t *pages; + struct page **pages; + phys_addr_t *phys; size_t page_bytes_remain; }; diff --git a/include/linux/fs.h b/include/linux/fs.h index 885266aae2d7d..440281f8564d8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3069,7 +3069,8 @@ static inline int vfs_lstat(const char __user *name, struct kstat *stat) static inline int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, int flags) { - return vfs_statx(dfd, filename, flags, stat, STATX_BASIC_STATS); + return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT, + stat, STATX_BASIC_STATS); } static inline int vfs_fstat(int fd, struct kstat *stat) { @@ -3175,6 +3176,20 @@ static inline bool vma_is_dax(struct vm_area_struct *vma) return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); } +static inline bool vma_is_fsdax(struct vm_area_struct *vma) +{ + struct inode *inode; + + if (!vma->vm_file) + return false; + if (!vma_is_dax(vma)) + return false; + inode = file_inode(vma->vm_file); + if (inode->i_mode == S_IFCHR) + return false; /* device-dax */ + return true; +} + static inline int iocb_flags(struct file *file) { int res = 0; diff --git a/include/linux/fscache.h b/include/linux/fscache.h index f4ff47d4a893a..fe0c349684fa8 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h @@ -755,7 +755,7 @@ bool fscache_maybe_release_page(struct fscache_cookie *cookie, { if (fscache_cookie_valid(cookie) && PageFsCache(page)) return __fscache_maybe_release_page(cookie, page, gfp); - return false; + return true; } /** diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 6dfec4d638df3..872f930f1b06d 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -32,6 +32,7 @@ #include #include +#include struct device; struct device_node; @@ -71,7 +72,7 @@ struct gen_pool { */ struct gen_pool_chunk { struct list_head next_chunk; /* next chunk in pool */ - atomic_t avail; + atomic_long_t avail; phys_addr_t phys_addr; /* physical starting address of memory chunk */ unsigned long start_addr; /* start address of memory chunk */ unsigned long end_addr; /* end address of memory chunk (inclusive) */ diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 44790523057f0..5ade8f2a69876 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -243,6 +243,7 @@ static inline dev_t part_devt(struct hd_struct *part) return part_to_dev(part)->devt; } +extern struct hd_struct *__disk_get_part(struct gendisk *disk, int partno); extern struct hd_struct *disk_get_part(struct gendisk *disk, int partno); static inline void disk_put_part(struct hd_struct *part) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index fbf5b31d47eea..82a25880714ac 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -239,14 +239,6 @@ static inline int pgd_write(pgd_t pgd) } #endif -#ifndef pud_write -static inline int pud_write(pud_t pud) -{ - BUG(); - return 0; -} -#endif - #define HUGETLB_ANON_FILE "anon_hugepage" enum { diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 6431087816ba5..ba74eaa8eadff 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -708,6 +708,7 @@ struct vmbus_channel { u8 monitor_bit; bool rescind; /* got rescind msg */ + struct completion rescind_event; u32 ringbuffer_gpadlhandle; diff --git a/include/linux/hypervisor.h b/include/linux/hypervisor.h index b4054fd5b6f66..b19563f9a8ebb 100644 --- a/include/linux/hypervisor.h +++ b/include/linux/hypervisor.h @@ -7,8 +7,12 @@ * Juergen Gross */ -#ifdef CONFIG_HYPERVISOR_GUEST -#include +#ifdef CONFIG_X86 +#include +static inline void hypervisor_pin_vcpu(int cpu) +{ + x86_platform.hyper.pin_vcpu(cpu); +} #else static inline void hypervisor_pin_vcpu(int cpu) { diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 7b0fa8b5c120d..ce0ef1c0a30ab 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -139,7 +139,7 @@ struct st_sensor_das { * @mask_ihl: mask to enable/disable active low on the INT lines. * @addr_od: address to enable/disable Open Drain on the INT lines. * @mask_od: mask to enable/disable Open Drain on the INT lines. - * @addr_stat_drdy: address to read status of DRDY (data ready) interrupt + * struct stat_drdy - status register of DRDY (data ready) interrupt. * struct ig1 - represents the Interrupt Generator 1 of sensors. * @en_addr: address of the enable ig1 register. * @en_mask: mask to write the on/off value for enable. @@ -152,7 +152,10 @@ struct st_sensor_data_ready_irq { u8 mask_ihl; u8 addr_od; u8 mask_od; - u8 addr_stat_drdy; + struct { + u8 addr; + u8 mask; + } stat_drdy; struct { u8 en_addr; u8 en_mask; diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h index 34d59bfdce2d2..464458d20b165 100644 --- a/include/linux/iio/timer/stm32-lptim-trigger.h +++ b/include/linux/iio/timer/stm32-lptim-trigger.h @@ -16,11 +16,14 @@ #define LPTIM2_OUT "lptim2_out" #define LPTIM3_OUT "lptim3_out" -#if IS_ENABLED(CONFIG_IIO_STM32_LPTIMER_TRIGGER) +#if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER) bool is_stm32_lptim_trigger(struct iio_trigger *trig); #else static inline bool is_stm32_lptim_trigger(struct iio_trigger *trig) { +#if IS_ENABLED(CONFIG_IIO_STM32_LPTIMER_TRIGGER) + pr_warn_once("stm32 lptim_trigger not linked in\n"); +#endif return false; } #endif diff --git a/include/linux/intel-pti.h b/include/linux/intel-pti.h new file mode 100644 index 0000000000000..2710d72de3c92 --- /dev/null +++ b/include/linux/intel-pti.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) Intel 2011 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The PTI (Parallel Trace Interface) driver directs trace data routed from + * various parts in the system out through the Intel Penwell PTI port and + * out of the mobile device for analysis with a debugging tool + * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7, + * compact JTAG, standard. + * + * This header file will allow other parts of the OS to use the + * interface to write out it's contents for debugging a mobile system. + */ + +#ifndef LINUX_INTEL_PTI_H_ +#define LINUX_INTEL_PTI_H_ + +/* offset for last dword of any PTI message. Part of MIPI P1149.7 */ +#define PTI_LASTDWORD_DTS 0x30 + +/* basic structure used as a write address to the PTI HW */ +struct pti_masterchannel { + u8 master; + u8 channel; +}; + +/* the following functions are defined in misc/pti.c */ +void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count); +struct pti_masterchannel *pti_request_masterchannel(u8 type, + const char *thread_name); +void pti_release_masterchannel(struct pti_masterchannel *mc); + +#endif /* LINUX_INTEL_PTI_H_ */ diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index ea04ca024f0d2..067a6fa675eda 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -272,7 +272,8 @@ struct ipv6_pinfo { * 100: prefer care-of address */ dontfrag:1, - autoflowlabel:1; + autoflowlabel:1, + autoflowlabel_set:1; __u8 min_hopcount; __u8 tclass; __be32 rcv_flowinfo; diff --git a/include/linux/irq.h b/include/linux/irq.h index 4536286cc4d24..0d53626405bf8 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -211,6 +211,7 @@ struct irq_data { * IRQD_MANAGED_SHUTDOWN - Interrupt was shutdown due to empty affinity * mask. Applies only to affinity managed irqs. * IRQD_SINGLE_TARGET - IRQ allows only a single affinity target + * IRQD_DEFAULT_TRIGGER_SET - Expected trigger already been set */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -231,6 +232,7 @@ enum { IRQD_IRQ_STARTED = (1 << 22), IRQD_MANAGED_SHUTDOWN = (1 << 23), IRQD_SINGLE_TARGET = (1 << 24), + IRQD_DEFAULT_TRIGGER_SET = (1 << 25), }; #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) @@ -260,18 +262,25 @@ static inline void irqd_mark_affinity_was_set(struct irq_data *d) __irqd_to_state(d) |= IRQD_AFFINITY_SET; } +static inline bool irqd_trigger_type_was_set(struct irq_data *d) +{ + return __irqd_to_state(d) & IRQD_DEFAULT_TRIGGER_SET; +} + static inline u32 irqd_get_trigger_type(struct irq_data *d) { return __irqd_to_state(d) & IRQD_TRIGGER_MASK; } /* - * Must only be called inside irq_chip.irq_set_type() functions. + * Must only be called inside irq_chip.irq_set_type() functions or + * from the DT/ACPI setup code. */ static inline void irqd_set_trigger_type(struct irq_data *d, u32 type) { __irqd_to_state(d) &= ~IRQD_TRIGGER_MASK; __irqd_to_state(d) |= type & IRQD_TRIGGER_MASK; + __irqd_to_state(d) |= IRQD_DEFAULT_TRIGGER_SET; } static inline bool irqd_is_level_type(struct irq_data *d) diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 2e6f90bd52aa6..f68db9e450eb3 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -2,7 +2,7 @@ #ifndef _LINUX_LINKAGE_H #define _LINUX_LINKAGE_H -#include +#include #include #include #include diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 895ec0c4942e6..a2246cf670bad 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -54,7 +54,7 @@ static inline struct page *new_page_nodemask(struct page *page, new_page = __alloc_pages_nodemask(gfp_mask, order, preferred_nid, nodemask); - if (new_page && PageTransHuge(page)) + if (new_page && PageTransHuge(new_page)) prep_transhuge_page(new_page); return new_page; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 401c8972cc3a8..a13525daf09b3 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -546,6 +547,7 @@ struct mlx5_core_sriov { }; struct mlx5_irq_info { + cpumask_var_t mask; char name[MLX5_MAX_IRQ_NAME]; }; @@ -1193,7 +1195,23 @@ enum { static inline const struct cpumask * mlx5_get_vector_affinity(struct mlx5_core_dev *dev, int vector) { - return pci_irq_get_affinity(dev->pdev, MLX5_EQ_VEC_COMP_BASE + vector); + const struct cpumask *mask; + struct irq_desc *desc; + unsigned int irq; + int eqn; + int err; + + err = mlx5_vector2eqn(dev, vector, &eqn, &irq); + if (err) + return NULL; + + desc = irq_to_desc(irq); +#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK + mask = irq_data_get_effective_affinity_mask(&desc->irq_data); +#else + mask = desc->irq_common_data.affinity; +#endif + return mask; } #endif /* MLX5_DRIVER_H */ diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 69772347f8666..f3765155fa4d9 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -147,7 +147,7 @@ enum { MLX5_CMD_OP_ALLOC_Q_COUNTER = 0x771, MLX5_CMD_OP_DEALLOC_Q_COUNTER = 0x772, MLX5_CMD_OP_QUERY_Q_COUNTER = 0x773, - MLX5_CMD_OP_SET_RATE_LIMIT = 0x780, + MLX5_CMD_OP_SET_PP_RATE_LIMIT = 0x780, MLX5_CMD_OP_QUERY_RATE_LIMIT = 0x781, MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT = 0x782, MLX5_CMD_OP_DESTROY_SCHEDULING_ELEMENT = 0x783, @@ -1023,8 +1023,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 log_max_wq_sz[0x5]; u8 nic_vport_change_event[0x1]; - u8 disable_local_lb[0x1]; - u8 reserved_at_3e2[0x9]; + u8 disable_local_lb_uc[0x1]; + u8 disable_local_lb_mc[0x1]; + u8 reserved_at_3e3[0x8]; u8 log_max_vlan_list[0x5]; u8 reserved_at_3f0[0x3]; u8 log_max_current_mc_list[0x5]; @@ -7233,7 +7234,7 @@ struct mlx5_ifc_add_vxlan_udp_dport_in_bits { u8 vxlan_udp_port[0x10]; }; -struct mlx5_ifc_set_rate_limit_out_bits { +struct mlx5_ifc_set_pp_rate_limit_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -7242,7 +7243,7 @@ struct mlx5_ifc_set_rate_limit_out_bits { u8 reserved_at_40[0x40]; }; -struct mlx5_ifc_set_rate_limit_in_bits { +struct mlx5_ifc_set_pp_rate_limit_in_bits { u8 opcode[0x10]; u8 reserved_at_10[0x10]; @@ -7255,6 +7256,8 @@ struct mlx5_ifc_set_rate_limit_in_bits { u8 reserved_at_60[0x20]; u8 rate_limit[0x20]; + + u8 reserved_at_a0[0x160]; }; struct mlx5_ifc_access_register_out_bits { diff --git a/include/linux/mm.h b/include/linux/mm.h index 43edf659453b2..f50deada0f5c5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -367,6 +367,7 @@ enum page_entry_size { struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); + int (*split)(struct vm_area_struct * area, unsigned long addr); int (*mremap)(struct vm_area_struct * area); int (*fault)(struct vm_fault *vmf); int (*huge_fault)(struct vm_fault *vmf, enum page_entry_size pe_size); @@ -1367,6 +1368,19 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, int *locked); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, struct page **pages, unsigned int gup_flags); +#ifdef CONFIG_FS_DAX +long get_user_pages_longterm(unsigned long start, unsigned long nr_pages, + unsigned int gup_flags, struct page **pages, + struct vm_area_struct **vmas); +#else +static inline long get_user_pages_longterm(unsigned long start, + unsigned long nr_pages, unsigned int gup_flags, + struct page **pages, struct vm_area_struct **vmas) +{ + return get_user_pages(start, nr_pages, gup_flags, pages, vmas); +} +#endif /* CONFIG_FS_DAX */ + int get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages); @@ -2496,7 +2510,7 @@ void vmemmap_populate_print_last(void); void vmemmap_free(unsigned long start, unsigned long end); #endif void register_page_bootmem_memmap(unsigned long section_nr, struct page *map, - unsigned long size); + unsigned long nr_pages); enum mf_flags { MF_COUNT_INCREASED = 1 << 0, diff --git a/include/linux/mman.h b/include/linux/mman.h index 7c87b6652244f..835a6f2fd8d4f 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -64,8 +64,9 @@ static inline bool arch_validate_prot(unsigned long prot) * ("bit1" and "bit2" must be single bits) */ #define _calc_vm_trans(x, bit1, bit2) \ + ((!(bit1) || !(bit2)) ? 0 : \ ((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \ - : ((x) & (bit1)) / ((bit1) / (bit2))) + : ((x) & (bit1)) / ((bit1) / (bit2)))) /* * Combine the mmap "prot" argument into "vm_flags" used internally. diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index c9c4a81b97671..f0938257ee6d3 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -700,7 +700,8 @@ typedef struct pglist_data { * is the first PFN that needs to be initialised. */ unsigned long first_deferred_pfn; - unsigned long static_init_size; + /* Number of non-deferred pages */ + unsigned long static_init_pgcnt; #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ #ifdef CONFIG_TRANSPARENT_HUGEPAGE @@ -1151,13 +1152,17 @@ struct mem_section { #define SECTION_ROOT_MASK (SECTIONS_PER_ROOT - 1) #ifdef CONFIG_SPARSEMEM_EXTREME -extern struct mem_section *mem_section[NR_SECTION_ROOTS]; +extern struct mem_section **mem_section; #else extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]; #endif static inline struct mem_section *__nr_to_section(unsigned long nr) { +#ifdef CONFIG_SPARSEMEM_EXTREME + if (!mem_section) + return NULL; +#endif if (!mem_section[SECTION_NR_TO_ROOT(nr)]) return NULL; return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK]; diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index dc8b4896b77b0..b1b0ca7ccb2ba 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -54,8 +54,9 @@ enum { NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */ NETIF_F_GSO_SCTP_BIT, /* ... SCTP fragmentation */ NETIF_F_GSO_ESP_BIT, /* ... ESP with TSO */ + NETIF_F_GSO_UDP_BIT, /* ... UFO, deprecated except tuntap */ /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ - NETIF_F_GSO_ESP_BIT, + NETIF_F_GSO_UDP_BIT, NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */ @@ -132,6 +133,7 @@ enum { #define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM) #define NETIF_F_GSO_SCTP __NETIF_F(GSO_SCTP) #define NETIF_F_GSO_ESP __NETIF_F(GSO_ESP) +#define NETIF_F_GSO_UDP __NETIF_F(GSO_UDP) #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2eaac7d75af4f..46bf7cc7d5d58 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4101,6 +4101,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_SCTP != (NETIF_F_GSO_SCTP >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_ESP != (NETIF_F_GSO_ESP >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_GSO_UDP >> NETIF_F_GSO_SHIFT)); return (features & feature) == feature; } diff --git a/include/linux/oom.h b/include/linux/oom.h index 01c91d874a57f..5bad038ac012e 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -66,6 +66,15 @@ static inline bool tsk_is_oom_victim(struct task_struct * tsk) return tsk->signal->oom_mm; } +/* + * Use this helper if tsk->mm != mm and the victim mm needs a special + * handling. This is guaranteed to stay true after once set. + */ +static inline bool mm_is_oom_victim(struct mm_struct *mm) +{ + return test_bit(MMF_OOM_VICTIM, &mm->flags); +} + /* * Checks whether a page fault on the given mm is still reliable. * This is no longer true if the oom reaper started to reap the diff --git a/include/linux/pti.h b/include/linux/pti.h index b3ea01a3197ef..0174883a935a2 100644 --- a/include/linux/pti.h +++ b/include/linux/pti.h @@ -1,43 +1,11 @@ -/* - * Copyright (C) Intel 2011 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * The PTI (Parallel Trace Interface) driver directs trace data routed from - * various parts in the system out through the Intel Penwell PTI port and - * out of the mobile device for analysis with a debugging tool - * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7, - * compact JTAG, standard. - * - * This header file will allow other parts of the OS to use the - * interface to write out it's contents for debugging a mobile system. - */ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _INCLUDE_PTI_H +#define _INCLUDE_PTI_H -#ifndef PTI_H_ -#define PTI_H_ +#ifdef CONFIG_PAGE_TABLE_ISOLATION +#include +#else +static inline void pti_init(void) { } +#endif -/* offset for last dword of any PTI message. Part of MIPI P1149.7 */ -#define PTI_LASTDWORD_DTS 0x30 - -/* basic structure used as a write address to the PTI HW */ -struct pti_masterchannel { - u8 master; - u8 channel; -}; - -/* the following functions are defined in misc/pti.c */ -void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count); -struct pti_masterchannel *pti_request_masterchannel(u8 type, - const char *thread_name); -void pti_release_masterchannel(struct pti_masterchannel *mc); - -#endif /*PTI_H_*/ +#endif diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h index 37b4bb2545b32..6866df4f31b59 100644 --- a/include/linux/ptr_ring.h +++ b/include/linux/ptr_ring.h @@ -101,12 +101,18 @@ static inline bool ptr_ring_full_bh(struct ptr_ring *r) /* Note: callers invoking this in a loop must use a compiler barrier, * for example cpu_relax(). Callers must hold producer_lock. + * Callers are responsible for making sure pointer that is being queued + * points to a valid data. */ static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr) { if (unlikely(!r->size) || r->queue[r->producer]) return -ENOSPC; + /* Make sure the pointer we are storing points to a valid data. */ + /* Pairs with smp_read_barrier_depends in __ptr_ring_consume. */ + smp_wmb(); + r->queue[r->producer++] = ptr; if (unlikely(r->producer >= r->size)) r->producer = 0; @@ -275,6 +281,9 @@ static inline void *__ptr_ring_consume(struct ptr_ring *r) if (ptr) __ptr_ring_discard_one(r); + /* Make sure anyone accessing data through the pointer is up to date. */ + /* Pairs with smp_wmb in __ptr_ring_produce. */ + smp_read_barrier_depends(); return ptr; } diff --git a/include/linux/rculist.h b/include/linux/rculist.h index c2cdd45a880aa..127f534fec94a 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -275,7 +275,7 @@ static inline void list_splice_tail_init_rcu(struct list_head *list, * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_entry_rcu(ptr, type, member) \ - container_of(lockless_dereference(ptr), type, member) + container_of(READ_ONCE(ptr), type, member) /* * Where are list_empty_rcu() and list_first_entry_rcu()? @@ -368,7 +368,7 @@ static inline void list_splice_tail_init_rcu(struct list_head *list, * example is when items are added to the list, but never deleted. */ #define list_entry_lockless(ptr, type, member) \ - container_of((typeof(ptr))lockless_dereference(ptr), type, member) + container_of((typeof(ptr))READ_ONCE(ptr), type, member) /** * list_for_each_entry_lockless - iterate over rcu list of given type diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h index a328e8181e49f..e4b257ff881bf 100644 --- a/include/linux/rculist_nulls.h +++ b/include/linux/rculist_nulls.h @@ -100,44 +100,6 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, first->pprev = &n->next; } -/** - * hlist_nulls_add_tail_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the end of the specified hlist_nulls, - * while permitting racing traversals. NOTE: tail insertion requires - * list traversal. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() - * or hlist_nulls_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n, - struct hlist_nulls_head *h) -{ - struct hlist_nulls_node *i, *last = NULL; - - for (i = hlist_nulls_first_rcu(h); !is_a_nulls(i); - i = hlist_nulls_next_rcu(i)) - last = i; - - if (last) { - n->next = last->next; - n->pprev = &last->next; - rcu_assign_pointer(hlist_nulls_next_rcu(last), n); - } else { - hlist_nulls_add_head_rcu(n, h); - } -} - /** * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type * @tpos: the type * to use as a loop cursor. diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 1a9f70d44af95..a6ddc42f87a57 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -346,7 +346,7 @@ static inline void rcu_preempt_sleep_check(void) { } #define __rcu_dereference_check(p, c, space) \ ({ \ /* Dependency order vs. p above. */ \ - typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \ + typeof(*p) *________p1 = (typeof(*p) *__force)READ_ONCE(p); \ RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(________p1)); \ @@ -360,7 +360,7 @@ static inline void rcu_preempt_sleep_check(void) { } #define rcu_dereference_raw(p) \ ({ \ /* Dependency order vs. p above. */ \ - typeof(p) ________p1 = lockless_dereference(p); \ + typeof(p) ________p1 = READ_ONCE(p); \ ((typeof(*p) __force __kernel *)(________p1)); \ }) diff --git a/include/linux/sched/coredump.h b/include/linux/sched/coredump.h index 9c8847395b5e1..ec912d01126f4 100644 --- a/include/linux/sched/coredump.h +++ b/include/linux/sched/coredump.h @@ -70,6 +70,7 @@ static inline int get_dumpable(struct mm_struct *mm) #define MMF_UNSTABLE 22 /* mm is unstable for copy_from_user */ #define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */ #define MMF_DISABLE_THP 24 /* disable THP for all VMAs */ +#define MMF_OOM_VICTIM 25 /* mm is the oom victim */ #define MMF_DISABLE_THP_MASK (1 << MMF_DISABLE_THP) #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\ diff --git a/include/linux/sh_eth.h b/include/linux/sh_eth.h index ff3642d267f7f..94081e9a50106 100644 --- a/include/linux/sh_eth.h +++ b/include/linux/sh_eth.h @@ -17,7 +17,6 @@ struct sh_eth_plat_data { unsigned char mac_addr[ETH_ALEN]; unsigned no_ether_link:1; unsigned ether_link_active_low:1; - unsigned needs_init:1; }; #endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d448a4804aeab..051e0939ec190 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -569,6 +569,8 @@ enum { SKB_GSO_SCTP = 1 << 14, SKB_GSO_ESP = 1 << 15, + + SKB_GSO_UDP = 1 << 16, }; #if BITS_PER_LONG > 32 diff --git a/include/linux/string.h b/include/linux/string.h index 410ecf17de3ce..cfd83eb2f926c 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -259,7 +259,10 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) { __kernel_size_t ret; size_t p_size = __builtin_object_size(p, 0); - if (p_size == (size_t)-1) + + /* Work around gcc excess stack consumption issue */ + if (p_size == (size_t)-1 || + (__builtin_constant_p(p[p_size - 1]) && p[p_size - 1] == '\0')) return __builtin_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) diff --git a/include/linux/swapops.h b/include/linux/swapops.h index 9c5a2628d6ce7..1d3877c39a000 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -124,6 +124,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry) return unlikely(swp_type(entry) == SWP_DEVICE_WRITE); } +static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +{ + return swp_offset(entry); +} + static inline struct page *device_private_entry_to_page(swp_entry_t entry) { return pfn_to_page(swp_offset(entry)); @@ -154,6 +159,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry) return false; } +static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +{ + return 0; +} + static inline struct page *device_private_entry_to_page(swp_entry_t entry) { return NULL; @@ -189,6 +199,11 @@ static inline int is_write_migration_entry(swp_entry_t entry) return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); } +static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +{ + return swp_offset(entry); +} + static inline struct page *migration_entry_to_page(swp_entry_t entry) { struct page *p = pfn_to_page(swp_offset(entry)); @@ -218,6 +233,12 @@ static inline int is_migration_entry(swp_entry_t swp) { return 0; } + +static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +{ + return 0; +} + static inline struct page *migration_entry_to_page(swp_entry_t entry) { return NULL; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index e32dfe098e822..40839c02d28c0 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -117,6 +117,12 @@ struct attribute_group { .show = _name##_show, \ } +#define __ATTR_RO_MODE(_name, _mode) { \ + .attr = { .name = __stringify(_name), \ + .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ + .show = _name##_show, \ +} + #define __ATTR_WO(_name) { \ .attr = { .name = __stringify(_name), .mode = S_IWUSR }, \ .store = _name##_store, \ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 4aa40ef02d32c..e8418fc77a43f 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -214,7 +214,8 @@ struct tcp_sock { u8 chrono_type:2, /* current chronograph type */ rate_app_limited:1, /* rate_{delivered,interval_us} limited? */ fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ - unused:4; + is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ + unused:3; u8 nonagle : 4,/* Disable Nagle algorithm? */ thin_lto : 1,/* Use linear timeouts for thin streams */ unused1 : 1, diff --git a/include/linux/tick.h b/include/linux/tick.h index cf413b344ddb7..5cdac11dd3170 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -119,6 +119,7 @@ extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); extern ktime_t tick_nohz_get_sleep_length(void); extern unsigned long tick_nohz_get_idle_calls(void); +extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); #else /* !CONFIG_NO_HZ_COMMON */ diff --git a/include/linux/timer.h b/include/linux/timer.h index ac66f29c69169..e0ea1fe87572e 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -246,9 +246,11 @@ unsigned long round_jiffies_up(unsigned long j); unsigned long round_jiffies_up_relative(unsigned long j); #ifdef CONFIG_HOTPLUG_CPU +int timers_prepare_cpu(unsigned int cpu); int timers_dead_cpu(unsigned int cpu); #else -#define timers_dead_cpu NULL +#define timers_prepare_cpu NULL +#define timers_dead_cpu NULL #endif #endif diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 97116379db5ff..e87a805cbfeff 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -81,6 +81,7 @@ struct usbnet { # define EVENT_RX_KILL 10 # define EVENT_LINK_CHANGE 11 # define EVENT_SET_RX_MODE 12 +# define EVENT_NO_IP_ALIGN 13 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 210034c896e31..f144216febc64 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -9,7 +9,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, const struct virtio_net_hdr *hdr, bool little_endian) { - unsigned short gso_type = 0; + unsigned int gso_type = 0; if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { @@ -19,6 +19,9 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, case VIRTIO_NET_HDR_GSO_TCPV6: gso_type = SKB_GSO_TCPV6; break; + case VIRTIO_NET_HDR_GSO_UDP: + gso_type = SKB_GSO_UDP; + break; default: return -EINVAL; } diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h new file mode 100644 index 0000000000000..f4a698a228803 --- /dev/null +++ b/include/linux/wakelock.h @@ -0,0 +1,67 @@ +/* include/linux/wakelock.h + * + * Copyright (C) 2007-2012 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_WAKELOCK_H +#define _LINUX_WAKELOCK_H + +#include +#include + +/* A wake_lock prevents the system from entering suspend or other low power + * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock + * prevents a full system suspend. + */ + +enum { + WAKE_LOCK_SUSPEND, /* Prevent suspend */ + WAKE_LOCK_TYPE_COUNT +}; + +struct wake_lock { + struct wakeup_source ws; +}; + +static inline void wake_lock_init(struct wake_lock *lock, int type, + const char *name) +{ + wakeup_source_init(&lock->ws, name); +} + +static inline void wake_lock_destroy(struct wake_lock *lock) +{ + wakeup_source_trash(&lock->ws); +} + +static inline void wake_lock(struct wake_lock *lock) +{ + __pm_stay_awake(&lock->ws); +} + +static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) +{ + __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); +} + +static inline void wake_unlock(struct wake_lock *lock) +{ + __pm_relax(&lock->ws); +} + +static inline int wake_lock_active(struct wake_lock *lock) +{ + return lock->ws.active; +} + +#endif diff --git a/include/net/arp.h b/include/net/arp.h index dc8cd47f883b8..977aabfcdc03b 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -20,6 +20,9 @@ static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) { + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) + key = INADDR_ANY; + return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev); } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f12fa5245a453..946ccff6ddc0f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3261,7 +3261,7 @@ enum wiphy_flags { WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), WIPHY_FLAG_IBSS_RSN = BIT(8), WIPHY_FLAG_MESH_AUTH = BIT(10), - /* use hole at 11 */ + WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), /* use hole at 12 */ WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), WIPHY_FLAG_AP_UAPSD = BIT(14), diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 5ac169a735f4b..b25568a44e59d 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -144,6 +144,51 @@ struct genl_ops { }; int genl_register_family(struct genl_family *family); + +/** + * genl_register_family_with_ops - register a generic netlink family with ops + * @family: generic netlink family + * @ops: operations to be registered + * @n_ops: number of elements to register + * + * Registers the specified family and operations from the specified table. + * Only one family may be registered with the same family name or identifier. + * + * The family id may equal GENL_ID_GENERATE causing an unique id to + * be automatically generated and assigned. + * + * Either a doit or dumpit callback must be specified for every registered + * operation or the function will fail. Only one operation structure per + * command identifier may be registered. + * + * See include/net/genetlink.h for more documenation on the operations + * structure. + * + * Return 0 on success or a negative error code. + */ +static inline int +_genl_register_family_with_ops_grps(struct genl_family *family, + const struct genl_ops *ops, size_t n_ops, + const struct genl_multicast_group *mcgrps, + size_t n_mcgrps) +{ + family->module = THIS_MODULE; + family->ops = ops; + family->n_ops = n_ops; + family->mcgrps = mcgrps; + family->n_mcgrps = n_mcgrps; + return genl_register_family(family); +} + +#define genl_register_family_with_ops(family, ops) \ + _genl_register_family_with_ops_grps((family), \ + (ops), ARRAY_SIZE(ops), \ + NULL, 0) +#define genl_register_family_with_ops_groups(family, ops, grps) \ + _genl_register_family_with_ops_grps((family), \ + (ops), ARRAY_SIZE(ops), \ + (grps), ARRAY_SIZE(grps)) + int genl_unregister_family(const struct genl_family *family); void genl_notify(const struct genl_family *family, struct sk_buff *skb, struct genl_info *info, u32 group, gfp_t flags); diff --git a/include/net/ip.h b/include/net/ip.h index 9896f46cbbf11..af8addbaa3c18 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -34,6 +34,7 @@ #include #define IPV4_MAX_PMTU 65535U /* RFC 2675, Section 5.1 */ +#define IPV4_MIN_MTU 68 /* RFC 791 */ struct sock; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 6eac5cf8f1e6e..9596aa93d6ef3 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -291,6 +291,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, int flags); int ip6_flowlabel_init(void); void ip6_flowlabel_cleanup(void); +bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np); static inline void fl6_sock_release(struct ip6_flowlabel *fl) { @@ -727,7 +728,7 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add __be32 ipv6_select_ident(struct net *net, const struct in6_addr *daddr, const struct in6_addr *saddr); -void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); +__be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); int ip6_dst_hoplimit(struct dst_entry *dst); diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 10f99dafd5acb..049008493faf6 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -223,6 +223,11 @@ int net_eq(const struct net *net1, const struct net *net2) return net1 == net2; } +static inline int check_net(const struct net *net) +{ + return atomic_read(&net->count) != 0; +} + void net_drop_ns(void *); #else @@ -247,6 +252,11 @@ int net_eq(const struct net *net1, const struct net *net2) return 1; } +static inline int check_net(const struct net *net) +{ + return 1; +} + #define net_drop_ns NULL #endif diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0477945de1a3c..8e1e1dc490fd9 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -955,7 +955,7 @@ void sctp_transport_burst_limited(struct sctp_transport *); void sctp_transport_burst_reset(struct sctp_transport *); unsigned long sctp_transport_timeout(struct sctp_transport *); void sctp_transport_reset(struct sctp_transport *t); -void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu); +bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu); void sctp_transport_immediate_rtx(struct sctp_transport *); void sctp_transport_dst_release(struct sctp_transport *t); void sctp_transport_dst_confirm(struct sctp_transport *t); diff --git a/include/net/sock.h b/include/net/sock.h index a6b9a8d1a6df3..006580155a87e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -683,11 +683,7 @@ static inline void sk_add_node_rcu(struct sock *sk, struct hlist_head *list) static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) { - if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport && - sk->sk_family == AF_INET6) - hlist_nulls_add_tail_rcu(&sk->sk_nulls_node, list); - else - hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); + hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); } static inline void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) diff --git a/include/net/tcp.h b/include/net/tcp.h index e6d0002a1b0bc..0a13574134b8b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -563,7 +563,7 @@ void tcp_push_one(struct sock *, unsigned int mss_now); void tcp_send_ack(struct sock *sk); void tcp_send_delayed_ack(struct sock *sk); void tcp_send_loss_probe(struct sock *sk); -bool tcp_schedule_loss_probe(struct sock *sk); +bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto); void tcp_skb_collapse_tstamp(struct sk_buff *skb, const struct sk_buff *next_skb); @@ -874,12 +874,11 @@ static inline int tcp_v6_sdif(const struct sk_buff *skb) } #endif -/* TCP_SKB_CB reference means this can not be used from early demux */ static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb) { #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) if (!net->ipv4.sysctl_tcp_l3mdev_accept && - skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags)) + skb && ipv4_l3mdev_skb(IPCB(skb)->flags)) return true; #endif return false; @@ -1086,7 +1085,7 @@ void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb); void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, struct rate_sample *rs); void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, - struct rate_sample *rs); + bool is_sack_reneg, struct rate_sample *rs); void tcp_rate_check_app_limited(struct sock *sk); /* These functions determine how the current flow behaves in respect of SACK diff --git a/include/net/tls.h b/include/net/tls.h index b89d397dd62fc..df950383b8c18 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -35,6 +35,10 @@ #define _TLS_OFFLOAD_H #include +#include +#include +#include +#include #include @@ -164,7 +168,7 @@ static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx) static inline void tls_err_abort(struct sock *sk) { - sk->sk_err = -EBADMSG; + sk->sk_err = EBADMSG; sk->sk_error_report(sk); } diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index ec5008cf5d51d..b2a10c7623047 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -245,10 +245,11 @@ static inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_g static inline enum ib_mtu iboe_get_mtu(int mtu) { /* - * reduce IB headers from effective IBoE MTU. 28 stands for - * atomic header which is the biggest possible header after BTH + * Reduce IB headers from effective IBoE MTU. */ - mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28; + mtu = mtu - (IB_GRH_BYTES + IB_UDP_BYTES + IB_BTH_BYTES + + IB_EXT_XRC_BYTES + IB_EXT_ATOMICETH_BYTES + + IB_ICRC_BYTES); if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) return IB_MTU_4096; @@ -305,12 +306,12 @@ static inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) static inline int rdma_is_multicast_addr(struct in6_addr *addr) { - u32 ipv4_addr; + __be32 ipv4_addr; if (addr->s6_addr[0] == 0xff) return 1; - memcpy(&ipv4_addr, addr->s6_addr + 12, 4); + ipv4_addr = addr->s6_addr32[3]; return (ipv6_addr_v4mapped(addr) && ipv4_is_multicast(ipv4_addr)); } diff --git a/include/rdma/ib_pack.h b/include/rdma/ib_pack.h index 36655899ee028..7ea1382ad0e59 100644 --- a/include/rdma/ib_pack.h +++ b/include/rdma/ib_pack.h @@ -37,14 +37,17 @@ #include enum { - IB_LRH_BYTES = 8, - IB_ETH_BYTES = 14, - IB_VLAN_BYTES = 4, - IB_GRH_BYTES = 40, - IB_IP4_BYTES = 20, - IB_UDP_BYTES = 8, - IB_BTH_BYTES = 12, - IB_DETH_BYTES = 8 + IB_LRH_BYTES = 8, + IB_ETH_BYTES = 14, + IB_VLAN_BYTES = 4, + IB_GRH_BYTES = 40, + IB_IP4_BYTES = 20, + IB_UDP_BYTES = 8, + IB_BTH_BYTES = 12, + IB_DETH_BYTES = 8, + IB_EXT_ATOMICETH_BYTES = 28, + IB_EXT_XRC_BYTES = 4, + IB_ICRC_BYTES = 4 }; struct ib_field { diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 6c0dc6155ee75..a966d281dedc3 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -165,11 +165,11 @@ struct expander_device { struct sata_device { unsigned int class; - struct smp_resp rps_resp; /* report_phy_sata_resp */ u8 port_no; /* port number, if this is a PM (Port) */ struct ata_port *ap; struct ata_host ata_host; + struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */ u8 fis[ATA_RESP_FIS_SIZE]; }; diff --git a/include/soc/mediatek/pmic_wrap.h b/include/soc/mediatek/pmic_wrap.h new file mode 100644 index 0000000000000..5b5c85272c58b --- /dev/null +++ b/include/soc/mediatek/pmic_wrap.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SOC_MEDIATEK_PMIC_WRAP_H +#define __SOC_MEDIATEK_PMIC_WRAP_H + +extern struct regmap *pwrap_node_to_regmap(struct device_node *np); + +#endif /* __SOC_MEDIATEK_PMIC_WRAP_H */ diff --git a/include/sound/control.h b/include/sound/control.h index a1f1152bc6876..ca13a44ae9d44 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -249,7 +249,9 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl, void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only); #define snd_ctl_sync_vmaster_hook(kctl) snd_ctl_sync_vmaster(kctl, true) int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, - int (*func)(struct snd_kcontrol *, void *), + int (*func)(struct snd_kcontrol *vslave, + struct snd_kcontrol *slave, + void *arg), void *arg); /* diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index f5db145e68eca..0d924e968c94b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -490,6 +490,7 @@ struct se_cmd { #define CMD_T_STOP (1 << 5) #define CMD_T_TAS (1 << 10) #define CMD_T_FABRIC_STOP (1 << 11) +#define CMD_T_PRE_EXECUTE (1 << 12) spinlock_t t_state_lock; struct kref cmd_kref; struct completion t_transport_stop_comp; diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index e4b0b8e099325..2c735a3e66133 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h @@ -211,7 +211,7 @@ TRACE_EVENT(kvm_ack_irq, { KVM_TRACE_MMIO_WRITE, "write" } TRACE_EVENT(kvm_mmio, - TP_PROTO(int type, int len, u64 gpa, u64 val), + TP_PROTO(int type, int len, u64 gpa, void *val), TP_ARGS(type, len, gpa, val), TP_STRUCT__entry( @@ -225,7 +225,10 @@ TRACE_EVENT(kvm_mmio, __entry->type = type; __entry->len = len; __entry->gpa = gpa; - __entry->val = val; + __entry->val = 0; + if (val) + memcpy(&__entry->val, val, + min_t(u32, sizeof(__entry->val), len)); ), TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx", diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 25a7739514cd8..3868b47523246 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -456,20 +456,22 @@ TRACE_EVENT(svc_recv, TP_ARGS(rqst, status), TP_STRUCT__entry( - __field(struct sockaddr *, addr) __field(__be32, xid) __field(int, status) __field(unsigned long, flags) + __dynamic_array(unsigned char, addr, rqst->rq_addrlen) ), TP_fast_assign( - __entry->addr = (struct sockaddr *)&rqst->rq_addr; __entry->xid = status > 0 ? rqst->rq_xid : 0; __entry->status = status; __entry->flags = rqst->rq_flags; + memcpy(__get_dynamic_array(addr), + &rqst->rq_addr, rqst->rq_addrlen); ), - TP_printk("addr=%pIScp xid=0x%x status=%d flags=%s", __entry->addr, + TP_printk("addr=%pIScp xid=0x%x status=%d flags=%s", + (struct sockaddr *)__get_dynamic_array(addr), be32_to_cpu(__entry->xid), __entry->status, show_rqstp_flags(__entry->flags)) ); @@ -514,22 +516,23 @@ DECLARE_EVENT_CLASS(svc_rqst_status, TP_ARGS(rqst, status), TP_STRUCT__entry( - __field(struct sockaddr *, addr) __field(__be32, xid) - __field(int, dropme) __field(int, status) __field(unsigned long, flags) + __dynamic_array(unsigned char, addr, rqst->rq_addrlen) ), TP_fast_assign( - __entry->addr = (struct sockaddr *)&rqst->rq_addr; __entry->xid = rqst->rq_xid; __entry->status = status; __entry->flags = rqst->rq_flags; + memcpy(__get_dynamic_array(addr), + &rqst->rq_addr, rqst->rq_addrlen); ), TP_printk("addr=%pIScp rq_xid=0x%x status=%d flags=%s", - __entry->addr, be32_to_cpu(__entry->xid), + (struct sockaddr *)__get_dynamic_array(addr), + be32_to_cpu(__entry->xid), __entry->status, show_rqstp_flags(__entry->flags)) ); diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h index 90fc490f973f9..821f71a2e48fa 100644 --- a/include/uapi/linux/bcache.h +++ b/include/uapi/linux/bcache.h @@ -91,7 +91,7 @@ PTR_FIELD(PTR_GEN, 0, 8) #define PTR_CHECK_DEV ((1 << PTR_DEV_BITS) - 1) -#define PTR(gen, offset, dev) \ +#define MAKE_PTR(gen, offset, dev) \ ((((__u64) dev) << 51) | ((__u64) offset) << 8 | gen) /* Bkey utility code */ diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h index 877f7fa954666..c8456b78cc258 100644 --- a/include/uapi/linux/genetlink.h +++ b/include/uapi/linux/genetlink.h @@ -27,6 +27,7 @@ struct genlmsghdr { /* * List of reserved static generic netlink identifiers: */ +#define GENL_ID_GENERATE 0 #define GENL_ID_CTRL NLMSG_MIN_TYPE #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) diff --git a/include/uapi/linux/rxrpc.h b/include/uapi/linux/rxrpc.h index 9656aad8f8f7b..9d4afea308a43 100644 --- a/include/uapi/linux/rxrpc.h +++ b/include/uapi/linux/rxrpc.h @@ -20,12 +20,12 @@ * RxRPC socket address */ struct sockaddr_rxrpc { - sa_family_t srx_family; /* address family */ - u16 srx_service; /* service desired */ - u16 transport_type; /* type of transport socket (SOCK_DGRAM) */ - u16 transport_len; /* length of transport address */ + __kernel_sa_family_t srx_family; /* address family */ + __u16 srx_service; /* service desired */ + __u16 transport_type; /* type of transport socket (SOCK_DGRAM) */ + __u16 transport_len; /* length of transport address */ union { - sa_family_t family; /* transport address family */ + __kernel_sa_family_t family; /* transport address family */ struct sockaddr_in sin; /* IPv4 transport address */ struct sockaddr_in6 sin6; /* IPv6 transport address */ } transport; diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h index f65b92e0e1f91..ee8220f8dcf5f 100644 --- a/include/uapi/linux/stddef.h +++ b/include/uapi/linux/stddef.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#include +#include #ifndef __always_inline #define __always_inline inline diff --git a/include/uapi/linux/tls.h b/include/uapi/linux/tls.h index d5e0682ab8371..293b2cdad88d9 100644 --- a/include/uapi/linux/tls.h +++ b/include/uapi/linux/tls.h @@ -35,10 +35,6 @@ #define _UAPI_LINUX_TLS_H #include -#include -#include -#include -#include /* TLS socket options */ #define TLS_TX 1 /* Set transmit parameters */ diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index cec06625f4076..8512777889b02 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -876,6 +876,8 @@ struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ __u8 bReserved; } __attribute__((packed)); +#define USB_DT_USB_WIRELESS_CAP_SIZE 11 + /* USB 2.0 Extension descriptor */ #define USB_CAP_TYPE_EXT 2 @@ -1068,6 +1070,7 @@ struct usb_ptm_cap_descriptor { __u8 bDevCapabilityType; } __attribute__((packed)); +#define USB_DT_USB_PTM_ID_SIZE 3 /* * The size of the descriptor for the Sublink Speed Attribute Count * (SSAC) specified in bmAttributes[4:0]. diff --git a/init/Kconfig b/init/Kconfig index 3c1faaa2af4aa..46075327c165d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1342,6 +1342,13 @@ config BPF_SYSCALL Enable the bpf() system call that allows to manipulate eBPF programs and maps via file descriptors. +config BPF_JIT_ALWAYS_ON + bool "Permanently enable BPF JIT and remove BPF interpreter" + depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT + help + Enables BPF JIT and removes BPF interpreter to avoid + speculative execution of BPF instructions by the interpreter + config SHMEM bool "Use full shmem filesystem" if EXPERT default y diff --git a/init/main.c b/init/main.c index 0ee9c6866ada1..b32ec72cdf3dd 100644 --- a/init/main.c +++ b/init/main.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -504,6 +505,10 @@ static void __init mm_init(void) pgtable_init(); vmalloc_init(); ioremap_huge_init(); + /* Should be run before the first non-init thread is created */ + init_espfix_bsp(); + /* Should be run after espfix64 is set up. */ + pti_init(); } asmlinkage __visible void __init start_kernel(void) @@ -673,10 +678,6 @@ asmlinkage __visible void __init start_kernel(void) #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); -#endif -#ifdef CONFIG_X86_ESPFIX64 - /* Should be run before the first non-init thread is created */ - init_espfix_bsp(); #endif thread_stack_cache_init(); cred_init(); diff --git a/kernel/acct.c b/kernel/acct.c index 6670fbd3e466d..354578d253d59 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -102,7 +102,7 @@ static int check_free_space(struct bsd_acct_struct *acct) { struct kstatfs sbuf; - if (time_is_before_jiffies(acct->needcheck)) + if (time_is_after_jiffies(acct->needcheck)) goto out; /* May block */ diff --git a/kernel/audit.c b/kernel/audit.c index be1c28fd4d575..5b34d3114af48 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -85,13 +85,13 @@ static int audit_initialized; #define AUDIT_OFF 0 #define AUDIT_ON 1 #define AUDIT_LOCKED 2 -u32 audit_enabled; -u32 audit_ever_enabled; +u32 audit_enabled = AUDIT_OFF; +u32 audit_ever_enabled = !!AUDIT_OFF; EXPORT_SYMBOL_GPL(audit_enabled); /* Default state when kernel boots without any parameters. */ -static u32 audit_default; +static u32 audit_default = AUDIT_OFF; /* If auditing cannot proceed, audit_failure selects what happens. */ static u32 audit_failure = AUDIT_FAIL_PRINTK; @@ -1197,25 +1197,28 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) pid_t auditd_pid; struct pid *req_pid = task_tgid(current); - /* sanity check - PID values must match */ - if (new_pid != pid_vnr(req_pid)) + /* Sanity check - PID values must match. Setting + * pid to 0 is how auditd ends auditing. */ + if (new_pid && (new_pid != pid_vnr(req_pid))) return -EINVAL; /* test the auditd connection */ audit_replace(req_pid); auditd_pid = auditd_pid_vnr(); - /* only the current auditd can unregister itself */ - if ((!new_pid) && (new_pid != auditd_pid)) { - audit_log_config_change("audit_pid", new_pid, - auditd_pid, 0); - return -EACCES; - } - /* replacing a healthy auditd is not allowed */ - if (auditd_pid && new_pid) { - audit_log_config_change("audit_pid", new_pid, - auditd_pid, 0); - return -EEXIST; + if (auditd_pid) { + /* replacing a healthy auditd is not allowed */ + if (new_pid) { + audit_log_config_change("audit_pid", + new_pid, auditd_pid, 0); + return -EEXIST; + } + /* only current auditd can unregister itself */ + if (pid_vnr(req_pid) != auditd_pid) { + audit_log_config_change("audit_pid", + new_pid, auditd_pid, 0); + return -EACCES; + } } if (new_pid) { @@ -1549,8 +1552,6 @@ static int __init audit_init(void) register_pernet_subsys(&audit_net_ops); audit_initialized = AUDIT_INITIALIZED; - audit_enabled = audit_default; - audit_ever_enabled |= !!audit_default; kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd"); if (IS_ERR(kauditd_task)) { @@ -1572,6 +1573,8 @@ static int __init audit_enable(char *str) audit_default = !!simple_strtol(str, NULL, 0); if (!audit_default) audit_initialized = AUDIT_DISABLED; + audit_enabled = audit_default; + audit_ever_enabled = !!audit_enabled; pr_info("%s\n", audit_default ? "enabled (after initialization)" : "disabled (until reboot)"); diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index e2636737b69bd..a4ae1ca44a576 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -50,9 +50,10 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) { bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; int numa_node = bpf_map_attr_numa_node(attr); + u32 elem_size, index_mask, max_entries; + bool unpriv = !capable(CAP_SYS_ADMIN); struct bpf_array *array; - u64 array_size; - u32 elem_size; + u64 array_size, mask64; /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 4 || @@ -68,11 +69,32 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) elem_size = round_up(attr->value_size, 8); + max_entries = attr->max_entries; + + /* On 32 bit archs roundup_pow_of_two() with max_entries that has + * upper most bit set in u32 space is undefined behavior due to + * resulting 1U << 32, so do it manually here in u64 space. + */ + mask64 = fls_long(max_entries - 1); + mask64 = 1ULL << mask64; + mask64 -= 1; + + index_mask = mask64; + if (unpriv) { + /* round up array size to nearest power of 2, + * since cpu will speculate within index_mask limits + */ + max_entries = index_mask + 1; + /* Check for overflows. */ + if (max_entries < attr->max_entries) + return ERR_PTR(-E2BIG); + } + array_size = sizeof(*array); if (percpu) - array_size += (u64) attr->max_entries * sizeof(void *); + array_size += (u64) max_entries * sizeof(void *); else - array_size += (u64) attr->max_entries * elem_size; + array_size += (u64) max_entries * elem_size; /* make sure there is no u32 overflow later in round_up() */ if (array_size >= U32_MAX - PAGE_SIZE) @@ -82,6 +104,8 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) array = bpf_map_area_alloc(array_size, numa_node); if (!array) return ERR_PTR(-ENOMEM); + array->index_mask = index_mask; + array->map.unpriv_array = unpriv; /* copy mandatory map attributes */ array->map.map_type = attr->map_type; @@ -117,12 +141,13 @@ static void *array_map_lookup_elem(struct bpf_map *map, void *key) if (unlikely(index >= array->map.max_entries)) return NULL; - return array->value + array->elem_size * index; + return array->value + array->elem_size * (index & array->index_mask); } /* emit BPF instructions equivalent to C code of array_map_lookup_elem() */ static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf) { + struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_insn *insn = insn_buf; u32 elem_size = round_up(map->value_size, 8); const int ret = BPF_REG_0; @@ -131,7 +156,12 @@ static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf) *insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value)); *insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); - *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 3); + if (map->unpriv_array) { + *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 4); + *insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask); + } else { + *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 3); + } if (is_power_of_2(elem_size)) { *insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size)); @@ -153,7 +183,7 @@ static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key) if (unlikely(index >= array->map.max_entries)) return NULL; - return this_cpu_ptr(array->pptrs[index]); + return this_cpu_ptr(array->pptrs[index & array->index_mask]); } int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value) @@ -173,7 +203,7 @@ int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value) */ size = round_up(map->value_size, 8); rcu_read_lock(); - pptr = array->pptrs[index]; + pptr = array->pptrs[index & array->index_mask]; for_each_possible_cpu(cpu) { bpf_long_memcpy(value + off, per_cpu_ptr(pptr, cpu), size); off += size; @@ -221,10 +251,11 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value, return -EEXIST; if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY) - memcpy(this_cpu_ptr(array->pptrs[index]), + memcpy(this_cpu_ptr(array->pptrs[index & array->index_mask]), value, map->value_size); else - memcpy(array->value + array->elem_size * index, + memcpy(array->value + + array->elem_size * (index & array->index_mask), value, map->value_size); return 0; } @@ -258,7 +289,7 @@ int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value, */ size = round_up(map->value_size, 8); rcu_read_lock(); - pptr = array->pptrs[index]; + pptr = array->pptrs[index & array->index_mask]; for_each_possible_cpu(cpu) { bpf_long_memcpy(per_cpu_ptr(pptr, cpu), value + off, size); off += size; @@ -609,6 +640,7 @@ static void *array_of_map_lookup_elem(struct bpf_map *map, void *key) static u32 array_of_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf) { + struct bpf_array *array = container_of(map, struct bpf_array, map); u32 elem_size = round_up(map->value_size, 8); struct bpf_insn *insn = insn_buf; const int ret = BPF_REG_0; @@ -617,7 +649,12 @@ static u32 array_of_map_gen_lookup(struct bpf_map *map, *insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value)); *insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); - *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5); + if (map->unpriv_array) { + *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 6); + *insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask); + } else { + *insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5); + } if (is_power_of_2(elem_size)) *insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size)); else diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 7b62df86be1d7..2246115365d99 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -760,6 +760,7 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) } EXPORT_SYMBOL_GPL(__bpf_call_base); +#ifndef CONFIG_BPF_JIT_ALWAYS_ON /** * __bpf_prog_run - run eBPF program on a given context * @ctx: is the data we are operating on @@ -948,7 +949,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, DST = tmp; CONT; ALU_MOD_X: - if (unlikely(SRC == 0)) + if (unlikely((u32)SRC == 0)) return 0; tmp = (u32) DST; DST = do_div(tmp, (u32) SRC); @@ -967,7 +968,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, DST = div64_u64(DST, SRC); CONT; ALU_DIV_X: - if (unlikely(SRC == 0)) + if (unlikely((u32)SRC == 0)) return 0; tmp = (u32) DST; do_div(tmp, (u32) SRC); @@ -1310,6 +1311,14 @@ EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384) EVAL4(PROG_NAME_LIST, 416, 448, 480, 512) }; +#else +static unsigned int __bpf_prog_ret0(const void *ctx, + const struct bpf_insn *insn) +{ + return 0; +} +#endif + bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp) { @@ -1357,9 +1366,13 @@ static int bpf_check_tail_call(const struct bpf_prog *fp) */ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) { +#ifndef CONFIG_BPF_JIT_ALWAYS_ON u32 stack_depth = max_t(u32, fp->aux->stack_depth, 1); fp->bpf_func = interpreters[(round_up(stack_depth, 32) / 32) - 1]; +#else + fp->bpf_func = __bpf_prog_ret0; +#endif /* eBPF JITs can rewrite the program in case constant * blinding is active. However, in case of error during @@ -1368,6 +1381,12 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) * be JITed, but falls back to the interpreter. */ fp = bpf_int_jit_compile(fp); +#ifdef CONFIG_BPF_JIT_ALWAYS_ON + if (!fp->jited) { + *err = -ENOTSUPP; + return fp; + } +#endif bpf_prog_lock_ro(fp); /* The tail call compatibility check can only be done at diff --git a/kernel/bpf/percpu_freelist.c b/kernel/bpf/percpu_freelist.c index 5c51d1985b510..673fa6fe2d73c 100644 --- a/kernel/bpf/percpu_freelist.c +++ b/kernel/bpf/percpu_freelist.c @@ -78,8 +78,10 @@ struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *s) { struct pcpu_freelist_head *head; struct pcpu_freelist_node *node; + unsigned long flags; int orig_cpu, cpu; + local_irq_save(flags); orig_cpu = cpu = raw_smp_processor_id(); while (1) { head = per_cpu_ptr(s->freelist, cpu); @@ -87,14 +89,16 @@ struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *s) node = head->first; if (node) { head->first = node->next; - raw_spin_unlock(&head->lock); + raw_spin_unlock_irqrestore(&head->lock, flags); return node; } raw_spin_unlock(&head->lock); cpu = cpumask_next(cpu, cpu_possible_mask); if (cpu >= nr_cpu_ids) cpu = 0; - if (cpu == orig_cpu) + if (cpu == orig_cpu) { + local_irq_restore(flags); return NULL; + } } } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c48ca2a34b5e1..f9339c3219bc4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -986,6 +986,13 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]); } +static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) +{ + const struct bpf_reg_state *reg = &env->cur_state.regs[regno]; + + return reg->type == PTR_TO_CTX; +} + static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, int off, int size, bool strict) { @@ -1061,6 +1068,11 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, break; case PTR_TO_STACK: pointer_desc = "stack "; + /* The stack spill tracking logic in check_stack_write() + * and check_stack_read() relies on stack accesses being + * aligned. + */ + strict = true; break; default: break; @@ -1068,6 +1080,29 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict); } +/* truncate register to smaller size (in bytes) + * must be called with size < BPF_REG_SIZE + */ +static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) +{ + u64 mask; + + /* clear high bits in bit representation */ + reg->var_off = tnum_cast(reg->var_off, size); + + /* fix arithmetic bounds */ + mask = ((u64)1 << (size * 8)) - 1; + if ((reg->umin_value & ~mask) == (reg->umax_value & ~mask)) { + reg->umin_value &= mask; + reg->umax_value &= mask; + } else { + reg->umin_value = 0; + reg->umax_value = mask; + } + reg->smin_value = reg->umin_value; + reg->smax_value = reg->umax_value; +} + /* check whether memory at (regno + off) is accessible for t = (read | write) * if t==write, value_regno is a register which value is stored into memory * if t==read, value_regno is a register which will receive the value from memory @@ -1200,9 +1235,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn if (!err && size < BPF_REG_SIZE && value_regno >= 0 && t == BPF_READ && state->regs[value_regno].type == SCALAR_VALUE) { /* b/h/w load zero-extends, mark upper bits as known 0 */ - state->regs[value_regno].var_off = tnum_cast( - state->regs[value_regno].var_off, size); - __update_reg_bounds(&state->regs[value_regno]); + coerce_reg_to_size(&state->regs[value_regno], size); } return err; } @@ -1232,6 +1265,12 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins return -EACCES; } + if (is_ctx_reg(env, insn->dst_reg)) { + verbose("BPF_XADD stores into R%d context is not allowed\n", + insn->dst_reg); + return -EACCES; + } + /* check whether atomic_add can read the memory */ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_READ, -1); @@ -1282,6 +1321,7 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno, tnum_strn(tn_buf, sizeof(tn_buf), regs[regno].var_off); verbose("invalid variable stack read R%d var_off=%s\n", regno, tn_buf); + return -EACCES; } off = regs[regno].off + regs[regno].var_off.value; if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 || @@ -1674,6 +1714,13 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) err = check_func_arg(env, BPF_REG_2, fn->arg2_type, &meta); if (err) return err; + if (func_id == BPF_FUNC_tail_call) { + if (meta.map_ptr == NULL) { + verbose("verifier bug\n"); + return -EINVAL; + } + env->insn_aux_data[insn_idx].map_ptr = meta.map_ptr; + } err = check_func_arg(env, BPF_REG_3, fn->arg3_type, &meta); if (err) return err; @@ -1742,14 +1789,6 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) return 0; } -static void coerce_reg_to_32(struct bpf_reg_state *reg) -{ - /* clear high 32 bits */ - reg->var_off = tnum_cast(reg->var_off, 4); - /* Update bounds */ - __update_reg_bounds(reg); -} - static bool signed_add_overflows(s64 a, s64 b) { /* Do the add in u64, where overflow is well-defined */ @@ -1770,6 +1809,41 @@ static bool signed_sub_overflows(s64 a, s64 b) return res > a; } +static bool check_reg_sane_offset(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, + enum bpf_reg_type type) +{ + bool known = tnum_is_const(reg->var_off); + s64 val = reg->var_off.value; + s64 smin = reg->smin_value; + + if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) { + verbose("math between %s pointer and %lld is not allowed\n", + reg_type_str[type], val); + return false; + } + + if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) { + verbose("%s pointer offset %d is not allowed\n", + reg_type_str[type], reg->off); + return false; + } + + if (smin == S64_MIN) { + verbose("math between %s pointer and register with unbounded min value is not allowed\n", + reg_type_str[type]); + return false; + } + + if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { + verbose("value %lld makes %s pointer be out of bounds\n", + smin, reg_type_str[type]); + return false; + } + + return true; +} + /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. * Caller should also handle BPF_MOV case separately. * If we return -EACCES, caller may want to try again treating pointer as a @@ -1835,6 +1909,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, dst_reg->type = ptr_reg->type; dst_reg->id = ptr_reg->id; + if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) || + !check_reg_sane_offset(env, ptr_reg, ptr_reg->type)) + return -EINVAL; + switch (opcode) { case BPF_ADD: /* We can take a fixed offset as long as it doesn't overflow @@ -1965,12 +2043,19 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, return -EACCES; } + if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type)) + return -EINVAL; + __update_reg_bounds(dst_reg); __reg_deduce_bounds(dst_reg); __reg_bound_offset(dst_reg); return 0; } +/* WARNING: This function does calculations on 64-bit values, but the actual + * execution may occur on 32-bit values. Therefore, things like bitshifts + * need extra checks in the 32-bit case. + */ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn *insn, struct bpf_reg_state *dst_reg, @@ -1981,12 +2066,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, bool src_known, dst_known; s64 smin_val, smax_val; u64 umin_val, umax_val; + u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; - if (BPF_CLASS(insn->code) != BPF_ALU64) { - /* 32-bit ALU ops are (32,32)->64 */ - coerce_reg_to_32(dst_reg); - coerce_reg_to_32(&src_reg); - } smin_val = src_reg.smin_value; smax_val = src_reg.smax_value; umin_val = src_reg.umin_value; @@ -1994,6 +2075,12 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, src_known = tnum_is_const(src_reg.var_off); dst_known = tnum_is_const(dst_reg->var_off); + if (!src_known && + opcode != BPF_ADD && opcode != BPF_SUB && opcode != BPF_AND) { + __mark_reg_unknown(dst_reg); + return 0; + } + switch (opcode) { case BPF_ADD: if (signed_add_overflows(dst_reg->smin_value, smin_val) || @@ -2122,9 +2209,9 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, __update_reg_bounds(dst_reg); break; case BPF_LSH: - if (umax_val > 63) { - /* Shifts greater than 63 are undefined. This includes - * shifts by a negative number. + if (umax_val >= insn_bitness) { + /* Shifts greater than 31 or 63 are undefined. + * This includes shifts by a negative number. */ mark_reg_unknown(regs, insn->dst_reg); break; @@ -2150,27 +2237,29 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, __update_reg_bounds(dst_reg); break; case BPF_RSH: - if (umax_val > 63) { - /* Shifts greater than 63 are undefined. This includes - * shifts by a negative number. + if (umax_val >= insn_bitness) { + /* Shifts greater than 31 or 63 are undefined. + * This includes shifts by a negative number. */ mark_reg_unknown(regs, insn->dst_reg); break; } - /* BPF_RSH is an unsigned shift, so make the appropriate casts */ - if (dst_reg->smin_value < 0) { - if (umin_val) { - /* Sign bit will be cleared */ - dst_reg->smin_value = 0; - } else { - /* Lost sign bit information */ - dst_reg->smin_value = S64_MIN; - dst_reg->smax_value = S64_MAX; - } - } else { - dst_reg->smin_value = - (u64)(dst_reg->smin_value) >> umax_val; - } + /* BPF_RSH is an unsigned shift. If the value in dst_reg might + * be negative, then either: + * 1) src_reg might be zero, so the sign bit of the result is + * unknown, so we lose our signed bounds + * 2) it's known negative, thus the unsigned bounds capture the + * signed bounds + * 3) the signed bounds cross zero, so they tell us nothing + * about the result + * If the value in dst_reg is known nonnegative, then again the + * unsigned bounts capture the signed bounds. + * Thus, in all cases it suffices to blow away our signed bounds + * and rely on inferring new ones from the unsigned bounds and + * var_off of the result. + */ + dst_reg->smin_value = S64_MIN; + dst_reg->smax_value = S64_MAX; if (src_known) dst_reg->var_off = tnum_rshift(dst_reg->var_off, umin_val); @@ -2186,6 +2275,12 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, break; } + if (BPF_CLASS(insn->code) != BPF_ALU64) { + /* 32-bit ALU ops are (32,32)->32 */ + coerce_reg_to_size(dst_reg, 4); + coerce_reg_to_size(&src_reg, 4); + } + __reg_deduce_bounds(dst_reg); __reg_bound_offset(dst_reg); return 0; @@ -2362,17 +2457,20 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) return -EACCES; } mark_reg_unknown(regs, insn->dst_reg); - /* high 32 bits are known zero. */ - regs[insn->dst_reg].var_off = tnum_cast( - regs[insn->dst_reg].var_off, 4); - __update_reg_bounds(®s[insn->dst_reg]); + coerce_reg_to_size(®s[insn->dst_reg], 4); } } else { /* case: R = imm * remember the value we stored into this reg */ regs[insn->dst_reg].type = SCALAR_VALUE; - __mark_reg_known(regs + insn->dst_reg, insn->imm); + if (BPF_CLASS(insn->code) == BPF_ALU64) { + __mark_reg_known(regs + insn->dst_reg, + insn->imm); + } else { + __mark_reg_known(regs + insn->dst_reg, + (u32)insn->imm); + } } } else if (opcode > BPF_END) { @@ -2408,6 +2506,11 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) return -EINVAL; } + if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) { + verbose("BPF_ARSH not supported for 32 bit ALU\n"); + return -EINVAL; + } + if ((opcode == BPF_LSH || opcode == BPF_RSH || opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) { int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32; @@ -3307,15 +3410,14 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, return range_within(rold, rcur) && tnum_in(rold->var_off, rcur->var_off); } else { - /* if we knew anything about the old value, we're not - * equal, because we can't know anything about the - * scalar value of the pointer in the new value. + /* We're trying to use a pointer in place of a scalar. + * Even if the scalar was unbounded, this could lead to + * pointer leaks because scalars are allowed to leak + * while pointers are not. We could make this safe in + * special cases if root is calling us, but it's + * probably not worth the hassle. */ - return rold->umin_value == 0 && - rold->umax_value == U64_MAX && - rold->smin_value == S64_MIN && - rold->smax_value == S64_MAX && - tnum_is_unknown(rold->var_off); + return false; } case PTR_TO_MAP_VALUE: /* If the new min/max/var_off satisfy the old ones and @@ -3665,6 +3767,7 @@ static int do_check(struct bpf_verifier_env *env) if (err) return err; + env->insn_aux_data[insn_idx].seen = true; if (class == BPF_ALU || class == BPF_ALU64) { err = check_alu_op(env, insn); if (err) @@ -3769,6 +3872,12 @@ static int do_check(struct bpf_verifier_env *env) if (err) return err; + if (is_ctx_reg(env, insn->dst_reg)) { + verbose("BPF_ST stores into R%d context is not allowed\n", + insn->dst_reg); + return -EACCES; + } + /* check that memory (dst_reg + off) is writeable */ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_WRITE, @@ -3855,6 +3964,7 @@ static int do_check(struct bpf_verifier_env *env) return err; insn_idx++; + env->insn_aux_data[insn_idx].seen = true; } else { verbose("invalid BPF_LD mode\n"); return -EINVAL; @@ -4035,6 +4145,7 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len, u32 off, u32 cnt) { struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data; + int i; if (cnt == 1) return 0; @@ -4044,6 +4155,8 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len, memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off); memcpy(new_data + off + cnt - 1, old_data + off, sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1)); + for (i = off; i < off + cnt - 1; i++) + new_data[i].seen = true; env->insn_aux_data = new_data; vfree(old_data); return 0; @@ -4062,6 +4175,25 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of return new_prog; } +/* The verifier does more data flow analysis than llvm and will not explore + * branches that are dead at run time. Malicious programs can have dead code + * too. Therefore replace all dead at-run-time code with nops. + */ +static void sanitize_dead_code(struct bpf_verifier_env *env) +{ + struct bpf_insn_aux_data *aux_data = env->insn_aux_data; + struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0); + struct bpf_insn *insn = env->prog->insnsi; + const int insn_cnt = env->prog->len; + int i; + + for (i = 0; i < insn_cnt; i++) { + if (aux_data[i].seen) + continue; + memcpy(insn + i, &nop, sizeof(nop)); + } +} + /* convert load instructions that access fields of 'struct __sk_buff' * into sequence of instructions that access fields of 'struct sk_buff' */ @@ -4191,6 +4323,24 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) int i, cnt, delta = 0; for (i = 0; i < insn_cnt; i++, insn++) { + if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) || + insn->code == (BPF_ALU | BPF_DIV | BPF_X)) { + /* due to JIT bugs clear upper 32-bits of src register + * before div/mod operation + */ + insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg); + insn_buf[1] = *insn; + cnt = 2; + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); + if (!new_prog) + return -ENOMEM; + + delta += cnt - 1; + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; + continue; + } + if (insn->code != (BPF_JMP | BPF_CALL)) continue; @@ -4214,6 +4364,35 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) */ insn->imm = 0; insn->code = BPF_JMP | BPF_TAIL_CALL; + + /* instead of changing every JIT dealing with tail_call + * emit two extra insns: + * if (index >= max_entries) goto out; + * index &= array->index_mask; + * to avoid out-of-bounds cpu speculation + */ + map_ptr = env->insn_aux_data[i + delta].map_ptr; + if (map_ptr == BPF_MAP_PTR_POISON) { + verbose("tail_call obusing map_ptr\n"); + return -EINVAL; + } + if (!map_ptr->unpriv_array) + continue; + insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3, + map_ptr->max_entries, 2); + insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3, + container_of(map_ptr, + struct bpf_array, + map)->index_mask); + insn_buf[2] = *insn; + cnt = 3; + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); + if (!new_prog) + return -ENOMEM; + + delta += cnt - 1; + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; continue; } @@ -4378,6 +4557,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) while (pop_stack(env, NULL) >= 0); free_states(env); + if (ret == 0) + sanitize_dead_code(env); + if (ret == 0) /* program is valid, convert *(u32*)(ctx + off) accesses */ ret = convert_ctx_accesses(env); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 44857278eb8aa..030e4286f14c7 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4059,26 +4059,24 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it) static void css_task_iter_advance(struct css_task_iter *it) { - struct list_head *l = it->task_pos; + struct list_head *next; lockdep_assert_held(&css_set_lock); - WARN_ON_ONCE(!l); - repeat: /* * Advance iterator to find next entry. cset->tasks is consumed * first and then ->mg_tasks. After ->mg_tasks, we move onto the * next cset. */ - l = l->next; + next = it->task_pos->next; - if (l == it->tasks_head) - l = it->mg_tasks_head->next; + if (next == it->tasks_head) + next = it->mg_tasks_head->next; - if (l == it->mg_tasks_head) + if (next == it->mg_tasks_head) css_task_iter_advance_css_set(it); else - it->task_pos = l; + it->task_pos = next; /* if PROCS, skip over tasks which aren't group leaders */ if ((it->flags & CSS_TASK_ITER_PROCS) && it->task_pos && diff --git a/kernel/cpu.c b/kernel/cpu.c index 04892a82f6ac3..f21bfa3172d8a 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1277,9 +1277,9 @@ static struct cpuhp_step cpuhp_bp_states[] = { * before blk_mq_queue_reinit_notify() from notify_dead(), * otherwise a RCU stall occurs. */ - [CPUHP_TIMERS_DEAD] = { + [CPUHP_TIMERS_PREPARE] = { .name = "timers:dead", - .startup.single = NULL, + .startup.single = timers_prepare_cpu, .teardown.single = timers_dead_cpu, }, /* Kicks the plugged cpu into life */ @@ -1289,11 +1289,6 @@ static struct cpuhp_step cpuhp_bp_states[] = { .teardown.single = NULL, .cant_stop = true, }, - [CPUHP_AP_SMPCFD_DYING] = { - .name = "smpcfd:dying", - .startup.single = NULL, - .teardown.single = smpcfd_dying_cpu, - }, /* * Handled on controll processor until the plugged processor manages * this itself. @@ -1335,6 +1330,11 @@ static struct cpuhp_step cpuhp_ap_states[] = { .startup.single = NULL, .teardown.single = rcutree_dying_cpu, }, + [CPUHP_AP_SMPCFD_DYING] = { + .name = "smpcfd:dying", + .startup.single = NULL, + .teardown.single = smpcfd_dying_cpu, + }, /* Entry state on starting. Interrupts enabled from here on. Transient * state for synchronsization */ [CPUHP_AP_ONLINE] = { diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 6db80fc0810b9..2d90996dbe771 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -409,7 +409,7 @@ static int __init crash_save_vmcoreinfo_init(void) VMCOREINFO_SYMBOL(contig_page_data); #endif #ifdef CONFIG_SPARSEMEM - VMCOREINFO_SYMBOL(mem_section); + VMCOREINFO_SYMBOL_ARRAY(mem_section); VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS); VMCOREINFO_STRUCT_SIZE(mem_section); VMCOREINFO_OFFSET(mem_section, section_mem_map); diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index e74be38245adf..ed5d34925ad06 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -350,7 +350,7 @@ static char *kdb_read(char *buffer, size_t bufsize) } kdb_printf("\n"); for (i = 0; i < count; i++) { - if (kallsyms_symbol_next(p_tmp, i) < 0) + if (WARN_ON(!kallsyms_symbol_next(p_tmp, i))) break; kdb_printf("%s ", p_tmp); *(p_tmp + len) = '\0'; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 4a1c33416b6a2..e2764d767f186 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -51,16 +51,16 @@ void __delayacct_tsk_init(struct task_struct *tsk) * Finish delay accounting for a statistic using its timestamps (@start), * accumalator (@total) and @count */ -static void delayacct_end(u64 *start, u64 *total, u32 *count) +static void delayacct_end(spinlock_t *lock, u64 *start, u64 *total, u32 *count) { s64 ns = ktime_get_ns() - *start; unsigned long flags; if (ns > 0) { - spin_lock_irqsave(¤t->delays->lock, flags); + spin_lock_irqsave(lock, flags); *total += ns; (*count)++; - spin_unlock_irqrestore(¤t->delays->lock, flags); + spin_unlock_irqrestore(lock, flags); } } @@ -69,17 +69,25 @@ void __delayacct_blkio_start(void) current->delays->blkio_start = ktime_get_ns(); } -void __delayacct_blkio_end(void) +/* + * We cannot rely on the `current` macro, as we haven't yet switched back to + * the process being woken. + */ +void __delayacct_blkio_end(struct task_struct *p) { - if (current->delays->flags & DELAYACCT_PF_SWAPIN) - /* Swapin block I/O */ - delayacct_end(¤t->delays->blkio_start, - ¤t->delays->swapin_delay, - ¤t->delays->swapin_count); - else /* Other block I/O */ - delayacct_end(¤t->delays->blkio_start, - ¤t->delays->blkio_delay, - ¤t->delays->blkio_count); + struct task_delay_info *delays = p->delays; + u64 *total; + u32 *count; + + if (p->delays->flags & DELAYACCT_PF_SWAPIN) { + total = &delays->swapin_delay; + count = &delays->swapin_count; + } else { + total = &delays->blkio_delay; + count = &delays->blkio_count; + } + + delayacct_end(&delays->lock, &delays->blkio_start, total, count); } int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) @@ -153,8 +161,10 @@ void __delayacct_freepages_start(void) void __delayacct_freepages_end(void) { - delayacct_end(¤t->delays->freepages_start, - ¤t->delays->freepages_delay, - ¤t->delays->freepages_count); + delayacct_end( + ¤t->delays->lock, + ¤t->delays->freepages_start, + ¤t->delays->freepages_delay, + ¤t->delays->freepages_count); } diff --git a/kernel/events/core.c b/kernel/events/core.c index 10cdb9c26b5d1..24ebad5567b4a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4233,7 +4233,7 @@ static void perf_remove_from_owner(struct perf_event *event) * indeed free this event, otherwise we need to serialize on * owner->perf_event_mutex. */ - owner = lockless_dereference(event->owner); + owner = READ_ONCE(event->owner); if (owner) { /* * Since delayed_put_task_struct() also drops the last @@ -4330,7 +4330,7 @@ int perf_event_release_kernel(struct perf_event *event) * Cannot change, child events are not migrated, see the * comment with perf_event_ctx_lock_nested(). */ - ctx = lockless_dereference(child->ctx); + ctx = READ_ONCE(child->ctx); /* * Since child_mutex nests inside ctx::mutex, we must jump * through hoops. We start by grabbing a reference on the ctx. @@ -4433,6 +4433,8 @@ static int __perf_read_group_add(struct perf_event *leader, if (ret) return ret; + raw_spin_lock_irqsave(&ctx->lock, flags); + /* * Since we co-schedule groups, {enabled,running} times of siblings * will be identical to those of the leader, so we only publish one @@ -4455,8 +4457,6 @@ static int __perf_read_group_add(struct perf_event *leader, if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(leader); - raw_spin_lock_irqsave(&ctx->lock, flags); - list_for_each_entry(sub, &leader->sibling_list, group_entry) { values[n++] += perf_event_count(sub); if (read_format & PERF_FORMAT_ID) diff --git a/kernel/fork.c b/kernel/fork.c index 07cc743698d36..500ce64517d93 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -721,8 +721,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, goto out; } /* a new mm has just been created */ - arch_dup_mmap(oldmm, mm); - retval = 0; + retval = arch_dup_mmap(oldmm, mm); out: up_write(&mm->mmap_sem); flush_tlb_mm(oldmm); diff --git a/kernel/futex.c b/kernel/futex.c index 76ed5921117a2..52b3f47031580 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1878,6 +1878,9 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, struct futex_q *this, *next; DEFINE_WAKE_Q(wake_q); + if (nr_wake < 0 || nr_requeue < 0) + return -EINVAL; + /* * When PI not supported: return -ENOSYS if requeue_pi is true, * consequently the compiler knows requeue_pi is always false past @@ -2294,21 +2297,17 @@ static void unqueue_me_pi(struct futex_q *q) spin_unlock(q->lock_ptr); } -/* - * Fixup the pi_state owner with the new owner. - * - * Must be called with hash bucket lock held and mm->sem held for non - * private futexes. - */ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, - struct task_struct *newowner) + struct task_struct *argowner) { - u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS; struct futex_pi_state *pi_state = q->pi_state; u32 uval, uninitialized_var(curval), newval; - struct task_struct *oldowner; + struct task_struct *oldowner, *newowner; + u32 newtid; int ret; + lockdep_assert_held(q->lock_ptr); + raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); oldowner = pi_state->owner; @@ -2317,11 +2316,17 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, newtid |= FUTEX_OWNER_DIED; /* - * We are here either because we stole the rtmutex from the - * previous highest priority waiter or we are the highest priority - * waiter but have failed to get the rtmutex the first time. + * We are here because either: + * + * - we stole the lock and pi_state->owner needs updating to reflect + * that (@argowner == current), + * + * or: + * + * - someone stole our lock and we need to fix things to point to the + * new owner (@argowner == NULL). * - * We have to replace the newowner TID in the user space variable. + * Either way, we have to replace the TID in the user space variable. * This must be atomic as we have to preserve the owner died bit here. * * Note: We write the user space value _before_ changing the pi_state @@ -2334,6 +2339,42 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, * in the PID check in lookup_pi_state. */ retry: + if (!argowner) { + if (oldowner != current) { + /* + * We raced against a concurrent self; things are + * already fixed up. Nothing to do. + */ + ret = 0; + goto out_unlock; + } + + if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) { + /* We got the lock after all, nothing to fix. */ + ret = 0; + goto out_unlock; + } + + /* + * Since we just failed the trylock; there must be an owner. + */ + newowner = rt_mutex_owner(&pi_state->pi_mutex); + BUG_ON(!newowner); + } else { + WARN_ON_ONCE(argowner != current); + if (oldowner == current) { + /* + * We raced against a concurrent self; things are + * already fixed up. Nothing to do. + */ + ret = 0; + goto out_unlock; + } + newowner = argowner; + } + + newtid = task_pid_vnr(newowner) | FUTEX_WAITERS; + if (get_futex_value_locked(&uval, uaddr)) goto handle_fault; @@ -2434,15 +2475,28 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) * Got the lock. We might not be the anticipated owner if we * did a lock-steal - fix up the PI-state in that case: * - * We can safely read pi_state->owner without holding wait_lock - * because we now own the rt_mutex, only the owner will attempt - * to change it. + * Speculative pi_state->owner read (we don't hold wait_lock); + * since we own the lock pi_state->owner == current is the + * stable state, anything else needs more attention. */ if (q->pi_state->owner != current) ret = fixup_pi_state_owner(uaddr, q, current); goto out; } + /* + * If we didn't get the lock; check if anybody stole it from us. In + * that case, we need to fix up the uval to point to them instead of + * us, otherwise bad things happen. [10] + * + * Another speculative read; pi_state->owner == current is unstable + * but needs our attention. + */ + if (q->pi_state->owner == current) { + ret = fixup_pi_state_owner(uaddr, q, NULL); + goto out; + } + /* * Paranoia check. If we did not take the lock, then we should not be * the owner of the rt_mutex. diff --git a/kernel/groups.c b/kernel/groups.c index e357bc8001110..daae2f2dc6d4f 100644 --- a/kernel/groups.c +++ b/kernel/groups.c @@ -86,11 +86,12 @@ static int gid_cmp(const void *_a, const void *_b) return gid_gt(a, b) - gid_lt(a, b); } -static void groups_sort(struct group_info *group_info) +void groups_sort(struct group_info *group_info) { sort(group_info->gid, group_info->ngroups, sizeof(*group_info->gid), gid_cmp, NULL); } +EXPORT_SYMBOL(groups_sort); /* a simple bsearch */ int groups_search(const struct group_info *group_info, kgid_t grp) @@ -122,7 +123,6 @@ int groups_search(const struct group_info *group_info, kgid_t grp) void set_groups(struct cred *new, struct group_info *group_info) { put_group_info(new->group_info); - groups_sort(group_info); get_group_info(group_info); new->group_info = group_info; } @@ -206,6 +206,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) return retval; } + groups_sort(group_info); retval = set_current_groups(group_info); put_group_info(group_info); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4bff6a10ae8ec..b02caa442776f 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1245,7 +1245,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) * set the trigger type must match. Also all must * agree on ONESHOT. */ - unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data); + unsigned int oldtype; + + /* + * If nobody did set the configuration before, inherit + * the one provided by the requester. + */ + if (irqd_trigger_type_was_set(&desc->irq_data)) { + oldtype = irqd_get_trigger_type(&desc->irq_data); + } else { + oldtype = new->flags & IRQF_TRIGGER_MASK; + irqd_set_trigger_type(&desc->irq_data, oldtype); + } if (!((old->flags & new->flags) & IRQF_SHARED) || (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 0bf2e8f5244ae..7c3774ac1d51f 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -769,7 +769,7 @@ static __init int jump_label_test(void) return 0; } -late_initcall(jump_label_test); +early_initcall(jump_label_test); #endif /* STATIC_KEYS_SELFTEST */ #endif /* HAVE_JUMP_LABEL */ diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a1606a4224e14..a66e838640eae 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -573,13 +573,15 @@ static void kprobe_optimizer(struct work_struct *work) do_unoptimize_kprobes(); /* - * Step 2: Wait for quiesence period to ensure all running interrupts - * are done. Because optprobe may modify multiple instructions - * there is a chance that Nth instruction is interrupted. In that - * case, running interrupt can return to 2nd-Nth byte of jump - * instruction. This wait is for avoiding it. + * Step 2: Wait for quiesence period to ensure all potentially + * preempted tasks to have normally scheduled. Because optprobe + * may modify multiple instructions, there is a chance that Nth + * instruction is preempted. In that case, such tasks can return + * to 2nd-Nth byte of jump instruction. This wait is for avoiding it. + * Note that on non-preemptive kernel, this is transparently converted + * to synchronoze_sched() to wait for all interrupts to have completed. */ - synchronize_sched(); + synchronize_rcu_tasks(); /* Step 3: Optimize kprobes after quiesence period */ do_optimize_kprobes(); diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 6f3dba6e4e9e1..65cc0cb984e6a 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1290,6 +1290,19 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, return ret; } +static inline int __rt_mutex_slowtrylock(struct rt_mutex *lock) +{ + int ret = try_to_take_rt_mutex(lock, current, NULL); + + /* + * try_to_take_rt_mutex() sets the lock waiters bit + * unconditionally. Clean this up. + */ + fixup_rt_mutex_waiters(lock); + + return ret; +} + /* * Slow path try-lock function: */ @@ -1312,13 +1325,7 @@ static inline int rt_mutex_slowtrylock(struct rt_mutex *lock) */ raw_spin_lock_irqsave(&lock->wait_lock, flags); - ret = try_to_take_rt_mutex(lock, current, NULL); - - /* - * try_to_take_rt_mutex() sets the lock waiters bit - * unconditionally. Clean this up. - */ - fixup_rt_mutex_waiters(lock); + ret = __rt_mutex_slowtrylock(lock); raw_spin_unlock_irqrestore(&lock->wait_lock, flags); @@ -1505,6 +1512,11 @@ int __sched rt_mutex_futex_trylock(struct rt_mutex *lock) return rt_mutex_slowtrylock(lock); } +int __sched __rt_mutex_futex_trylock(struct rt_mutex *lock) +{ + return __rt_mutex_slowtrylock(lock); +} + /** * rt_mutex_timed_lock - lock a rt_mutex interruptible * the timeout structure is provided diff --git a/kernel/locking/rtmutex_common.h b/kernel/locking/rtmutex_common.h index 124e98ca0b174..68686b3ec3c17 100644 --- a/kernel/locking/rtmutex_common.h +++ b/kernel/locking/rtmutex_common.h @@ -148,6 +148,7 @@ extern bool rt_mutex_cleanup_proxy_lock(struct rt_mutex *lock, struct rt_mutex_waiter *waiter); extern int rt_mutex_futex_trylock(struct rt_mutex *l); +extern int __rt_mutex_futex_trylock(struct rt_mutex *l); extern void rt_mutex_futex_unlock(struct rt_mutex *lock); extern bool __rt_mutex_futex_unlock(struct rt_mutex *lock, diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ccd2d20e6b067..0685c44994314 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -437,7 +437,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = suspend_ops->enter(state); trace_suspend_resume(TPS("machine_suspend"), state, false); - events_check_enabled = false; } else if (*wakeup) { error = -EBUSY; } @@ -582,6 +581,7 @@ static int enter_state(suspend_state_t state) pm_restore_gfp_mask(); Finish: + events_check_enabled = false; pm_pr_dbg("Finishing wakeup.\n"); suspend_finish(); Unlock: diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index e012b9be777e3..fed95fa941e61 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1507,7 +1507,7 @@ static void rcu_prepare_for_idle(void) rdtp->last_accelerate = jiffies; for_each_rcu_flavor(rsp) { rdp = this_cpu_ptr(rsp->rda); - if (rcu_segcblist_pend_cbs(&rdp->cblist)) + if (!rcu_segcblist_pend_cbs(&rdp->cblist)) continue; rnp = rdp->mynode; raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index d17c5da523a0b..55062461b2fd1 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -505,8 +505,7 @@ void resched_cpu(int cpu) struct rq *rq = cpu_rq(cpu); unsigned long flags; - if (!raw_spin_trylock_irqsave(&rq->lock, flags)) - return; + raw_spin_lock_irqsave(&rq->lock, flags); resched_curr(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); } @@ -2047,7 +2046,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) p->state = TASK_WAKING; if (p->in_iowait) { - delayacct_blkio_end(); + delayacct_blkio_end(p); atomic_dec(&task_rq(p)->nr_iowait); } @@ -2060,7 +2059,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) #else /* CONFIG_SMP */ if (p->in_iowait) { - delayacct_blkio_end(); + delayacct_blkio_end(p); atomic_dec(&task_rq(p)->nr_iowait); } @@ -2113,7 +2112,7 @@ static void try_to_wake_up_local(struct task_struct *p, struct rq_flags *rf) if (!task_on_rq_queued(p)) { if (p->in_iowait) { - delayacct_blkio_end(); + delayacct_blkio_end(p); atomic_dec(&rq->nr_iowait); } ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_NOCLOCK); diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index ba0da243fdd83..d6717a3331a1b 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -244,7 +244,7 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util, #ifdef CONFIG_NO_HZ_COMMON static bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { - unsigned long idle_calls = tick_nohz_get_idle_calls(); + unsigned long idle_calls = tick_nohz_get_idle_calls_cpu(sg_cpu->cpu); bool ret = idle_calls == sg_cpu->saved_idle_calls; sg_cpu->saved_idle_calls = idle_calls; @@ -282,8 +282,12 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, * Do not reduce the frequency if the CPU has not been idle * recently, as the reduction is likely to be premature then. */ - if (busy && next_f < sg_policy->next_freq) + if (busy && next_f < sg_policy->next_freq) { next_f = sg_policy->next_freq; + + /* Reset cached freq as next_freq has changed */ + sg_policy->cached_raw_freq = 0; + } } sugov_update_commit(sg_policy, time, next_f); } diff --git a/kernel/sched/membarrier.c b/kernel/sched/membarrier.c index dd7908743dab6..9bcbacba82a81 100644 --- a/kernel/sched/membarrier.c +++ b/kernel/sched/membarrier.c @@ -89,7 +89,9 @@ static int membarrier_private_expedited(void) rcu_read_unlock(); } if (!fallback) { + preempt_disable(); smp_call_function_many(tmpmask, ipi_mb, NULL, 1); + preempt_enable(); free_cpumask_var(tmpmask); } cpus_read_unlock(); diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 3c96c80e0992a..7464c5c4de467 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -74,10 +74,6 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b) raw_spin_unlock(&rt_b->rt_runtime_lock); } -#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI) -static void push_irq_work_func(struct irq_work *work); -#endif - void init_rt_rq(struct rt_rq *rt_rq) { struct rt_prio_array *array; @@ -97,13 +93,6 @@ void init_rt_rq(struct rt_rq *rt_rq) rt_rq->rt_nr_migratory = 0; rt_rq->overloaded = 0; plist_head_init(&rt_rq->pushable_tasks); - -#ifdef HAVE_RT_PUSH_IPI - rt_rq->push_flags = 0; - rt_rq->push_cpu = nr_cpu_ids; - raw_spin_lock_init(&rt_rq->push_lock); - init_irq_work(&rt_rq->push_work, push_irq_work_func); -#endif #endif /* CONFIG_SMP */ /* We start is dequeued state, because no RT tasks are queued */ rt_rq->rt_queued = 0; @@ -1876,241 +1865,166 @@ static void push_rt_tasks(struct rq *rq) } #ifdef HAVE_RT_PUSH_IPI + /* - * The search for the next cpu always starts at rq->cpu and ends - * when we reach rq->cpu again. It will never return rq->cpu. - * This returns the next cpu to check, or nr_cpu_ids if the loop - * is complete. + * When a high priority task schedules out from a CPU and a lower priority + * task is scheduled in, a check is made to see if there's any RT tasks + * on other CPUs that are waiting to run because a higher priority RT task + * is currently running on its CPU. In this case, the CPU with multiple RT + * tasks queued on it (overloaded) needs to be notified that a CPU has opened + * up that may be able to run one of its non-running queued RT tasks. + * + * All CPUs with overloaded RT tasks need to be notified as there is currently + * no way to know which of these CPUs have the highest priority task waiting + * to run. Instead of trying to take a spinlock on each of these CPUs, + * which has shown to cause large latency when done on machines with many + * CPUs, sending an IPI to the CPUs to have them push off the overloaded + * RT tasks waiting to run. + * + * Just sending an IPI to each of the CPUs is also an issue, as on large + * count CPU machines, this can cause an IPI storm on a CPU, especially + * if its the only CPU with multiple RT tasks queued, and a large number + * of CPUs scheduling a lower priority task at the same time. + * + * Each root domain has its own irq work function that can iterate over + * all CPUs with RT overloaded tasks. Since all CPUs with overloaded RT + * tassk must be checked if there's one or many CPUs that are lowering + * their priority, there's a single irq work iterator that will try to + * push off RT tasks that are waiting to run. + * + * When a CPU schedules a lower priority task, it will kick off the + * irq work iterator that will jump to each CPU with overloaded RT tasks. + * As it only takes the first CPU that schedules a lower priority task + * to start the process, the rto_start variable is incremented and if + * the atomic result is one, then that CPU will try to take the rto_lock. + * This prevents high contention on the lock as the process handles all + * CPUs scheduling lower priority tasks. + * + * All CPUs that are scheduling a lower priority task will increment the + * rt_loop_next variable. This will make sure that the irq work iterator + * checks all RT overloaded CPUs whenever a CPU schedules a new lower + * priority task, even if the iterator is in the middle of a scan. Incrementing + * the rt_loop_next will cause the iterator to perform another scan. * - * rq->rt.push_cpu holds the last cpu returned by this function, - * or if this is the first instance, it must hold rq->cpu. */ static int rto_next_cpu(struct rq *rq) { - int prev_cpu = rq->rt.push_cpu; + struct root_domain *rd = rq->rd; + int next; int cpu; - cpu = cpumask_next(prev_cpu, rq->rd->rto_mask); - /* - * If the previous cpu is less than the rq's CPU, then it already - * passed the end of the mask, and has started from the beginning. - * We end if the next CPU is greater or equal to rq's CPU. + * When starting the IPI RT pushing, the rto_cpu is set to -1, + * rt_next_cpu() will simply return the first CPU found in + * the rto_mask. + * + * If rto_next_cpu() is called with rto_cpu is a valid cpu, it + * will return the next CPU found in the rto_mask. + * + * If there are no more CPUs left in the rto_mask, then a check is made + * against rto_loop and rto_loop_next. rto_loop is only updated with + * the rto_lock held, but any CPU may increment the rto_loop_next + * without any locking. */ - if (prev_cpu < rq->cpu) { - if (cpu >= rq->cpu) - return nr_cpu_ids; + for (;;) { - } else if (cpu >= nr_cpu_ids) { - /* - * We passed the end of the mask, start at the beginning. - * If the result is greater or equal to the rq's CPU, then - * the loop is finished. - */ - cpu = cpumask_first(rq->rd->rto_mask); - if (cpu >= rq->cpu) - return nr_cpu_ids; - } - rq->rt.push_cpu = cpu; + /* When rto_cpu is -1 this acts like cpumask_first() */ + cpu = cpumask_next(rd->rto_cpu, rd->rto_mask); - /* Return cpu to let the caller know if the loop is finished or not */ - return cpu; -} + rd->rto_cpu = cpu; -static int find_next_push_cpu(struct rq *rq) -{ - struct rq *next_rq; - int cpu; + if (cpu < nr_cpu_ids) + return cpu; - while (1) { - cpu = rto_next_cpu(rq); - if (cpu >= nr_cpu_ids) - break; - next_rq = cpu_rq(cpu); + rd->rto_cpu = -1; + + /* + * ACQUIRE ensures we see the @rto_mask changes + * made prior to the @next value observed. + * + * Matches WMB in rt_set_overload(). + */ + next = atomic_read_acquire(&rd->rto_loop_next); - /* Make sure the next rq can push to this rq */ - if (next_rq->rt.highest_prio.next < rq->rt.highest_prio.curr) + if (rd->rto_loop == next) break; + + rd->rto_loop = next; } - return cpu; + return -1; } -#define RT_PUSH_IPI_EXECUTING 1 -#define RT_PUSH_IPI_RESTART 2 +static inline bool rto_start_trylock(atomic_t *v) +{ + return !atomic_cmpxchg_acquire(v, 0, 1); +} -/* - * When a high priority task schedules out from a CPU and a lower priority - * task is scheduled in, a check is made to see if there's any RT tasks - * on other CPUs that are waiting to run because a higher priority RT task - * is currently running on its CPU. In this case, the CPU with multiple RT - * tasks queued on it (overloaded) needs to be notified that a CPU has opened - * up that may be able to run one of its non-running queued RT tasks. - * - * On large CPU boxes, there's the case that several CPUs could schedule - * a lower priority task at the same time, in which case it will look for - * any overloaded CPUs that it could pull a task from. To do this, the runqueue - * lock must be taken from that overloaded CPU. Having 10s of CPUs all fighting - * for a single overloaded CPU's runqueue lock can produce a large latency. - * (This has actually been observed on large boxes running cyclictest). - * Instead of taking the runqueue lock of the overloaded CPU, each of the - * CPUs that scheduled a lower priority task simply sends an IPI to the - * overloaded CPU. An IPI is much cheaper than taking an runqueue lock with - * lots of contention. The overloaded CPU will look to push its non-running - * RT task off, and if it does, it can then ignore the other IPIs coming - * in, and just pass those IPIs off to any other overloaded CPU. - * - * When a CPU schedules a lower priority task, it only sends an IPI to - * the "next" CPU that has overloaded RT tasks. This prevents IPI storms, - * as having 10 CPUs scheduling lower priority tasks and 10 CPUs with - * RT overloaded tasks, would cause 100 IPIs to go out at once. - * - * The overloaded RT CPU, when receiving an IPI, will try to push off its - * overloaded RT tasks and then send an IPI to the next CPU that has - * overloaded RT tasks. This stops when all CPUs with overloaded RT tasks - * have completed. Just because a CPU may have pushed off its own overloaded - * RT task does not mean it should stop sending the IPI around to other - * overloaded CPUs. There may be another RT task waiting to run on one of - * those CPUs that are of higher priority than the one that was just - * pushed. - * - * An optimization that could possibly be made is to make a CPU array similar - * to the cpupri array mask of all running RT tasks, but for the overloaded - * case, then the IPI could be sent to only the CPU with the highest priority - * RT task waiting, and that CPU could send off further IPIs to the CPU with - * the next highest waiting task. Since the overloaded case is much less likely - * to happen, the complexity of this implementation may not be worth it. - * Instead, just send an IPI around to all overloaded CPUs. - * - * The rq->rt.push_flags holds the status of the IPI that is going around. - * A run queue can only send out a single IPI at a time. The possible flags - * for rq->rt.push_flags are: - * - * (None or zero): No IPI is going around for the current rq - * RT_PUSH_IPI_EXECUTING: An IPI for the rq is being passed around - * RT_PUSH_IPI_RESTART: The priority of the running task for the rq - * has changed, and the IPI should restart - * circulating the overloaded CPUs again. - * - * rq->rt.push_cpu contains the CPU that is being sent the IPI. It is updated - * before sending to the next CPU. - * - * Instead of having all CPUs that schedule a lower priority task send - * an IPI to the same "first" CPU in the RT overload mask, they send it - * to the next overloaded CPU after their own CPU. This helps distribute - * the work when there's more than one overloaded CPU and multiple CPUs - * scheduling in lower priority tasks. - * - * When a rq schedules a lower priority task than what was currently - * running, the next CPU with overloaded RT tasks is examined first. - * That is, if CPU 1 and 5 are overloaded, and CPU 3 schedules a lower - * priority task, it will send an IPI first to CPU 5, then CPU 5 will - * send to CPU 1 if it is still overloaded. CPU 1 will clear the - * rq->rt.push_flags if RT_PUSH_IPI_RESTART is not set. - * - * The first CPU to notice IPI_RESTART is set, will clear that flag and then - * send an IPI to the next overloaded CPU after the rq->cpu and not the next - * CPU after push_cpu. That is, if CPU 1, 4 and 5 are overloaded when CPU 3 - * schedules a lower priority task, and the IPI_RESTART gets set while the - * handling is being done on CPU 5, it will clear the flag and send it back to - * CPU 4 instead of CPU 1. - * - * Note, the above logic can be disabled by turning off the sched_feature - * RT_PUSH_IPI. Then the rq lock of the overloaded CPU will simply be - * taken by the CPU requesting a pull and the waiting RT task will be pulled - * by that CPU. This may be fine for machines with few CPUs. - */ -static void tell_cpu_to_push(struct rq *rq) +static inline void rto_start_unlock(atomic_t *v) { - int cpu; + atomic_set_release(v, 0); +} - if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) { - raw_spin_lock(&rq->rt.push_lock); - /* Make sure it's still executing */ - if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) { - /* - * Tell the IPI to restart the loop as things have - * changed since it started. - */ - rq->rt.push_flags |= RT_PUSH_IPI_RESTART; - raw_spin_unlock(&rq->rt.push_lock); - return; - } - raw_spin_unlock(&rq->rt.push_lock); - } +static void tell_cpu_to_push(struct rq *rq) +{ + int cpu = -1; - /* When here, there's no IPI going around */ + /* Keep the loop going if the IPI is currently active */ + atomic_inc(&rq->rd->rto_loop_next); - rq->rt.push_cpu = rq->cpu; - cpu = find_next_push_cpu(rq); - if (cpu >= nr_cpu_ids) + /* Only one CPU can initiate a loop at a time */ + if (!rto_start_trylock(&rq->rd->rto_loop_start)) return; - rq->rt.push_flags = RT_PUSH_IPI_EXECUTING; + raw_spin_lock(&rq->rd->rto_lock); - irq_work_queue_on(&rq->rt.push_work, cpu); + /* + * The rto_cpu is updated under the lock, if it has a valid cpu + * then the IPI is still running and will continue due to the + * update to loop_next, and nothing needs to be done here. + * Otherwise it is finishing up and an ipi needs to be sent. + */ + if (rq->rd->rto_cpu < 0) + cpu = rto_next_cpu(rq); + + raw_spin_unlock(&rq->rd->rto_lock); + + rto_start_unlock(&rq->rd->rto_loop_start); + + if (cpu >= 0) + irq_work_queue_on(&rq->rd->rto_push_work, cpu); } /* Called from hardirq context */ -static void try_to_push_tasks(void *arg) +void rto_push_irq_work_func(struct irq_work *work) { - struct rt_rq *rt_rq = arg; - struct rq *rq, *src_rq; - int this_cpu; + struct rq *rq; int cpu; - this_cpu = rt_rq->push_cpu; - - /* Paranoid check */ - BUG_ON(this_cpu != smp_processor_id()); - - rq = cpu_rq(this_cpu); - src_rq = rq_of_rt_rq(rt_rq); + rq = this_rq(); -again: + /* + * We do not need to grab the lock to check for has_pushable_tasks. + * When it gets updated, a check is made if a push is possible. + */ if (has_pushable_tasks(rq)) { raw_spin_lock(&rq->lock); - push_rt_task(rq); + push_rt_tasks(rq); raw_spin_unlock(&rq->lock); } - /* Pass the IPI to the next rt overloaded queue */ - raw_spin_lock(&rt_rq->push_lock); - /* - * If the source queue changed since the IPI went out, - * we need to restart the search from that CPU again. - */ - if (rt_rq->push_flags & RT_PUSH_IPI_RESTART) { - rt_rq->push_flags &= ~RT_PUSH_IPI_RESTART; - rt_rq->push_cpu = src_rq->cpu; - } + raw_spin_lock(&rq->rd->rto_lock); - cpu = find_next_push_cpu(src_rq); + /* Pass the IPI to the next rt overloaded queue */ + cpu = rto_next_cpu(rq); - if (cpu >= nr_cpu_ids) - rt_rq->push_flags &= ~RT_PUSH_IPI_EXECUTING; - raw_spin_unlock(&rt_rq->push_lock); + raw_spin_unlock(&rq->rd->rto_lock); - if (cpu >= nr_cpu_ids) + if (cpu < 0) return; - /* - * It is possible that a restart caused this CPU to be - * chosen again. Don't bother with an IPI, just see if we - * have more to push. - */ - if (unlikely(cpu == rq->cpu)) - goto again; - /* Try the next RT overloaded CPU */ - irq_work_queue_on(&rt_rq->push_work, cpu); -} - -static void push_irq_work_func(struct irq_work *work) -{ - struct rt_rq *rt_rq = container_of(work, struct rt_rq, push_work); - - try_to_push_tasks(rt_rq); + irq_work_queue_on(&rq->rd->rto_push_work, cpu); } #endif /* HAVE_RT_PUSH_IPI */ @@ -2120,8 +2034,9 @@ static void pull_rt_task(struct rq *this_rq) bool resched = false; struct task_struct *p; struct rq *src_rq; + int rt_overload_count = rt_overloaded(this_rq); - if (likely(!rt_overloaded(this_rq))) + if (likely(!rt_overload_count)) return; /* @@ -2130,6 +2045,11 @@ static void pull_rt_task(struct rq *this_rq) */ smp_rmb(); + /* If we are the only overloaded CPU do nothing */ + if (rt_overload_count == 1 && + cpumask_test_cpu(this_rq->cpu, this_rq->rd->rto_mask)) + return; + #ifdef HAVE_RT_PUSH_IPI if (sched_feat(RT_PUSH_IPI)) { tell_cpu_to_push(this_rq); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 3b448ba82225d..b732e779fe7d5 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -502,7 +502,7 @@ static inline int rt_bandwidth_enabled(void) } /* RT IPI pull logic requires IRQ_WORK */ -#ifdef CONFIG_IRQ_WORK +#if defined(CONFIG_IRQ_WORK) && defined(CONFIG_SMP) # define HAVE_RT_PUSH_IPI #endif @@ -524,12 +524,6 @@ struct rt_rq { unsigned long rt_nr_total; int overloaded; struct plist_head pushable_tasks; -#ifdef HAVE_RT_PUSH_IPI - int push_flags; - int push_cpu; - struct irq_work push_work; - raw_spinlock_t push_lock; -#endif #endif /* CONFIG_SMP */ int rt_queued; @@ -638,6 +632,19 @@ struct root_domain { struct dl_bw dl_bw; struct cpudl cpudl; +#ifdef HAVE_RT_PUSH_IPI + /* + * For IPI pull requests, loop across the rto_mask. + */ + struct irq_work rto_push_work; + raw_spinlock_t rto_lock; + /* These are only updated and read within rto_lock */ + int rto_loop; + int rto_cpu; + /* These atomics are updated outside of a lock */ + atomic_t rto_loop_next; + atomic_t rto_loop_start; +#endif /* * The "RT overload" flag: it gets set if a CPU has more than * one runnable RT task. @@ -655,6 +662,9 @@ extern void init_defrootdomain(void); extern int sched_init_domains(const struct cpumask *cpu_map); extern void rq_attach_root(struct rq *rq, struct root_domain *rd); +#ifdef HAVE_RT_PUSH_IPI +extern void rto_push_irq_work_func(struct irq_work *work); +#endif #endif /* CONFIG_SMP */ /* diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 6798276d29af2..093f2ceba2e24 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -269,6 +269,12 @@ static int init_rootdomain(struct root_domain *rd) if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) goto free_dlo_mask; +#ifdef HAVE_RT_PUSH_IPI + rd->rto_cpu = -1; + raw_spin_lock_init(&rd->rto_lock); + init_irq_work(&rd->rto_push_work, rto_push_irq_work_func); +#endif + init_dl_bw(&rd->dl_bw); if (cpudl_init(&rd->cpudl) != 0) goto free_rto_mask; diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 418a1c045933d..5f0dfb2abb8d3 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -190,7 +190,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd, u32 ret = SECCOMP_RET_ALLOW; /* Make sure cross-thread synced filter points somewhere sane. */ struct seccomp_filter *f = - lockless_dereference(current->seccomp.filter); + READ_ONCE(current->seccomp.filter); /* Ensure unexpected behavior doesn't result in failing open. */ if (unlikely(WARN_ON(f == NULL))) diff --git a/kernel/signal.c b/kernel/signal.c index 8dcd8825b2ded..1facff1dbbaec 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -78,7 +78,7 @@ static int sig_task_ignored(struct task_struct *t, int sig, bool force) handler = sig_handler(t, sig); if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && - handler == SIG_DFL && !force) + handler == SIG_DFL && !(force && sig_kernel_only(sig))) return 1; return sig_handler_ignored(handler, sig); @@ -94,13 +94,15 @@ static int sig_ignored(struct task_struct *t, int sig, bool force) if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) return 0; - if (!sig_task_ignored(t, sig, force)) - return 0; - /* - * Tracers may want to know about even ignored signals. + * Tracers may want to know about even ignored signal unless it + * is SIGKILL which can't be reported anyway but can be ignored + * by SIGNAL_UNKILLABLE task. */ - return !t->ptrace; + if (t->ptrace && sig != SIGKILL) + return 0; + + return sig_task_ignored(t, sig, force); } /* @@ -929,9 +931,9 @@ static void complete_signal(int sig, struct task_struct *p, int group) * then start taking the whole group down immediately. */ if (sig_fatal(p, sig) && - !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && + !(signal->flags & SIGNAL_GROUP_EXIT) && !sigismember(&t->real_blocked, sig) && - (sig == SIGKILL || !t->ptrace)) { + (sig == SIGKILL || !p->ptrace)) { /* * This signal will be fatal to the whole group. */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d9c31bc2eaea2..56aca862c4f58 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1822,7 +1822,7 @@ static struct ctl_table fs_table[] = { { .procname = "pipe-max-size", .data = &pipe_max_size, - .maxlen = sizeof(int), + .maxlen = sizeof(pipe_max_size), .mode = 0644, .proc_handler = &pipe_proc_fn, .extra1 = &pipe_min_size, diff --git a/kernel/task_work.c b/kernel/task_work.c index 5718b3ea202a3..0fef395662a6e 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -68,7 +68,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) * we raced with task_work_run(), *pprev == NULL/exited. */ raw_spin_lock_irqsave(&task->pi_lock, flags); - while ((work = lockless_dereference(*pprev))) { + while ((work = READ_ONCE(*pprev))) { if (work->func != func) pprev = &work->next; else if (cmpxchg(pprev, work, work->next) == work) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 88f75f92ef368..052773df9f03f 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -655,7 +655,9 @@ static void hrtimer_reprogram(struct hrtimer *timer, static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { base->expires_next = KTIME_MAX; + base->hang_detected = 0; base->hres_active = 0; + base->next_timer = NULL; } /* @@ -1591,6 +1593,7 @@ int hrtimers_prepare_cpu(unsigned int cpu) timerqueue_init_head(&cpu_base->clock_base[i].active); } + cpu_base->active_bases = 0; cpu_base->cpu = cpu; hrtimer_init_hres(cpu_base); return 0; diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 13d6881f908b7..ec999f32c8405 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -434,17 +434,22 @@ static struct pid *good_sigevent(sigevent_t * event) { struct task_struct *rtn = current->group_leader; - if ((event->sigev_notify & SIGEV_THREAD_ID ) && - (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) || - !same_thread_group(rtn, current) || - (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL)) + switch (event->sigev_notify) { + case SIGEV_SIGNAL | SIGEV_THREAD_ID: + rtn = find_task_by_vpid(event->sigev_notify_thread_id); + if (!rtn || !same_thread_group(rtn, current)) + return NULL; + /* FALLTHRU */ + case SIGEV_SIGNAL: + case SIGEV_THREAD: + if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX) + return NULL; + /* FALLTHRU */ + case SIGEV_NONE: + return task_pid(rtn); + default: return NULL; - - if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) && - ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) - return NULL; - - return task_pid(rtn); + } } static struct k_itimer * alloc_posix_timer(void) @@ -669,7 +674,7 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) struct timespec64 ts64; bool sig_none; - sig_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE; + sig_none = timr->it_sigev_notify == SIGEV_NONE; iv = timr->it_interval; /* interval timer ? */ @@ -856,7 +861,7 @@ int common_timer_set(struct k_itimer *timr, int flags, timr->it_interval = timespec64_to_ktime(new_setting->it_interval); expires = timespec64_to_ktime(new_setting->it_value); - sigev_none = (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE; + sigev_none = timr->it_sigev_notify == SIGEV_NONE; kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none); timr->it_active = !sigev_none; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index c7a899c5ce643..dfa4a117fee34 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -674,6 +674,11 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) ts->next_tick = 0; } +static inline bool local_timer_softirq_pending(void) +{ + return local_softirq_pending() & TIMER_SOFTIRQ; +} + static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, ktime_t now, int cpu) { @@ -690,8 +695,18 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, } while (read_seqretry(&jiffies_lock, seq)); ts->last_jiffies = basejiff; - if (rcu_needs_cpu(basemono, &next_rcu) || - arch_needs_cpu() || irq_work_needs_cpu()) { + /* + * Keep the periodic tick, when RCU, architecture or irq_work + * requests it. + * Aside of that check whether the local timer softirq is + * pending. If so its a bad idea to call get_next_timer_interrupt() + * because there is an already expired timer, so it will request + * immeditate expiry, which rearms the hardware timer with a + * minimal delta which brings us back to this place + * immediately. Lather, rinse and repeat... + */ + if (rcu_needs_cpu(basemono, &next_rcu) || arch_needs_cpu() || + irq_work_needs_cpu() || local_timer_softirq_pending()) { next_tick = basemono + TICK_NSEC; } else { /* @@ -1009,6 +1024,19 @@ ktime_t tick_nohz_get_sleep_length(void) return ts->sleep_length; } +/** + * tick_nohz_get_idle_calls_cpu - return the current idle calls counter value + * for a particular CPU. + * + * Called from the schedutil frequency scaling governor in scheduler context. + */ +unsigned long tick_nohz_get_idle_calls_cpu(int cpu) +{ + struct tick_sched *ts = tick_get_tick_sched(cpu); + + return ts->idle_calls; +} + /** * tick_nohz_get_idle_calls - return the current idle calls counter value * diff --git a/kernel/time/timer.c b/kernel/time/timer.c index f2674a056c268..db5e6daadd94e 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -814,11 +814,10 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. + * If the timer is deferrable and NO_HZ_COMMON is set then we need + * to use the deferrable base. */ - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && - (tflags & TIMER_DEFERRABLE)) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); return base; } @@ -828,11 +827,10 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. + * If the timer is deferrable and NO_HZ_COMMON is set then we need + * to use the deferrable base. */ - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && - (tflags & TIMER_DEFERRABLE)) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) base = this_cpu_ptr(&timer_bases[BASE_DEF]); return base; } @@ -984,8 +982,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) if (!ret && pending_only) goto out_unlock; - debug_activate(timer, expires); - new_base = get_target_base(base, timer->flags); if (base != new_base) { @@ -1009,6 +1005,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) } } + debug_activate(timer, expires); + timer->expires = expires; /* * If 'idx' was calculated above and the base time did not advance @@ -1644,7 +1642,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) base->must_forward_clk = false; __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); } @@ -1658,7 +1656,7 @@ void run_local_timers(void) hrtimer_run_queues(); /* Raise the softirq only if required. */ if (time_before(jiffies, base->clk)) { - if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) + if (!IS_ENABLED(CONFIG_NO_HZ_COMMON)) return; /* CPU is awake, so check the deferrable base. */ base++; @@ -1803,6 +1801,21 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h } } +int timers_prepare_cpu(unsigned int cpu) +{ + struct timer_base *base; + int b; + + for (b = 0; b < NR_BASES; b++) { + base = per_cpu_ptr(&timer_bases[b], cpu); + base->clk = jiffies; + base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA; + base->is_idle = false; + base->must_forward_clk = true; + } + return 0; +} + int timers_dead_cpu(unsigned int cpu) { struct timer_base *old_base; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index dc498b605d5dd..6350f64d5aa40 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -293,14 +293,13 @@ static const struct bpf_func_proto bpf_perf_event_read_proto = { .arg2_type = ARG_ANYTHING, }; -static DEFINE_PER_CPU(struct perf_sample_data, bpf_sd); +static DEFINE_PER_CPU(struct perf_sample_data, bpf_trace_sd); static __always_inline u64 __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, - u64 flags, struct perf_raw_record *raw) + u64 flags, struct perf_sample_data *sd) { struct bpf_array *array = container_of(map, struct bpf_array, map); - struct perf_sample_data *sd = this_cpu_ptr(&bpf_sd); unsigned int cpu = smp_processor_id(); u64 index = flags & BPF_F_INDEX_MASK; struct bpf_event_entry *ee; @@ -323,8 +322,6 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, if (unlikely(event->oncpu != cpu)) return -EOPNOTSUPP; - perf_sample_data_init(sd, 0, 0); - sd->raw = raw; perf_event_output(event, sd, regs); return 0; } @@ -332,6 +329,7 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map, BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, u64, flags, void *, data, u64, size) { + struct perf_sample_data *sd = this_cpu_ptr(&bpf_trace_sd); struct perf_raw_record raw = { .frag = { .size = size, @@ -342,7 +340,10 @@ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map, if (unlikely(flags & ~(BPF_F_INDEX_MASK))) return -EINVAL; - return __bpf_perf_event_output(regs, map, flags, &raw); + perf_sample_data_init(sd, 0, 0); + sd->raw = &raw; + + return __bpf_perf_event_output(regs, map, flags, sd); } static const struct bpf_func_proto bpf_perf_event_output_proto = { @@ -357,10 +358,12 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = { }; static DEFINE_PER_CPU(struct pt_regs, bpf_pt_regs); +static DEFINE_PER_CPU(struct perf_sample_data, bpf_misc_sd); u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy) { + struct perf_sample_data *sd = this_cpu_ptr(&bpf_misc_sd); struct pt_regs *regs = this_cpu_ptr(&bpf_pt_regs); struct perf_raw_frag frag = { .copy = ctx_copy, @@ -378,8 +381,10 @@ u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, }; perf_fetch_caller_regs(regs); + perf_sample_data_init(sd, 0, 0); + sd->raw = &raw; - return __bpf_perf_event_output(regs, map, flags, &raw); + return __bpf_perf_event_output(regs, map, flags, sd); } BPF_CALL_0(bpf_get_current_task) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 81279c6602ff1..0476a93720147 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -281,6 +281,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data); /* Missed count stored at end */ #define RB_MISSED_STORED (1 << 30) +#define RB_MISSED_FLAGS (RB_MISSED_EVENTS|RB_MISSED_STORED) + struct buffer_data_page { u64 time_stamp; /* page time stamp */ local_t commit; /* write committed index */ @@ -332,7 +334,9 @@ static void rb_init_page(struct buffer_data_page *bpage) */ size_t ring_buffer_page_len(void *page) { - return local_read(&((struct buffer_data_page *)page)->commit) + struct buffer_data_page *bpage = page; + + return (local_read(&bpage->commit) & ~RB_MISSED_FLAGS) + BUF_PAGE_HDR_SIZE; } @@ -4439,8 +4443,13 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data) { struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; struct buffer_data_page *bpage = data; + struct page *page = virt_to_page(bpage); unsigned long flags; + /* If the page is still in use someplace else, we can't reuse it */ + if (page_ref_count(page) > 1) + goto out; + local_irq_save(flags); arch_spin_lock(&cpu_buffer->lock); @@ -4452,6 +4461,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data) arch_spin_unlock(&cpu_buffer->lock); local_irq_restore(flags); + out: free_page((unsigned long)bpage); } EXPORT_SYMBOL_GPL(ring_buffer_free_read_page); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 752e5daf0896f..76bcc80b893eb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4178,37 +4178,30 @@ static const struct file_operations show_traces_fops = { .llseek = seq_lseek, }; -/* - * The tracer itself will not take this lock, but still we want - * to provide a consistent cpumask to user-space: - */ -static DEFINE_MUTEX(tracing_cpumask_update_lock); - -/* - * Temporary storage for the character representation of the - * CPU bitmask (and one more byte for the newline): - */ -static char mask_str[NR_CPUS + 1]; - static ssize_t tracing_cpumask_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { struct trace_array *tr = file_inode(filp)->i_private; + char *mask_str; int len; - mutex_lock(&tracing_cpumask_update_lock); + len = snprintf(NULL, 0, "%*pb\n", + cpumask_pr_args(tr->tracing_cpumask)) + 1; + mask_str = kmalloc(len, GFP_KERNEL); + if (!mask_str) + return -ENOMEM; - len = snprintf(mask_str, count, "%*pb\n", + len = snprintf(mask_str, len, "%*pb\n", cpumask_pr_args(tr->tracing_cpumask)); if (len >= count) { count = -EINVAL; goto out_err; } - count = simple_read_from_buffer(ubuf, count, ppos, mask_str, NR_CPUS+1); + count = simple_read_from_buffer(ubuf, count, ppos, mask_str, len); out_err: - mutex_unlock(&tracing_cpumask_update_lock); + kfree(mask_str); return count; } @@ -4228,8 +4221,6 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, if (err) goto err_unlock; - mutex_lock(&tracing_cpumask_update_lock); - local_irq_disable(); arch_spin_lock(&tr->max_lock); for_each_tracing_cpu(cpu) { @@ -4252,8 +4243,6 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, local_irq_enable(); cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new); - - mutex_unlock(&tracing_cpumask_update_lock); free_cpumask_var(tracing_cpumask_new); return count; @@ -6780,7 +6769,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, .spd_release = buffer_spd_release, }; struct buffer_ref *ref; - int entries, size, i; + int entries, i; ssize_t ret = 0; #ifdef CONFIG_TRACER_MAX_TRACE @@ -6834,14 +6823,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, break; } - /* - * zero out any left over data, this is going to - * user land. - */ - size = ring_buffer_page_len(ref->page); - if (size < PAGE_SIZE) - memset(ref->page + size, 0, PAGE_SIZE - size); - page = virt_to_page(ref->page); spd.pages[i] = page; @@ -7599,6 +7580,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size buf->data = alloc_percpu(struct trace_array_cpu); if (!buf->data) { ring_buffer_free(buf->buffer); + buf->buffer = NULL; return -ENOMEM; } @@ -7622,7 +7604,9 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) allocate_snapshot ? size : 1); if (WARN_ON(ret)) { ring_buffer_free(tr->trace_buffer.buffer); + tr->trace_buffer.buffer = NULL; free_percpu(tr->trace_buffer.data); + tr->trace_buffer.data = NULL; return -ENOMEM; } tr->allocated_snapshot = allocate_snapshot; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 87468398b9ed6..d53268a4e1671 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -2213,6 +2213,7 @@ void trace_event_eval_update(struct trace_eval_map **map, int len) { struct trace_event_call *call, *p; const char *last_system = NULL; + bool first = false; int last_i; int i; @@ -2220,15 +2221,28 @@ void trace_event_eval_update(struct trace_eval_map **map, int len) list_for_each_entry_safe(call, p, &ftrace_events, list) { /* events are usually grouped together with systems */ if (!last_system || call->class->system != last_system) { + first = true; last_i = 0; last_system = call->class->system; } + /* + * Since calls are grouped by systems, the likelyhood that the + * next call in the iteration belongs to the same system as the + * previous call is high. As an optimization, we skip seaching + * for a map[] that matches the call's system if the last call + * was from the same system. That's what last_i is for. If the + * call has the same system as the previous call, then last_i + * will be the index of the first map[] that has a matching + * system. + */ for (i = last_i; i < len; i++) { if (call->class->system == map[i]->system) { /* Save the first system if need be */ - if (!last_i) + if (first) { last_i = i; + first = false; + } update_event_printk(call, map[i]); } } diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 1c21d0e2a145a..7eb975a2d0e13 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -450,7 +450,7 @@ static int create_val_field(struct hist_trigger_data *hist_data, } field = trace_find_event_field(file->event_call, field_name); - if (!field) { + if (!field || !field->size) { ret = -EINVAL; goto out; } @@ -548,7 +548,7 @@ static int create_key_field(struct hist_trigger_data *hist_data, } field = trace_find_event_field(file->event_call, field_name); - if (!field) { + if (!field || !field->size) { ret = -EINVAL; goto out; } diff --git a/kernel/uid16.c b/kernel/uid16.c index ce74a4901d2b0..ef1da2a5f9bd0 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -192,6 +192,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) return retval; } + groups_sort(group_info); retval = set_current_groups(group_info); put_group_info(group_info); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index a2dccfe1acec3..8365a52a74c52 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "workqueue_internal.h" @@ -4479,6 +4480,12 @@ void show_workqueue_state(void) if (pwq->nr_active || !list_empty(&pwq->delayed_works)) show_pwq(pwq); spin_unlock_irqrestore(&pwq->pool->lock, flags); + /* + * We could be printing a lot from atomic context, e.g. + * sysrq-t -> show_workqueue_state(). Avoid triggering + * hard lockup. + */ + touch_nmi_watchdog(); } } @@ -4506,6 +4513,12 @@ void show_workqueue_state(void) pr_cont("\n"); next_pool: spin_unlock_irqrestore(&pool->lock, flags); + /* + * We could be printing a lot from atomic context, e.g. + * sysrq-t -> show_workqueue_state(). Avoid triggering + * hard lockup. + */ + touch_nmi_watchdog(); } rcu_read_unlock_sched(); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index dfdad67d8f6cc..ff21b4dbb3922 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -376,7 +376,7 @@ config STACK_VALIDATION that runtime stack traces are more reliable. This is also a prerequisite for generation of ORC unwind data, which - is needed for CONFIG_ORC_UNWINDER. + is needed for CONFIG_UNWINDER_ORC. For more information, see tools/objtool/Documentation/stack-validation.txt. diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 1ef0cec38d787..dc14beae2c9aa 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -313,42 +313,47 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, /* Decide how to handle the operation */ switch (op) { - case ASN1_OP_MATCH_ANY_ACT: - case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: - case ASN1_OP_COND_MATCH_ANY_ACT: - case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: - ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); - if (ret < 0) - return ret; - goto skip_data; - - case ASN1_OP_MATCH_ACT: - case ASN1_OP_MATCH_ACT_OR_SKIP: - case ASN1_OP_COND_MATCH_ACT_OR_SKIP: - ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len); - if (ret < 0) - return ret; - goto skip_data; - case ASN1_OP_MATCH: case ASN1_OP_MATCH_OR_SKIP: + case ASN1_OP_MATCH_ACT: + case ASN1_OP_MATCH_ACT_OR_SKIP: case ASN1_OP_MATCH_ANY: case ASN1_OP_MATCH_ANY_OR_SKIP: + case ASN1_OP_MATCH_ANY_ACT: + case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: case ASN1_OP_COND_MATCH_OR_SKIP: + case ASN1_OP_COND_MATCH_ACT_OR_SKIP: case ASN1_OP_COND_MATCH_ANY: case ASN1_OP_COND_MATCH_ANY_OR_SKIP: - skip_data: + case ASN1_OP_COND_MATCH_ANY_ACT: + case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: + if (!(flags & FLAG_CONS)) { if (flags & FLAG_INDEFINITE_LENGTH) { + size_t tmp = dp; + ret = asn1_find_indefinite_length( - data, datalen, &dp, &len, &errmsg); + data, datalen, &tmp, &len, &errmsg); if (ret < 0) goto error; - } else { - dp += len; } pr_debug("- LEAF: %zu\n", len); } + + if (op & ASN1_OP_MATCH__ACT) { + unsigned char act; + + if (op & ASN1_OP_MATCH__ANY) + act = machine[pc + 1]; + else + act = machine[pc + 2]; + ret = actions[act](context, hdr, tag, data + dp, len); + if (ret < 0) + return ret; + } + + if (!(flags & FLAG_CONS)) + dp += len; pc += asn1_op_lengths[op]; goto next_op; @@ -434,6 +439,8 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, else act = machine[pc + 1]; ret = actions[act](context, hdr, 0, data + tdp, len); + if (ret < 0) + return ret; } pc += asn1_op_lengths[op]; goto next_op; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index da796e2dc4f50..c7c96bc7654af 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -360,6 +360,10 @@ static int ddebug_parse_query(char *words[], int nwords, if (parse_lineno(last, &query->last_lineno) < 0) return -EINVAL; + /* special case for last lineno not specified */ + if (query->last_lineno == 0) + query->last_lineno = UINT_MAX; + if (query->last_lineno < query->first_lineno) { pr_err("last-line:%d < 1st-line:%d\n", query->last_lineno, diff --git a/lib/genalloc.c b/lib/genalloc.c index 144fe6b1a03ea..ca06adc4f4451 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -194,7 +194,7 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy chunk->phys_addr = phys; chunk->start_addr = virt; chunk->end_addr = virt + size - 1; - atomic_set(&chunk->avail, size); + atomic_long_set(&chunk->avail, size); spin_lock(&pool->lock); list_add_rcu(&chunk->next_chunk, &pool->chunks); @@ -304,7 +304,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size, nbits = (size + (1UL << order) - 1) >> order; rcu_read_lock(); list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) { - if (size > atomic_read(&chunk->avail)) + if (size > atomic_long_read(&chunk->avail)) continue; start_bit = 0; @@ -324,7 +324,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size, addr = chunk->start_addr + ((unsigned long)start_bit << order); size = nbits << order; - atomic_sub(size, &chunk->avail); + atomic_long_sub(size, &chunk->avail); break; } rcu_read_unlock(); @@ -390,7 +390,7 @@ void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size) remain = bitmap_clear_ll(chunk->bits, start_bit, nbits); BUG_ON(remain); size = nbits << order; - atomic_add(size, &chunk->avail); + atomic_long_add(size, &chunk->avail); rcu_read_unlock(); return; } @@ -464,7 +464,7 @@ size_t gen_pool_avail(struct gen_pool *pool) rcu_read_lock(); list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) - avail += atomic_read(&chunk->avail); + avail += atomic_long_read(&chunk->avail); rcu_read_unlock(); return avail; } diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c index e24388a863a76..468fb7cd1221e 100644 --- a/lib/mpi/mpi-pow.c +++ b/lib/mpi/mpi-pow.c @@ -26,6 +26,7 @@ * however I decided to publish this code under the plain GPL. */ +#include #include #include "mpi-internal.h" #include "longlong.h" @@ -256,6 +257,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) } e <<= 1; c--; + cond_resched(); } i--; diff --git a/lib/test_bpf.c b/lib/test_bpf.c index aa8812ae6776e..6fbb73f3f531d 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -6207,9 +6207,8 @@ static struct bpf_prog *generate_filter(int which, int *err) return NULL; } } - /* We don't expect to fail. */ if (*err) { - pr_cont("FAIL to attach err=%d len=%d\n", + pr_cont("FAIL to prog_create err=%d len=%d\n", *err, fprog.len); return NULL; } @@ -6233,6 +6232,10 @@ static struct bpf_prog *generate_filter(int which, int *err) * checks. */ fp = bpf_prog_select_runtime(fp, err); + if (*err) { + pr_cont("FAIL to select_runtime err=%d\n", *err); + return NULL; + } break; } @@ -6418,8 +6421,8 @@ static __init int test_bpf(void) pass_cnt++; continue; } - - return err; + err_cnt++; + continue; } pr_cont("jited:%u ", fp->jited); diff --git a/mm/frame_vector.c b/mm/frame_vector.c index 2f98df0d460ee..297c7238f7d40 100644 --- a/mm/frame_vector.c +++ b/mm/frame_vector.c @@ -53,6 +53,18 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, ret = -EFAULT; goto out; } + + /* + * While get_vaddr_frames() could be used for transient (kernel + * controlled lifetime) pinning of memory pages all current + * users establish long term (userspace controlled lifetime) + * page pinning. Treat get_vaddr_frames() like + * get_user_pages_longterm() and disallow it for filesystem-dax + * mappings. + */ + if (vma_is_fsdax(vma)) + return -EOPNOTSUPP; + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) { vec->got_ref = true; vec->is_pfns = false; diff --git a/mm/gup.c b/mm/gup.c index b2b4d4263768d..e0d82b6706d72 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1095,6 +1095,70 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, } EXPORT_SYMBOL(get_user_pages); +#ifdef CONFIG_FS_DAX +/* + * This is the same as get_user_pages() in that it assumes we are + * operating on the current task's mm, but it goes further to validate + * that the vmas associated with the address range are suitable for + * longterm elevated page reference counts. For example, filesystem-dax + * mappings are subject to the lifetime enforced by the filesystem and + * we need guarantees that longterm users like RDMA and V4L2 only + * establish mappings that have a kernel enforced revocation mechanism. + * + * "longterm" == userspace controlled elevated page count lifetime. + * Contrast this to iov_iter_get_pages() usages which are transient. + */ +long get_user_pages_longterm(unsigned long start, unsigned long nr_pages, + unsigned int gup_flags, struct page **pages, + struct vm_area_struct **vmas_arg) +{ + struct vm_area_struct **vmas = vmas_arg; + struct vm_area_struct *vma_prev = NULL; + long rc, i; + + if (!pages) + return -EINVAL; + + if (!vmas) { + vmas = kcalloc(nr_pages, sizeof(struct vm_area_struct *), + GFP_KERNEL); + if (!vmas) + return -ENOMEM; + } + + rc = get_user_pages(start, nr_pages, gup_flags, pages, vmas); + + for (i = 0; i < rc; i++) { + struct vm_area_struct *vma = vmas[i]; + + if (vma == vma_prev) + continue; + + vma_prev = vma; + + if (vma_is_fsdax(vma)) + break; + } + + /* + * Either get_user_pages() failed, or the vma validation + * succeeded, in either case we don't need to put_page() before + * returning. + */ + if (i >= rc) + goto out; + + for (i = 0; i < rc; i++) + put_page(pages[i]); + rc = -EOPNOTSUPP; +out: + if (vmas != vmas_arg) + kfree(vmas); + return rc; +} +EXPORT_SYMBOL(get_user_pages_longterm); +#endif /* CONFIG_FS_DAX */ + /** * populate_vma_page_range() - populate a range of pages in the vma. * @vma: target vma @@ -1643,6 +1707,47 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end, return 1; } +static void gup_pgd_range(unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + unsigned long next; + pgd_t *pgdp; + + pgdp = pgd_offset(current->mm, addr); + do { + pgd_t pgd = READ_ONCE(*pgdp); + + next = pgd_addr_end(addr, end); + if (pgd_none(pgd)) + return; + if (unlikely(pgd_huge(pgd))) { + if (!gup_huge_pgd(pgd, pgdp, addr, next, write, + pages, nr)) + return; + } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) { + if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr, + PGDIR_SHIFT, next, write, pages, nr)) + return; + } else if (!gup_p4d_range(pgd, addr, next, write, pages, nr)) + return; + } while (pgdp++, addr = next, addr != end); +} + +#ifndef gup_fast_permitted +/* + * Check if it's allowed to use __get_user_pages_fast() for the range, or + * we need to fall back to the slow version: + */ +bool gup_fast_permitted(unsigned long start, int nr_pages, int write) +{ + unsigned long len, end; + + len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; + return end >= start; +} +#endif + /* * Like get_user_pages_fast() except it's IRQ-safe in that it won't fall back to * the regular GUP. It will only return non-negative values. @@ -1650,10 +1755,8 @@ static int gup_p4d_range(pgd_t pgd, unsigned long addr, unsigned long end, int __get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages) { - struct mm_struct *mm = current->mm; unsigned long addr, len, end; - unsigned long next, flags; - pgd_t *pgdp; + unsigned long flags; int nr = 0; start &= PAGE_MASK; @@ -1677,45 +1780,15 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, * block IPIs that come from THPs splitting. */ - local_irq_save(flags); - pgdp = pgd_offset(mm, addr); - do { - pgd_t pgd = READ_ONCE(*pgdp); - - next = pgd_addr_end(addr, end); - if (pgd_none(pgd)) - break; - if (unlikely(pgd_huge(pgd))) { - if (!gup_huge_pgd(pgd, pgdp, addr, next, write, - pages, &nr)) - break; - } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) { - if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr, - PGDIR_SHIFT, next, write, pages, &nr)) - break; - } else if (!gup_p4d_range(pgd, addr, next, write, pages, &nr)) - break; - } while (pgdp++, addr = next, addr != end); - local_irq_restore(flags); + if (gup_fast_permitted(start, nr_pages, write)) { + local_irq_save(flags); + gup_pgd_range(addr, end, write, pages, &nr); + local_irq_restore(flags); + } return nr; } -#ifndef gup_fast_permitted -/* - * Check if it's allowed to use __get_user_pages_fast() for the range, or - * we need to fall back to the slow version: - */ -bool gup_fast_permitted(unsigned long start, int nr_pages, int write) -{ - unsigned long len, end; - - len = (unsigned long) nr_pages << PAGE_SHIFT; - end = start + len; - return end >= start; -} -#endif - /** * get_user_pages_fast() - pin user pages in memory * @start: starting user address @@ -1735,12 +1808,22 @@ bool gup_fast_permitted(unsigned long start, int nr_pages, int write) int get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages) { + unsigned long addr, len, end; int nr = 0, ret = 0; start &= PAGE_MASK; + addr = start; + len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; + + if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, + (void __user *)start, len))) + return 0; if (gup_fast_permitted(start, nr_pages, write)) { - nr = __get_user_pages_fast(start, nr_pages, write, pages); + local_irq_disable(); + gup_pgd_range(addr, end, write, pages, &nr); + local_irq_enable(); ret = nr; } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1981ed697dabb..eba34cdfc3e5b 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -842,20 +842,15 @@ EXPORT_SYMBOL_GPL(vmf_insert_pfn_pud); #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ static void touch_pmd(struct vm_area_struct *vma, unsigned long addr, - pmd_t *pmd) + pmd_t *pmd, int flags) { pmd_t _pmd; - /* - * We should set the dirty bit only for FOLL_WRITE but for now - * the dirty bit in the pmd is meaningless. And if the dirty - * bit will become meaningful and we'll only set it with - * FOLL_WRITE, an atomic set_bit will be required on the pmd to - * set the young bit, instead of the current set_pmd_at. - */ - _pmd = pmd_mkyoung(pmd_mkdirty(*pmd)); + _pmd = pmd_mkyoung(*pmd); + if (flags & FOLL_WRITE) + _pmd = pmd_mkdirty(_pmd); if (pmdp_set_access_flags(vma, addr & HPAGE_PMD_MASK, - pmd, _pmd, 1)) + pmd, _pmd, flags & FOLL_WRITE)) update_mmu_cache_pmd(vma, addr, pmd); } @@ -884,7 +879,7 @@ struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr, return NULL; if (flags & FOLL_TOUCH) - touch_pmd(vma, addr, pmd); + touch_pmd(vma, addr, pmd, flags); /* * device mapped pages can only be returned if the @@ -995,20 +990,15 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD static void touch_pud(struct vm_area_struct *vma, unsigned long addr, - pud_t *pud) + pud_t *pud, int flags) { pud_t _pud; - /* - * We should set the dirty bit only for FOLL_WRITE but for now - * the dirty bit in the pud is meaningless. And if the dirty - * bit will become meaningful and we'll only set it with - * FOLL_WRITE, an atomic set_bit will be required on the pud to - * set the young bit, instead of the current set_pud_at. - */ - _pud = pud_mkyoung(pud_mkdirty(*pud)); + _pud = pud_mkyoung(*pud); + if (flags & FOLL_WRITE) + _pud = pud_mkdirty(_pud); if (pudp_set_access_flags(vma, addr & HPAGE_PUD_MASK, - pud, _pud, 1)) + pud, _pud, flags & FOLL_WRITE)) update_mmu_cache_pud(vma, addr, pud); } @@ -1031,7 +1021,7 @@ struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr, return NULL; if (flags & FOLL_TOUCH) - touch_pud(vma, addr, pud); + touch_pud(vma, addr, pud, flags); /* * device mapped pages can only be returned if the @@ -1407,7 +1397,7 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, page = pmd_page(*pmd); VM_BUG_ON_PAGE(!PageHead(page) && !is_zone_device_page(page), page); if (flags & FOLL_TOUCH) - touch_pmd(vma, addr, pmd); + touch_pmd(vma, addr, pmd, flags); if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) { /* * We don't mlock() pte-mapped THPs. This way we can avoid diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 2d2ff5e8bf2bc..c539941671b4e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3125,6 +3125,13 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) } } +static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr) +{ + if (addr & ~(huge_page_mask(hstate_vma(vma)))) + return -EINVAL; + return 0; +} + /* * We cannot handle pagefaults against hugetlb pages at all. They cause * handle_mm_fault() to try to instantiate regular-sized pages in the @@ -3141,6 +3148,7 @@ const struct vm_operations_struct hugetlb_vm_ops = { .fault = hugetlb_vm_op_fault, .open = hugetlb_vm_op_open, .close = hugetlb_vm_op_close, + .split = hugetlb_vm_op_split, }; static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page, @@ -4617,7 +4625,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, pte_t *pte = NULL; pgd = pgd_offset(mm, addr); - p4d = p4d_offset(pgd, addr); + p4d = p4d_alloc(mm, pgd, addr); + if (!p4d) + return NULL; pud = pud_alloc(mm, p4d, addr); if (pud) { if (sz == PUD_SIZE) { diff --git a/mm/madvise.c b/mm/madvise.c index 375cf32087e4a..751e97aa22106 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -276,15 +276,14 @@ static long madvise_willneed(struct vm_area_struct *vma, { struct file *file = vma->vm_file; + *prev = vma; #ifdef CONFIG_SWAP if (!file) { - *prev = vma; force_swapin_readahead(vma, start, end); return 0; } if (shmem_mapping(file->f_mapping)) { - *prev = vma; force_shm_swapin_readahead(vma, start, end, file->f_mapping); return 0; @@ -299,7 +298,6 @@ static long madvise_willneed(struct vm_area_struct *vma, return 0; } - *prev = vma; start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; if (end > vma->vm_end) end = vma->vm_end; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 661f046ad3181..53f7c919b9160 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6044,7 +6044,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) memcg_check_events(memcg, page); if (!mem_cgroup_is_root(memcg)) - css_put(&memcg->css); + css_put_many(&memcg->css, nr_entries); } /** diff --git a/mm/mmap.c b/mm/mmap.c index 680506faceae9..0de87a376aaa1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2540,9 +2540,11 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *new; int err; - if (is_vm_hugetlb_page(vma) && (addr & - ~(huge_page_mask(hstate_vma(vma))))) - return -EINVAL; + if (vma->vm_ops && vma->vm_ops->split) { + err = vma->vm_ops->split(vma, addr); + if (err) + return err; + } new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!new) @@ -3002,20 +3004,20 @@ void exit_mmap(struct mm_struct *mm) /* Use -1 here to ensure all VMAs in the mm are unmapped */ unmap_vmas(&tlb, vma, 0, -1); - set_bit(MMF_OOM_SKIP, &mm->flags); - if (unlikely(tsk_is_oom_victim(current))) { + if (unlikely(mm_is_oom_victim(mm))) { /* * Wait for oom_reap_task() to stop working on this * mm. Because MMF_OOM_SKIP is already set before * calling down_read(), oom_reap_task() will not run * on this "mm" post up_write(). * - * tsk_is_oom_victim() cannot be set from under us - * either because current->mm is already set to NULL + * mm_is_oom_victim() cannot be set from under us + * either because victim->mm is already set to NULL * under task_lock before calling mmput and oom_mm is - * set not NULL by the OOM killer only if current->mm + * set not NULL by the OOM killer only if victim->mm * is found not NULL while holding the task_lock. */ + set_bit(MMF_OOM_SKIP, &mm->flags); down_write(&mm->mmap_sem); up_write(&mm->mmap_sem); } diff --git a/mm/mprotect.c b/mm/mprotect.c index ec39f730a0bfe..58b629bb70de3 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -166,7 +166,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, next = pmd_addr_end(addr, end); if (!is_swap_pmd(*pmd) && !pmd_trans_huge(*pmd) && !pmd_devmap(*pmd) && pmd_none_or_clear_bad(pmd)) - continue; + goto next; /* invoke the mmu notifier if the pmd is populated */ if (!mni_start) { @@ -188,7 +188,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, } /* huge pmd was handled */ - continue; + goto next; } } /* fall through, the trans huge pmd just split */ @@ -196,6 +196,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, this_pages = change_pte_range(vma, pmd, addr, next, newprot, dirty_accountable, prot_numa); pages += this_pages; +next: + cond_resched(); } while (pmd++, addr = next, addr != end); if (mni_start) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index dee0f75c30133..10aed8d8c0807 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -532,7 +532,6 @@ static bool __oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm) */ set_bit(MMF_UNSTABLE, &mm->flags); - tlb_gather_mmu(&tlb, mm, 0, -1); for (vma = mm->mmap ; vma; vma = vma->vm_next) { if (!can_madv_dontneed_vma(vma)) continue; @@ -547,11 +546,13 @@ static bool __oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm) * we do not want to block exit_mmap by keeping mm ref * count elevated without a good reason. */ - if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) + if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) { + tlb_gather_mmu(&tlb, mm, vma->vm_start, vma->vm_end); unmap_page_range(&tlb, vma, vma->vm_start, vma->vm_end, NULL); + tlb_finish_mmu(&tlb, vma->vm_start, vma->vm_end); + } } - tlb_finish_mmu(&tlb, 0, -1); pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n", task_pid_nr(tsk), tsk->comm, K(get_mm_counter(mm, MM_ANONPAGES)), @@ -672,8 +673,10 @@ static void mark_oom_victim(struct task_struct *tsk) return; /* oom_mm is bound to the signal struct life time. */ - if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) + if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) { mmgrab(tsk->signal->oom_mm); + set_bit(MMF_OOM_VICTIM, &mm->flags); + } /* * Make sure that the task is woken up from uninterruptible sleep diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 77e4d3c5c57b7..2de080003693c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -290,28 +290,37 @@ EXPORT_SYMBOL(nr_online_nodes); int page_group_by_mobility_disabled __read_mostly; #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT + +/* + * Determine how many pages need to be initialized durig early boot + * (non-deferred initialization). + * The value of first_deferred_pfn will be set later, once non-deferred pages + * are initialized, but for now set it ULONG_MAX. + */ static inline void reset_deferred_meminit(pg_data_t *pgdat) { - unsigned long max_initialise; - unsigned long reserved_lowmem; + phys_addr_t start_addr, end_addr; + unsigned long max_pgcnt; + unsigned long reserved; /* * Initialise at least 2G of a node but also take into account that * two large system hashes that can take up 1GB for 0.25TB/node. */ - max_initialise = max(2UL << (30 - PAGE_SHIFT), - (pgdat->node_spanned_pages >> 8)); + max_pgcnt = max(2UL << (30 - PAGE_SHIFT), + (pgdat->node_spanned_pages >> 8)); /* * Compensate the all the memblock reservations (e.g. crash kernel) * from the initial estimation to make sure we will initialize enough * memory to boot. */ - reserved_lowmem = memblock_reserved_memory_within(pgdat->node_start_pfn, - pgdat->node_start_pfn + max_initialise); - max_initialise += reserved_lowmem; + start_addr = PFN_PHYS(pgdat->node_start_pfn); + end_addr = PFN_PHYS(pgdat->node_start_pfn + max_pgcnt); + reserved = memblock_reserved_memory_within(start_addr, end_addr); + max_pgcnt += PHYS_PFN(reserved); - pgdat->static_init_size = min(max_initialise, pgdat->node_spanned_pages); + pgdat->static_init_pgcnt = min(max_pgcnt, pgdat->node_spanned_pages); pgdat->first_deferred_pfn = ULONG_MAX; } @@ -338,7 +347,7 @@ static inline bool update_defer_init(pg_data_t *pgdat, if (zone_end < pgdat_end_pfn(pgdat)) return true; (*nr_initialised)++; - if ((*nr_initialised > pgdat->static_init_size) && + if ((*nr_initialised > pgdat->static_init_pgcnt) && (pfn & (PAGES_PER_SECTION - 1)) == 0) { pgdat->first_deferred_pfn = pfn; return false; @@ -2478,10 +2487,6 @@ void drain_all_pages(struct zone *zone) if (WARN_ON_ONCE(!mm_percpu_wq)) return; - /* Workqueues cannot recurse */ - if (current->flags & PF_WQ_WORKER) - return; - /* * Do not drain if one is already in progress unless it's specific to * a zone. Such callers are primarily CMA and memory hotplug and need @@ -3006,9 +3011,6 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, if (!area->nr_free) continue; - if (alloc_harder) - return true; - for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) { if (!list_empty(&area->free_list[mt])) return true; @@ -3020,6 +3022,9 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; } #endif + if (alloc_harder && + !list_empty(&area->free_list[MIGRATE_HIGHATOMIC])) + return true; } return false; } @@ -7582,11 +7587,18 @@ int alloc_contig_range(unsigned long start, unsigned long end, /* * In case of -EBUSY, we'd like to know which page causes problem. - * So, just fall through. We will check it in test_pages_isolated(). + * So, just fall through. test_pages_isolated() has a tracepoint + * which will report the busy page. + * + * It is possible that busy pages could become available before + * the call to test_pages_isolated, and the range will actually be + * allocated. So, if we fall through be sure to clear ret so that + * -EBUSY is not accidentally used or returned to caller. */ ret = __alloc_contig_migrate_range(&cc, start, end); if (ret && ret != -EBUSY) goto done; + ret =0; /* * Pages from [start, end) are within a MAX_ORDER_NR_PAGES diff --git a/mm/page_ext.c b/mm/page_ext.c index 4f0367d472c49..2c16216c29b62 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -125,7 +125,6 @@ struct page_ext *lookup_page_ext(struct page *page) struct page_ext *base; base = NODE_DATA(page_to_nid(page))->node_page_ext; -#if defined(CONFIG_DEBUG_VM) /* * The sanity checks the page allocator does upon freeing a * page can reach here before the page_ext arrays are @@ -134,7 +133,6 @@ struct page_ext *lookup_page_ext(struct page *page) */ if (unlikely(!base)) return NULL; -#endif index = pfn - round_down(node_start_pfn(page_to_nid(page)), MAX_ORDER_NR_PAGES); return get_entry(base, index); @@ -199,7 +197,6 @@ struct page_ext *lookup_page_ext(struct page *page) { unsigned long pfn = page_to_pfn(page); struct mem_section *section = __pfn_to_section(pfn); -#if defined(CONFIG_DEBUG_VM) /* * The sanity checks the page allocator does upon freeing a * page can reach here before the page_ext arrays are @@ -208,7 +205,6 @@ struct page_ext *lookup_page_ext(struct page *page) */ if (!section->page_ext) return NULL; -#endif return get_entry(section->page_ext, pfn); } diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c index d22b84310f6d4..9560156143953 100644 --- a/mm/page_vma_mapped.c +++ b/mm/page_vma_mapped.c @@ -30,10 +30,29 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw) return true; } +/** + * check_pte - check if @pvmw->page is mapped at the @pvmw->pte + * + * page_vma_mapped_walk() found a place where @pvmw->page is *potentially* + * mapped. check_pte() has to validate this. + * + * @pvmw->pte may point to empty PTE, swap PTE or PTE pointing to arbitrary + * page. + * + * If PVMW_MIGRATION flag is set, returns true if @pvmw->pte contains migration + * entry that points to @pvmw->page or any subpage in case of THP. + * + * If PVMW_MIGRATION flag is not set, returns true if @pvmw->pte points to + * @pvmw->page or any subpage in case of THP. + * + * Otherwise, return false. + * + */ static bool check_pte(struct page_vma_mapped_walk *pvmw) { + unsigned long pfn; + if (pvmw->flags & PVMW_MIGRATION) { -#ifdef CONFIG_MIGRATION swp_entry_t entry; if (!is_swap_pte(*pvmw->pte)) return false; @@ -41,37 +60,31 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw) if (!is_migration_entry(entry)) return false; - if (migration_entry_to_page(entry) - pvmw->page >= - hpage_nr_pages(pvmw->page)) { - return false; - } - if (migration_entry_to_page(entry) < pvmw->page) - return false; -#else - WARN_ON_ONCE(1); -#endif - } else { - if (is_swap_pte(*pvmw->pte)) { - swp_entry_t entry; - entry = pte_to_swp_entry(*pvmw->pte); - if (is_device_private_entry(entry) && - device_private_entry_to_page(entry) == pvmw->page) - return true; - } + pfn = migration_entry_to_pfn(entry); + } else if (is_swap_pte(*pvmw->pte)) { + swp_entry_t entry; - if (!pte_present(*pvmw->pte)) + /* Handle un-addressable ZONE_DEVICE memory */ + entry = pte_to_swp_entry(*pvmw->pte); + if (!is_device_private_entry(entry)) return false; - /* THP can be referenced by any subpage */ - if (pte_page(*pvmw->pte) - pvmw->page >= - hpage_nr_pages(pvmw->page)) { - return false; - } - if (pte_page(*pvmw->pte) < pvmw->page) + pfn = device_private_entry_to_pfn(entry); + } else { + if (!pte_present(*pvmw->pte)) return false; + + pfn = pte_pfn(*pvmw->pte); } + if (pfn < page_to_pfn(pvmw->page)) + return false; + + /* THP can be referenced by any subpage */ + if (pfn - page_to_pfn(pvmw->page) >= hpage_nr_pages(pvmw->page)) + return false; + return true; } diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 8bd4afa83cb89..23a3e415ac2ce 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -188,8 +188,12 @@ static int walk_hugetlb_range(unsigned long addr, unsigned long end, do { next = hugetlb_entry_end(h, addr, end); pte = huge_pte_offset(walk->mm, addr & hmask, sz); - if (pte && walk->hugetlb_entry) + + if (pte) err = walk->hugetlb_entry(pte, hmask, addr, next, walk); + else if (walk->pte_hole) + err = walk->pte_hole(addr, next, walk); + if (err) break; } while (addr = next, addr != end); diff --git a/mm/slab.h b/mm/slab.h index 028cdc7df67ec..86d7c7d860f92 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -259,7 +259,7 @@ cache_from_memcg_idx(struct kmem_cache *s, int idx) * memcg_caches issues a write barrier to match this (see * memcg_create_kmem_cache()). */ - cachep = lockless_dereference(arr->entries[idx]); + cachep = READ_ONCE(arr->entries[idx]); rcu_read_unlock(); return cachep; diff --git a/mm/slub.c b/mm/slub.c index 1efbb81230374..8e1c027a30f4d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5704,6 +5704,10 @@ static int sysfs_slab_add(struct kmem_cache *s) return 0; } + if (!unmergeable && disable_higher_order_debug && + (slub_debug & DEBUG_METADATA_FLAGS)) + unmergeable = 1; + if (unmergeable) { /* * Slabcache can never be merged so we can use the name proper. diff --git a/mm/sparse.c b/mm/sparse.c index 4900707ae146c..30e56a100ee85 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -23,8 +23,7 @@ * 1) mem_section - memory sections, mem_map's for valid memory */ #ifdef CONFIG_SPARSEMEM_EXTREME -struct mem_section *mem_section[NR_SECTION_ROOTS] - ____cacheline_internodealigned_in_smp; +struct mem_section **mem_section; #else struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] ____cacheline_internodealigned_in_smp; @@ -101,7 +100,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid) int __section_nr(struct mem_section* ms) { unsigned long root_nr; - struct mem_section* root; + struct mem_section *root = NULL; for (root_nr = 0; root_nr < NR_SECTION_ROOTS; root_nr++) { root = __nr_to_section(root_nr * SECTIONS_PER_ROOT); @@ -112,7 +111,7 @@ int __section_nr(struct mem_section* ms) break; } - VM_BUG_ON(root_nr == NR_SECTION_ROOTS); + VM_BUG_ON(!root); return (root_nr * SECTIONS_PER_ROOT) + (ms - root); } @@ -208,6 +207,16 @@ void __init memory_present(int nid, unsigned long start, unsigned long end) { unsigned long pfn; +#ifdef CONFIG_SPARSEMEM_EXTREME + if (unlikely(!mem_section)) { + unsigned long size, align; + + size = sizeof(struct mem_section*) * NR_SECTION_ROOTS; + align = 1 << (INTERNODE_CACHE_SHIFT); + mem_section = memblock_virt_alloc(size, align); + } +#endif + start &= PAGE_SECTION_MASK; mminit_validate_memmodel_limits(&start, &end); for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { @@ -330,11 +339,17 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat, static void __init check_usemap_section_nr(int nid, unsigned long *usemap) { unsigned long usemap_snr, pgdat_snr; - static unsigned long old_usemap_snr = NR_MEM_SECTIONS; - static unsigned long old_pgdat_snr = NR_MEM_SECTIONS; + static unsigned long old_usemap_snr; + static unsigned long old_pgdat_snr; struct pglist_data *pgdat = NODE_DATA(nid); int usemap_nid; + /* First call */ + if (!old_usemap_snr) { + old_usemap_snr = NR_MEM_SECTIONS; + old_pgdat_snr = NR_MEM_SECTIONS; + } + usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT); pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); if (usemap_snr == pgdat_snr) diff --git a/mm/z3fold.c b/mm/z3fold.c index b2ba2ba585f3c..39e19125d6a01 100644 --- a/mm/z3fold.c +++ b/mm/z3fold.c @@ -404,8 +404,7 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked) WARN_ON(z3fold_page_trylock(zhdr)); else z3fold_page_lock(zhdr); - if (test_bit(PAGE_STALE, &page->private) || - !test_and_clear_bit(NEEDS_COMPACTING, &page->private)) { + if (WARN_ON(!test_and_clear_bit(NEEDS_COMPACTING, &page->private))) { z3fold_page_unlock(zhdr); return; } @@ -413,6 +412,11 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked) list_del_init(&zhdr->buddy); spin_unlock(&pool->lock); + if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) { + atomic64_dec(&pool->pages_nr); + return; + } + z3fold_compact_page(zhdr); unbuddied = get_cpu_ptr(pool->unbuddied); fchunks = num_free_chunks(zhdr); @@ -753,9 +757,11 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle) list_del_init(&zhdr->buddy); spin_unlock(&pool->lock); zhdr->cpu = -1; + kref_get(&zhdr->refcount); do_compact_page(zhdr, true); return; } + kref_get(&zhdr->refcount); queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work); z3fold_page_unlock(zhdr); } diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 7c38e850a8fc5..685049a9048d8 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1349,7 +1349,7 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle, * pools/users, we can't allow mapping in interrupt context * because it can corrupt another users mappings. */ - WARN_ON_ONCE(in_interrupt()); + BUG_ON(in_interrupt()); /* From now on, migration cannot move the object */ pin_tag(handle); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 4a72ee4e2ae96..cf2e70003a534 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -111,12 +111,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) vlan_gvrp_uninit_applicant(real_dev); } - /* Take it out of our own structures, but be sure to interlock with - * HW accelerating devices or SW vlan input packet processing if - * VLAN is not 0 (leave it there for 802.1p). - */ - if (vlan_id) - vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); + vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); /* Get rid of the vlan's reference to real_dev */ dev_put(real_dev); diff --git a/net/9p/client.c b/net/9p/client.c index 4674235b0d9b1..b433aff5ff13c 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -82,7 +82,7 @@ int p9_show_client_options(struct seq_file *m, struct p9_client *clnt) { if (clnt->msize != 8192) seq_printf(m, ",msize=%u", clnt->msize); - seq_printf(m, "trans=%s", clnt->trans_mod->name); + seq_printf(m, ",trans=%s", clnt->trans_mod->name); switch (clnt->proto_version) { case p9_proto_legacy: @@ -773,8 +773,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) } again: /* Wait for the response */ - err = wait_event_interruptible(*req->wq, - req->status >= REQ_STATUS_RCVD); + err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD); /* * Make sure our req is coherent with regard to updates in other diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 903a190319b94..985046ae42312 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -724,12 +724,12 @@ static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt) { if (clnt->trans_mod == &p9_tcp_trans) { if (clnt->trans_opts.tcp.port != P9_PORT) - seq_printf(m, "port=%u", clnt->trans_opts.tcp.port); + seq_printf(m, ",port=%u", clnt->trans_opts.tcp.port); } else if (clnt->trans_mod == &p9_fd_trans) { if (clnt->trans_opts.fd.rfd != ~0) - seq_printf(m, "rfd=%u", clnt->trans_opts.fd.rfd); + seq_printf(m, ",rfd=%u", clnt->trans_opts.fd.rfd); if (clnt->trans_opts.fd.wfd != ~0) - seq_printf(m, "wfd=%u", clnt->trans_opts.fd.wfd); + seq_printf(m, ",wfd=%u", clnt->trans_opts.fd.wfd); } return 0; } diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index f24b25c25106f..f3a4efcf14564 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -286,8 +286,8 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) if (err == -ENOSPC) { chan->ring_bufs_avail = 0; spin_unlock_irqrestore(&chan->lock, flags); - err = wait_event_interruptible(*chan->vc_wq, - chan->ring_bufs_avail); + err = wait_event_killable(*chan->vc_wq, + chan->ring_bufs_avail); if (err == -ERESTARTSYS) return err; @@ -327,7 +327,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, * Other zc request to finish here */ if (atomic_read(&vp_pinned) >= chan->p9_max_pages) { - err = wait_event_interruptible(vp_wq, + err = wait_event_killable(vp_wq, (atomic_read(&vp_pinned) < chan->p9_max_pages)); if (err == -ERESTARTSYS) return err; @@ -471,8 +471,8 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, if (err == -ENOSPC) { chan->ring_bufs_avail = 0; spin_unlock_irqrestore(&chan->lock, flags); - err = wait_event_interruptible(*chan->vc_wq, - chan->ring_bufs_avail); + err = wait_event_killable(*chan->vc_wq, + chan->ring_bufs_avail); if (err == -ERESTARTSYS) goto err_out; @@ -489,8 +489,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, virtqueue_kick(chan->vq); spin_unlock_irqrestore(&chan->lock, flags); p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n"); - err = wait_event_interruptible(*req->wq, - req->status >= REQ_STATUS_RCVD); + err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD); /* * Non kernel buffers are pinned, unpin them */ diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index 6ad3e043c6174..325c56043007d 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -156,8 +156,8 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req) ring = &priv->rings[num]; again: - while (wait_event_interruptible(ring->wq, - p9_xen_write_todo(ring, size)) != 0) + while (wait_event_killable(ring->wq, + p9_xen_write_todo(ring, size)) != 0) ; spin_lock_irqsave(&ring->lock, flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b4dba08a14ec..53de7b9b0b4c1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -637,8 +637,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, if (rp->status) return; - - if (hdev->max_page < rp->max_page) + if (hdev->max_page < rp->max_page) hdev->max_page = rp->max_page; if (rp->page < HCI_MAX_PAGES) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 43ba91c440bcd..fc6615d591652 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3363,9 +3363,10 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data break; case L2CAP_CONF_EFS: - remote_efs = 1; - if (olen == sizeof(efs)) + if (olen == sizeof(efs)) { + remote_efs = 1; memcpy(&efs, (void *) val, olen); + } break; case L2CAP_CONF_EWS: @@ -3584,16 +3585,17 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, break; case L2CAP_CONF_EFS: - if (olen == sizeof(efs)) + if (olen == sizeof(efs)) { memcpy(&efs, (void *)val, olen); - if (chan->local_stype != L2CAP_SERV_NOTRAFIC && - efs.stype != L2CAP_SERV_NOTRAFIC && - efs.stype != chan->local_stype) - return -ECONNREFUSED; + if (chan->local_stype != L2CAP_SERV_NOTRAFIC && + efs.stype != L2CAP_SERV_NOTRAFIC && + efs.stype != chan->local_stype) + return -ECONNREFUSED; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), - (unsigned long) &efs, endptr - ptr); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), + (unsigned long) &efs, endptr - ptr); + } break; case L2CAP_CONF_FCS: diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index de21527308093..08190db0a2dca 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1223,19 +1223,20 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev, struct net_bridge *br = netdev_priv(dev); int err; + err = register_netdevice(dev); + if (err) + return err; + if (tb[IFLA_ADDRESS]) { spin_lock_bh(&br->lock); br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS])); spin_unlock_bh(&br->lock); } - err = register_netdevice(dev); - if (err) - return err; - err = br_changelink(dev, tb, data, extack); if (err) - unregister_netdevice(dev); + br_dev_delete(dev, NULL); + return err; } diff --git a/net/can/af_can.c b/net/can/af_can.c index ecd5c703d11e8..e3626e8500c24 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -721,20 +721,16 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, { struct canfd_frame *cfd = (struct canfd_frame *)skb->data; - if (WARN_ONCE(dev->type != ARPHRD_CAN || - skb->len != CAN_MTU || - cfd->len > CAN_MAX_DLEN, - "PF_CAN: dropped non conform CAN skbuf: " - "dev type %d, len %d, datalen %d\n", - dev->type, skb->len, cfd->len)) - goto drop; + if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU || + cfd->len > CAN_MAX_DLEN)) { + pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n", + dev->type, skb->len, cfd->len); + kfree_skb(skb); + return NET_RX_DROP; + } can_receive(skb, dev); return NET_RX_SUCCESS; - -drop: - kfree_skb(skb); - return NET_RX_DROP; } static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, @@ -742,20 +738,16 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, { struct canfd_frame *cfd = (struct canfd_frame *)skb->data; - if (WARN_ONCE(dev->type != ARPHRD_CAN || - skb->len != CANFD_MTU || - cfd->len > CANFD_MAX_DLEN, - "PF_CAN: dropped non conform CAN FD skbuf: " - "dev type %d, len %d, datalen %d\n", - dev->type, skb->len, cfd->len)) - goto drop; + if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU || + cfd->len > CANFD_MAX_DLEN)) { + pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n", + dev->type, skb->len, cfd->len); + kfree_skb(skb); + return NET_RX_DROP; + } can_receive(skb, dev); return NET_RX_SUCCESS; - -drop: - kfree_skb(skb); - return NET_RX_DROP; } /* diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 489610ac1cdda..bf9d079cbafd6 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -37,7 +37,9 @@ static int set_secret(struct ceph_crypto_key *key, void *buf) return -ENOTSUPP; } - WARN_ON(!key->len); + if (!key->len) + return -EINVAL; + key->key = kmemdup(buf, key->len, GFP_NOIO); if (!key->key) { ret = -ENOMEM; diff --git a/net/core/dev.c b/net/core/dev.c index 11596a302a265..ffee085f03571 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2735,7 +2735,8 @@ EXPORT_SYMBOL(skb_mac_gso_segment); static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) { if (tx_path) - return skb->ip_summed != CHECKSUM_PARTIAL; + return skb->ip_summed != CHECKSUM_PARTIAL && + skb->ip_summed != CHECKSUM_UNNECESSARY; return skb->ip_summed == CHECKSUM_NONE; } @@ -3127,10 +3128,21 @@ static void qdisc_pkt_len_init(struct sk_buff *skb) hdr_len = skb_transport_header(skb) - skb_mac_header(skb); /* + transport layer */ - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) - hdr_len += tcp_hdrlen(skb); - else - hdr_len += sizeof(struct udphdr); + if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { + const struct tcphdr *th; + struct tcphdr _tcphdr; + + th = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_tcphdr), &_tcphdr); + if (likely(th)) + hdr_len += __tcp_hdrlen(th); + } else { + struct udphdr _udphdr; + + if (skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_udphdr), &_udphdr)) + hdr_len += sizeof(struct udphdr); + } if (shinfo->gso_type & SKB_GSO_DODGY) gso_segs = DIV_ROUND_UP(skb->len - hdr_len, diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 9a9a3d77e3274..d374a904f1b17 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -754,15 +754,6 @@ static int ethtool_set_link_ksettings(struct net_device *dev, return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings); } -static void -warn_incomplete_ethtool_legacy_settings_conversion(const char *details) -{ - char name[sizeof(current->comm)]; - - pr_info_once("warning: `%s' uses legacy ethtool link settings API, %s\n", - get_task_comm(name, current), details); -} - /* Query device for its ethtool_cmd settings. * * Backward compatibility note: for compatibility with legacy ethtool, @@ -789,10 +780,8 @@ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) &link_ksettings); if (err < 0) return err; - if (!convert_link_ksettings_to_legacy_settings(&cmd, - &link_ksettings)) - warn_incomplete_ethtool_legacy_settings_conversion( - "link modes are only partially reported"); + convert_link_ksettings_to_legacy_settings(&cmd, + &link_ksettings); /* send a sensible cmd tag back to user */ cmd.cmd = ETHTOOL_GSET; diff --git a/net/core/filter.c b/net/core/filter.c index 6ae94f825f72e..d5158a10ac8f6 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -457,6 +457,10 @@ static int bpf_convert_filter(struct sock_filter *prog, int len, convert_bpf_extensions(fp, &insn)) break; + if (fp->code == (BPF_ALU | BPF_DIV | BPF_X) || + fp->code == (BPF_ALU | BPF_MOD | BPF_X)) + *insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X); + *insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k); break; @@ -1053,11 +1057,9 @@ static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp) */ goto out_err_free; - /* We are guaranteed to never error here with cBPF to eBPF - * transitions, since there's no issue with type compatibility - * checks on program arrays. - */ fp = bpf_prog_select_runtime(fp, &err); + if (err) + goto out_err_free; kfree(old_prog); return fp; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 0a977373d0033..f950b80c0dd1b 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -876,8 +876,8 @@ bool __skb_flow_dissect(const struct sk_buff *skb, out_good: ret = true; - key_control->thoff = (u16)nhoff; out: + key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen); key_basic->n_proto = proto; key_basic->ip_proto = ip_proto; @@ -885,7 +885,6 @@ bool __skb_flow_dissect(const struct sk_buff *skb, out_bad: ret = false; - key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen); goto out; } EXPORT_SYMBOL(__skb_flow_dissect); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 16a1a4c4eb57f..741ae2554190a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -532,7 +532,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, if (atomic_read(&tbl->entries) > (1 << nht->hash_shift)) nht = neigh_hash_grow(tbl, nht->hash_shift + 1); - hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); + hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift); if (n->parms->dead) { rc = ERR_PTR(-EINVAL); @@ -544,7 +544,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, n1 != NULL; n1 = rcu_dereference_protected(n1->next, lockdep_is_held(&tbl->lock))) { - if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { + if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) { if (want_ref) neigh_hold(n1); rc = n1; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 6cfdc7c84c480..0dd6359e59242 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -266,7 +266,7 @@ struct net *get_net_ns_by_id(struct net *net, int id) spin_lock_bh(&net->nsid_lock); peer = idr_find(&net->netns_ids, id); if (peer) - get_net(peer); + peer = maybe_get_net(peer); spin_unlock_bh(&net->nsid_lock); rcu_read_unlock(); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e140ba49b30a4..15fa5baa8faef 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1181,12 +1181,12 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) int i, new_frags; u32 d_off; - if (!num_frags) - return 0; - if (skb_shared(skb) || skb_unclone(skb, gfp_mask)) return -EINVAL; + if (!num_frags) + goto release; + new_frags = (__skb_pagelen(skb) + PAGE_SIZE - 1) >> PAGE_SHIFT; for (i = 0; i < new_frags; i++) { page = alloc_page(gfp_mask); @@ -1242,6 +1242,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) __skb_fill_page_desc(skb, new_frags - 1, head, 0, d_off); skb_shinfo(skb)->nr_frags = new_frags; +release: skb_zcopy_clear(skb, false); return 0; } @@ -3657,8 +3658,6 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, skb_shinfo(nskb)->tx_flags |= skb_shinfo(head_skb)->tx_flags & SKBTX_SHARED_FRAG; - if (skb_zerocopy_clone(nskb, head_skb, GFP_ATOMIC)) - goto err; while (pos < offset + len) { if (i >= nfrags) { @@ -3684,6 +3683,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC))) goto err; + if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) + goto err; *nskb_frag = *frag; __skb_frag_ref(nskb_frag); @@ -4296,7 +4297,7 @@ void skb_complete_tx_timestamp(struct sk_buff *skb, struct sock *sk = skb->sk; if (!skb_may_tx_timestamp(sk, false)) - return; + goto err; /* Take a reference to prevent skb_orphan() from freeing the socket, * but only if the socket refcount is not zero. @@ -4305,7 +4306,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb, *skb_hwtstamps(skb) = *hwtstamps; __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND, false); sock_put(sk); + return; } + +err: + kfree_skb(skb); } EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp); diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 217f4e3b82f6e..146b50e30659d 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -288,7 +288,7 @@ static int sock_diag_bind(struct net *net, int group) case SKNLGRP_INET6_UDP_DESTROY: if (!sock_diag_handlers[AF_INET6]) request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); + NETLINK_SOCK_DIAG, AF_INET6); break; } return 0; diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index cbc3dde4cfccc..a47ad6cd41c03 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -325,7 +325,13 @@ static struct ctl_table net_core_table[] = { .data = &bpf_jit_enable, .maxlen = sizeof(int), .mode = 0644, +#ifndef CONFIG_BPF_JIT_ALWAYS_ON .proc_handler = proc_dointvec +#else + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, + .extra2 = &one, +#endif }, # ifdef CONFIG_HAVE_EBPF_JIT { diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index e1295d5f2c562..97791b0b1b514 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -140,6 +140,9 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) ccid2_pr_debug("RTO_EXPIRE\n"); + if (sk->sk_state == DCCP_CLOSED) + goto out; + /* back-off timer */ hc->tx_rto <<= 1; if (hc->tx_rto > DCCP_RTO_MAX) diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index abd07a4432198..178bb9833311f 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -57,10 +57,16 @@ void dccp_time_wait(struct sock *sk, int state, int timeo) if (state == DCCP_TIME_WAIT) timeo = DCCP_TIMEWAIT_LEN; + /* tw_timer is pinned, so we need to make sure BH are disabled + * in following section, otherwise timer handler could run before + * we complete the initialization. + */ + local_bh_disable(); inet_twsk_schedule(tw, timeo); /* Linkage updates. */ __inet_twsk_hashdance(tw, sk, &dccp_hashinfo); inet_twsk_put(tw); + local_bh_enable(); } else { /* Sorry, if we're out of memory, just CLOSE this * socket up. We've got bigger problems than diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e31108e5ef79c..b9d9a2b8792c7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1221,9 +1221,10 @@ EXPORT_SYMBOL(inet_sk_rebuild_header); struct sk_buff *inet_gso_segment(struct sk_buff *skb, netdev_features_t features) { - bool fixedid = false, gso_partial, encap; + bool udpfrag = false, fixedid = false, gso_partial, encap; struct sk_buff *segs = ERR_PTR(-EINVAL); const struct net_offload *ops; + unsigned int offset = 0; struct iphdr *iph; int proto, tot_len; int nhoff; @@ -1258,6 +1259,7 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb, segs = ERR_PTR(-EPROTONOSUPPORT); if (!skb->encapsulation || encap) { + udpfrag = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID); /* fixed ID is invalid if DF bit is not set */ @@ -1277,7 +1279,13 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb, skb = segs; do { iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); - if (skb_is_gso(skb)) { + if (udpfrag) { + iph->frag_off = htons(offset >> 3); + if (skb->next) + iph->frag_off |= htons(IP_MF); + offset += skb->len - nhoff - ihl; + tot_len = skb->len - nhoff; + } else if (skb_is_gso(skb)) { if (!fixedid) { iph->id = htons(id); id += skb_shinfo(skb)->gso_segs; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 7c45b88967098..a1d1f50e0e19c 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -223,11 +223,16 @@ static bool arp_key_eq(const struct neighbour *neigh, const void *pkey) static int arp_constructor(struct neighbour *neigh) { - __be32 addr = *(__be32 *)neigh->primary_key; + __be32 addr; struct net_device *dev = neigh->dev; struct in_device *in_dev; struct neigh_parms *parms; + u32 inaddr_any = INADDR_ANY; + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) + memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len); + + addr = *(__be32 *)neigh->primary_key; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (!in_dev) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index d7adc06165998..bffa88ecc534b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1420,7 +1420,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) static bool inetdev_valid_mtu(unsigned int mtu) { - return mtu >= 68; + return mtu >= IPV4_MIN_MTU; } static void inetdev_send_gratuitous_arp(struct net_device *dev, diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index f8b918c766b0a..56c49623bb9d7 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c @@ -121,6 +121,9 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb, if (!xo) goto out; + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_ESP)) + goto out; + seq = xo->seq.low; x = skb->sp->xvec[skb->sp->len - 1]; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 37819ab4cc749..d72874150905b 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1274,14 +1274,19 @@ static int __net_init ip_fib_net_init(struct net *net) static void ip_fib_net_exit(struct net *net) { - unsigned int i; + int i; rtnl_lock(); #ifdef CONFIG_IP_MULTIPLE_TABLES RCU_INIT_POINTER(net->ipv4.fib_main, NULL); RCU_INIT_POINTER(net->ipv4.fib_default, NULL); #endif - for (i = 0; i < FIB_TABLE_HASHSZ; i++) { + /* Destroy the tables in reverse order to guarantee that the + * local table, ID 255, is destroyed before the main table, ID + * 254. This is necessary as the local table may contain + * references to data contained in the main table. + */ + for (i = FIB_TABLE_HASHSZ - 1; i >= 0; i--) { struct hlist_head *head = &net->ipv4.fib_table_hash[i]; struct hlist_node *tmp; struct fib_table *tb; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 01ed22139ac2b..aff3751df9503 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -706,7 +706,7 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { int type = nla_type(nla); - u32 val; + u32 fi_val, val; if (!type) continue; @@ -723,7 +723,11 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) val = nla_get_u32(nla); } - if (fi->fib_metrics->metrics[type - 1] != val) + fi_val = fi->fib_metrics->metrics[type - 1]; + if (type == RTAX_FEATURES) + fi_val &= ~DST_FEATURE_ECN_CA; + + if (fi_val != val) return false; } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 681e33998e03b..3c1570d3e22fa 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -782,7 +782,7 @@ static bool icmp_tag_validation(int proto) } /* - * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and + * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEEDED, ICMP_QUENCH, and * ICMP_PARAMETERPROB. */ @@ -810,7 +810,8 @@ static bool icmp_unreach(struct sk_buff *skb) if (iph->ihl < 5) /* Mangled header, drop. */ goto out_err; - if (icmph->type == ICMP_DEST_UNREACH) { + switch (icmph->type) { + case ICMP_DEST_UNREACH: switch (icmph->code & 15) { case ICMP_NET_UNREACH: case ICMP_HOST_UNREACH: @@ -846,8 +847,16 @@ static bool icmp_unreach(struct sk_buff *skb) } if (icmph->code > NR_ICMP_UNREACH) goto out; - } else if (icmph->type == ICMP_PARAMETERPROB) + break; + case ICMP_PARAMETERPROB: info = ntohl(icmph->un.gateway) >> 24; + break; + case ICMP_TIME_EXCEEDED: + __ICMP_INC_STATS(net, ICMP_MIB_INTIMEEXCDS); + if (icmph->code == ICMP_EXC_FRAGTIME) + goto out; + break; + } /* * Throw it at our lower layers diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index ab183af0b5b6a..013fed55b610f 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,23 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) return scount; } +/* source address selection per RFC 3376 section 4.2.13 */ +static __be32 igmpv3_get_srcaddr(struct net_device *dev, + const struct flowi4 *fl4) +{ + struct in_device *in_dev = __in_dev_get_rcu(dev); + + if (!in_dev) + return htonl(INADDR_ANY); + + for_ifa(in_dev) { + if (fl4->saddr == ifa->ifa_local) + return fl4->saddr; + } endfor_ifa(in_dev); + + return htonl(INADDR_ANY); +} + static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) { struct sk_buff *skb; @@ -368,7 +386,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) pip->frag_off = htons(IP_DF); pip->ttl = 1; pip->daddr = fl4.daddr; - pip->saddr = fl4.saddr; + pip->saddr = igmpv3_get_srcaddr(dev, &fl4); pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(net, skb, NULL); @@ -404,16 +422,17 @@ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, - int type, struct igmpv3_grec **ppgr) + int type, struct igmpv3_grec **ppgr, unsigned int mtu) { struct net_device *dev = pmc->interface->dev; struct igmpv3_report *pih; struct igmpv3_grec *pgr; - if (!skb) - skb = igmpv3_newpack(dev, dev->mtu); - if (!skb) - return NULL; + if (!skb) { + skb = igmpv3_newpack(dev, mtu); + if (!skb) + return NULL; + } pgr = skb_put(skb, sizeof(struct igmpv3_grec)); pgr->grec_type = type; pgr->grec_auxwords = 0; @@ -436,12 +455,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, struct igmpv3_grec *pgr = NULL; struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list; int scount, stotal, first, isquery, truncate; + unsigned int mtu; if (pmc->multiaddr == IGMP_ALL_HOSTS) return skb; if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) return skb; + mtu = READ_ONCE(dev->mtu); + if (mtu < IPV4_MIN_MTU) + return skb; + isquery = type == IGMPV3_MODE_IS_INCLUDE || type == IGMPV3_MODE_IS_EXCLUDE; truncate = type == IGMPV3_MODE_IS_EXCLUDE || @@ -462,7 +486,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); } } first = 1; @@ -498,12 +522,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, pgr->grec_nsrcs = htons(scount); if (skb) igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); + skb = igmpv3_newpack(dev, mtu); first = 1; scount = 0; } if (first) { - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); first = 0; } if (!skb) @@ -538,7 +562,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, igmpv3_sendpack(skb); skb = NULL; /* add_grhead will get a new one */ } - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); } } if (pgr) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 467e44d7587dc..045331204097a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -579,8 +579,8 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, if (gre_handle_offloads(skb, false)) goto err_free_rt; - if (skb->len > dev->mtu) { - pskb_trim(skb, dev->mtu); + if (skb->len > dev->mtu + dev->hard_header_len) { + pskb_trim(skb, dev->mtu + dev->hard_header_len); truncate = true; } @@ -731,8 +731,8 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, if (skb_cow_head(skb, dev->needed_headroom)) goto free_skb; - if (skb->len - dev->hard_header_len > dev->mtu) { - pskb_trim(skb, dev->mtu); + if (skb->len > dev->mtu + dev->hard_header_len) { + pskb_trim(skb, dev->mtu + dev->hard_header_len); truncate = true; } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e9805ad664ac2..4e90082b23a6e 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -349,8 +349,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) dev->needed_headroom = t_hlen + hlen; mtu -= (dev->hard_header_len + t_hlen); - if (mtu < 68) - mtu = 68; + if (mtu < IPV4_MIN_MTU) + mtu = IPV4_MIN_MTU; return mtu; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 33b70bfd1122f..125c1eab3eaa6 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -513,11 +513,16 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) int err; struct ip_options_data opt_copy; struct raw_frag_vec rfv; + int hdrincl; err = -EMSGSIZE; if (len > 0xFFFF) goto out; + /* hdrincl should be READ_ONCE(inet->hdrincl) + * but READ_ONCE() doesn't work with bit fields + */ + hdrincl = inet->hdrincl; /* * Check the flags. */ @@ -593,7 +598,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) /* Linux does not mangle headers on raw sockets, * so that IP options + IP_HDRINCL is non-sense. */ - if (inet->hdrincl) + if (hdrincl) goto done; if (ipc.opt->opt.srr) { if (!daddr) @@ -615,12 +620,12 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, + hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | - (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), + (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), daddr, saddr, 0, 0, sk->sk_uid); - if (!inet->hdrincl) { + if (!hdrincl) { rfv.msg = msg; rfv.hlen = 0; @@ -645,7 +650,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) goto do_confirm; back_from_confirm: - if (inet->hdrincl) + if (hdrincl) err = raw_send_hdrinc(sk, &fl4, msg, len, &rt, msg->msg_flags, &ipc.sockc); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3d9f1c2f81c58..0ba88efca7ada 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -651,9 +651,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, struct fnhe_hash_bucket *hash; struct fib_nh_exception *fnhe; struct rtable *rt; + u32 genid, hval; unsigned int i; int depth; - u32 hval = fnhe_hashfun(daddr); + + genid = fnhe_genid(dev_net(nh->nh_dev)); + hval = fnhe_hashfun(daddr); spin_lock_bh(&fnhe_lock); @@ -676,12 +679,13 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, } if (fnhe) { + if (fnhe->fnhe_genid != genid) + fnhe->fnhe_genid = genid; if (gw) fnhe->fnhe_gw = gw; - if (pmtu) { + if (pmtu) fnhe->fnhe_pmtu = pmtu; - fnhe->fnhe_expires = max(1UL, expires); - } + fnhe->fnhe_expires = max(1UL, expires); /* Update all cached dsts too */ rt = rcu_dereference(fnhe->fnhe_rth_input); if (rt) @@ -700,7 +704,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, fnhe->fnhe_next = hash->chain; rcu_assign_pointer(hash->chain, fnhe); } - fnhe->fnhe_genid = fnhe_genid(dev_net(nh->nh_dev)); + fnhe->fnhe_genid = genid; fnhe->fnhe_daddr = daddr; fnhe->fnhe_gw = gw; fnhe->fnhe_pmtu = pmtu; @@ -1250,7 +1254,7 @@ static void set_class_tag(struct rtable *rt, u32 tag) static unsigned int ipv4_default_advmss(const struct dst_entry *dst) { unsigned int header_size = sizeof(struct tcphdr) + sizeof(struct iphdr); - unsigned int advmss = max_t(unsigned int, dst->dev->mtu - header_size, + unsigned int advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size, ip_rt_min_advmss); return min(advmss, IPV4_MAX_PMTU - header_size); @@ -2758,6 +2762,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, if (err == 0 && rt->dst.error) err = -rt->dst.error; } else { + fl4.flowi4_iif = LOOPBACK_IFINDEX; rt = ip_route_output_key_hash_rcu(net, &fl4, &res, skb); err = 0; if (IS_ERR(rt)) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5091402720abc..2a65d806b562b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2273,6 +2273,9 @@ void tcp_close(struct sock *sk, long timeout) tcp_send_active_reset(sk, GFP_ATOMIC); __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); + } else if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_set_state(sk, TCP_CLOSE); } } @@ -2356,6 +2359,7 @@ int tcp_disconnect(struct sock *sk, int flags) tp->snd_cwnd_cnt = 0; tp->window_clamp = 0; tcp_set_ca_state(sk, TCP_CA_Open); + tp->is_sack_reneg = 0; tcp_clear_retrans(tp); inet_csk_delack_init(sk); /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 69ee877574d08..8322f26e770e4 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -110,7 +110,8 @@ struct bbr { u32 lt_last_lost; /* LT intvl start: tp->lost */ u32 pacing_gain:10, /* current gain for setting pacing rate */ cwnd_gain:10, /* current gain for setting cwnd */ - full_bw_cnt:3, /* number of rounds without large bw gains */ + full_bw_reached:1, /* reached full bw in Startup? */ + full_bw_cnt:2, /* number of rounds without large bw gains */ cycle_idx:3, /* current index in pacing_gain cycle array */ has_seen_rtt:1, /* have we seen an RTT sample yet? */ unused_b:5; @@ -180,7 +181,7 @@ static bool bbr_full_bw_reached(const struct sock *sk) { const struct bbr *bbr = inet_csk_ca(sk); - return bbr->full_bw_cnt >= bbr_full_bw_cnt; + return bbr->full_bw_reached; } /* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ @@ -717,6 +718,7 @@ static void bbr_check_full_bw_reached(struct sock *sk, return; } ++bbr->full_bw_cnt; + bbr->full_bw_reached = bbr->full_bw_cnt >= bbr_full_bw_cnt; } /* If pipe is probably full, drain the queue and then enter steady-state. */ @@ -850,6 +852,7 @@ static void bbr_init(struct sock *sk) bbr->restore_cwnd = 0; bbr->round_start = 0; bbr->idle_restart = 0; + bbr->full_bw_reached = 0; bbr->full_bw = 0; bbr->full_bw_cnt = 0; bbr->cycle_mstamp = 0; @@ -871,6 +874,11 @@ static u32 bbr_sndbuf_expand(struct sock *sk) */ static u32 bbr_undo_cwnd(struct sock *sk) { + struct bbr *bbr = inet_csk_ca(sk); + + bbr->full_bw = 0; /* spurious slow-down; reset full pipe detection */ + bbr->full_bw_cnt = 0; + bbr_reset_lt_bw_sampling(sk); return tcp_sk(sk)->snd_cwnd; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b6bb3cdfad09e..ff48ac654e5ae 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -521,9 +521,6 @@ static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep) u32 new_sample = tp->rcv_rtt_est.rtt_us; long m = sample; - if (m == 0) - m = 1; - if (new_sample != 0) { /* If we sample in larger samples in the non-timestamp * case, we could grossly overestimate the RTT especially @@ -560,6 +557,8 @@ static inline void tcp_rcv_rtt_measure(struct tcp_sock *tp) if (before(tp->rcv_nxt, tp->rcv_rtt_est.seq)) return; delta_us = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcv_rtt_est.time); + if (!delta_us) + delta_us = 1; tcp_rcv_rtt_update(tp, delta_us, 1); new_measure: @@ -576,8 +575,11 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, (TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq >= inet_csk(sk)->icsk_ack.rcv_mss)) { u32 delta = tcp_time_stamp(tp) - tp->rx_opt.rcv_tsecr; - u32 delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ); + u32 delta_us; + if (!delta) + delta = 1; + delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ); tcp_rcv_rtt_update(tp, delta_us, 0); } } @@ -592,6 +594,7 @@ void tcp_rcv_space_adjust(struct sock *sk) int time; int copied; + tcp_mstamp_refresh(tp); time = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcvq_space.time); if (time < (tp->rcv_rtt_est.rtt_us >> 3) || tp->rcv_rtt_est.rtt_us == 0) return; @@ -1974,6 +1977,8 @@ void tcp_enter_loss(struct sock *sk) NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); tp->sacked_out = 0; tp->fackets_out = 0; + /* Mark SACK reneging until we recover from this loss event. */ + tp->is_sack_reneg = 1; } tcp_clear_all_retrans_hints(tp); @@ -2427,6 +2432,7 @@ static bool tcp_try_undo_recovery(struct sock *sk) return true; } tcp_set_ca_state(sk, TCP_CA_Open); + tp->is_sack_reneg = 0; return false; } @@ -2458,8 +2464,10 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSPURIOUSRTOS); inet_csk(sk)->icsk_retransmits = 0; - if (frto_undo || tcp_is_sack(tp)) + if (frto_undo || tcp_is_sack(tp)) { tcp_set_ca_state(sk, TCP_CA_Open); + tp->is_sack_reneg = 0; + } return true; } return false; @@ -3020,7 +3028,7 @@ void tcp_rearm_rto(struct sock *sk) /* Try to schedule a loss probe; if that doesn't work, then schedule an RTO. */ static void tcp_set_xmit_timer(struct sock *sk) { - if (!tcp_schedule_loss_probe(sk)) + if (!tcp_schedule_loss_probe(sk, true)) tcp_rearm_rto(sk); } @@ -3550,6 +3558,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) struct tcp_sacktag_state sack_state; struct rate_sample rs = { .prior_delivered = 0 }; u32 prior_snd_una = tp->snd_una; + bool is_sack_reneg = tp->is_sack_reneg; u32 ack_seq = TCP_SKB_CB(skb)->seq; u32 ack = TCP_SKB_CB(skb)->ack_seq; bool is_dupack = false; @@ -3665,7 +3674,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) delivered = tp->delivered - delivered; /* freshly ACKed or SACKed */ lost = tp->lost - lost; /* freshly marked lost */ - tcp_rate_gen(sk, delivered, lost, sack_state.rate); + tcp_rate_gen(sk, delivered, lost, is_sack_reneg, sack_state.rate); tcp_cong_control(sk, ack, delivered, flag, sack_state.rate); tcp_xmit_recovery(sk, rexmit); return 1; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5b027c69cbc54..cab4b935e4743 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -844,7 +844,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, req->ts_recent, 0, - tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr, AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, ip_hdr(skb)->tos); @@ -1587,6 +1587,34 @@ int tcp_filter(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(tcp_filter); +static void tcp_v4_restore_cb(struct sk_buff *skb) +{ + memmove(IPCB(skb), &TCP_SKB_CB(skb)->header.h4, + sizeof(struct inet_skb_parm)); +} + +static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, + const struct tcphdr *th) +{ + /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() + * barrier() makes sure compiler wont play fool^Waliasing games. + */ + memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), + sizeof(struct inet_skb_parm)); + barrier(); + + TCP_SKB_CB(skb)->seq = ntohl(th->seq); + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff * 4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); + TCP_SKB_CB(skb)->sacked = 0; + TCP_SKB_CB(skb)->has_rxtstamp = + skb->tstamp || skb_hwtstamps(skb)->hwtstamp; +} + /* * From tcp_input.c */ @@ -1627,24 +1655,6 @@ int tcp_v4_rcv(struct sk_buff *skb) th = (const struct tcphdr *)skb->data; iph = ip_hdr(skb); - /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() - * barrier() makes sure compiler wont play fool^Waliasing games. - */ - memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), - sizeof(struct inet_skb_parm)); - barrier(); - - TCP_SKB_CB(skb)->seq = ntohl(th->seq); - TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - skb->len - th->doff * 4); - TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); - TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; - TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); - TCP_SKB_CB(skb)->sacked = 0; - TCP_SKB_CB(skb)->has_rxtstamp = - skb->tstamp || skb_hwtstamps(skb)->hwtstamp; - lookup: sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, th->dest, sdif, &refcounted); @@ -1675,14 +1685,19 @@ int tcp_v4_rcv(struct sk_buff *skb) sock_hold(sk); refcounted = true; nsk = NULL; - if (!tcp_filter(sk, skb)) + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; + iph = ip_hdr(skb); + tcp_v4_fill_cb(skb, iph, th); nsk = tcp_check_req(sk, skb, req, false); + } if (!nsk) { reqsk_put(req); goto discard_and_relse; } if (nsk == sk) { reqsk_put(req); + tcp_v4_restore_cb(skb); } else if (tcp_child_process(sk, nsk, skb)) { tcp_v4_send_reset(nsk, skb); goto discard_and_relse; @@ -1708,6 +1723,7 @@ int tcp_v4_rcv(struct sk_buff *skb) goto discard_and_relse; th = (const struct tcphdr *)skb->data; iph = ip_hdr(skb); + tcp_v4_fill_cb(skb, iph, th); skb->dev = NULL; @@ -1738,6 +1754,8 @@ int tcp_v4_rcv(struct sk_buff *skb) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; + tcp_v4_fill_cb(skb, iph, th); + if (tcp_checksum_complete(skb)) { csum_error: __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); @@ -1764,6 +1782,8 @@ int tcp_v4_rcv(struct sk_buff *skb) goto discard_it; } + tcp_v4_fill_cb(skb, iph, th); + if (tcp_checksum_complete(skb)) { inet_twsk_put(inet_twsk(sk)); goto csum_error; @@ -1780,6 +1800,7 @@ int tcp_v4_rcv(struct sk_buff *skb) if (sk2) { inet_twsk_deschedule_put(inet_twsk(sk)); sk = sk2; + tcp_v4_restore_cb(skb); refcounted = false; goto process; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 188a6f31356db..420fecbb98fe7 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -312,10 +312,16 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) if (state == TCP_TIME_WAIT) timeo = TCP_TIMEWAIT_LEN; + /* tw_timer is pinned, so we need to make sure BH are disabled + * in following section, otherwise timer handler could run before + * we complete the initialization. + */ + local_bh_disable(); inet_twsk_schedule(tw, timeo); /* Linkage updates. */ __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); inet_twsk_put(tw); + local_bh_enable(); } else { /* Sorry, if we're out of memory, just CLOSE this * socket up. We've got bigger problems than diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index b6a2aa1dcf56c..4d58e2ce0b5b1 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -32,6 +32,9 @@ static void tcp_gso_tstamp(struct sk_buff *skb, unsigned int ts_seq, static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb, netdev_features_t features) { + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)) + return ERR_PTR(-EINVAL); + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) return ERR_PTR(-EINVAL); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 478909f4694d0..cd3d60bb7cc8a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2337,7 +2337,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, /* Send one loss probe per tail loss episode. */ if (push_one != 2) - tcp_schedule_loss_probe(sk); + tcp_schedule_loss_probe(sk, false); is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); tcp_cwnd_validate(sk, is_cwnd_limited); return false; @@ -2345,7 +2345,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, return !tp->packets_out && tcp_send_head(sk); } -bool tcp_schedule_loss_probe(struct sock *sk) +bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); @@ -2384,7 +2384,9 @@ bool tcp_schedule_loss_probe(struct sock *sk) } /* If the RTO formula yields an earlier time, then use that time. */ - rto_delta_us = tcp_rto_delta_us(sk); /* How far in future is RTO? */ + rto_delta_us = advancing_rto ? + jiffies_to_usecs(inet_csk(sk)->icsk_rto) : + tcp_rto_delta_us(sk); /* How far in future is RTO? */ if (rto_delta_us > 0) timeout = min_t(u32, timeout, usecs_to_jiffies(rto_delta_us)); diff --git a/net/ipv4/tcp_rate.c b/net/ipv4/tcp_rate.c index 3330a370d3061..c61240e43923d 100644 --- a/net/ipv4/tcp_rate.c +++ b/net/ipv4/tcp_rate.c @@ -106,7 +106,7 @@ void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, /* Update the connection delivery information and generate a rate sample. */ void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, - struct rate_sample *rs) + bool is_sack_reneg, struct rate_sample *rs) { struct tcp_sock *tp = tcp_sk(sk); u32 snd_us, ack_us; @@ -124,8 +124,12 @@ void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, rs->acked_sacked = delivered; /* freshly ACKed or SACKed */ rs->losses = lost; /* freshly marked lost */ - /* Return an invalid sample if no timing information is available. */ - if (!rs->prior_mstamp) { + /* Return an invalid sample if no timing information is available or + * in recovery from loss with SACK reneging. Rate samples taken during + * a SACK reneging event may overestimate bw by including packets that + * were SACKed before the reneg. + */ + if (!rs->prior_mstamp || is_sack_reneg) { rs->delivered = -1; rs->interval_us = -1; return; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 655dd8d7f064f..14ac7df953801 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -50,11 +50,19 @@ static void tcp_write_err(struct sock *sk) * to prevent DoS attacks. It is called when a retransmission timeout * or zero probe timeout occurs on orphaned socket. * + * Also close if our net namespace is exiting; in that case there is no + * hope of ever communicating again since all netns interfaces are already + * down (or about to be down), and we need to release our dst references, + * which have been moved to the netns loopback interface, so the namespace + * can finish exiting. This condition is only possible if we are a kernel + * socket, as those do not hold references to the namespace. + * * Criteria is still not confirmed experimentally and may change. * We kill the socket, if: * 1. If number of orphaned sockets exceeds an administratively configured * limit. * 2. If we have strong memory pressure. + * 3. If our net namespace is exiting. */ static int tcp_out_of_resources(struct sock *sk, bool do_reset) { @@ -83,6 +91,13 @@ static int tcp_out_of_resources(struct sock *sk, bool do_reset) __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); return 1; } + + if (!check_net(sock_net(sk))) { + /* Not possible to send reset; just close */ + tcp_done(sk); + return 1; + } + return 0; } @@ -264,6 +279,7 @@ void tcp_delack_timer_handler(struct sock *sk) icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } + tcp_mstamp_refresh(tcp_sk(sk)); tcp_send_ack(sk); __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); } @@ -627,6 +643,7 @@ static void tcp_keepalive_timer (unsigned long data) goto out; } + tcp_mstamp_refresh(tp); if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { if (tp->linger2 >= 0) { const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 218cfcc776500..ee113ff15fd02 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -158,7 +158,7 @@ EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event); static inline u32 tcp_vegas_ssthresh(struct tcp_sock *tp) { - return min(tp->snd_ssthresh, tp->snd_cwnd-1); + return min(tp->snd_ssthresh, tp->snd_cwnd); } static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index e360d55be5554..ea6e6e7df0eec 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -187,16 +187,60 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, } EXPORT_SYMBOL(skb_udp_tunnel_segment); -static struct sk_buff *udp4_tunnel_segment(struct sk_buff *skb, - netdev_features_t features) +static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); + unsigned int mss; + __wsum csum; + struct udphdr *uh; + struct iphdr *iph; if (skb->encapsulation && (skb_shinfo(skb)->gso_type & - (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) + (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) { segs = skb_udp_tunnel_segment(skb, features, false); + goto out; + } + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP)) + goto out; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto out; + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) + goto out; + + /* Do software UFO. Complete and fill in the UDP checksum as + * HW cannot do checksum of UDP packets sent as multiple + * IP fragments. + */ + + uh = udp_hdr(skb); + iph = ip_hdr(skb); + + uh->check = 0; + csum = skb_checksum(skb, 0, skb->len, 0); + uh->check = udp_v4_check(skb->len, iph->saddr, iph->daddr, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* If there is no outer header we can fake a checksum offload + * due to the fact that we have already done the checksum in + * software prior to segmenting the frame. + */ + if (!skb->encap_hdr_csum) + features |= NETIF_F_HW_CSUM; + + /* Fragment the skb. IP headers of the fragments are updated in + * inet_gso_segment() + */ + segs = skb_segment(skb, features); +out: return segs; } @@ -330,7 +374,7 @@ static int udp4_gro_complete(struct sk_buff *skb, int nhoff) static const struct net_offload udpv4_offload = { .callbacks = { - .gso_segment = udp4_tunnel_segment, + .gso_segment = udp4_ufo_fragment, .gro_receive = udp4_gro_receive, .gro_complete = udp4_gro_complete, }, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8a1c846d3df94..c5318f5f6a144 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -231,7 +231,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, - .accept_dad = 1, + .accept_dad = 0, .suppress_frag_ndisc = 1, .accept_ra_mtu = 1, .stable_secret = { @@ -303,10 +303,10 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .disable_policy = 0, }; -/* Check if a valid qdisc is available */ -static inline bool addrconf_qdisc_ok(const struct net_device *dev) +/* Check if link is ready: is it up and is a valid qdisc available */ +static inline bool addrconf_link_ready(const struct net_device *dev) { - return !qdisc_tx_is_noop(dev); + return netif_oper_up(dev) && !qdisc_tx_is_noop(dev); } static void addrconf_del_rs_timer(struct inet6_dev *idev) @@ -451,7 +451,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ndev->token = in6addr_any; - if (netif_running(dev) && addrconf_qdisc_ok(dev)) + if (netif_running(dev) && addrconf_link_ready(dev)) ndev->if_flags |= IF_READY; ipv6_mc_init_dev(ndev); @@ -3404,7 +3404,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, /* restore routes for permanent addresses */ addrconf_permanent_addr(dev); - if (!addrconf_qdisc_ok(dev)) { + if (!addrconf_link_ready(dev)) { /* device is not ready yet. */ pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", dev->name); @@ -3419,7 +3419,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, run_pending = 1; } } else if (event == NETDEV_CHANGE) { - if (!addrconf_qdisc_ok(dev)) { + if (!addrconf_link_ready(dev)) { /* device is still not ready. */ break; } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index fe5262fd6aa5c..bcbd5f3bf8bd0 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -210,7 +210,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; np->mc_loop = 1; np->pmtudisc = IPV6_PMTUDISC_WANT; - np->autoflowlabel = ip6_default_np_autolabel(net); np->repflow = net->ipv6.sysctl.flowlabel_reflect; sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index 333a478aa1610..1ea9d794447e7 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c @@ -148,6 +148,9 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, if (!xo) goto out; + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_ESP)) + goto out; + seq = xo->seq.low; x = skb->sp->xvec[skb->sp->len - 1]; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 95516138e861c..d6189c2a35e4f 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -884,6 +884,15 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto, sr_phdr->segments[0] = **addr_p; *addr_p = &sr_ihdr->segments[sr_ihdr->segments_left]; + if (sr_ihdr->hdrlen > hops * 2) { + int tlvs_offset, tlvs_length; + + tlvs_offset = (1 + hops * 2) << 3; + tlvs_length = (sr_ihdr->hdrlen - hops * 2) << 3; + memcpy((char *)sr_phdr + tlvs_offset, + (char *)sr_ihdr + tlvs_offset, tlvs_length); + } + #ifdef CONFIG_IPV6_SEG6_HMAC if (sr_has_hmac(sr_phdr)) { struct net *net = NULL; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 59c121b932ac5..5b4870caf2680 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -337,11 +337,12 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, nt->dev = dev; nt->net = dev_net(dev); - ip6gre_tnl_link_config(nt, 1); if (register_netdevice(dev) < 0) goto failed_free; + ip6gre_tnl_link_config(nt, 1); + /* Can use a lockless transmit, unless we generate output sequences */ if (!(nt->parms.o_flags & TUNNEL_SEQ)) dev->features |= NETIF_F_LLTX; @@ -461,7 +462,7 @@ static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) &ipv6h->saddr, &ipv6h->daddr, tpi->key, tpi->proto); if (tunnel) { - ip6_tnl_rcv(tunnel, skb, tpi, NULL, false); + ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error); return PACKET_RCVD; } @@ -1020,6 +1021,36 @@ static void ip6gre_tunnel_setup(struct net_device *dev) eth_random_addr(dev->perm_addr); } +#define GRE6_FEATURES (NETIF_F_SG | \ + NETIF_F_FRAGLIST | \ + NETIF_F_HIGHDMA | \ + NETIF_F_HW_CSUM) + +static void ip6gre_tnl_init_features(struct net_device *dev) +{ + struct ip6_tnl *nt = netdev_priv(dev); + + dev->features |= GRE6_FEATURES; + dev->hw_features |= GRE6_FEATURES; + + if (!(nt->parms.o_flags & TUNNEL_SEQ)) { + /* TCP offload with GRE SEQ is not supported, nor + * can we support 2 levels of outer headers requiring + * an update. + */ + if (!(nt->parms.o_flags & TUNNEL_CSUM) || + nt->encap.type == TUNNEL_ENCAP_NONE) { + dev->features |= NETIF_F_GSO_SOFTWARE; + dev->hw_features |= NETIF_F_GSO_SOFTWARE; + } + + /* Can use a lockless transmit, unless we generate + * output sequences + */ + dev->features |= NETIF_F_LLTX; + } +} + static int ip6gre_tunnel_init_common(struct net_device *dev) { struct ip6_tnl *tunnel; @@ -1054,6 +1085,8 @@ static int ip6gre_tunnel_init_common(struct net_device *dev) if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) dev->mtu -= 8; + ip6gre_tnl_init_features(dev); + return 0; } @@ -1275,7 +1308,6 @@ static void ip6gre_netlink_parms(struct nlattr *data[], static int ip6gre_tap_init(struct net_device *dev) { - struct ip6_tnl *tunnel; int ret; ret = ip6gre_tunnel_init_common(dev); @@ -1284,10 +1316,6 @@ static int ip6gre_tap_init(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - tunnel = netdev_priv(dev); - - ip6gre_tnl_link_config(tunnel, 1); - return 0; } @@ -1302,11 +1330,6 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = { .ndo_get_iflink = ip6_tnl_get_iflink, }; -#define GRE6_FEATURES (NETIF_F_SG | \ - NETIF_F_FRAGLIST | \ - NETIF_F_HIGHDMA | \ - NETIF_F_HW_CSUM) - static void ip6gre_tap_setup(struct net_device *dev) { @@ -1384,32 +1407,16 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev, nt->dev = dev; nt->net = dev_net(dev); - ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]); - - dev->features |= GRE6_FEATURES; - dev->hw_features |= GRE6_FEATURES; - - if (!(nt->parms.o_flags & TUNNEL_SEQ)) { - /* TCP offload with GRE SEQ is not supported, nor - * can we support 2 levels of outer headers requiring - * an update. - */ - if (!(nt->parms.o_flags & TUNNEL_CSUM) || - (nt->encap.type == TUNNEL_ENCAP_NONE)) { - dev->features |= NETIF_F_GSO_SOFTWARE; - dev->hw_features |= NETIF_F_GSO_SOFTWARE; - } - - /* Can use a lockless transmit, unless we generate - * output sequences - */ - dev->features |= NETIF_F_LLTX; - } err = register_netdevice(dev); if (err) goto out; + ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]); + + if (tb[IFLA_MTU]) + ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); + dev_hold(dev); ip6gre_tunnel_link(ign, nt); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5110a418cc4d0..3763dc01e3747 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -166,6 +166,14 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) !(IP6CB(skb)->flags & IP6SKB_REROUTED)); } +bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np) +{ + if (!np->autoflowlabel_set) + return ip6_default_np_autolabel(net); + else + return np->autoflowlabel; +} + /* * xmit an sk_buff (used by TCP, SCTP and DCCP) * Note : socket lock is not held for SYNACK packets, but might be modified @@ -230,7 +238,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, hlimit = ip6_dst_hoplimit(dst); ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, - np->autoflowlabel, fl6)); + ip6_autoflowlabel(net, np), fl6)); hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; @@ -1198,14 +1206,16 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, v6_cork->tclass = ipc6->tclass; if (rt->dst.flags & DST_XFRM_TUNNEL) mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(&rt->dst); + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst); else mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(rt->dst.path); + READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path); if (np->frag_size < mtu) { if (np->frag_size) mtu = np->frag_size; } + if (mtu < IPV6_MIN_MTU) + return -EINVAL; cork->base.fragsize = mtu; if (dst_allfrag(rt->dst.path)) cork->base.flags |= IPCORK_ALLFRAG; @@ -1626,7 +1636,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, ip6_flow_hdr(hdr, v6_cork->tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, - np->autoflowlabel, fl6)); + ip6_autoflowlabel(net, np), fl6)); hdr->hop_limit = v6_cork->hop_limit; hdr->nexthdr = proto; hdr->saddr = fl6->saddr; @@ -1725,11 +1735,13 @@ struct sk_buff *ip6_make_skb(struct sock *sk, cork.base.flags = 0; cork.base.addr = 0; cork.base.opt = NULL; + cork.base.dst = NULL; v6_cork.opt = NULL; err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6); - if (err) + if (err) { + ip6_cork_release(&cork, &v6_cork); return ERR_PTR(err); - + } if (ipc6->dontfrag < 0) ipc6->dontfrag = inet6_sk(sk)->dontfrag; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a1c24443cd9e0..3f46121ad139b 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -912,7 +912,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto, if (t->parms.collect_md) { tun_dst = ipv6_tun_rx_dst(skb, 0, 0, 0); if (!tun_dst) - return 0; + goto drop; } ret = __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate, log_ecn_error); @@ -1081,10 +1081,11 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); neigh_release(neigh); } - } else if (!(t->parms.flags & - (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) { - /* enable the cache only only if the routing decision does - * not depend on the current inner header value + } else if (t->parms.proto != 0 && !(t->parms.flags & + (IP6_TNL_F_USE_ORIG_TCLASS | + IP6_TNL_F_USE_ORIG_FWMARK))) { + /* enable the cache only if neither the outer protocol nor the + * routing decision depends on the current inner header value */ use_cache = true; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a5e466d4e0931..3b251760cb8c3 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -878,6 +878,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, break; case IPV6_AUTOFLOWLABEL: np->autoflowlabel = valbool; + np->autoflowlabel_set = 1; retv = 0; break; case IPV6_RECVFRAGSIZE: @@ -1323,7 +1324,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, break; case IPV6_AUTOFLOWLABEL: - val = np->autoflowlabel; + val = ip6_autoflowlabel(sock_net(sk), np); break; case IPV6_RECVFRAGSIZE: diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 12b7c27ce5ce9..9a38a2c641fac 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1682,16 +1682,16 @@ static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, - int type, struct mld2_grec **ppgr) + int type, struct mld2_grec **ppgr, unsigned int mtu) { - struct net_device *dev = pmc->idev->dev; struct mld2_report *pmr; struct mld2_grec *pgr; - if (!skb) - skb = mld_newpack(pmc->idev, dev->mtu); - if (!skb) - return NULL; + if (!skb) { + skb = mld_newpack(pmc->idev, mtu); + if (!skb) + return NULL; + } pgr = skb_put(skb, sizeof(struct mld2_grec)); pgr->grec_type = type; pgr->grec_auxwords = 0; @@ -1714,10 +1714,15 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, struct mld2_grec *pgr = NULL; struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list; int scount, stotal, first, isquery, truncate; + unsigned int mtu; if (pmc->mca_flags & MAF_NOREPORT) return skb; + mtu = READ_ONCE(dev->mtu); + if (mtu < IPV6_MIN_MTU) + return skb; + isquery = type == MLD2_MODE_IS_INCLUDE || type == MLD2_MODE_IS_EXCLUDE; truncate = type == MLD2_MODE_IS_EXCLUDE || @@ -1738,7 +1743,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { if (skb) mld_sendpack(skb); - skb = mld_newpack(idev, dev->mtu); + skb = mld_newpack(idev, mtu); } } first = 1; @@ -1774,12 +1779,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, pgr->grec_nsrcs = htons(scount); if (skb) mld_sendpack(skb); - skb = mld_newpack(idev, dev->mtu); + skb = mld_newpack(idev, mtu); first = 1; scount = 0; } if (first) { - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); first = 0; } if (!skb) @@ -1814,7 +1819,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, mld_sendpack(skb); skb = NULL; /* add_grhead will get a new one */ } - skb = add_grhead(skb, pmc, type, &pgr); + skb = add_grhead(skb, pmc, type, &pgr, mtu); } } if (pgr) diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index a338bbc33cf3c..4fe7c90962dda 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -39,7 +39,7 @@ static u32 __ipv6_select_ident(struct net *net, u32 hashrnd, * * The network header must be set before calling this. */ -void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) +__be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) { static u32 ip6_proxy_idents_hashrnd __read_mostly; struct in6_addr buf[2]; @@ -51,14 +51,14 @@ void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) offsetof(struct ipv6hdr, saddr), sizeof(buf), buf); if (!addrs) - return; + return 0; net_get_random_once(&ip6_proxy_idents_hashrnd, sizeof(ip6_proxy_idents_hashrnd)); id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd, &addrs[1], &addrs[0]); - skb_shinfo(skb)->ip6_frag_id = htonl(id); + return htonl(id); } EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a96d5b385d8fa..ca8d3266e92e0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -960,7 +960,7 @@ static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt) { struct net_device *dev = rt->dst.dev; - if (rt->rt6i_flags & RTF_LOCAL) { + if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) { /* for copies of local routes, dst->dev needs to be the * device if it is a master device, the master device if * device is enslaved, and the loopback as the default @@ -3700,19 +3700,13 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, if (!ipv6_addr_any(&fl6.saddr)) flags |= RT6_LOOKUP_F_HAS_SADDR; - if (!fibmatch) - dst = ip6_route_input_lookup(net, dev, &fl6, flags); - else - dst = ip6_route_lookup(net, &fl6, 0); + dst = ip6_route_input_lookup(net, dev, &fl6, flags); rcu_read_unlock(); } else { fl6.flowi6_oif = oif; - if (!fibmatch) - dst = ip6_route_output(net, NULL, &fl6); - else - dst = ip6_route_lookup(net, &fl6, 0); + dst = ip6_route_output(net, NULL, &fl6); } @@ -3729,6 +3723,15 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, goto errout; } + if (fibmatch && rt->dst.from) { + struct rt6_info *ort = container_of(rt->dst.from, + struct rt6_info, dst); + + dst_hold(&ort->dst); + ip6_rt_put(rt); + rt = ort; + } + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) { ip6_rt_put(rt); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ac912bb217471..e79854cc57908 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1087,6 +1087,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p, ipip6_tunnel_link(sitn, t); t->parms.iph.ttl = p->iph.ttl; t->parms.iph.tos = p->iph.tos; + t->parms.iph.frag_off = p->iph.frag_off; if (t->parms.link != p->link || t->fwmark != fwmark) { t->parms.link = p->link; t->fwmark = fwmark; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 64d94afa427f8..237cc6187c5a4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -988,7 +988,7 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, req->ts_recent, sk->sk_bound_dev_if, - tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), + tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), 0, 0); } @@ -1448,7 +1448,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) struct sock *nsk; sk = req->rsk_listener; - tcp_v6_fill_cb(skb, hdr, th); if (tcp_v6_inbound_md5_hash(sk, skb)) { sk_drops_add(sk, skb); reqsk_put(req); @@ -1461,8 +1460,12 @@ static int tcp_v6_rcv(struct sk_buff *skb) sock_hold(sk); refcounted = true; nsk = NULL; - if (!tcp_filter(sk, skb)) + if (!tcp_filter(sk, skb)) { + th = (const struct tcphdr *)skb->data; + hdr = ipv6_hdr(skb); + tcp_v6_fill_cb(skb, hdr, th); nsk = tcp_check_req(sk, skb, req, false); + } if (!nsk) { reqsk_put(req); goto discard_and_relse; @@ -1486,8 +1489,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; - tcp_v6_fill_cb(skb, hdr, th); - if (tcp_v6_inbound_md5_hash(sk, skb)) goto discard_and_relse; @@ -1495,6 +1496,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) goto discard_and_relse; th = (const struct tcphdr *)skb->data; hdr = ipv6_hdr(skb); + tcp_v6_fill_cb(skb, hdr, th); skb->dev = NULL; @@ -1583,7 +1585,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) tcp_v6_timewait_ack(sk, skb); break; case TCP_TW_RST: - tcp_v6_restore_cb(skb); tcp_v6_send_reset(sk, skb); inet_twsk_deschedule_put(inet_twsk(sk)); goto discard_it; diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index d883c9204c01d..278e49cd67d4e 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -46,6 +46,9 @@ static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb, { struct tcphdr *th; + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)) + return ERR_PTR(-EINVAL); + if (!pskb_may_pull(skb, sizeof(*th))) return ERR_PTR(-EINVAL); diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 455fd4e393332..2a04dc9c781b5 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -17,15 +17,97 @@ #include #include "ip6_offload.h" -static struct sk_buff *udp6_tunnel_segment(struct sk_buff *skb, - netdev_features_t features) +static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); + unsigned int mss; + unsigned int unfrag_ip6hlen, unfrag_len; + struct frag_hdr *fptr; + u8 *packet_start, *prevhdr; + u8 nexthdr; + u8 frag_hdr_sz = sizeof(struct frag_hdr); + __wsum csum; + int tnl_hlen; + int err; + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) + goto out; if (skb->encapsulation && skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)) segs = skb_udp_tunnel_segment(skb, features, true); + else { + const struct ipv6hdr *ipv6h; + struct udphdr *uh; + + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP)) + goto out; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto out; + + /* Do software UFO. Complete and fill in the UDP checksum as HW cannot + * do checksum of UDP packets sent as multiple IP fragments. + */ + + uh = udp_hdr(skb); + ipv6h = ipv6_hdr(skb); + + uh->check = 0; + csum = skb_checksum(skb, 0, skb->len, 0); + uh->check = udp_v6_check(skb->len, &ipv6h->saddr, + &ipv6h->daddr, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* If there is no outer header we can fake a checksum offload + * due to the fact that we have already done the checksum in + * software prior to segmenting the frame. + */ + if (!skb->encap_hdr_csum) + features |= NETIF_F_HW_CSUM; + + /* Check if there is enough headroom to insert fragment header. */ + tnl_hlen = skb_tnl_header_len(skb); + if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) { + if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz)) + goto out; + } + + /* Find the unfragmentable header and shift it left by frag_hdr_sz + * bytes to insert fragment header. + */ + err = ip6_find_1stfragopt(skb, &prevhdr); + if (err < 0) + return ERR_PTR(err); + unfrag_ip6hlen = err; + nexthdr = *prevhdr; + *prevhdr = NEXTHDR_FRAGMENT; + unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) + + unfrag_ip6hlen + tnl_hlen; + packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset; + memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len); + + SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz; + skb->mac_header -= frag_hdr_sz; + skb->network_header -= frag_hdr_sz; + + fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); + fptr->nexthdr = nexthdr; + fptr->reserved = 0; + fptr->identification = ipv6_proxy_select_ident(dev_net(skb->dev), skb); + + /* Fragment the skb. ipv6 header and the remaining fields of the + * fragment header are updated in ipv6_gso_segment() + */ + segs = skb_segment(skb, features); + } +out: return segs; } @@ -75,7 +157,7 @@ static int udp6_gro_complete(struct sk_buff *skb, int nhoff) static const struct net_offload udpv6_offload = { .callbacks = { - .gso_segment = udp6_tunnel_segment, + .gso_segment = udp6_ufo_fragment, .gro_receive = udp6_gro_receive, .gro_complete = udp6_gro_complete, }, diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index af4e76ac88ff0..c5fa634e63ca2 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1625,60 +1625,35 @@ static struct proto kcm_proto = { }; /* Clone a kcm socket. */ -static int kcm_clone(struct socket *osock, struct kcm_clone *info, - struct socket **newsockp) +static struct file *kcm_clone(struct socket *osock) { struct socket *newsock; struct sock *newsk; - struct file *newfile; - int err, newfd; + struct file *file; - err = -ENFILE; newsock = sock_alloc(); if (!newsock) - goto out; + return ERR_PTR(-ENFILE); newsock->type = osock->type; newsock->ops = osock->ops; __module_get(newsock->ops->owner); - newfd = get_unused_fd_flags(0); - if (unlikely(newfd < 0)) { - err = newfd; - goto out_fd_fail; - } - - newfile = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name); - if (unlikely(IS_ERR(newfile))) { - err = PTR_ERR(newfile); - goto out_sock_alloc_fail; - } - newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, &kcm_proto, true); if (!newsk) { - err = -ENOMEM; - goto out_sk_alloc_fail; + sock_release(newsock); + return ERR_PTR(-ENOMEM); } - sock_init_data(newsock, newsk); init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux); - fd_install(newfd, newfile); - *newsockp = newsock; - info->fd = newfd; - - return 0; + file = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name); + if (IS_ERR(file)) + sock_release(newsock); -out_sk_alloc_fail: - fput(newfile); -out_sock_alloc_fail: - put_unused_fd(newfd); -out_fd_fail: - sock_release(newsock); -out: - return err; + return file; } static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) @@ -1708,17 +1683,25 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCKCMCLONE: { struct kcm_clone info; - struct socket *newsock = NULL; - - err = kcm_clone(sock, &info, &newsock); - if (!err) { - if (copy_to_user((void __user *)arg, &info, - sizeof(info))) { - err = -EFAULT; - sys_close(info.fd); - } - } + struct file *file; + + info.fd = get_unused_fd_flags(0); + if (unlikely(info.fd < 0)) + return info.fd; + file = kcm_clone(sock); + if (IS_ERR(file)) { + put_unused_fd(info.fd); + return PTR_ERR(file); + } + if (copy_to_user((void __user *)arg, &info, + sizeof(info))) { + put_unused_fd(info.fd); + fput(file); + return -EFAULT; + } + fd_install(info.fd, file); + err = 0; break; } default: diff --git a/net/key/af_key.c b/net/key/af_key.c index a00d607e7224d..2ad693232f748 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -401,6 +401,11 @@ static int verify_address_len(const void *p) #endif int len; + if (sp->sadb_address_len < + DIV_ROUND_UP(sizeof(*sp) + offsetofend(typeof(*addr), sa_family), + sizeof(uint64_t))) + return -EINVAL; + switch (addr->sa_family) { case AF_INET: len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t)); @@ -511,6 +516,9 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void * uint16_t ext_type; int ext_len; + if (len < sizeof(*ehdr)) + return -EINVAL; + ext_len = ehdr->sadb_ext_len; ext_len *= sizeof(uint64_t); ext_type = ehdr->sadb_ext_type; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 02d61101b108d..af22aa8ae35bd 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1891,7 +1891,7 @@ static __net_exit void l2tp_exit_net(struct net *net) rcu_read_lock_bh(); list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { - (void)l2tp_tunnel_delete(tunnel); + l2tp_tunnel_delete(tunnel); } rcu_read_unlock_bh(); diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 7135f4645d3aa..c28223d8092b1 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -282,7 +282,7 @@ static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info l2tp_tunnel_notify(&l2tp_nl_family, info, tunnel, L2TP_CMD_TUNNEL_DELETE); - (void) l2tp_tunnel_delete(tunnel); + l2tp_tunnel_delete(tunnel); l2tp_tunnel_dec_refcount(tunnel); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 4f940d7eb2f7e..b3245f9a37d14 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2034,12 +2034,16 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) seq_puts(seq, " -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"); } else { + struct net *net = seq_file_net(seq); + struct netns_ipvs *ipvs = net_ipvs(net); const struct ip_vs_service *svc = v; const struct ip_vs_iter *iter = seq->private; const struct ip_vs_dest *dest; struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler); char *sched_name = sched ? sched->name : "none"; + if (svc->ipvs != ipvs) + return 0; if (iter->table == ip_vs_svc_table) { #ifdef CONFIG_IP_VS_IPV6 if (svc->af == AF_INET6) diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index 41628b3936731..d33ce6d5ebce9 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -407,6 +408,9 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; int ret = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) return -EINVAL; @@ -611,6 +615,9 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; bool tuple_set = false; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = nfnl_cthelper_dump_table, @@ -678,6 +685,9 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth, *n; int j = 0, ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (tb[NFCTH_NAME]) helper_name = nla_data(tb[NFCTH_NAME]); diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 36e14b1f061dd..a34f314a8c238 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,9 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *kf = NULL, *sf; int err = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; @@ -115,6 +119,9 @@ static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *sf; int err = -ENOENT; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b93148e8e9fb2..533fd0503ba03 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -254,6 +254,9 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct sock *sk = skb->sk; int ret = -ENOMEM; + if (!net_eq(dev_net(dev), sock_net(sk))) + return 0; + dev_hold(dev); if (is_vmalloc_addr(skb->head)) @@ -2136,7 +2139,7 @@ static int netlink_dump(struct sock *sk) struct sk_buff *skb = NULL; struct nlmsghdr *nlh; struct module *module; - int len, err = -ENOBUFS; + int err = -ENOBUFS; int alloc_min_size; int alloc_size; @@ -2183,9 +2186,11 @@ static int netlink_dump(struct sock *sk) skb_reserve(skb, skb_tailroom(skb) - alloc_size); netlink_skb_set_owner_r(skb, sk); - len = cb->dump(skb, cb); + if (nlk->dump_done_errno > 0) + nlk->dump_done_errno = cb->dump(skb, cb); - if (len > 0) { + if (nlk->dump_done_errno > 0 || + skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { mutex_unlock(nlk->cb_mutex); if (sk_filter(sk, skb)) @@ -2195,13 +2200,15 @@ static int netlink_dump(struct sock *sk) return 0; } - nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); - if (!nlh) + nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, + sizeof(nlk->dump_done_errno), NLM_F_MULTI); + if (WARN_ON(!nlh)) goto errout_skb; nl_dump_check_consistent(cb, nlh); - memcpy(nlmsg_data(nlh), &len, sizeof(len)); + memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, + sizeof(nlk->dump_done_errno)); if (sk_filter(sk, skb)) kfree_skb(skb); @@ -2273,6 +2280,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, } nlk->cb_running = true; + nlk->dump_done_errno = INT_MAX; mutex_unlock(nlk->cb_mutex); @@ -2385,13 +2393,14 @@ int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, struct nlmsghdr *, struct netlink_ext_ack *)) { - struct netlink_ext_ack extack = {}; + struct netlink_ext_ack extack; struct nlmsghdr *nlh; int err; while (skb->len >= nlmsg_total_size(0)) { int msglen; + memset(&extack, 0, sizeof(extack)); nlh = nlmsg_hdr(skb); err = 0; diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 028188597eaa9..962de7b3c023d 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -34,6 +34,7 @@ struct netlink_sock { wait_queue_head_t wait; bool bound; bool cb_running; + int dump_done_errno; struct netlink_callback cb; struct mutex *cb_mutex; struct mutex cb_def_mutex; diff --git a/net/nfc/core.c b/net/nfc/core.c index 5cf33df888c3d..c699d64a0753a 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1106,7 +1106,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, err_free_dev: kfree(dev); - return ERR_PTR(rc); + return NULL; } EXPORT_SYMBOL(nfc_allocate_device); diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index c3aec6227c91b..363dd904733dd 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -335,6 +335,8 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_info *upcall_info, uint32_t cutlen) { + unsigned int gso_type = skb_shinfo(skb)->gso_type; + struct sw_flow_key later_key; struct sk_buff *segs, *nskb; int err; @@ -345,9 +347,21 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, if (segs == NULL) return -EINVAL; + if (gso_type & SKB_GSO_UDP) { + /* The initial flow key extracted by ovs_flow_key_extract() + * in this case is for a first fragment, so we need to + * properly mark later fragments. + */ + later_key = *key; + later_key.ip.frag = OVS_FRAG_TYPE_LATER; + } + /* Queue all of the segments. */ skb = segs; do { + if (gso_type & SKB_GSO_UDP && skb != segs) + key = &later_key; + err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen); if (err) break; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 8c94cef25a72b..dbe1079a1651e 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -532,6 +532,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) return -EINVAL; skb_reset_network_header(skb); + key->eth.type = skb->protocol; } else { eth = eth_hdr(skb); ether_addr_copy(key->eth.src, eth->h_source); @@ -545,15 +546,23 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) if (unlikely(parse_vlan(skb, key))) return -ENOMEM; - skb->protocol = parse_ethertype(skb); - if (unlikely(skb->protocol == htons(0))) + key->eth.type = parse_ethertype(skb); + if (unlikely(key->eth.type == htons(0))) return -ENOMEM; + /* Multiple tagged packets need to retain TPID to satisfy + * skb_vlan_pop(), which will later shift the ethertype into + * skb->protocol. + */ + if (key->eth.cvlan.tci & htons(VLAN_TAG_PRESENT)) + skb->protocol = key->eth.cvlan.tpid; + else + skb->protocol = key->eth.type; + skb_reset_network_header(skb); __skb_push(skb, skb->data - skb_mac_header(skb)); } skb_reset_mac_len(skb); - key->eth.type = skb->protocol; /* Network layer. */ if (key->eth.type == htons(ETH_P_IP)) { @@ -584,7 +593,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) key->ip.frag = OVS_FRAG_TYPE_LATER; return 0; } - if (nh->frag_off & htons(IP_MF)) + if (nh->frag_off & htons(IP_MF) || + skb_shinfo(skb)->gso_type & SKB_GSO_UDP) key->ip.frag = OVS_FRAG_TYPE_FIRST; else key->ip.frag = OVS_FRAG_TYPE_NONE; @@ -700,6 +710,9 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) if (key->ip.frag == OVS_FRAG_TYPE_LATER) return 0; + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + key->ip.frag = OVS_FRAG_TYPE_FIRST; + /* Transport layer. */ if (key->ip.proto == NEXTHDR_TCP) { if (tcphdr_ok(skb)) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2986941164b19..f4a0587b7d5ec 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1697,7 +1697,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) atomic_long_set(&rollover->num, 0); atomic_long_set(&rollover->num_huge, 0); atomic_long_set(&rollover->num_failed, 0); - po->rollover = rollover; } if (type_flags & PACKET_FANOUT_FLAG_UNIQUEID) { @@ -1755,6 +1754,8 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) if (refcount_read(&match->sk_ref) < PACKET_FANOUT_MAX) { __dev_remove_pack(&po->prot_hook); po->fanout = match; + po->rollover = rollover; + rollover = NULL; refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1); __fanout_link(sk, po); err = 0; @@ -1768,10 +1769,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) } out: - if (err && rollover) { - kfree_rcu(rollover, rcu); - po->rollover = NULL; - } + kfree(rollover); mutex_unlock(&fanout_mutex); return err; } @@ -1795,11 +1793,6 @@ static struct packet_fanout *fanout_release(struct sock *sk) list_del(&f->list); else f = NULL; - - if (po->rollover) { - kfree_rcu(po->rollover, rcu); - po->rollover = NULL; - } } mutex_unlock(&fanout_mutex); @@ -3039,6 +3032,7 @@ static int packet_release(struct socket *sock) synchronize_net(); if (f) { + kfree(po->rollover); fanout_release_data(f); kfree(f); } @@ -3107,6 +3101,10 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, if (need_rehook) { if (po->running) { rcu_read_unlock(); + /* prevents packet_notifier() from calling + * register_prot_hook() + */ + po->num = 0; __unregister_prot_hook(sk, true); rcu_read_lock(); dev_curr = po->prot_hook.dev; @@ -3115,6 +3113,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, dev->ifindex); } + BUG_ON(po->running); po->num = proto; po->prot_hook.type = proto; @@ -3853,7 +3852,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, void *data = &val; union tpacket_stats_u st; struct tpacket_rollover_stats rstats; - struct packet_rollover *rollover; if (level != SOL_PACKET) return -ENOPROTOOPT; @@ -3932,18 +3930,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, 0); break; case PACKET_ROLLOVER_STATS: - rcu_read_lock(); - rollover = rcu_dereference(po->rollover); - if (rollover) { - rstats.tp_all = atomic_long_read(&rollover->num); - rstats.tp_huge = atomic_long_read(&rollover->num_huge); - rstats.tp_failed = atomic_long_read(&rollover->num_failed); - data = &rstats; - lv = sizeof(rstats); - } - rcu_read_unlock(); - if (!rollover) + if (!po->rollover) return -EINVAL; + rstats.tp_all = atomic_long_read(&po->rollover->num); + rstats.tp_huge = atomic_long_read(&po->rollover->num_huge); + rstats.tp_failed = atomic_long_read(&po->rollover->num_failed); + data = &rstats; + lv = sizeof(rstats); break; case PACKET_TX_HAS_OFF: val = po->tp_tx_has_off; diff --git a/net/packet/internal.h b/net/packet/internal.h index 562fbc1550063..a1d2b2319ae99 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -95,7 +95,6 @@ struct packet_fanout { struct packet_rollover { int sock; - struct rcu_head rcu; atomic_long_t num; atomic_long_t num_huge; atomic_long_t num_failed; diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 8886f15abe90e..634cfcb7bba68 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -183,7 +183,7 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args, long i; int ret; - if (rs->rs_bound_addr == 0) { + if (rs->rs_bound_addr == 0 || !rs->rs_transport) { ret = -ENOTCONN; /* XXX not a great errno */ goto out; } @@ -525,6 +525,9 @@ int rds_rdma_extra_size(struct rds_rdma_args *args) local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr; + if (args->nr_local == 0) + return -EINVAL; + /* figure out the number of pages in the vector */ for (i = 0; i < args->nr_local; i++) { if (copy_from_user(&vec, &local_vec[i], @@ -874,6 +877,7 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm, err: if (page) put_page(page); + rm->atomic.op_active = 0; kfree(rm->atomic.op_notifier); return ret; diff --git a/net/rds/send.c b/net/rds/send.c index b52cdc8ae4288..f72466c63f0c5 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1009,6 +1009,9 @@ static int rds_rdma_bytes(struct msghdr *msg, size_t *rdma_bytes) continue; if (cmsg->cmsg_type == RDS_CMSG_RDMA_ARGS) { + if (cmsg->cmsg_len < + CMSG_LEN(sizeof(struct rds_rdma_args))) + return -EINVAL; args = CMSG_DATA(cmsg); *rdma_bytes += args->remote_vec.bytes; } diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 1c40caadcff95..d836f998117b2 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -229,6 +229,9 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl, const struct iphdr *iph; u16 ul; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + return 1; + /* * Support both UDP and UDPLITE checksum algorithms, Don't use * udph->len to get the real length without any protocol check, @@ -282,6 +285,9 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl, const struct ipv6hdr *ip6h; u16 ul; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + return 1; + /* * Support both UDP and UDPLITE checksum algorithms, Don't use * udph->len to get the real length without any protocol check, diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index e29a48ef7fc34..a0ac42b3ed065 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -159,7 +159,7 @@ static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets, if (action == TC_ACT_SHOT) this_cpu_ptr(gact->common.cpu_qstats)->drops += packets; - tm->lastuse = lastuse; + tm->lastuse = max_t(u64, tm->lastuse, lastuse); } static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 416627c66f081..6ce8de373f835 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -238,7 +238,7 @@ static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets, struct tcf_t *tm = &m->tcf_tm; _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); - tm->lastuse = lastuse; + tm->lastuse = max_t(u64, tm->lastuse, lastuse); } static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 990eb4d91d542..3a499530f3211 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -246,11 +246,8 @@ static int cls_bpf_init(struct tcf_proto *tp) return 0; } -static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog) +static void cls_bpf_free_parms(struct cls_bpf_prog *prog) { - tcf_exts_destroy(&prog->exts); - tcf_exts_put_net(&prog->exts); - if (cls_bpf_is_ebpf(prog)) bpf_prog_put(prog->filter); else @@ -258,6 +255,14 @@ static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog) kfree(prog->bpf_name); kfree(prog->bpf_ops); +} + +static void __cls_bpf_delete_prog(struct cls_bpf_prog *prog) +{ + tcf_exts_destroy(&prog->exts); + tcf_exts_put_net(&prog->exts); + + cls_bpf_free_parms(prog); kfree(prog); } @@ -509,10 +514,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, goto errout; ret = cls_bpf_offload(tp, prog, oldprog); - if (ret) { - __cls_bpf_delete_prog(prog); - return ret; - } + if (ret) + goto errout_parms; if (!tc_in_hw(prog->gen_flags)) prog->gen_flags |= TCA_CLS_FLAGS_NOT_IN_HW; @@ -529,6 +532,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, *arg = prog; return 0; +errout_parms: + cls_bpf_free_parms(prog); errout: tcf_exts_destroy(&prog->exts); kfree(prog); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index dcef97fa80473..aeffa320429d8 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1157,9 +1157,13 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL) return -EINVAL; + err = tcf_block_get(&q->link.block, &q->link.filter_list); + if (err) + goto put_rtab; + err = qdisc_class_hash_init(&q->clhash); if (err < 0) - goto put_rtab; + goto put_block; q->link.sibling = &q->link; q->link.common.classid = sch->handle; @@ -1193,6 +1197,9 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) cbq_addprio(q, &q->link); return 0; +put_block: + tcf_block_put(q->link.block); + put_rtab: qdisc_put_rtab(q->link.R_tab); return err; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 44de4ee51ce9f..a08a32fa09493 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -59,11 +59,12 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt) struct net_device *dev = qdisc_dev(sch); int err; + net_inc_ingress_queue(); + err = tcf_block_get(&q->block, &dev->ingress_cl_list); if (err) return err; - net_inc_ingress_queue(); sch->flags |= TCQ_F_CPUSTATS; return 0; @@ -153,6 +154,9 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt) struct net_device *dev = qdisc_dev(sch); int err; + net_inc_ingress_queue(); + net_inc_egress_queue(); + err = tcf_block_get(&q->ingress_block, &dev->ingress_cl_list); if (err) return err; @@ -161,9 +165,6 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt) if (err) return err; - net_inc_ingress_queue(); - net_inc_egress_queue(); - sch->flags |= TCQ_F_CPUSTATS; return 0; diff --git a/net/sctp/input.c b/net/sctp/input.c index 621b5ca3fd1c1..141c9c466ec17 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -399,20 +399,24 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, return; } - if (t->param_flags & SPP_PMTUD_ENABLE) { - /* Update transports view of the MTU */ - sctp_transport_update_pmtu(t, pmtu); - - /* Update association pmtu. */ - sctp_assoc_sync_pmtu(asoc); - } + if (!(t->param_flags & SPP_PMTUD_ENABLE)) + /* We can't allow retransmitting in such case, as the + * retransmission would be sized just as before, and thus we + * would get another icmp, and retransmit again. + */ + return; - /* Retransmit with the new pmtu setting. - * Normally, if PMTU discovery is disabled, an ICMP Fragmentation - * Needed will never be sent, but if a message was sent before - * PMTU discovery was disabled that was larger than the PMTU, it - * would not be fragmented, so it must be re-transmitted fragmented. + /* Update transports view of the MTU. Return if no update was needed. + * If an update wasn't needed/possible, it also doesn't make sense to + * try to retransmit now. */ + if (!sctp_transport_update_pmtu(t, pmtu)) + return; + + /* Update association pmtu. */ + sctp_assoc_sync_pmtu(asoc); + + /* Retransmit with the new pmtu setting. */ sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a6dfa86c02016..3b18085e3b102 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -807,9 +807,10 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, addr->v6.sin6_flowinfo = 0; addr->v6.sin6_port = sh->source; addr->v6.sin6_addr = ipv6_hdr(skb)->saddr; - if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { + if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) addr->v6.sin6_scope_id = sctp_v6_skb_iif(skb); - } + else + addr->v6.sin6_scope_id = 0; } *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr); diff --git a/net/sctp/offload.c b/net/sctp/offload.c index 275925b93b290..35bc7106d1827 100644 --- a/net/sctp/offload.c +++ b/net/sctp/offload.c @@ -45,6 +45,9 @@ static struct sk_buff *sctp_gso_segment(struct sk_buff *skb, struct sk_buff *segs = ERR_PTR(-EINVAL); struct sctphdr *sh; + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP)) + goto out; + sh = sctp_hdr(skb); if (!pskb_may_pull(skb, sizeof(*sh))) goto out; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6f45d1713452d..1c08d86efe949 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -83,7 +83,7 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); static void sctp_wfree(struct sk_buff *skb); -static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, +static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, size_t msg_len); static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); @@ -187,13 +187,13 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, list_for_each_entry(chunk, &t->transmitted, transmitted_list) cb(chunk); - list_for_each_entry(chunk, &q->retransmit, list) + list_for_each_entry(chunk, &q->retransmit, transmitted_list) cb(chunk); - list_for_each_entry(chunk, &q->sacked, list) + list_for_each_entry(chunk, &q->sacked, transmitted_list) cb(chunk); - list_for_each_entry(chunk, &q->abandoned, list) + list_for_each_entry(chunk, &q->abandoned, transmitted_list) cb(chunk); list_for_each_entry(chunk, &q->out_chunk_list, list) @@ -334,16 +334,14 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, if (len < sizeof (struct sockaddr)) return NULL; + if (!opt->pf->af_supported(addr->sa.sa_family, opt)) + return NULL; + /* V4 mapped address are really of AF_INET family */ if (addr->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr->v6.sin6_addr)) { - if (!opt->pf->af_supported(AF_INET, opt)) - return NULL; - } else { - /* Does this PF support this AF? */ - if (!opt->pf->af_supported(addr->sa.sa_family, opt)) - return NULL; - } + ipv6_addr_v4mapped(&addr->v6.sin6_addr) && + !opt->pf->af_supported(AF_INET, opt)) + return NULL; /* If we get this far, af is valid. */ af = sctp_get_af_specific(addr->sa.sa_family); @@ -1882,8 +1880,14 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) */ if (sinit) { if (sinit->sinit_num_ostreams) { - asoc->c.sinit_num_ostreams = - sinit->sinit_num_ostreams; + __u16 outcnt = sinit->sinit_num_ostreams; + + asoc->c.sinit_num_ostreams = outcnt; + /* outcnt has been changed, so re-init stream */ + err = sctp_stream_init(&asoc->stream, outcnt, 0, + GFP_KERNEL); + if (err) + goto out_free; } if (sinit->sinit_max_instreams) { asoc->c.sinit_max_instreams = @@ -1962,9 +1966,16 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); if (!sctp_wspace(asoc)) { + /* sk can be changed by peel off when waiting for buf. */ err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); - if (err) + if (err) { + if (err == -ESRCH) { + /* asoc is already dead. */ + new_asoc = NULL; + err = -EPIPE; + } goto out_free; + } } /* If an address is passed with the sendto/sendmsg call, it is used @@ -3867,13 +3878,17 @@ static int sctp_setsockopt_reset_streams(struct sock *sk, struct sctp_association *asoc; int retval = -EINVAL; - if (optlen < sizeof(struct sctp_reset_streams)) + if (optlen < sizeof(*params)) return -EINVAL; params = memdup_user(optval, optlen); if (IS_ERR(params)) return PTR_ERR(params); + if (params->srs_number_streams * sizeof(__u16) > + optlen - sizeof(*params)) + goto out; + asoc = sctp_id2assoc(sk, params->srs_assoc_id); if (!asoc) goto out; @@ -4406,7 +4421,7 @@ static int sctp_init_sock(struct sock *sk) SCTP_DBG_OBJCNT_INC(sock); local_bh_disable(); - percpu_counter_inc(&sctp_sockets_allocated); + sk_sockets_allocated_inc(sk); sock_prot_inuse_add(net, sk->sk_prot, 1); /* Nothing can fail after this block, otherwise @@ -4450,7 +4465,7 @@ static void sctp_destroy_sock(struct sock *sk) } sctp_endpoint_free(sp->ep); local_bh_disable(); - percpu_counter_dec(&sctp_sockets_allocated); + sk_sockets_allocated_dec(sk); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); local_bh_enable(); } @@ -4943,12 +4958,6 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) if (!asoc) return -EINVAL; - /* If there is a thread waiting on more sndbuf space for - * sending on this asoc, it cannot be peeled. - */ - if (waitqueue_active(&asoc->wait)) - return -EBUSY; - /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ @@ -7825,9 +7834,9 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, size_t msg_len) { struct sock *sk = asoc->base.sk; - int err = 0; long current_timeo = *timeo_p; DEFINE_WAIT(wait); + int err = 0; pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc, *timeo_p, msg_len); @@ -7839,10 +7848,11 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, for (;;) { prepare_to_wait_exclusive(&asoc->wait, &wait, TASK_INTERRUPTIBLE); + if (asoc->base.dead) + goto do_dead; if (!*timeo_p) goto do_nonblock; - if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || - asoc->base.dead) + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING) goto do_error; if (signal_pending(current)) goto do_interrupted; @@ -7855,6 +7865,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, release_sock(sk); current_timeo = schedule_timeout(current_timeo); lock_sock(sk); + if (sk != asoc->base.sk) + goto do_error; *timeo_p = current_timeo; } @@ -7867,6 +7879,10 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, return err; +do_dead: + err = -ESRCH; + goto out; + do_error: err = -EPIPE; goto out; diff --git a/net/sctp/stream.c b/net/sctp/stream.c index fa8371ff05c43..724adf2786a23 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -40,9 +40,14 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, { int i; + gfp |= __GFP_NOWARN; + /* Initial stream->out size may be very big, so free it and alloc - * a new one with new outcnt to save memory. + * a new one with new outcnt to save memory if needed. */ + if (outcnt == stream->outcnt) + goto in; + kfree(stream->out); stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp); @@ -53,6 +58,7 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, for (i = 0; i < stream->outcnt; i++) stream->out[i].state = SCTP_STREAM_OPEN; +in: if (!incnt) return 0; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2d9bd3776bc83..7ef77fd7b52a1 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -251,28 +251,37 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } -void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) +bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) { struct dst_entry *dst = sctp_transport_dst_check(t); + bool change = true; if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { - pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", - __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); - /* Use default minimum segment size and disable - * pmtu discovery on this transport. - */ - t->pathmtu = SCTP_DEFAULT_MINSEGMENT; - } else { - t->pathmtu = pmtu; + pr_warn_ratelimited("%s: Reported pmtu %d too low, using default minimum of %d\n", + __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); + /* Use default minimum segment instead */ + pmtu = SCTP_DEFAULT_MINSEGMENT; } + pmtu = SCTP_TRUNC4(pmtu); if (dst) { dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu); dst = sctp_transport_dst_check(t); } - if (!dst) + if (!dst) { t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk); + dst = t->dst; + } + + if (dst) { + /* Re-fetch, as under layers may have a higher minimum size */ + pmtu = SCTP_TRUNC4(dst_mtu(dst)); + change = t->pathmtu != pmtu; + } + t->pathmtu = pmtu; + + return change; } /* Caches the dst entry and source address for a transport's destination diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 413e3868fbf36..7166e7ecbe861 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -571,7 +571,7 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_rmb) /* use socket send buffer size (w/o overhead) as start value */ sk_buf_size = smc->sk.sk_sndbuf / 2; - for (bufsize_short = smc_compress_bufsize(smc->sk.sk_sndbuf / 2); + for (bufsize_short = smc_compress_bufsize(sk_buf_size); bufsize_short >= 0; bufsize_short--) { if (is_rmb) { diff --git a/net/socket.c b/net/socket.c index c729625eb5d36..d894c7c5fa549 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2642,6 +2642,15 @@ static int __init sock_init(void) core_initcall(sock_init); /* early initcall */ +static int __init jit_init(void) +{ +#ifdef CONFIG_BPF_JIT_ALWAYS_ON + bpf_jit_enable = 1; +#endif + return 0; +} +pure_initcall(jit_init); + #ifdef CONFIG_PROC_FS void socket_seq_show(struct seq_file *seq) { diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index c4778cae58ef1..444380f968f11 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -231,6 +231,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, goto out_free_groups; creds->cr_group_info->gid[i] = kgid; } + groups_sort(creds->cr_group_info); return 0; out_free_groups: diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 7b1ee5a0b03cd..f41ffb22652c7 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -481,6 +481,7 @@ static int rsc_parse(struct cache_detail *cd, goto out; rsci.cred.cr_group_info->gid[i] = kgid; } + groups_sort(rsci.cred.cr_group_info); /* mech name */ len = qword_get(&mesg, buf, mlen); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 0cc83839c13c3..f9db5fe52d367 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -274,10 +274,9 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task) static void rpc_set_active(struct rpc_task *task) { - trace_rpc_task_begin(task->tk_client, task, NULL); - rpc_task_set_debuginfo(task); set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); + trace_rpc_task_begin(task->tk_client, task, NULL); } /* diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index f81eaa8e08888..acb70d235e475 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -520,6 +520,7 @@ static int unix_gid_parse(struct cache_detail *cd, ug.gi->gid[i] = kgid; } + groups_sort(ug.gi); ugp = unix_gid_lookup(cd, uid); if (ugp) { struct cache_head *ch; @@ -819,6 +820,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); cred->cr_group_info->gid[i] = kgid; } + groups_sort(cred->cr_group_info); if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { *authp = rpc_autherr_badverf; return SVC_DENIED; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 898485e3ece4e..8eb0c4f3b3e96 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1001,6 +1001,7 @@ void xprt_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + unsigned int connect_cookie; int status, numreqs; dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); @@ -1024,6 +1025,7 @@ void xprt_transmit(struct rpc_task *task) } else if (!req->rq_bytes_sent) return; + connect_cookie = xprt->connect_cookie; req->rq_xtime = ktime_get(); status = xprt->ops->send_request(task); trace_xprt_transmit(xprt, req->rq_xid, status); @@ -1047,20 +1049,28 @@ void xprt_transmit(struct rpc_task *task) xprt->stat.bklog_u += xprt->backlog.qlen; xprt->stat.sending_u += xprt->sending.qlen; xprt->stat.pending_u += xprt->pending.qlen; + spin_unlock_bh(&xprt->transport_lock); - /* Don't race with disconnect */ - if (!xprt_connected(xprt)) - task->tk_status = -ENOTCONN; - else { + req->rq_connect_cookie = connect_cookie; + if (rpc_reply_expected(task) && !READ_ONCE(req->rq_reply_bytes_recvd)) { /* - * Sleep on the pending queue since - * we're expecting a reply. + * Sleep on the pending queue if we're expecting a reply. + * The spinlock ensures atomicity between the test of + * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). */ - if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) + spin_lock(&xprt->recv_lock); + if (!req->rq_reply_bytes_recvd) { rpc_sleep_on(&xprt->pending, task, xprt_timer); - req->rq_connect_cookie = xprt->connect_cookie; + /* + * Send an extra queue wakeup call if the + * connection was dropped in case the call to + * rpc_sleep_on() raced. + */ + if (!xprt_connected(xprt)) + xprt_wake_pending_tasks(xprt, -ENOTCONN); + } + spin_unlock(&xprt->recv_lock); } - spin_unlock_bh(&xprt->transport_lock); } static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 992594b7cc6b6..af7893501e40a 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -133,6 +133,10 @@ static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma, if (ret) goto out_err; + /* Bump page refcnt so Send completion doesn't release + * the rq_buffer before all retransmits are complete. + */ + get_page(virt_to_page(rqst->rq_buffer)); ret = svc_rdma_post_send_wr(rdma, ctxt, 1, 0); if (ret) goto out_unmap; @@ -165,7 +169,6 @@ xprt_rdma_bc_allocate(struct rpc_task *task) return -EINVAL; } - /* svc_rdma_sendto releases this page */ page = alloc_page(RPCRDMA_DEF_GFP); if (!page) return -ENOMEM; @@ -184,6 +187,7 @@ xprt_rdma_bc_free(struct rpc_task *task) { struct rpc_rqst *rqst = task->tk_rqstp; + put_page(virt_to_page(rqst->rq_buffer)); kfree(rqst->rq_rbuffer); } diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index c84e2b644e133..8cf5ccfe180d3 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -686,7 +686,7 @@ xprt_rdma_free(struct rpc_task *task) dprintk("RPC: %s: called on 0x%p\n", __func__, req->rl_reply); if (!list_empty(&req->rl_registered)) - ia->ri_ops->ro_unmap_safe(r_xprt, req, !RPC_IS_ASYNC(task)); + ia->ri_ops->ro_unmap_sync(r_xprt, &req->rl_registered); rpcrdma_unmap_sges(ia, req); rpcrdma_buffer_put(req); } diff --git a/net/tipc/node.c b/net/tipc/node.c index 198dbc7adbe12..f6c5743c170e7 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1848,36 +1848,38 @@ int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info) if (strcmp(name, tipc_bclink_name) == 0) { err = tipc_nl_add_bc_link(net, &msg); - if (err) { - nlmsg_free(msg.skb); - return err; - } + if (err) + goto err_free; } else { int bearer_id; struct tipc_node *node; struct tipc_link *link; node = tipc_node_find_by_name(net, name, &bearer_id); - if (!node) - return -EINVAL; + if (!node) { + err = -EINVAL; + goto err_free; + } tipc_node_read_lock(node); link = node->links[bearer_id].link; if (!link) { tipc_node_read_unlock(node); - nlmsg_free(msg.skb); - return -EINVAL; + err = -EINVAL; + goto err_free; } err = __tipc_nl_add_link(net, &msg, link, 0); tipc_node_read_unlock(node); - if (err) { - nlmsg_free(msg.skb); - return err; - } + if (err) + goto err_free; } return genlmsg_reply(msg.skb, info); + +err_free: + nlmsg_free(msg.skb); + return err; } int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info) diff --git a/net/tipc/server.c b/net/tipc/server.c index 3cd6402e812cb..f4c1b18c5fb07 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c @@ -313,6 +313,7 @@ static int tipc_accept_from_sock(struct tipc_conn *con) newcon->usr_data = s->tipc_conn_new(newcon->conid); if (!newcon->usr_data) { sock_release(newsock); + conn_put(newcon); return -ENOMEM; } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d50edd6e00196..98a44ecb11e7b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -709,11 +709,11 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, switch (sk->sk_state) { case TIPC_ESTABLISHED: + case TIPC_CONNECTING: if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk)) mask |= POLLOUT; /* fall thru' */ case TIPC_LISTEN: - case TIPC_CONNECTING: if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= (POLLIN | POLLRDNORM); break; diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index ecca64fc6a6f2..3deabcab48821 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -371,10 +371,6 @@ static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb) goto rcu_out; } - tipc_rcv(sock_net(sk), skb, b); - rcu_read_unlock(); - return 0; - rcu_out: rcu_read_unlock(); out: diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 60aff60e30ad4..282361ac02632 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -364,14 +364,16 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval, crypto_info = &ctx->crypto_send; /* Currently we don't support set crypto info more than one time */ - if (TLS_CRYPTO_INFO_READY(crypto_info)) + if (TLS_CRYPTO_INFO_READY(crypto_info)) { + rc = -EBUSY; goto out; + } switch (tmp_crypto_info.cipher_type) { case TLS_CIPHER_AES_GCM_128: { if (optlen != sizeof(struct tls12_crypto_info_aes_gcm_128)) { rc = -EINVAL; - goto out; + goto err_crypto_info; } rc = copy_from_user( crypto_info, @@ -386,7 +388,7 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval, } default: rc = -EINVAL; - goto out; + goto err_crypto_info; } ctx->sk_write_space = sk->sk_write_space; @@ -444,6 +446,15 @@ static int tls_init(struct sock *sk) struct tls_context *ctx; int rc = 0; + /* The TLS ulp is currently supported only for TCP sockets + * in ESTABLISHED state. + * Supporting sockets in LISTEN state will require us + * to modify the accept implementation to clone rather then + * share the ulp context. + */ + if (sk->sk_state != TCP_ESTABLISHED) + return -ENOTSUPP; + /* allocate tls context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 7d80040a37b6d..83f886d7c1f8b 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -219,7 +219,7 @@ static int tls_do_encryption(struct tls_context *tls_ctx, struct aead_request *aead_req; int rc; - aead_req = kmalloc(req_size, flags); + aead_req = kzalloc(req_size, flags); if (!aead_req) return -ENOMEM; @@ -407,7 +407,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) while (msg_data_left(msg)) { if (sk->sk_err) { - ret = sk->sk_err; + ret = -sk->sk_err; goto send_end; } @@ -560,7 +560,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, size_t copy, required_size; if (sk->sk_err) { - ret = sk->sk_err; + ret = -sk->sk_err; goto sendpage_end; } @@ -697,18 +697,17 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx) } default: rc = -EINVAL; - goto out; + goto free_priv; } ctx->prepend_size = TLS_HEADER_SIZE + nonce_size; ctx->tag_size = tag_size; ctx->overhead_size = ctx->prepend_size + ctx->tag_size; ctx->iv_size = iv_size; - ctx->iv = kmalloc(iv_size + TLS_CIPHER_AES_GCM_128_SALT_SIZE, - GFP_KERNEL); + ctx->iv = kmalloc(iv_size + TLS_CIPHER_AES_GCM_128_SALT_SIZE, GFP_KERNEL); if (!ctx->iv) { rc = -ENOMEM; - goto out; + goto free_priv; } memcpy(ctx->iv, gcm_128_info->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE); memcpy(ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, iv, iv_size); @@ -756,7 +755,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx) rc = crypto_aead_setauthsize(sw_ctx->aead_send, ctx->tag_size); if (!rc) - goto out; + return 0; free_aead: crypto_free_aead(sw_ctx->aead_send); @@ -767,6 +766,9 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx) free_iv: kfree(ctx->iv); ctx->iv = NULL; +free_priv: + kfree(ctx->priv_ctx); + ctx->priv_ctx = NULL; out: return rc; } diff --git a/net/wireless/shipped-certs.c b/net/wireless/shipped-certs.c new file mode 100644 index 0000000000000..e75af11438ca6 --- /dev/null +++ b/net/wireless/shipped-certs.c @@ -0,0 +1,684 @@ +#include "reg.h" +const u8 shipped_regdb_certs[] = { +0x30, +0x82, +0x02, +0xa4, +0x30, +0x82, +0x01, +0x8c, +0x02, +0x09, +0x00, +0xb2, +0x8d, +0xdf, +0x47, +0xae, +0xf9, +0xce, +0xa7, +0x30, +0x0d, +0x06, +0x09, +0x2a, +0x86, +0x48, +0x86, +0xf7, +0x0d, +0x01, +0x01, +0x0b, +0x05, +0x00, +0x30, +0x13, +0x31, +0x11, +0x30, +0x0f, +0x06, +0x03, +0x55, +0x04, +0x03, +0x0c, +0x08, +0x73, +0x66, +0x6f, +0x72, +0x73, +0x68, +0x65, +0x65, +0x30, +0x20, +0x17, +0x0d, +0x31, +0x37, +0x31, +0x30, +0x30, +0x36, +0x31, +0x39, +0x34, +0x30, +0x33, +0x35, +0x5a, +0x18, +0x0f, +0x32, +0x31, +0x31, +0x37, +0x30, +0x39, +0x31, +0x32, +0x31, +0x39, +0x34, +0x30, +0x33, +0x35, +0x5a, +0x30, +0x13, +0x31, +0x11, +0x30, +0x0f, +0x06, +0x03, +0x55, +0x04, +0x03, +0x0c, +0x08, +0x73, +0x66, +0x6f, +0x72, +0x73, +0x68, +0x65, +0x65, +0x30, +0x82, +0x01, +0x22, +0x30, +0x0d, +0x06, +0x09, +0x2a, +0x86, +0x48, +0x86, +0xf7, +0x0d, +0x01, +0x01, +0x01, +0x05, +0x00, +0x03, +0x82, +0x01, +0x0f, +0x00, +0x30, +0x82, +0x01, +0x0a, +0x02, +0x82, +0x01, +0x01, +0x00, +0xb5, +0x40, +0xe3, +0x9c, +0x28, +0x84, +0x39, +0x03, +0xf2, +0x39, +0xd7, +0x66, +0x2c, +0x41, +0x38, +0x15, +0xac, +0x7e, +0xa5, +0x83, +0x71, +0x25, +0x7e, +0x90, +0x7c, +0x68, +0xdd, +0x6f, +0x3f, +0xd9, +0xd7, +0x59, +0x38, +0x9f, +0x7c, +0x6a, +0x52, +0xc2, +0x03, +0x2a, +0x2d, +0x7e, +0x66, +0xf4, +0x1e, +0xb3, +0x12, +0x70, +0x20, +0x5b, +0xd4, +0x97, +0x32, +0x3d, +0x71, +0x8b, +0x3b, +0x1b, +0x08, +0x17, +0x14, +0x6b, +0x61, +0xc4, +0x57, +0x8b, +0x96, +0x16, +0x1c, +0xfd, +0x24, +0xd5, +0x0b, +0x09, +0xf9, +0x68, +0x11, +0x84, +0xfb, +0xca, +0x51, +0x0c, +0xd1, +0x45, +0x19, +0xda, +0x10, +0x44, +0x8a, +0xd9, +0xfe, +0x76, +0xa9, +0xfd, +0x60, +0x2d, +0x18, +0x0b, +0x28, +0x95, +0xb2, +0x2d, +0xea, +0x88, +0x98, +0xb8, +0xd1, +0x56, +0x21, +0xf0, +0x53, +0x1f, +0xf1, +0x02, +0x6f, +0xe9, +0x46, +0x9b, +0x93, +0x5f, +0x28, +0x90, +0x0f, +0xac, +0x36, +0xfa, +0x68, +0x23, +0x71, +0x57, +0x56, +0xf6, +0xcc, +0xd3, +0xdf, +0x7d, +0x2a, +0xd9, +0x1b, +0x73, +0x45, +0xeb, +0xba, +0x27, +0x85, +0xef, +0x7a, +0x7f, +0xa5, +0xcb, +0x80, +0xc7, +0x30, +0x36, +0xd2, +0x53, +0xee, +0xec, +0xac, +0x1e, +0xe7, +0x31, +0xf1, +0x36, +0xa2, +0x9c, +0x63, +0xc6, +0x65, +0x5b, +0x7f, +0x25, +0x75, +0x68, +0xa1, +0xea, +0xd3, +0x7e, +0x00, +0x5c, +0x9a, +0x5e, +0xd8, +0x20, +0x18, +0x32, +0x77, +0x07, +0x29, +0x12, +0x66, +0x1e, +0x36, +0x73, +0xe7, +0x97, +0x04, +0x41, +0x37, +0xb1, +0xb1, +0x72, +0x2b, +0xf4, +0xa1, +0x29, +0x20, +0x7c, +0x96, +0x79, +0x0b, +0x2b, +0xd0, +0xd8, +0xde, +0xc8, +0x6c, +0x3f, +0x93, +0xfb, +0xc5, +0xee, +0x78, +0x52, +0x11, +0x15, +0x1b, +0x7a, +0xf6, +0xe2, +0x68, +0x99, +0xe7, +0xfb, +0x46, +0x16, +0x84, +0xe3, +0xc7, +0xa1, +0xe6, +0xe0, +0xd2, +0x46, +0xd5, +0xe1, +0xc4, +0x5f, +0xa0, +0x66, +0xf4, +0xda, +0xc4, +0xff, +0x95, +0x1d, +0x02, +0x03, +0x01, +0x00, +0x01, +0x30, +0x0d, +0x06, +0x09, +0x2a, +0x86, +0x48, +0x86, +0xf7, +0x0d, +0x01, +0x01, +0x0b, +0x05, +0x00, +0x03, +0x82, +0x01, +0x01, +0x00, +0x87, +0x03, +0xda, +0xf2, +0x82, +0xc2, +0xdd, +0xaf, +0x7c, +0x44, +0x2f, +0x86, +0xd3, +0x5f, +0x4c, +0x93, +0x48, +0xb9, +0xfe, +0x07, +0x17, +0xbb, +0x21, +0xf7, +0x25, +0x23, +0x4e, +0xaa, +0x22, +0x0c, +0x16, +0xb9, +0x73, +0xae, +0x9d, +0x46, +0x7c, +0x75, +0xd9, +0xc3, +0x49, +0x57, +0x47, +0xbf, +0x33, +0xb7, +0x97, +0xec, +0xf5, +0x40, +0x75, +0xc0, +0x46, +0x22, +0xf0, +0xa0, +0x5d, +0x9c, +0x79, +0x13, +0xa1, +0xff, +0xb8, +0xa3, +0x2f, +0x7b, +0x8e, +0x06, +0x3f, +0xc8, +0xb6, +0xe4, +0x6a, +0x28, +0xf2, +0x34, +0x5c, +0x23, +0x3f, +0x32, +0xc0, +0xe6, +0xad, +0x0f, +0xac, +0xcf, +0x55, +0x74, +0x47, +0x73, +0xd3, +0x01, +0x85, +0xb7, +0x0b, +0x22, +0x56, +0x24, +0x7d, +0x9f, +0x09, +0xa9, +0x0e, +0x86, +0x9e, +0x37, +0x5b, +0x9c, +0x6d, +0x02, +0xd9, +0x8c, +0xc8, +0x50, +0x6a, +0xe2, +0x59, +0xf3, +0x16, +0x06, +0xea, +0xb2, +0x42, +0xb5, +0x58, +0xfe, +0xba, +0xd1, +0x81, +0x57, +0x1a, +0xef, +0xb2, +0x38, +0x88, +0x58, +0xf6, +0xaa, +0xc4, +0x2e, +0x8b, +0x5a, +0x27, +0xe4, +0xa5, +0xe8, +0xa4, +0xca, +0x67, +0x5c, +0xac, +0x72, +0x67, +0xc3, +0x6f, +0x13, +0xc3, +0x2d, +0x35, +0x79, +0xd7, +0x8a, +0xe7, +0xf5, +0xd4, +0x21, +0x30, +0x4a, +0xd5, +0xf6, +0xa3, +0xd9, +0x79, +0x56, +0xf2, +0x0f, +0x10, +0xf7, +0x7d, +0xd0, +0x51, +0x93, +0x2f, +0x47, +0xf8, +0x7d, +0x4b, +0x0a, +0x84, +0x55, +0x12, +0x0a, +0x7d, +0x4e, +0x3b, +0x1f, +0x2b, +0x2f, +0xfc, +0x28, +0xb3, +0x69, +0x34, +0xe1, +0x80, +0x80, +0xbb, +0xe2, +0xaf, +0xb9, +0xd6, +0x30, +0xf1, +0x1d, +0x54, +0x87, +0x23, +0x99, +0x9f, +0x51, +0x03, +0x4c, +0x45, +0x7d, +0x02, +0x65, +0x73, +0xab, +0xfd, +0xcf, +0x94, +0xcc, +0x0d, +0x3a, +0x60, +0xfd, +0x3c, +0x14, +0x2f, +0x16, +0x33, +0xa9, +0x21, +0x1f, +0xcb, +0x50, +0xb1, +0x8f, +0x03, +0xee, +0xa0, +0x66, +0xa9, +0x16, +0x79, +0x14, +}; +unsigned int shipped_regdb_certs_len = sizeof(shipped_regdb_certs); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 6eb228a701310..688ed34f0671f 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1306,6 +1306,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) newp->xfrm_nr = old->xfrm_nr; newp->index = old->index; newp->type = old->type; + newp->family = old->family; memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); spin_lock_bh(&net->xfrm.xfrm_policy_lock); @@ -1361,29 +1362,36 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, struct net *net = xp_net(policy); int nx; int i, error; + xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); + xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); xfrm_address_t tmp; for (nx = 0, i = 0; i < policy->xfrm_nr; i++) { struct xfrm_state *x; - xfrm_address_t *local; - xfrm_address_t *remote; + xfrm_address_t *remote = daddr; + xfrm_address_t *local = saddr; struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; - remote = &tmpl->id.daddr; - local = &tmpl->saddr; - if (xfrm_addr_any(local, tmpl->encap_family)) { - error = xfrm_get_saddr(net, fl->flowi_oif, - &tmp, remote, - tmpl->encap_family, 0); - if (error) - goto fail; - local = &tmp; + if (tmpl->mode == XFRM_MODE_TUNNEL || + tmpl->mode == XFRM_MODE_BEET) { + remote = &tmpl->id.daddr; + local = &tmpl->saddr; + if (xfrm_addr_any(local, tmpl->encap_family)) { + error = xfrm_get_saddr(net, fl->flowi_oif, + &tmp, remote, + tmpl->encap_family, 0); + if (error) + goto fail; + local = &tmp; + } } x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); if (x && x->km.state == XFRM_STATE_VALID) { xfrm[nx++] = x; + daddr = remote; + saddr = local; continue; } if (x) { @@ -2048,8 +2056,11 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, if (num_xfrms <= 0) goto make_dummy_bundle; + local_bh_disable(); xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, - xflo->dst_orig); + xflo->dst_orig); + local_bh_enable(); + if (IS_ERR(xdst)) { err = PTR_ERR(xdst); if (err != -EAGAIN) @@ -2136,9 +2147,12 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, goto no_transform; } + local_bh_disable(); xdst = xfrm_resolve_and_create_bundle( pols, num_pols, fl, family, dst_orig); + local_bh_enable(); + if (IS_ERR(xdst)) { xfrm_pols_put(pols, num_pols); err = PTR_ERR(xdst); diff --git a/samples/bpf/xdp1_user.c b/samples/bpf/xdp1_user.c index 2431c0321b712..fdaefe91801d9 100644 --- a/samples/bpf/xdp1_user.c +++ b/samples/bpf/xdp1_user.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "bpf_load.h" #include "bpf_util.h" @@ -69,6 +70,7 @@ static void usage(const char *prog) int main(int argc, char **argv) { + struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; const char *optstr = "SN"; char filename[256]; int opt; @@ -91,6 +93,12 @@ int main(int argc, char **argv) usage(basename(argv[0])); return 1; } + + if (setrlimit(RLIMIT_MEMLOCK, &r)) { + perror("setrlimit(RLIMIT_MEMLOCK)"); + return 1; + } + ifindex = strtoul(argv[optind], NULL, 0); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); diff --git a/scripts/Makefile.build b/scripts/Makefile.build index bb831d49bcfd5..6bed45dc2cb1b 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -259,7 +259,7 @@ ifneq ($(SKIP_STACK_VALIDATION),1) __objtool_obj := $(objtree)/tools/objtool/objtool -objtool_args = $(if $(CONFIG_ORC_UNWINDER),orc generate,check) +objtool_args = $(if $(CONFIG_UNWINDER_ORC),orc generate,check) ifndef CONFIG_FRAME_POINTER objtool_args += --no-fp @@ -270,12 +270,18 @@ else objtool_args += $(call cc-ifversion, -lt, 0405, --no-unreachable) endif +ifdef CONFIG_MODVERSIONS +objtool_o = $(@D)/.tmp_$(@F) +else +objtool_o = $(@) +endif + # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file cmd_objtool = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(__objtool_obj) $(objtool_args) "$(@)";) + $(__objtool_obj) $(objtool_args) "$(objtool_o)";) objtool_obj = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ $(__objtool_obj)) @@ -291,15 +297,15 @@ objtool_dep = $(objtool_obj) \ define rule_cc_o_c $(call echo-cmd,checksrc) $(cmd_checksrc) \ $(call cmd_and_fixdep,cc_o_c) \ - $(cmd_modversions_c) \ $(call echo-cmd,objtool) $(cmd_objtool) \ + $(cmd_modversions_c) \ $(call echo-cmd,record_mcount) $(cmd_record_mcount) endef define rule_as_o_S $(call cmd_and_fixdep,as_o_S) \ - $(cmd_modversions_S) \ - $(call echo-cmd,objtool) $(cmd_objtool) + $(call echo-cmd,objtool) $(cmd_objtool) \ + $(cmd_modversions_S) endef # List module undefined symbols (or empty line if not enabled) diff --git a/scripts/coccicheck b/scripts/coccicheck index 28ad1feff9e12..dda283aba96b4 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -30,12 +30,6 @@ else VERBOSE=0 fi -if [ -z "$J" ]; then - NPROC=$(getconf _NPROCESSORS_ONLN) -else - NPROC="$J" -fi - FLAGS="--very-quiet" # You can use SPFLAGS to append extra arguments to coccicheck or override any @@ -70,6 +64,9 @@ if [ "$C" = "1" -o "$C" = "2" ]; then # Take only the last argument, which is the C file to test shift $(( $# - 1 )) OPTIONS="$COCCIINCLUDE $1" + + # No need to parallelize Coccinelle since this mode takes one input file. + NPROC=1 else ONLINE=0 if [ "$KBUILD_EXTMOD" = "" ] ; then @@ -77,6 +74,12 @@ else else OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE" fi + + if [ -z "$J" ]; then + NPROC=$(getconf _NPROCESSORS_ONLN) + else + NPROC="$J" + fi fi if [ "$KBUILD_EXTMOD" != "" ] ; then diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 1bf949c43b76c..f6ab3ccf698ff 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -96,6 +96,8 @@ def get_thread_info(task): thread_info_addr = task.address + ia64_task_size thread_info = thread_info_addr.cast(thread_info_ptr_type) else: + if task.type.fields()[0].type == thread_info_type.get_type(): + return task['thread_info'] thread_info = task['stack'].cast(thread_info_ptr_type) return thread_info.dereference() diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index 4d1ea96e8794c..a18bca7209957 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -34,7 +34,7 @@ do sed -r \ -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \ -e 's/__attribute_const__([ \t]|$)/\1/g' \ - -e 's@^#include @@' \ + -e 's@^#include @@' \ -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \ -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \ diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 73f9f3192b9fb..34de8b953ecfc 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -39,10 +39,9 @@ if test "$(objtree)" != "$(srctree)"; then \ false; \ fi ; \ $(srctree)/scripts/setlocalversion --save-scmversion; \ -ln -sf $(srctree) $(2); \ tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ - $(addprefix $(2)/,$(TAR_CONTENT) $(3)); \ -rm -f $(2) $(objtree)/.scmversion + --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3); \ +rm -f $(objtree)/.scmversion # rpm-pkg # --------------------------------------------------------------------------- @@ -50,7 +49,7 @@ rpm-pkg rpm: FORCE $(MAKE) clean $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec $(call cmd,src_tar,$(KERNELPATH),kernel.spec) - rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz + +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz rm $(KERNELPATH).tar.gz kernel.spec # binrpm-pkg @@ -58,7 +57,7 @@ rpm-pkg rpm: FORCE binrpm-pkg: FORCE $(MAKE) KBUILD_SRC= $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec - rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ + +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ $(UTS_MACHINE) -bb $(objtree)/binkernel.spec rm binkernel.spec diff --git a/search.sh b/search.sh new file mode 100755 index 0000000000000..bd52a299f6d2c --- /dev/null +++ b/search.sh @@ -0,0 +1,4 @@ +#!/bin/bash +#sufu() { + find -type f -name '*.h' -exec fgrep -Hn --color=auto "$1" {} + +#} diff --git a/security/Kconfig b/security/Kconfig index e8e449444e658..b5c2b5d0c6c0e 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -54,6 +54,17 @@ config SECURITY_NETWORK implement socket and networking access controls. If you are unsure how to answer this question, answer N. +config PAGE_TABLE_ISOLATION + bool "Remove the kernel mapping in user mode" + depends on X86_64 && !UML + default y + help + This feature reduces the number of hardware side channels by + ensuring that the majority of kernel addresses are not mapped + into userspace. + + See Documentation/x86/pti.txt for more details. + config SECURITY_INFINIBAND bool "Infiniband Security Hooks" depends on SECURITY && INFINIBAND diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 620e811696592..4ac0951187170 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -121,17 +121,19 @@ struct apparmor_audit_data { /* these entries require a custom callback fn */ struct { struct aa_label *peer; - struct { - const char *target; - kuid_t ouid; - } fs; + union { + struct { + const char *target; + kuid_t ouid; + } fs; + int signal; + }; }; struct { struct aa_profile *profile; const char *ns; long pos; } iface; - int signal; struct { int rlim; unsigned long max; diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 2b27bb79aec44..d7b7e71151601 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -133,6 +133,9 @@ extern struct aa_perms allperms; #define xcheck_labels_profiles(L1, L2, FN, args...) \ xcheck_ns_labels((L1), (L2), xcheck_ns_profile_label, (FN), args) +#define xcheck_labels(L1, L2, P, FN1, FN2) \ + xcheck(fn_for_each((L1), (P), (FN1)), fn_for_each((L2), (P), (FN2))) + void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 7ca0032e7ba96..b40678f3c1d5a 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -64,40 +64,48 @@ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) FLAGS_NONE, GFP_ATOMIC); } +/* assumes check for PROFILE_MEDIATES is already done */ /* TODO: conditionals */ static int profile_ptrace_perm(struct aa_profile *profile, - struct aa_profile *peer, u32 request, - struct common_audit_data *sa) + struct aa_label *peer, u32 request, + struct common_audit_data *sa) { struct aa_perms perms = { }; - /* need because of peer in cross check */ - if (profile_unconfined(profile) || - !PROFILE_MEDIATES(profile, AA_CLASS_PTRACE)) - return 0; - - aad(sa)->peer = &peer->label; - aa_profile_match_label(profile, &peer->label, AA_CLASS_PTRACE, request, + aad(sa)->peer = peer; + aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, &perms); aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); } -static int cross_ptrace_perm(struct aa_profile *tracer, - struct aa_profile *tracee, u32 request, - struct common_audit_data *sa) +static int profile_tracee_perm(struct aa_profile *tracee, + struct aa_label *tracer, u32 request, + struct common_audit_data *sa) { + if (profile_unconfined(tracee) || unconfined(tracer) || + !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) + return 0; + + return profile_ptrace_perm(tracee, tracer, request, sa); +} + +static int profile_tracer_perm(struct aa_profile *tracer, + struct aa_label *tracee, u32 request, + struct common_audit_data *sa) +{ + if (profile_unconfined(tracer)) + return 0; + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) - return xcheck(profile_ptrace_perm(tracer, tracee, request, sa), - profile_ptrace_perm(tracee, tracer, - request << PTRACE_PERM_SHIFT, - sa)); - /* policy uses the old style capability check for ptrace */ - if (profile_unconfined(tracer) || tracer == tracee) + return profile_ptrace_perm(tracer, tracee, request, sa); + + /* profile uses the old style capability check for ptrace */ + if (&tracer->label == tracee) return 0; aad(sa)->label = &tracer->label; - aad(sa)->peer = &tracee->label; + aad(sa)->peer = tracee; aad(sa)->request = 0; aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); @@ -115,10 +123,13 @@ static int cross_ptrace_perm(struct aa_profile *tracer, int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, u32 request) { + struct aa_profile *profile; + u32 xrequest = request << PTRACE_PERM_SHIFT; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - return xcheck_labels_profiles(tracer, tracee, cross_ptrace_perm, - request, &sa); + return xcheck_labels(tracer, tracee, profile, + profile_tracer_perm(profile, tracee, request, &sa), + profile_tracee_perm(profile, tracer, xrequest, &sa)); } diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 82a64b58041d2..e395137ecff15 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -330,6 +330,9 @@ static int match_mnt_path_str(struct aa_profile *profile, AA_BUG(!mntpath); AA_BUG(!buffer); + if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + return 0; + error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, &mntpnt, &info, profile->disconnected); if (error) @@ -381,6 +384,9 @@ static int match_mnt(struct aa_profile *profile, const struct path *path, AA_BUG(!profile); AA_BUG(devpath && !devbuffer); + if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + return 0; + if (devpath) { error = aa_path_name(devpath, path_flags(profile, devpath), devbuffer, &devname, &info, @@ -559,6 +565,9 @@ static int profile_umount(struct aa_profile *profile, struct path *path, AA_BUG(!profile); AA_BUG(!path); + if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) + return 0; + error = aa_path_name(path, path_flags(profile, path), buffer, &name, &info, profile->disconnected); if (error) @@ -614,7 +623,8 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, AA_BUG(!new_path); AA_BUG(!old_path); - if (profile_unconfined(profile)) + if (profile_unconfined(profile) || + !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) return aa_get_newest_label(&profile->label); error = aa_path_name(old_path, path_flags(profile, old_path), diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4243b0c3f0e4a..586b249d3b46a 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -502,7 +502,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, { struct aa_profile *p, *profile; const char *bname; - char *name; + char *name = NULL; AA_BUG(!parent); @@ -562,6 +562,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, return profile; fail: + kfree(name); aa_free_profile(profile); return NULL; } diff --git a/security/commoncap.c b/security/commoncap.c index fc46f5b852510..7b01431d1e197 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -348,21 +348,18 @@ static __u32 sansflags(__u32 m) return m & ~VFS_CAP_FLAGS_EFFECTIVE; } -static bool is_v2header(size_t size, __le32 magic) +static bool is_v2header(size_t size, const struct vfs_cap_data *cap) { - __u32 m = le32_to_cpu(magic); if (size != XATTR_CAPS_SZ_2) return false; - return sansflags(m) == VFS_CAP_REVISION_2; + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2; } -static bool is_v3header(size_t size, __le32 magic) +static bool is_v3header(size_t size, const struct vfs_cap_data *cap) { - __u32 m = le32_to_cpu(magic); - if (size != XATTR_CAPS_SZ_3) return false; - return sansflags(m) == VFS_CAP_REVISION_3; + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3; } /* @@ -405,7 +402,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, fs_ns = inode->i_sb->s_user_ns; cap = (struct vfs_cap_data *) tmpbuf; - if (is_v2header((size_t) ret, cap->magic_etc)) { + if (is_v2header((size_t) ret, cap)) { /* If this is sizeof(vfs_cap_data) then we're ok with the * on-disk value, so return that. */ if (alloc) @@ -413,7 +410,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, else kfree(tmpbuf); return ret; - } else if (!is_v3header((size_t) ret, cap->magic_etc)) { + } else if (!is_v3header((size_t) ret, cap)) { kfree(tmpbuf); return -EINVAL; } @@ -470,9 +467,9 @@ static kuid_t rootid_from_xattr(const void *value, size_t size, return make_kuid(task_ns, rootid); } -static bool validheader(size_t size, __le32 magic) +static bool validheader(size_t size, const struct vfs_cap_data *cap) { - return is_v2header(size, magic) || is_v3header(size, magic); + return is_v2header(size, cap) || is_v3header(size, cap); } /* @@ -495,7 +492,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) if (!*ivalue) return -EINVAL; - if (!validheader(size, cap->magic_etc)) + if (!validheader(size, cap)) return -EINVAL; if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) return -EPERM; diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 809ba70fbbbfb..7d769b948de89 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -320,6 +320,9 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) if (iint->flags & IMA_DIGSIG) return; + if (iint->ima_file_status != INTEGRITY_PASS) + return; + rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); if (rc < 0) return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2aebb7984437f..ab70a395f4903 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -51,6 +51,8 @@ static int __init hash_setup(char *str) ima_hash_algo = HASH_ALGO_SHA1; else if (strncmp(str, "md5", 3) == 0) ima_hash_algo = HASH_ALGO_MD5; + else + return 1; goto out; } @@ -60,6 +62,8 @@ static int __init hash_setup(char *str) break; } } + if (i == HASH_ALGO__LAST) + return 1; out: hash_setup_done = 1; return 1; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 76d22f726ae49..1ffe60bb2845f 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1588,9 +1588,8 @@ long keyctl_session_to_parent(void) * The caller must have Setattr permission to change keyring restrictions. * * The requested type name may be a NULL pointer to reject all attempts - * to link to the keyring. If _type is non-NULL, _restriction can be - * NULL or a pointer to a string describing the restriction. If _type is - * NULL, _restriction must also be NULL. + * to link to the keyring. In this case, _restriction must also be NULL. + * Otherwise, both _type and _restriction must be non-NULL. * * Returns 0 if successful. */ @@ -1598,7 +1597,6 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, const char __user *_restriction) { key_ref_t key_ref; - bool link_reject = !_type; char type[32]; char *restriction = NULL; long ret; @@ -1607,31 +1605,29 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, if (IS_ERR(key_ref)) return PTR_ERR(key_ref); + ret = -EINVAL; if (_type) { - ret = key_get_type_from_user(type, _type, sizeof(type)); - if (ret < 0) + if (!_restriction) goto error; - } - if (_restriction) { - if (!_type) { - ret = -EINVAL; + ret = key_get_type_from_user(type, _type, sizeof(type)); + if (ret < 0) goto error; - } restriction = strndup_user(_restriction, PAGE_SIZE); if (IS_ERR(restriction)) { ret = PTR_ERR(restriction); goto error; } + } else { + if (_restriction) + goto error; } - ret = keyring_restrict(key_ref, link_reject ? NULL : type, restriction); + ret = keyring_restrict(key_ref, _type ? type : NULL, restriction); kfree(restriction); - error: key_ref_put(key_ref); - return ret; } diff --git a/security/keys/request_key.c b/security/keys/request_key.c index e8036cd0ad543..7dc7413821542 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -251,11 +251,12 @@ static int construct_key(struct key *key, const void *callout_info, * The keyring selected is returned with an extra reference upon it which the * caller must release. */ -static void construct_get_dest_keyring(struct key **_dest_keyring) +static int construct_get_dest_keyring(struct key **_dest_keyring) { struct request_key_auth *rka; const struct cred *cred = current_cred(); struct key *dest_keyring = *_dest_keyring, *authkey; + int ret; kenter("%p", dest_keyring); @@ -264,6 +265,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) /* the caller supplied one */ key_get(dest_keyring); } else { + bool do_perm_check = true; + /* use a default keyring; falling through the cases until we * find one that we actually have */ switch (cred->jit_keyring) { @@ -278,8 +281,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) dest_keyring = key_get(rka->dest_keyring); up_read(&authkey->sem); - if (dest_keyring) + if (dest_keyring) { + do_perm_check = false; break; + } } case KEY_REQKEY_DEFL_THREAD_KEYRING: @@ -314,11 +319,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) default: BUG(); } + + /* + * Require Write permission on the keyring. This is essential + * because the default keyring may be the session keyring, and + * joining a keyring only requires Search permission. + * + * However, this check is skipped for the "requestor keyring" so + * that /sbin/request-key can itself use request_key() to add + * keys to the original requestor's destination keyring. + */ + if (dest_keyring && do_perm_check) { + ret = key_permission(make_key_ref(dest_keyring, 1), + KEY_NEED_WRITE); + if (ret) { + key_put(dest_keyring); + return ret; + } + } } *_dest_keyring = dest_keyring; kleave(" [dk %d]", key_serial(dest_keyring)); - return; + return 0; } /* @@ -444,11 +467,15 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, if (ctx->index_key.type == &key_type_keyring) return ERR_PTR(-EPERM); - user = key_user_lookup(current_fsuid()); - if (!user) - return ERR_PTR(-ENOMEM); + ret = construct_get_dest_keyring(&dest_keyring); + if (ret) + goto error; - construct_get_dest_keyring(&dest_keyring); + user = key_user_lookup(current_fsuid()); + if (!user) { + ret = -ENOMEM; + goto error_put_dest_keyring; + } ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); key_user_put(user); @@ -463,7 +490,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, } else if (ret == -EINPROGRESS) { ret = 0; } else { - goto couldnt_alloc_key; + goto error_put_dest_keyring; } key_put(dest_keyring); @@ -473,8 +500,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); -couldnt_alloc_key: +error_put_dest_keyring: key_put(dest_keyring); +error: kleave(" = %d", ret); return ERR_PTR(ret); } diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e49f448ee04f4..c2db7e905f7d6 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -455,7 +455,6 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, v = snd_pcm_hw_param_last(pcm, params, var, dir); else v = snd_pcm_hw_param_first(pcm, params, var, dir); - snd_BUG_ON(v < 0); return v; } @@ -1335,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; - mutex_lock(&runtime->oss.params_lock); while (bytes > 0) { + if (mutex_lock_interruptible(&runtime->oss.params_lock)) { + tmp = -ERESTARTSYS; + break; + } if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) @@ -1380,14 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha xfer += tmp; if ((substream->f_flags & O_NONBLOCK) != 0 && tmp != runtime->oss.period_bytes) - break; + tmp = -EAGAIN; } - } - mutex_unlock(&runtime->oss.params_lock); - return xfer; - err: - mutex_unlock(&runtime->oss.params_lock); + mutex_unlock(&runtime->oss.params_lock); + if (tmp < 0) + break; + if (signal_pending(current)) { + tmp = -ERESTARTSYS; + break; + } + tmp = 0; + } return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } @@ -1435,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; - mutex_lock(&runtime->oss.params_lock); while (bytes > 0) { + if (mutex_lock_interruptible(&runtime->oss.params_lock)) { + tmp = -ERESTARTSYS; + break; + } if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); @@ -1467,12 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use bytes -= tmp; xfer += tmp; } - } - mutex_unlock(&runtime->oss.params_lock); - return xfer; - err: - mutex_unlock(&runtime->oss.params_lock); + mutex_unlock(&runtime->oss.params_lock); + if (tmp < 0) + break; + if (signal_pending(current)) { + tmp = -ERESTARTSYS; + break; + } + tmp = 0; + } return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index cadc937928683..85a56af104bd6 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -592,18 +592,26 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st snd_pcm_sframes_t frames = size; plugin = snd_pcm_plug_first(plug); - while (plugin && frames > 0) { + while (plugin) { + if (frames <= 0) + return frames; if ((next = plugin->next) != NULL) { snd_pcm_sframes_t frames1 = frames; - if (plugin->dst_frames) + if (plugin->dst_frames) { frames1 = plugin->dst_frames(plugin, frames); + if (frames1 <= 0) + return frames1; + } if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { return err; } if (err != frames1) { frames = err; - if (plugin->src_frames) + if (plugin->src_frames) { frames = plugin->src_frames(plugin, frames1); + if (frames <= 0) + return frames; + } } } else dst_channels = NULL; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7eadb7fd80747..7fea724d093af 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -153,7 +153,9 @@ static int snd_pcm_control_ioctl(struct snd_card *card, err = -ENXIO; goto _error; } + mutex_lock(&pcm->open_mutex); err = snd_pcm_info_user(substream, info); + mutex_unlock(&pcm->open_mutex); _error: mutex_unlock(®ister_mutex); return err; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a93a4235a3328..faa67861cbc17 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -248,8 +248,10 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream, runtime->rate); *audio_tstamp = ns_to_timespec(audio_nsecs); } - runtime->status->audio_tstamp = *audio_tstamp; - runtime->status->tstamp = *curr_tstamp; + if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) { + runtime->status->audio_tstamp = *audio_tstamp; + runtime->status->tstamp = *curr_tstamp; + } /* * re-take a driver timestamp to let apps detect if the reference tstamp @@ -558,7 +560,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, { u_int64_t n = (u_int64_t) a * b; if (c == 0) { - snd_BUG_ON(!n); *r = 0; return UINT_MAX; } @@ -1630,7 +1631,7 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); - if (snd_BUG_ON(err < 0)) + if (err < 0) return err; } return snd_pcm_hw_param_value(params, var, dir); @@ -1676,7 +1677,7 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, return changed; if (params->rmask) { int err = snd_pcm_hw_refine(pcm, params); - if (snd_BUG_ON(err < 0)) + if (err < 0) return err; } return snd_pcm_hw_param_value(params, var, dir); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2fec2feac387d..499f75b18e096 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2582,7 +2582,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, return ret < 0 ? ret : frames; } -/* decrease the appl_ptr; returns the processed frames or a negative error */ +/* decrease the appl_ptr; returns the processed frames or zero for error */ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames, snd_pcm_sframes_t avail) @@ -2599,7 +2599,12 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, if (appl_ptr < 0) appl_ptr += runtime->boundary; ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); - return ret < 0 ? ret : frames; + /* NOTE: we return zero for errors because PulseAudio gets depressed + * upon receiving an error from rewind ioctl and stops processing + * any longer. Returning zero means that no rewind is done, so + * it's not absolutely wrong to answer like that. + */ + return ret < 0 ? 0 : frames; } static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index b3b353d725272..f055ca10bbc1d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -579,15 +579,14 @@ static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream, return 0; } -int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) +static int __snd_rawmidi_info_select(struct snd_card *card, + struct snd_rawmidi_info *info) { struct snd_rawmidi *rmidi; struct snd_rawmidi_str *pstr; struct snd_rawmidi_substream *substream; - mutex_lock(®ister_mutex); rmidi = snd_rawmidi_search(card, info->device); - mutex_unlock(®ister_mutex); if (!rmidi) return -ENXIO; if (info->stream < 0 || info->stream > 1) @@ -603,6 +602,16 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info } return -ENXIO; } + +int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) +{ + int ret; + + mutex_lock(®ister_mutex); + ret = __snd_rawmidi_info_select(card, info); + mutex_unlock(®ister_mutex); + return ret; +} EXPORT_SYMBOL(snd_rawmidi_info_select); static int snd_rawmidi_info_select_user(struct snd_card *card, diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index d10c780dfd546..ac30fc1ab98bf 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -221,6 +221,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) rwlock_init(&client->ports_lock); mutex_init(&client->ports_mutex); INIT_LIST_HEAD(&client->ports_list_head); + mutex_init(&client->ioctl_mutex); /* find free slot in the client table */ spin_lock_irqsave(&clients_lock, flags); @@ -2126,7 +2127,9 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, return -EFAULT; } + mutex_lock(&client->ioctl_mutex); err = handler->func(client, &buf); + mutex_unlock(&client->ioctl_mutex); if (err >= 0) { /* Some commands includes a bug in 'dir' field. */ if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT || diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index c6614254ef8af..0611e1e0ed5ba 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -61,6 +61,7 @@ struct snd_seq_client { struct list_head ports_list_head; rwlock_t ports_lock; struct mutex ports_mutex; + struct mutex ioctl_mutex; int convert32; /* convert 32->64bit */ /* output pool */ diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 37d9cfbc29f9c..b80985fbc334c 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -355,7 +355,7 @@ static int initialize_timer(struct snd_seq_timer *tmr) unsigned long freq; t = tmr->timeri->timer; - if (snd_BUG_ON(!t)) + if (!t) return -EINVAL; freq = tmr->preferred_resolution; diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 59127b6ef39ee..e00f7e399e462 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -66,11 +66,11 @@ static int snd_timer_user_info_compat(struct file *file, struct snd_timer *t; tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; + if (!tu->timeri) + return -EBADFD; t = tu->timeri->timer; - if (snd_BUG_ON(!t)) - return -ENXIO; + if (!t) + return -EBADFD; memset(&info, 0, sizeof(info)); info.card = t->card ? t->card->number : -1; if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) @@ -99,8 +99,8 @@ static int snd_timer_user_status_compat(struct file *file, struct snd_timer_status32 status; tu = file->private_data; - if (snd_BUG_ON(!tu->timeri)) - return -ENXIO; + if (!tu->timeri) + return -EBADFD; memset(&status, 0, sizeof(status)); status.tstamp.tv_sec = tu->tstamp.tv_sec; status.tstamp.tv_nsec = tu->tstamp.tv_nsec; diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index e43af18d43836..8632301489fa6 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -495,7 +495,9 @@ EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); * Returns 0 if successful, or a negative error code. */ int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, - int (*func)(struct snd_kcontrol *, void *), + int (*func)(struct snd_kcontrol *vslave, + struct snd_kcontrol *slave, + void *arg), void *arg) { struct link_master *master; @@ -507,7 +509,7 @@ int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, if (err < 0) return err; list_for_each_entry(slave, &master->slaves, list) { - err = func(&slave->slave, arg); + err = func(slave->kctl, &slave->slave, arg); if (err < 0) return err; } diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 135adb17703cc..386ee829c6555 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -305,19 +306,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static void params_change_substream(struct loopback_pcm *dpcm, - struct snd_pcm_runtime *runtime) -{ - struct snd_pcm_runtime *dst_runtime; - - if (dpcm == NULL || dpcm->substream == NULL) - return; - dst_runtime = dpcm->substream->runtime; - if (dst_runtime == NULL) - return; - dst_runtime->hw = dpcm->cable->hw; -} - static void params_change(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -329,10 +317,6 @@ static void params_change(struct snd_pcm_substream *substream) cable->hw.rate_max = runtime->rate; cable->hw.channels_min = runtime->channels; cable->hw.channels_max = runtime->channels; - params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], - runtime); - params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], - runtime); } static int loopback_prepare(struct snd_pcm_substream *substream) @@ -620,26 +604,29 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream) static int rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct loopback_pcm *dpcm = rule->private; + struct loopback_cable *cable = dpcm->cable; + struct snd_mask m; - struct snd_pcm_hardware *hw = rule->private; - struct snd_mask *maskp = hw_param_mask(params, rule->var); - - maskp->bits[0] &= (u_int32_t)hw->formats; - maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); - memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ - if (! maskp->bits[0] && ! maskp->bits[1]) - return -EINVAL; - return 0; + snd_mask_none(&m); + mutex_lock(&dpcm->loopback->cable_lock); + m.bits[0] = (u_int32_t)cable->hw.formats; + m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); + mutex_unlock(&dpcm->loopback->cable_lock); + return snd_mask_refine(hw_param_mask(params, rule->var), &m); } static int rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { - struct snd_pcm_hardware *hw = rule->private; + struct loopback_pcm *dpcm = rule->private; + struct loopback_cable *cable = dpcm->cable; struct snd_interval t; - t.min = hw->rate_min; - t.max = hw->rate_max; + mutex_lock(&dpcm->loopback->cable_lock); + t.min = cable->hw.rate_min; + t.max = cable->hw.rate_max; + mutex_unlock(&dpcm->loopback->cable_lock); t.openmin = t.openmax = 0; t.integer = 0; return snd_interval_refine(hw_param_interval(params, rule->var), &t); @@ -648,22 +635,44 @@ static int rule_rate(struct snd_pcm_hw_params *params, static int rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { - struct snd_pcm_hardware *hw = rule->private; + struct loopback_pcm *dpcm = rule->private; + struct loopback_cable *cable = dpcm->cable; struct snd_interval t; - t.min = hw->channels_min; - t.max = hw->channels_max; + mutex_lock(&dpcm->loopback->cable_lock); + t.min = cable->hw.channels_min; + t.max = cable->hw.channels_max; + mutex_unlock(&dpcm->loopback->cable_lock); t.openmin = t.openmax = 0; t.integer = 0; return snd_interval_refine(hw_param_interval(params, rule->var), &t); } +static void free_cable(struct snd_pcm_substream *substream) +{ + struct loopback *loopback = substream->private_data; + int dev = get_cable_index(substream); + struct loopback_cable *cable; + + cable = loopback->cables[substream->number][dev]; + if (!cable) + return; + if (cable->streams[!substream->stream]) { + /* other stream is still alive */ + cable->streams[substream->stream] = NULL; + } else { + /* free the cable */ + loopback->cables[substream->number][dev] = NULL; + kfree(cable); + } +} + static int loopback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct loopback *loopback = substream->private_data; struct loopback_pcm *dpcm; - struct loopback_cable *cable; + struct loopback_cable *cable = NULL; int err = 0; int dev = get_cable_index(substream); @@ -682,7 +691,6 @@ static int loopback_open(struct snd_pcm_substream *substream) if (!cable) { cable = kzalloc(sizeof(*cable), GFP_KERNEL); if (!cable) { - kfree(dpcm); err = -ENOMEM; goto unlock; } @@ -700,19 +708,19 @@ static int loopback_open(struct snd_pcm_substream *substream) /* are cached -> they do not reflect the actual state */ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, - rule_format, &runtime->hw, + rule_format, dpcm, SNDRV_PCM_HW_PARAM_FORMAT, -1); if (err < 0) goto unlock; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - rule_rate, &runtime->hw, + rule_rate, dpcm, SNDRV_PCM_HW_PARAM_RATE, -1); if (err < 0) goto unlock; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - rule_channels, &runtime->hw, + rule_channels, dpcm, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (err < 0) goto unlock; @@ -724,6 +732,10 @@ static int loopback_open(struct snd_pcm_substream *substream) else runtime->hw = cable->hw; unlock: + if (err < 0) { + free_cable(substream); + kfree(dpcm); + } mutex_unlock(&loopback->cable_lock); return err; } @@ -732,20 +744,10 @@ static int loopback_close(struct snd_pcm_substream *substream) { struct loopback *loopback = substream->private_data; struct loopback_pcm *dpcm = substream->runtime->private_data; - struct loopback_cable *cable; - int dev = get_cable_index(substream); loopback_timer_stop(dpcm); mutex_lock(&loopback->cable_lock); - cable = loopback->cables[substream->number][dev]; - if (cable->streams[!substream->stream]) { - /* other stream is still alive */ - cable->streams[substream->stream] = NULL; - } else { - /* free the cable */ - loopback->cables[substream->number][dev] = NULL; - kfree(cable); - } + free_cable(substream); mutex_unlock(&loopback->cable_lock); return 0; } diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 038a180d3f811..cbe818eda3363 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -325,7 +325,7 @@ static int hdac_component_master_match(struct device *dev, void *data) */ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops) { - if (WARN_ON(!hdac_acomp)) + if (!hdac_acomp) return -ENODEV; hdac_acomp->audio_ops = aops; diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 81acc20c25358..f21633cd9b38e 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -746,7 +746,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, memset(pcm_chmap, 0, sizeof(pcm_chmap)); chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap); - for (i = 0; i < sizeof(chmap); i++) + for (i = 0; i < ARRAY_SIZE(pcm_chmap); i++) ucontrol->value.integer.value[i] = pcm_chmap[i]; return 0; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a0989d231fd00..417abbb1f72ca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1823,7 +1823,9 @@ struct slave_init_arg { }; /* initialize the slave volume with 0dB via snd_ctl_apply_vmaster_slaves() */ -static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) +static int init_slave_0dB(struct snd_kcontrol *slave, + struct snd_kcontrol *kctl, + void *_arg) { struct slave_init_arg *arg = _arg; int _tlv[4]; @@ -1860,7 +1862,7 @@ static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) arg->step = step; val = -tlv[2] / step; if (val > 0) { - put_kctl_with_value(kctl, val); + put_kctl_with_value(slave, val); return val; } @@ -1868,7 +1870,9 @@ static int init_slave_0dB(struct snd_kcontrol *kctl, void *_arg) } /* unmute the slave via snd_ctl_apply_vmaster_slaves() */ -static int init_slave_unmute(struct snd_kcontrol *slave, void *_arg) +static int init_slave_unmute(struct snd_kcontrol *slave, + struct snd_kcontrol *kctl, + void *_arg) { return put_kctl_with_value(slave, 1); } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f958d8d54d159..c71dcacea807b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2463,6 +2463,9 @@ static const struct pci_device_id azx_ids[] = { /* AMD Hudson */ { PCI_DEVICE(0x1022, 0x780d), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, + /* AMD Raven */ + { PCI_DEVICE(0x1022, 0x15e3), + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* ATI HDMI */ { PCI_DEVICE(0x1002, 0x0002), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 80bbadc837214..d6e079f4ec09d 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -408,6 +408,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ /* codec SSID */ + SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index a81aacf684b26..37e1cf8218ff0 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -271,6 +271,8 @@ enum { CXT_FIXUP_HP_SPECTRE, CXT_FIXUP_HP_GATE_MIC, CXT_FIXUP_MUTE_LED_GPIO, + CXT_FIXUP_HEADSET_MIC, + CXT_FIXUP_HP_MIC_NO_PRESENCE, }; /* for hda_fixup_thinkpad_acpi() */ @@ -350,6 +352,18 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec, } } +static void cxt_fixup_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct conexant_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + break; + } +} + /* OPLC XO 1.5 fixup */ /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) @@ -880,6 +894,19 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_mute_led_gpio, }, + [CXT_FIXUP_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_headset_mic, + }, + [CXT_FIXUP_HP_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02a1113c }, + { } + }, + .chained = true, + .chain_id = CXT_FIXUP_HEADSET_MIC, + }, }; static const struct snd_pci_quirk cxt5045_fixups[] = { @@ -934,6 +961,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index c19c81d230bd7..b4f1b6e883054 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -55,10 +55,11 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b) #define is_geminilake(codec) (((codec)->core.vendor_id == 0x8086280d) || \ ((codec)->core.vendor_id == 0x80862800)) +#define is_cannonlake(codec) ((codec)->core.vendor_id == 0x8086280c) #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ || is_skylake(codec) || is_broxton(codec) \ - || is_kabylake(codec)) || is_geminilake(codec) - + || is_kabylake(codec)) || is_geminilake(codec) \ + || is_cannonlake(codec) #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) #define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) @@ -3841,6 +3842,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi), HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi), HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi), HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi), +HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dce0682c50019..145e92d6ca94a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -324,23 +324,29 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0292: alc_update_coef_idx(codec, 0x4, 1<<15, 0); break; - case 0x10ec0215: case 0x10ec0225: + case 0x10ec0295: + case 0x10ec0299: + alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + /* fallthrough */ + case 0x10ec0215: case 0x10ec0233: case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: + case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: case 0x10ec0286: case 0x10ec0288: case 0x10ec0285: - case 0x10ec0295: case 0x10ec0298: case 0x10ec0289: - case 0x10ec0299: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; + case 0x10ec0275: + alc_update_coef_idx(codec, 0xe, 0, 1<<0); + break; case 0x10ec0293: alc_update_coef_idx(codec, 0xa, 1<<13, 0); break; @@ -2746,6 +2752,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC257, ALC269_TYPE_ALC215, ALC269_TYPE_ALC225, ALC269_TYPE_ALC294, @@ -2779,6 +2786,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC257: case ALC269_TYPE_ALC215: case ALC269_TYPE_ALC225: case ALC269_TYPE_ALC294: @@ -5156,6 +5164,22 @@ static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec, } } +/* Forcibly assign NID 0x03 to HP/LO while NID 0x02 to SPK for EQ */ +static void alc274_fixup_bind_dacs(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static hda_nid_t preferred_pairs[] = { + 0x21, 0x03, 0x1b, 0x03, 0x16, 0x02, + 0 + }; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + spec->gen.preferred_dacs = preferred_pairs; +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -5273,6 +5297,8 @@ enum { ALC233_FIXUP_LENOVO_MULTI_CODECS, ALC294_FIXUP_LENOVO_MIC_LOCATION, ALC700_FIXUP_INTEL_REFERENCE, + ALC274_FIXUP_DELL_BIND_DACS, + ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, }; static const struct hda_fixup alc269_fixups[] = { @@ -6083,6 +6109,21 @@ static const struct hda_fixup alc269_fixups[] = { {} } }, + [ALC274_FIXUP_DELL_BIND_DACS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc274_fixup_bind_dacs, + .chained = true, + .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE + }, + [ALC274_FIXUP_DELL_AIO_LINEOUT_VERB] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x0401102f }, + { } + }, + .chained = true, + .chain_id = ALC274_FIXUP_DELL_BIND_DACS + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -6132,6 +6173,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), + SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -6266,6 +6308,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), + SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), @@ -6518,6 +6561,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x1b, 0x01011020}, {0x21, 0x02211010}), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, {0x14, 0x90170120}, @@ -6544,7 +6592,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x14, 0x90170110}, {0x1b, 0x90a70130}, {0x21, 0x03211020}), - SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, {0x12, 0xb7a60130}, {0x13, 0xb8a61140}, {0x16, 0x90170110}, @@ -6836,6 +6884,10 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0257: + spec->codec_variant = ALC269_TYPE_ALC257; + spec->gen.mixer_nid = 0; + break; case 0x10ec0215: case 0x10ec0285: case 0x10ec0289: @@ -6863,7 +6915,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0703: spec->codec_variant = ALC269_TYPE_ALC700; spec->gen.mixer_nid = 0; /* ALC700 does not have any loopback mixer path */ - alc_update_coef_idx(codec, 0x4a, 0, 1 << 15); /* Combo jack auto trigger control */ + alc_update_coef_idx(codec, 0x4a, 1 << 15, 0); /* Combo jack auto trigger control */ break; } @@ -7883,6 +7935,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index b2d42ec1dcd9f..56564ce90cb6b 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -2520,7 +2520,7 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec) } if (da7218->dev_id == DA7218_DEV_ID) { - hpldet_np = of_find_node_by_name(np, "da7218_hpldet"); + hpldet_np = of_get_child_by_name(np, "da7218_hpldet"); if (!hpldet_np) return pdata; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 549c269acc7df..8c7063e1aa46a 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -104,7 +104,7 @@ #define CDC_A_MICB_1_VAL (0xf141) #define MICB_MIN_VAL 1600 #define MICB_STEP_SIZE 50 -#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE) +#define MICB_VOLTAGE_REGVAL(v) (((v - MICB_MIN_VAL)/MICB_STEP_SIZE) << 3) #define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3) #define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3) #define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3) @@ -267,7 +267,7 @@ #define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) #define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) + SNDRV_PCM_FMTBIT_S32_LE) static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4; @@ -349,8 +349,9 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); if (wcd->micbias_mv) { - snd_soc_write(codec, CDC_A_MICB_1_VAL, - MICB_VOLTAGE_REGVAL(wcd->micbias_mv)); + snd_soc_update_bits(codec, CDC_A_MICB_1_VAL, + MICB_1_VAL_MICB_OUT_VAL_MASK, + MICB_VOLTAGE_REGVAL(wcd->micbias_mv)); /* * Special headset needs MICBIAS as 2.7V so wait for * 50 msec for the MICBIAS to reach 2.7 volts. @@ -1241,6 +1242,8 @@ static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { { } }; +MODULE_DEVICE_TABLE(of, pm8916_wcd_analog_spmi_match_table); + static struct platform_driver pm8916_wcd_analog_spmi_driver = { .driver = { .name = "qcom,pm8916-wcd-spmi-codec", diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 66df8f810f0d7..694db27b11fa5 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -194,7 +194,7 @@ SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_48000) #define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) + SNDRV_PCM_FMTBIT_S32_LE) struct msm8916_wcd_digital_priv { struct clk *ahbclk, *mclk; @@ -645,7 +645,7 @@ static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, RX_I2S_CTL_RX_I2S_MODE_MASK, RX_I2S_CTL_RX_I2S_MODE_16); break; - case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, TX_I2S_CTL_TX_I2S_MODE_MASK, TX_I2S_CTL_TX_I2S_MODE_32); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 730fb20588699..1ff3edb7bbb6b 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -116,7 +116,7 @@ struct aic31xx_pdata { /* INT2 interrupt control */ #define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) /* GPIO1 control */ -#define AIC31XX_GPIO1 AIC31XX_REG(0, 50) +#define AIC31XX_GPIO1 AIC31XX_REG(0, 51) #define AIC31XX_DACPRB AIC31XX_REG(0, 60) /* ADC Instruction Set Register */ diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c482b2e7a7d2a..cfe72b9d43560 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -232,7 +232,7 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec) struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev); struct device_node *twl4030_codec_node = NULL; - twl4030_codec_node = of_find_node_by_name(codec->dev->parent->of_node, + twl4030_codec_node = of_get_child_by_name(codec->dev->parent->of_node, "codec"); if (!pdata && twl4030_codec_node) { @@ -241,9 +241,11 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec) GFP_KERNEL); if (!pdata) { dev_err(codec->dev, "Can not allocate memory\n"); + of_node_put(twl4030_codec_node); return NULL; } twl4030_setup_pdata_of(pdata, twl4030_codec_node); + of_node_put(twl4030_codec_node); } return pdata; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 65c059b5ffd78..66e32f5d2917f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1733,7 +1733,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) le64_to_cpu(footer->timestamp)); while (pos < firmware->size && - pos - firmware->size > sizeof(*region)) { + sizeof(*region) < firmware->size - pos) { region = (void *)&(firmware->data[pos]); region_name = "Unknown"; reg = 0; @@ -1782,8 +1782,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) regions, le32_to_cpu(region->len), offset, region_name); - if ((pos + le32_to_cpu(region->len) + sizeof(*region)) > - firmware->size) { + if (le32_to_cpu(region->len) > + firmware->size - pos - sizeof(*region)) { adsp_err(dsp, "%s.%d: %s region len %d bytes exceeds file length %zu\n", file, regions, region_name, @@ -2253,7 +2253,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) blocks = 0; while (pos < firmware->size && - pos - firmware->size > sizeof(*blk)) { + sizeof(*blk) < firmware->size - pos) { blk = (void *)(&firmware->data[pos]); type = le16_to_cpu(blk->type); @@ -2327,8 +2327,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) } if (reg) { - if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) > - firmware->size) { + if (le32_to_cpu(blk->len) > + firmware->size - pos - sizeof(*blk)) { adsp_err(dsp, "%s.%d: %s region len %d bytes exceeds file length %zu\n", file, blocks, region_name, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 64598d1183f8f..3ffbb498cc702 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1452,12 +1452,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) sizeof(fsl_ssi_ac97_dai)); fsl_ac97_data = ssi_private; - - ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); - if (ret) { - dev_err(&pdev->dev, "could not set AC'97 ops\n"); - return ret; - } } else { /* Initialize this copy of the CPU DAI driver structure */ memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, @@ -1568,6 +1562,14 @@ static int fsl_ssi_probe(struct platform_device *pdev) return ret; } + if (fsl_ssi_is_ac97(ssi_private)) { + ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); + if (ret) { + dev_err(&pdev->dev, "could not set AC'97 ops\n"); + goto error_ac97_ops; + } + } + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_ssi_component, &ssi_private->cpu_dai_drv, 1); if (ret) { @@ -1651,6 +1653,10 @@ static int fsl_ssi_probe(struct platform_device *pdev) fsl_ssi_debugfs_remove(&ssi_private->dbg_stats); error_asoc_register: + if (fsl_ssi_is_ac97(ssi_private)) + snd_soc_set_ac97_ops(NULL); + +error_ac97_ops: if (ssi_private->soc->imx) fsl_ssi_imx_clean(pdev, ssi_private); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index 23b0f0f6ec9cb..2fc8a63722060 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -164,9 +164,11 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } + pm_runtime_get_sync(prl->dev); reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set; img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + pm_runtime_put(prl->dev); return 0; } diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 369ef7ce981c7..8ff89280d9fd4 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -251,6 +251,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, struct uuid_module *module; struct firmware stripped_fw; unsigned int safe_file; + int ret = 0; /* Get the FW pointer to derive ADSP header */ stripped_fw.data = fw->data; @@ -299,8 +300,10 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, for (i = 0; i < num_entry; i++, mod_entry++) { module = kzalloc(sizeof(*module), GFP_KERNEL); - if (!module) - return -ENOMEM; + if (!module) { + ret = -ENOMEM; + goto free_uuid_list; + } uuid_bin = (uuid_le *)mod_entry->uuid.id; memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); @@ -311,8 +314,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, size = sizeof(int) * mod_entry->instance_max_count; module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); if (!module->instance_id) { - kfree(module); - return -ENOMEM; + ret = -ENOMEM; + goto free_uuid_list; } list_add_tail(&module->list, &skl->uuid_list); @@ -323,6 +326,10 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, } return 0; + +free_uuid_list: + skl_freeup_uuid_list(skl); + return ret; } void skl_freeup_uuid_list(struct skl_sst *ctx) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index fffc07e726274..2aef7c00cca11 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -198,10 +198,15 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + u32 mods; - return rsnd_ssi_multi_slaves_runtime(io) | - 1 << rsnd_mod_id(ssi_mod) | - 1 << rsnd_mod_id(ssi_parent_mod); + mods = rsnd_ssi_multi_slaves_runtime(io) | + 1 << rsnd_mod_id(ssi_mod); + + if (ssi_parent_mod) + mods |= 1 << rsnd_mod_id(ssi_parent_mod); + + return mods; } u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index abfb710df7cbc..7a312168f8647 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -73,6 +73,7 @@ #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) +#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) struct sun8i_codec { struct device *dev; @@ -170,11 +171,11 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* clock masters */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */ - value = 0x0; /* Codec Master */ + case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */ + value = 0x1; break; - case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */ - value = 0x1; /* Codec Slave */ + case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */ + value = 0x0; break; default: return -EINVAL; @@ -199,7 +200,7 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), - value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); + !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); /* DAI format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -226,12 +227,57 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +struct sun8i_codec_clk_div { + u8 div; + u8 val; +}; + +static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { + { .div = 1, .val = 0 }, + { .div = 2, .val = 1 }, + { .div = 4, .val = 2 }, + { .div = 6, .val = 3 }, + { .div = 8, .val = 4 }, + { .div = 12, .val = 5 }, + { .div = 16, .val = 6 }, + { .div = 24, .val = 7 }, + { .div = 32, .val = 8 }, + { .div = 48, .val = 9 }, + { .div = 64, .val = 10 }, + { .div = 96, .val = 11 }, + { .div = 128, .val = 12 }, + { .div = 192, .val = 13 }, +}; + +static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, + unsigned int rate, + unsigned int word_size) +{ + unsigned long clk_rate = clk_get_rate(scodec->clk_module); + unsigned int div = clk_rate / rate / word_size / 2; + unsigned int best_val = 0, best_diff = ~0; + int i; + + for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) { + const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i]; + unsigned int diff = abs(bdiv->div - div); + + if (diff < best_diff) { + best_diff = diff; + best_val = bdiv->val; + } + } + + return best_val; +} + static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); int sample_rate; + u8 bclk_div; /* * The CPU DAI handles only a sample of 16 bits. Configure the @@ -241,6 +287,11 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); + bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, + bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 26dd5f20f1494..eb3396ffba4c4 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -43,7 +43,7 @@ static struct uac_clock_source_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_SOURCE))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) return cs; } @@ -59,8 +59,11 @@ static struct uac_clock_selector_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_SELECTOR))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) { + if (cs->bLength < 5 + cs->bNrInPins) + return NULL; return cs; + } } return NULL; @@ -75,7 +78,7 @@ static struct uac_clock_multiplier_descriptor * while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, cs, UAC2_CLOCK_MULTIPLIER))) { - if (cs->bClockID == clock_id) + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) return cs; } diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 91bc8f18791e4..75bce127d768c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -204,6 +204,10 @@ static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen) { int len = usb_string(state->chip->dev, index, buf, maxlen - 1); + + if (len < 0) + return 0; + buf[len] = 0; return len; } @@ -1469,6 +1473,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, __u8 *bmaControls; if (state->mixer->protocol == UAC_VERSION_1) { + if (hdr->bLength < 7) { + usb_audio_err(state->chip, + "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } csize = hdr->bControlSize; if (!csize) { usb_audio_dbg(state->chip, @@ -1486,6 +1496,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, } } else { struct uac2_feature_unit_descriptor *ftr = _ftr; + if (hdr->bLength < 6) { + usb_audio_err(state->chip, + "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", + unitid); + return -EINVAL; + } csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; @@ -2086,7 +2102,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, const struct usbmix_name_map *map; char **namelist; - if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) { + if (desc->bLength < 5 || !desc->bNrInPins || + desc->bLength < 5 + desc->bNrInPins) { usb_audio_err(state->chip, "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; @@ -2156,19 +2173,25 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, kctl->private_value = (unsigned long)namelist; kctl->private_free = usb_mixer_selector_elem_free; - nameid = uac_selector_unit_iSelector(desc); + /* check the static mapping table at first */ len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); - if (len) - ; - else if (nameid) - snd_usb_copy_string_desc(state, nameid, kctl->id.name, - sizeof(kctl->id.name)); - else { - len = get_term_name(state, &state->oterm, + if (!len) { + /* no mapping ? */ + /* if iSelector is given, use it */ + nameid = uac_selector_unit_iSelector(desc); + if (nameid) + len = snd_usb_copy_string_desc(state, nameid, + kctl->id.name, + sizeof(kctl->id.name)); + /* ... or pick up the terminal name at next */ + if (!len) + len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 0); + /* ... or use the fixed string "USB" as the last resort */ if (!len) strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); + /* and add the proper suffix */ if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) append_ctl_name(kctl, " Clock Source"); else if ((state->oterm.type & 0xff00) == 0x0100) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 20624320b753f..8d7db7cd4f880 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1172,10 +1172,11 @@ static bool is_marantz_denon_dac(unsigned int id) /* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch * between PCM/DOP and native DSD mode */ -static bool is_teac_50X_dac(unsigned int id) +static bool is_teac_dsd_dac(unsigned int id) { switch (id) { case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ + case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */ return true; } return false; @@ -1208,7 +1209,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, break; } mdelay(20); - } else if (is_teac_50X_dac(subs->stream->chip->usb_id)) { + } else if (is_teac_dsd_dac(subs->stream->chip->usb_id)) { /* Vendor mode switch cmd is required. */ switch (fmt->altsetting) { case 3: /* DSD mode (DSD_U32) requested */ @@ -1398,7 +1399,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, } /* TEAC devices with USB DAC functionality */ - if (is_teac_50X_dac(chip->usb_id)) { + if (is_teac_dsd_dac(chip->usb_id)) { if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; } diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index eaa3bec273c8e..4c99c57736cef 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -193,11 +193,14 @@ static void kvp_update_mem_state(int pool) for (;;) { readp = &record[records_read]; records_read += fread(readp, sizeof(struct kvp_record), - ENTRIES_PER_BLOCK * num_blocks, - filep); + ENTRIES_PER_BLOCK * num_blocks - records_read, + filep); if (ferror(filep)) { - syslog(LOG_ERR, "Failed to read file, pool: %d", pool); + syslog(LOG_ERR, + "Failed to read file, pool: %d; error: %d %s", + pool, errno, strerror(errno)); + kvp_release_lock(pool); exit(EXIT_FAILURE); } @@ -210,6 +213,7 @@ static void kvp_update_mem_state(int pool) if (record == NULL) { syslog(LOG_ERR, "malloc failed"); + kvp_release_lock(pool); exit(EXIT_FAILURE); } continue; @@ -224,15 +228,11 @@ static void kvp_update_mem_state(int pool) fclose(filep); kvp_release_lock(pool); } + static int kvp_file_init(void) { int fd; - FILE *filep; - size_t records_read; char *fname; - struct kvp_record *record; - struct kvp_record *readp; - int num_blocks; int i; int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; @@ -246,61 +246,19 @@ static int kvp_file_init(void) for (i = 0; i < KVP_POOL_COUNT; i++) { fname = kvp_file_info[i].fname; - records_read = 0; - num_blocks = 1; sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); if (fd == -1) return 1; - - filep = fopen(fname, "re"); - if (!filep) { - close(fd); - return 1; - } - - record = malloc(alloc_unit * num_blocks); - if (record == NULL) { - fclose(filep); - close(fd); - return 1; - } - for (;;) { - readp = &record[records_read]; - records_read += fread(readp, sizeof(struct kvp_record), - ENTRIES_PER_BLOCK, - filep); - - if (ferror(filep)) { - syslog(LOG_ERR, "Failed to read file, pool: %d", - i); - exit(EXIT_FAILURE); - } - - if (!feof(filep)) { - /* - * We have more data to read. - */ - num_blocks++; - record = realloc(record, alloc_unit * - num_blocks); - if (record == NULL) { - fclose(filep); - close(fd); - return 1; - } - continue; - } - break; - } kvp_file_info[i].fd = fd; - kvp_file_info[i].num_blocks = num_blocks; - kvp_file_info[i].records = record; - kvp_file_info[i].num_records = records_read; - fclose(filep); - + kvp_file_info[i].num_blocks = 1; + kvp_file_info[i].records = malloc(alloc_unit); + if (kvp_file_info[i].records == NULL) + return 1; + kvp_file_info[i].num_records = 0; + kvp_update_mem_state(i); } return 0; diff --git a/tools/include/linux/poison.h b/tools/include/linux/poison.h index 4bf6777a8a035..9fdcd3eaac3b3 100644 --- a/tools/include/linux/poison.h +++ b/tools/include/linux/poison.h @@ -15,6 +15,10 @@ # define POISON_POINTER_DELTA 0 #endif +#ifdef __cplusplus +#define LIST_POISON1 NULL +#define LIST_POISON2 NULL +#else /* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses @@ -22,6 +26,7 @@ */ #define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) #define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) +#endif /********** include/linux/timer.h **********/ /* diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore index d3102c865a95e..914cff12899b6 100644 --- a/tools/objtool/.gitignore +++ b/tools/objtool/.gitignore @@ -1,3 +1,3 @@ -arch/x86/insn/inat-tables.c +arch/x86/lib/inat-tables.c objtool fixdep diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 424b1965d06f2..e6acc281dd375 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -7,9 +7,11 @@ ARCH := x86 endif # always use the host compiler -CC = gcc -LD = ld -AR = ar +HOSTCC ?= gcc +HOSTLD ?= ld +CC = $(HOSTCC) +LD = $(HOSTLD) +AR = ar ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(CURDIR))) @@ -25,7 +27,9 @@ OBJTOOL_IN := $(OBJTOOL)-in.o all: $(OBJTOOL) -INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi +INCLUDES := -I$(srctree)/tools/include \ + -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ + -I$(srctree)/tools/objtool/arch/$(ARCH)/include WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) @@ -41,22 +45,8 @@ include $(srctree)/tools/build/Makefile.include $(OBJTOOL_IN): fixdep FORCE @$(MAKE) $(build)=objtool -# Busybox's diff doesn't have -I, avoid warning in that case -# $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) - @(diff -I 2>&1 | grep -q 'option requires an argument' && \ - test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ - diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ - diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ - diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ - diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ - diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ - diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ - diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ - || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true - @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ - diff ../../arch/x86/include/asm/orc_types.h orc_types.h >/dev/null) \ - || echo "warning: objtool: orc_types.h differs from kernel" >&2 )) || true + @$(CONFIG_SHELL) ./sync-check.sh $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ @@ -66,7 +56,7 @@ $(LIBSUBCMD): fixdep FORCE clean: $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete - $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep + $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep FORCE: diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index debbdb0b5c430..b998412c017d9 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build @@ -1,12 +1,12 @@ objtool-y += decode.o -inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk -inat_tables_maps = arch/x86/insn/x86-opcode-map.txt +inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk +inat_tables_maps = arch/x86/lib/x86-opcode-map.txt -$(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) +$(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) $(call rule_mkdir) $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ -$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c +$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/lib/inat-tables.c -CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn +CFLAGS_decode.o += -I$(OUTPUT)arch/x86/lib diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 34a579f806e39..540a209b78ab3 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -19,9 +19,9 @@ #include #define unlikely(cond) (cond) -#include "insn/insn.h" -#include "insn/inat.c" -#include "insn/insn.c" +#include +#include "lib/inat.c" +#include "lib/insn.c" #include "../../elf.h" #include "../../arch.h" @@ -138,7 +138,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, *type = INSN_STACK; op->src.type = OP_SRC_ADD; op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; - op->dest.type = OP_SRC_REG; + op->dest.type = OP_DEST_REG; op->dest.reg = CFI_SP; } break; diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/include/asm/inat.h similarity index 95% rename from tools/objtool/arch/x86/insn/inat.h rename to tools/objtool/arch/x86/include/asm/inat.h index 125ecd2a300d7..1c78580e58bea 100644 --- a/tools/objtool/arch/x86/insn/inat.h +++ b/tools/objtool/arch/x86/include/asm/inat.h @@ -20,7 +20,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -#include "inat_types.h" +#include /* * Internal bits. Don't use bitmasks directly, because these bits are @@ -97,6 +97,16 @@ #define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) #define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) +/* Identifiers for segment registers */ +#define INAT_SEG_REG_IGNORE 0 +#define INAT_SEG_REG_DEFAULT 1 +#define INAT_SEG_REG_CS 2 +#define INAT_SEG_REG_SS 3 +#define INAT_SEG_REG_DS 4 +#define INAT_SEG_REG_ES 5 +#define INAT_SEG_REG_FS 6 +#define INAT_SEG_REG_GS 7 + /* Attribute search APIs */ extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); extern int inat_get_last_prefix_id(insn_byte_t last_pfx); diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/include/asm/inat_types.h similarity index 100% rename from tools/objtool/arch/x86/insn/inat_types.h rename to tools/objtool/arch/x86/include/asm/inat_types.h diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/include/asm/insn.h similarity index 99% rename from tools/objtool/arch/x86/insn/insn.h rename to tools/objtool/arch/x86/include/asm/insn.h index e23578c7b1be9..b3e32b010ab19 100644 --- a/tools/objtool/arch/x86/insn/insn.h +++ b/tools/objtool/arch/x86/include/asm/insn.h @@ -21,7 +21,7 @@ */ /* insn_attr_t is defined in inat.h */ -#include "inat.h" +#include struct insn_field { union { diff --git a/tools/objtool/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h similarity index 100% rename from tools/objtool/orc_types.h rename to tools/objtool/arch/x86/include/asm/orc_types.h diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/lib/inat.c similarity index 99% rename from tools/objtool/arch/x86/insn/inat.c rename to tools/objtool/arch/x86/lib/inat.c index e4bf28e6f4c7a..c1f01a8e9f65e 100644 --- a/tools/objtool/arch/x86/insn/inat.c +++ b/tools/objtool/arch/x86/lib/inat.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -#include "insn.h" +#include /* Attribute tables are generated from opcode map */ #include "inat-tables.c" diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/lib/insn.c similarity index 99% rename from tools/objtool/arch/x86/insn/insn.c rename to tools/objtool/arch/x86/lib/insn.c index ca983e2bea8b2..1088eb8f3a5fe 100644 --- a/tools/objtool/arch/x86/insn/insn.c +++ b/tools/objtool/arch/x86/lib/insn.c @@ -23,8 +23,8 @@ #else #include #endif -#include "inat.h" -#include "insn.h" +#include +#include /* Verify next sizeof(t) bytes can be on the same instruction */ #define validate_next(t, insn, n) \ diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt similarity index 99% rename from tools/objtool/arch/x86/insn/x86-opcode-map.txt rename to tools/objtool/arch/x86/lib/x86-opcode-map.txt index 12e377184ee4a..e0b85930dd773 100644 --- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt +++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt @@ -607,7 +607,7 @@ fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -ff: +ff: UD0 EndTable Table: 3-byte opcode 1 (0x0f 0x38) @@ -717,7 +717,7 @@ AVXcode: 2 7e: vpermt2d/q Vx,Hx,Wx (66),(ev) 7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) 80: INVEPT Gy,Mdq (66) -81: INVPID Gy,Mdq (66) +81: INVVPID Gy,Mdq (66) 82: INVPCID Gy,Mdq (66) 83: vpmultishiftqb Vx,Hx,Wx (66),(ev) 88: vexpandps/d Vpd,Wpd (66),(ev) @@ -896,7 +896,7 @@ EndTable GrpTable: Grp3_1 0: TEST Eb,Ib -1: +1: TEST Eb,Ib 2: NOT Eb 3: NEG Eb 4: MUL AL,Eb @@ -970,6 +970,15 @@ GrpTable: Grp9 EndTable GrpTable: Grp10 +# all are UD1 +0: UD1 +1: UD1 +2: UD1 +3: UD1 +4: UD1 +5: UD1 +6: UD1 +7: UD1 EndTable # Grp11A and Grp11B are expressed as Grp11 in Intel SDM diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk similarity index 100% rename from tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk rename to tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c index 4c6b5c9ef073b..91e8e19ff5e06 100644 --- a/tools/objtool/builtin-orc.c +++ b/tools/objtool/builtin-orc.c @@ -44,6 +44,9 @@ int cmd_orc(int argc, const char **argv) const char *objname; argc--; argv++; + if (argc <= 0) + usage_with_options(orc_usage, check_options); + if (!strncmp(argv[0], "gen", 3)) { argc = parse_options(argc, argv, check_options, orc_usage, 0); if (argc != 1) @@ -52,7 +55,6 @@ int cmd_orc(int argc, const char **argv) objname = argv[0]; return check(objname, no_fp, no_unreachable, true); - } if (!strcmp(argv[0], "dump")) { diff --git a/tools/objtool/check.c b/tools/objtool/check.c index c0e26ad1fa7e3..f40d46e24bcce 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -427,6 +427,40 @@ static void add_ignores(struct objtool_file *file) } } +/* + * FIXME: For now, just ignore any alternatives which add retpolines. This is + * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. + * But it at least allows objtool to understand the control flow *around* the + * retpoline. + */ +static int add_nospec_ignores(struct objtool_file *file) +{ + struct section *sec; + struct rela *rela; + struct instruction *insn; + + sec = find_section_by_name(file->elf, ".rela.discard.nospec"); + if (!sec) + return 0; + + list_for_each_entry(rela, &sec->rela_list, list) { + if (rela->sym->type != STT_SECTION) { + WARN("unexpected relocation symbol type in %s", sec->name); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { + WARN("bad .discard.nospec entry"); + return -1; + } + + insn->ignore_alts = true; + } + + return 0; +} + /* * Find the destination instructions for all jumps. */ @@ -456,6 +490,13 @@ static int add_jump_destinations(struct objtool_file *file) } else if (rela->sym->sec->idx) { dest_sec = rela->sym->sec; dest_off = rela->sym->sym.st_value + rela->addend + 4; + } else if (strstr(rela->sym->name, "_indirect_thunk_")) { + /* + * Retpoline jumps are really dynamic jumps in + * disguise, so convert them accordingly. + */ + insn->type = INSN_JUMP_DYNAMIC; + continue; } else { /* sibling call */ insn->jump_dest = 0; @@ -502,11 +543,18 @@ static int add_call_destinations(struct objtool_file *file) dest_off = insn->offset + insn->len + insn->immediate; insn->call_dest = find_symbol_by_offset(insn->sec, dest_off); + /* + * FIXME: Thanks to retpolines, it's now considered + * normal for a function to call within itself. So + * disable this warning for now. + */ +#if 0 if (!insn->call_dest) { WARN_FUNC("can't find call dest symbol at offset 0x%lx", insn->sec, insn->offset, dest_off); return -1; } +#endif } else if (rela->sym->type == STT_SECTION) { insn->call_dest = find_symbol_by_offset(rela->sym->sec, rela->addend+4); @@ -671,12 +719,6 @@ static int add_special_section_alts(struct objtool_file *file) return ret; list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { - alt = malloc(sizeof(*alt)); - if (!alt) { - WARN("malloc failed"); - ret = -1; - goto out; - } orig_insn = find_insn(file, special_alt->orig_sec, special_alt->orig_off); @@ -687,6 +729,10 @@ static int add_special_section_alts(struct objtool_file *file) goto out; } + /* Ignore retpoline alternatives. */ + if (orig_insn->ignore_alts) + continue; + new_insn = NULL; if (!special_alt->group || special_alt->new_len) { new_insn = find_insn(file, special_alt->new_sec, @@ -712,6 +758,13 @@ static int add_special_section_alts(struct objtool_file *file) goto out; } + alt = malloc(sizeof(*alt)); + if (!alt) { + WARN("malloc failed"); + ret = -1; + goto out; + } + alt->insn = new_insn; list_add_tail(&alt->list, &orig_insn->alts); @@ -1028,6 +1081,10 @@ static int decode_sections(struct objtool_file *file) add_ignores(file); + ret = add_nospec_ignores(file); + if (ret) + return ret; + ret = add_jump_destinations(file); if (ret) return ret; @@ -1757,11 +1814,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, if (insn->dead_end) return 0; - insn = next_insn; - if (!insn) { + if (!next_insn) { + if (state.cfa.base == CFI_UNDEFINED) + return 0; WARN("%s: unexpected end of section", sec->name); return 1; } + + insn = next_insn; } return 0; diff --git a/tools/objtool/check.h b/tools/objtool/check.h index 47d9ea70a83d9..dbadb304a410a 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -44,7 +44,7 @@ struct instruction { unsigned int len; unsigned char type; unsigned long immediate; - bool alt_group, visited, dead_end, ignore, hint, save, restore; + bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; struct symbol *call_dest; struct instruction *jump_dest; struct list_head alts; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 24460155c82c9..c1c3386616997 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "elf.h" #include "warn.h" @@ -358,7 +359,8 @@ struct elf *elf_open(const char *name, int flags) elf->fd = open(name, flags); if (elf->fd == -1) { - perror("open"); + fprintf(stderr, "objtool: Can't open '%s': %s\n", + name, strerror(errno)); goto err; } diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 31e0f91438400..07f3299198284 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -70,7 +70,7 @@ static void cmd_usage(void) printf("\n"); - exit(1); + exit(129); } static void handle_options(int *argc, const char ***argv) @@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv) break; } else { fprintf(stderr, "Unknown option: %s\n", cmd); - fprintf(stderr, "\n Usage: %s\n", - objtool_usage_string); - exit(1); + cmd_usage(); } (*argv)++; diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h index a4139e386ef37..b0e92a6d0903b 100644 --- a/tools/objtool/orc.h +++ b/tools/objtool/orc.h @@ -18,7 +18,7 @@ #ifndef _ORC_H #define _ORC_H -#include "orc_types.h" +#include struct objtool_file; diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index 36c5bf6a26751..c3343820916a6 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -76,7 +76,8 @@ int orc_dump(const char *_objname) int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; struct orc_entry *orc = NULL; char *name; - unsigned long nr_sections, orc_ip_addr = 0; + size_t nr_sections; + Elf64_Addr orc_ip_addr = 0; size_t shstrtab_idx; Elf *elf; Elf_Scn *scn; @@ -187,10 +188,10 @@ int orc_dump(const char *_objname) return -1; } - printf("%s+%lx:", name, rela.r_addend); + printf("%s+%llx:", name, (unsigned long long)rela.r_addend); } else { - printf("%lx:", orc_ip_addr + (i * sizeof(int)) + orc_ip[i]); + printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i])); } diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index e5ca31429c9ba..e61fe703197ba 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -165,6 +165,8 @@ int create_orc_sections(struct objtool_file *file) /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); + if (!sec) + return -1; ip_relasec = elf_create_rela_section(file->elf, sec); if (!ip_relasec) diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh new file mode 100644 index 0000000000000..1470e74e9d661 --- /dev/null +++ b/tools/objtool/sync-check.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +FILES=' +arch/x86/lib/insn.c +arch/x86/lib/inat.c +arch/x86/lib/x86-opcode-map.txt +arch/x86/tools/gen-insn-attr-x86.awk +arch/x86/include/asm/insn.h +arch/x86/include/asm/inat.h +arch/x86/include/asm/inat_types.h +arch/x86/include/asm/orc_types.h +' + +check() +{ + local file=$1 + + diff $file ../../$file > /dev/null || + echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" +} + +if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then + exit 0 +fi + +for i in $FILES; do + check $i +done diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index fd32ad08c6d47..d00aac51130da 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2733,6 +2733,7 @@ static int perf_c2c__record(int argc, const char **argv) if (!perf_mem_events[j].supported) { pr_err("failed: event '%s' not supported\n", perf_mem_events[j].name); + free(rec_argv); return -1; } diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 4db9600852730..e15efba605f6d 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -113,6 +113,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) if (!perf_mem_events[j].supported) { pr_err("failed: event '%s' not supported\n", perf_mem_events__name(j)); + free(rec_argv); return -1; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4e2e616959863..01de01ca14f20 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1732,8 +1732,10 @@ static int timechart__io_record(int argc, const char **argv) if (rec_argv == NULL) return -ENOMEM; - if (asprintf(&filter, "common_pid != %d", getpid()) < 0) + if (asprintf(&filter, "common_pid != %d", getpid()) < 0) { + free(rec_argv); return -ENOMEM; + } p = rec_argv; for (i = 0; i < common_args_nr; i++) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d5d7fff1c211c..8e3c4ec00017d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2086,6 +2086,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv) rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit"; else { pr_err("Neither raw_syscalls nor syscalls events exist.\n"); + free(rec_argv); return -1; } } diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index c180bbcdbef60..0e1367f90af53 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -167,7 +167,7 @@ static int run_dir(const char *d, const char *perf) snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", d, d, perf, vcnt, v); - return system(cmd); + return system(cmd) ? TEST_FAIL : TEST_OK; } int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused) diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index 907b1b2f56ad4..ff9b60b99f52a 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py @@ -238,6 +238,7 @@ def compare(self, expect, result): # events in result. Fail if there's not any. for exp_name, exp_event in expect.items(): exp_list = [] + res_event = {} log.debug(" matching [%s]" % exp_name) for res_name, res_event in result.items(): log.debug(" to [%s]" % res_name) @@ -254,7 +255,10 @@ def compare(self, expect, result): if exp_event.optional(): log.debug(" %s does not match, but is optional" % exp_name) else: - exp_event.diff(res_event) + if not res_event: + log.debug(" res_event is empty"); + else: + exp_event.diff(res_event) raise Fail(self, 'match failure'); match[exp_name] = exp_list diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 12e377184ee4a..e0b85930dd773 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -607,7 +607,7 @@ fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -ff: +ff: UD0 EndTable Table: 3-byte opcode 1 (0x0f 0x38) @@ -717,7 +717,7 @@ AVXcode: 2 7e: vpermt2d/q Vx,Hx,Wx (66),(ev) 7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) 80: INVEPT Gy,Mdq (66) -81: INVPID Gy,Mdq (66) +81: INVVPID Gy,Mdq (66) 82: INVPCID Gy,Mdq (66) 83: vpmultishiftqb Vx,Hx,Wx (66),(ev) 88: vexpandps/d Vpd,Wpd (66),(ev) @@ -896,7 +896,7 @@ EndTable GrpTable: Grp3_1 0: TEST Eb,Ib -1: +1: TEST Eb,Ib 2: NOT Eb 3: NEG Eb 4: MUL AL,Eb @@ -970,6 +970,15 @@ GrpTable: Grp9 EndTable GrpTable: Grp10 +# all are UD1 +0: UD1 +1: UD1 +2: UD1 +3: UD1 +4: UD1 +5: UD1 +6: UD1 +7: UD1 EndTable # Grp11A and Grp11B are expressed as Grp11 in Intel SDM diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 64ae21f644896..16299939d3fff 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -272,6 +272,46 @@ static struct bpf_test tests[] = { .errstr = "invalid bpf_ld_imm64 insn", .result = REJECT, }, + { + "arsh32 on imm", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_ALU32_IMM(BPF_ARSH, BPF_REG_0, 5), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "BPF_ARSH not supported for 32 bit ALU", + }, + { + "arsh32 on reg", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_MOV64_IMM(BPF_REG_1, 5), + BPF_ALU32_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "BPF_ARSH not supported for 32 bit ALU", + }, + { + "arsh64 on imm", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_ALU64_IMM(BPF_ARSH, BPF_REG_0, 5), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, + { + "arsh64 on reg", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_MOV64_IMM(BPF_REG_1, 5), + BPF_ALU64_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, { "no bpf_exit", .insns = { @@ -606,7 +646,6 @@ static struct bpf_test tests[] = { }, .errstr = "misaligned stack access", .result = REJECT, - .flags = F_LOAD_WITH_STRICT_ALIGNMENT, }, { "invalid map_fd for function call", @@ -1797,7 +1836,6 @@ static struct bpf_test tests[] = { }, .result = REJECT, .errstr = "misaligned stack access off (0x0; 0x0)+-8+2 size 8", - .flags = F_LOAD_WITH_STRICT_ALIGNMENT, }, { "PTR_TO_STACK store/load - bad alignment on reg", @@ -1810,7 +1848,6 @@ static struct bpf_test tests[] = { }, .result = REJECT, .errstr = "misaligned stack access off (0x0; 0x0)+-10+8 size 8", - .flags = F_LOAD_WITH_STRICT_ALIGNMENT, }, { "PTR_TO_STACK store/load - out of bounds low", @@ -2558,6 +2595,29 @@ static struct bpf_test tests[] = { .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, + { + "context stores via ST", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0), + BPF_EXIT_INSN(), + }, + .errstr = "BPF_ST stores into R1 context is not allowed", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "context stores via XADD", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_1, + BPF_REG_0, offsetof(struct __sk_buff, mark), 0), + BPF_EXIT_INSN(), + }, + .errstr = "BPF_XADD stores into R1 context is not allowed", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, { "direct packet access: test1", .insns = { @@ -4280,7 +4340,8 @@ static struct bpf_test tests[] = { .fixup_map1 = { 2 }, .errstr_unpriv = "R2 leaks addr into mem", .result_unpriv = REJECT, - .result = ACCEPT, + .result = REJECT, + .errstr = "BPF_XADD stores into R1 context is not allowed", }, { "leak pointer into ctx 2", @@ -4294,7 +4355,8 @@ static struct bpf_test tests[] = { }, .errstr_unpriv = "R10 leaks addr into mem", .result_unpriv = REJECT, - .result = ACCEPT, + .result = REJECT, + .errstr = "BPF_XADD stores into R1 context is not allowed", }, { "leak pointer into ctx 3", @@ -6115,7 +6177,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6139,7 +6201,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6165,7 +6227,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R8 invalid mem access 'inv'", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6190,7 +6252,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R8 invalid mem access 'inv'", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6238,7 +6300,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6309,7 +6371,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6360,7 +6422,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6387,7 +6449,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6413,7 +6475,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6442,7 +6504,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6472,7 +6534,7 @@ static struct bpf_test tests[] = { BPF_JMP_IMM(BPF_JA, 0, 0, -7), }, .fixup_map1 = { 4 }, - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, }, { @@ -6500,8 +6562,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 3 }, - .errstr_unpriv = "R0 pointer comparison prohibited", - .errstr = "R0 min value is negative", + .errstr = "unbounded min value", .result = REJECT, .result_unpriv = REJECT, }, @@ -6556,6 +6617,462 @@ static struct bpf_test tests[] = { .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", .result = REJECT, }, + { + "bounds check based on zero-extended MOV", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + /* r2 = 0x0000'0000'ffff'ffff */ + BPF_MOV32_IMM(BPF_REG_2, 0xffffffff), + /* r2 = 0 */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32), + /* no-op */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), + /* access at offset 0 */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT + }, + { + "bounds check based on sign-extended MOV. test1", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + /* r2 = 0xffff'ffff'ffff'ffff */ + BPF_MOV64_IMM(BPF_REG_2, 0xffffffff), + /* r2 = 0xffff'ffff */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 32), + /* r0 = */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), + /* access to OOB pointer */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "map_value pointer and 4294967295", + .result = REJECT + }, + { + "bounds check based on sign-extended MOV. test2", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + /* r2 = 0xffff'ffff'ffff'ffff */ + BPF_MOV64_IMM(BPF_REG_2, 0xffffffff), + /* r2 = 0xfff'ffff */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 36), + /* r0 = */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_2), + /* access to OOB pointer */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "R0 min value is outside of the array range", + .result = REJECT + }, + { + "bounds check based on reg_off + var_off + insn_off. test1", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct __sk_buff, mark)), + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 29) - 1), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1), + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 4 }, + .errstr = "value_size=8 off=1073741825", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "bounds check based on reg_off + var_off + insn_off. test2", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct __sk_buff, mark)), + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 1), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, (1 << 30) - 1), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, (1 << 29) - 1), + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 3), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 4 }, + .errstr = "value 1073741823", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "bounds check after truncation of non-boundary-crossing range", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), + /* r1 = [0x00, 0xff] */ + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_2, 1), + /* r2 = 0x10'0000'0000 */ + BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 36), + /* r1 = [0x10'0000'0000, 0x10'0000'00ff] */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), + /* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), + /* r1 = [0x00, 0xff] */ + BPF_ALU32_IMM(BPF_SUB, BPF_REG_1, 0x7fffffff), + /* r1 = 0 */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), + /* no-op */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* access at offset 0 */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT + }, + { + "bounds check after truncation of boundary-crossing range (1)", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), + /* r1 = [0x00, 0xff] */ + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0xffff'ff80, 0x1'0000'007f] */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0xffff'ff80, 0xffff'ffff] or + * [0x0000'0000, 0x0000'007f] + */ + BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0x00, 0xff] or + * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff] + */ + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = 0 or + * [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff] + */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), + /* no-op or OOB pointer computation */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* potentially OOB access */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + /* not actually fully unbounded, but the bound is very high */ + .errstr = "R0 unbounded memory access", + .result = REJECT + }, + { + "bounds check after truncation of boundary-crossing range (2)", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), + /* r1 = [0x00, 0xff] */ + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0xffff'ff80, 0x1'0000'007f] */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0xffff'ff80, 0xffff'ffff] or + * [0x0000'0000, 0x0000'007f] + * difference to previous test: truncation via MOV32 + * instead of ALU32. + */ + BPF_MOV32_REG(BPF_REG_1, BPF_REG_1), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = [0x00, 0xff] or + * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff] + */ + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 0xffffff80 >> 1), + /* r1 = 0 or + * [0x00ff'ffff'ff00'0000, 0x00ff'ffff'ffff'ffff] + */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), + /* no-op or OOB pointer computation */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* potentially OOB access */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + /* not actually fully unbounded, but the bound is very high */ + .errstr = "R0 unbounded memory access", + .result = REJECT + }, + { + "bounds check after wrapping 32-bit addition", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), + /* r1 = 0x7fff'ffff */ + BPF_MOV64_IMM(BPF_REG_1, 0x7fffffff), + /* r1 = 0xffff'fffe */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), + /* r1 = 0 */ + BPF_ALU32_IMM(BPF_ADD, BPF_REG_1, 2), + /* no-op */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* access at offset 0 */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT + }, + { + "bounds check after shift with oversized count operand", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), + BPF_MOV64_IMM(BPF_REG_2, 32), + BPF_MOV64_IMM(BPF_REG_1, 1), + /* r1 = (u32)1 << (u32)32 = ? */ + BPF_ALU32_REG(BPF_LSH, BPF_REG_1, BPF_REG_2), + /* r1 = [0x0000, 0xffff] */ + BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xffff), + /* computes unknown pointer, potentially OOB */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* potentially OOB access */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "R0 max value is outside of the array range", + .result = REJECT + }, + { + "bounds check after right shift of maybe-negative number", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), + /* r1 = [0x00, 0xff] */ + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + /* r1 = [-0x01, 0xfe] */ + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1), + /* r1 = 0 or 0xff'ffff'ffff'ffff */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), + /* r1 = 0 or 0xffff'ffff'ffff */ + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 8), + /* computes unknown pointer, potentially OOB */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + /* potentially OOB access */ + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + /* exit */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "R0 unbounded memory access", + .result = REJECT + }, + { + "bounds check map access with off+size signed 32bit overflow. test1", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x7ffffffe), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), + BPF_JMP_A(0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "map_value pointer and 2147483646", + .result = REJECT + }, + { + "bounds check map access with off+size signed 32bit overflow. test2", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 0x1fffffff), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), + BPF_JMP_A(0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "pointer offset 1073741822", + .result = REJECT + }, + { + "bounds check map access with off+size signed 32bit overflow. test3", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 0x1fffffff), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2), + BPF_JMP_A(0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "pointer offset -1073741822", + .result = REJECT + }, + { + "bounds check map access with off+size signed 32bit overflow. test4", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_1, 1000000), + BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 1000000), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 2), + BPF_JMP_A(0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .errstr = "map_value pointer and 1000000000000", + .result = REJECT + }, + { + "pointer/scalar confusion in state equality check (way 1)", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), + BPF_JMP_A(1), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_10), + BPF_JMP_A(0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "R0 leaks addr as return value" + }, + { + "pointer/scalar confusion in state equality check (way 2)", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_10), + BPF_JMP_A(1), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "R0 leaks addr as return value" + }, { "variable-offset ctx access", .insns = { @@ -6597,6 +7114,71 @@ static struct bpf_test tests[] = { .result = REJECT, .prog_type = BPF_PROG_TYPE_LWT_IN, }, + { + "indirect variable-offset stack access", + .insns = { + /* Fill the top 8 bytes of the stack */ + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + /* Get an unknown value */ + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), + /* Make it small and 4-byte aligned */ + BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8), + /* add it to fp. We now have either fp-4 or fp-8, but + * we don't know which + */ + BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10), + /* dereference it indirectly */ + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 5 }, + .errstr = "variable stack read R2", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_LWT_IN, + }, + { + "direct stack access with 32-bit wraparound. test1", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x7fffffff), + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_EXIT_INSN() + }, + .errstr = "fp pointer and 2147483647", + .result = REJECT + }, + { + "direct stack access with 32-bit wraparound. test2", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x3fffffff), + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_EXIT_INSN() + }, + .errstr = "fp pointer and 1073741823", + .result = REJECT + }, + { + "direct stack access with 32-bit wraparound. test3", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0x1fffffff), + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_EXIT_INSN() + }, + .errstr = "fp pointer offset 1073741822", + .result = REJECT + }, { "liveness pruning and write screening", .insns = { diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 7b1adeee4b0f1..91fbfa8fdc150 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -7,7 +7,7 @@ include ../lib.mk TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \ - protection_keys test_vdso + protection_keys test_vdso test_vsyscall TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c index 961e3ee26c272..1aef72df20a11 100644 --- a/tools/testing/selftests/x86/ldt_gdt.c +++ b/tools/testing/selftests/x86/ldt_gdt.c @@ -115,7 +115,14 @@ static void check_valid_segment(uint16_t index, int ldt, return; } - if (ar != expected_ar) { + /* The SDM says "bits 19:16 are undefined". Thanks. */ + ar &= ~0xF0000; + + /* + * NB: Different Linux versions do different things with the + * accessed bit in set_thread_area(). + */ + if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) { printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n", (ldt ? "LDT" : "GDT"), index, ar, expected_ar); nerrs++; @@ -129,30 +136,51 @@ static void check_valid_segment(uint16_t index, int ldt, } } -static bool install_valid_mode(const struct user_desc *desc, uint32_t ar, - bool oldmode) +static bool install_valid_mode(const struct user_desc *d, uint32_t ar, + bool oldmode, bool ldt) { - int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11, - desc, sizeof(*desc)); - if (ret < -1) - errno = -ret; + struct user_desc desc = *d; + int ret; + + if (!ldt) { +#ifndef __i386__ + /* No point testing set_thread_area in a 64-bit build */ + return false; +#endif + if (!gdt_entry_num) + return false; + desc.entry_number = gdt_entry_num; + + ret = syscall(SYS_set_thread_area, &desc); + } else { + ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11, + &desc, sizeof(desc)); + + if (ret < -1) + errno = -ret; + + if (ret != 0 && errno == ENOSYS) { + printf("[OK]\tmodify_ldt returned -ENOSYS\n"); + return false; + } + } + if (ret == 0) { - uint32_t limit = desc->limit; - if (desc->limit_in_pages) + uint32_t limit = desc.limit; + if (desc.limit_in_pages) limit = (limit << 12) + 4095; - check_valid_segment(desc->entry_number, 1, ar, limit, true); + check_valid_segment(desc.entry_number, ldt, ar, limit, true); return true; - } else if (errno == ENOSYS) { - printf("[OK]\tmodify_ldt returned -ENOSYS\n"); - return false; } else { - if (desc->seg_32bit) { - printf("[FAIL]\tUnexpected modify_ldt failure %d\n", + if (desc.seg_32bit) { + printf("[FAIL]\tUnexpected %s failure %d\n", + ldt ? "modify_ldt" : "set_thread_area", errno); nerrs++; return false; } else { - printf("[OK]\tmodify_ldt rejected 16 bit segment\n"); + printf("[OK]\t%s rejected 16 bit segment\n", + ldt ? "modify_ldt" : "set_thread_area"); return false; } } @@ -160,7 +188,15 @@ static bool install_valid_mode(const struct user_desc *desc, uint32_t ar, static bool install_valid(const struct user_desc *desc, uint32_t ar) { - return install_valid_mode(desc, ar, false); + bool ret = install_valid_mode(desc, ar, false, true); + + if (desc->contents <= 1 && desc->seg_32bit && + !desc->seg_not_present) { + /* Should work in the GDT, too. */ + install_valid_mode(desc, ar, false, false); + } + + return ret; } static void install_invalid(const struct user_desc *desc, bool oldmode) @@ -367,9 +403,24 @@ static void do_simple_tests(void) install_invalid(&desc, false); desc.seg_not_present = 0; - desc.read_exec_only = 0; desc.seg_32bit = 1; + desc.read_exec_only = 0; + desc.limit = 0xfffff; + install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB); + + desc.limit_in_pages = 1; + + install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB | AR_G); + desc.read_exec_only = 1; + install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P | AR_DB | AR_G); + desc.contents = 1; + desc.read_exec_only = 0; + install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G); + desc.read_exec_only = 1; + install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G); + + desc.limit = 0; install_invalid(&desc, true); } @@ -575,13 +626,10 @@ static void do_multicpu_tests(void) static int finish_exec_test(void) { /* - * In a sensible world, this would be check_invalid_segment(0, 1); - * For better or for worse, though, the LDT is inherited across exec. - * We can probably change this safely, but for now we test it. + * Older kernel versions did inherit the LDT on exec() which is + * wrong because exec() starts from a clean state. */ - check_valid_segment(0, 1, - AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB, - 42, true); + check_invalid_segment(0, 1); return nerrs ? 1 : 0; } diff --git a/tools/testing/selftests/x86/mpx-hw.h b/tools/testing/selftests/x86/mpx-hw.h index 3f0093911f03d..d1b61ab870f8d 100644 --- a/tools/testing/selftests/x86/mpx-hw.h +++ b/tools/testing/selftests/x86/mpx-hw.h @@ -52,14 +52,14 @@ struct mpx_bd_entry { union { char x[MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES]; - void *contents[1]; + void *contents[0]; }; } __attribute__((packed)); struct mpx_bt_entry { union { char x[MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES]; - unsigned long contents[1]; + unsigned long contents[0]; }; } __attribute__((packed)); diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 555e43ca846b2..7a1cc0e56d2d6 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -189,17 +189,29 @@ void lots_o_noops_around_write(int *write_to_me) #define u64 uint64_t #ifdef __i386__ -#define SYS_mprotect_key 380 -#define SYS_pkey_alloc 381 -#define SYS_pkey_free 382 + +#ifndef SYS_mprotect_key +# define SYS_mprotect_key 380 +#endif +#ifndef SYS_pkey_alloc +# define SYS_pkey_alloc 381 +# define SYS_pkey_free 382 +#endif #define REG_IP_IDX REG_EIP #define si_pkey_offset 0x14 + #else -#define SYS_mprotect_key 329 -#define SYS_pkey_alloc 330 -#define SYS_pkey_free 331 + +#ifndef SYS_mprotect_key +# define SYS_mprotect_key 329 +#endif +#ifndef SYS_pkey_alloc +# define SYS_pkey_alloc 330 +# define SYS_pkey_free 331 +#endif #define REG_IP_IDX REG_RIP #define si_pkey_offset 0x20 + #endif void dump_mem(void *dumpme, int len_bytes) diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c new file mode 100644 index 0000000000000..6e0bd52ad53d0 --- /dev/null +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -0,0 +1,500 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __x86_64__ +# define VSYS(x) (x) +#else +# define VSYS(x) 0 +#endif + +#ifndef SYS_getcpu +# ifdef __x86_64__ +# define SYS_getcpu 309 +# else +# define SYS_getcpu 318 +# endif +#endif + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +/* vsyscalls and vDSO */ +bool should_read_vsyscall = false; + +typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); +gtod_t vgtod = (gtod_t)VSYS(0xffffffffff600000); +gtod_t vdso_gtod; + +typedef int (*vgettime_t)(clockid_t, struct timespec *); +vgettime_t vdso_gettime; + +typedef long (*time_func_t)(time_t *t); +time_func_t vtime = (time_func_t)VSYS(0xffffffffff600400); +time_func_t vdso_time; + +typedef long (*getcpu_t)(unsigned *, unsigned *, void *); +getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800); +getcpu_t vdso_getcpu; + +static void init_vdso(void) +{ + void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) + vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) { + printf("[WARN]\tfailed to find vDSO\n"); + return; + } + + vdso_gtod = (gtod_t)dlsym(vdso, "__vdso_gettimeofday"); + if (!vdso_gtod) + printf("[WARN]\tfailed to find gettimeofday in vDSO\n"); + + vdso_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); + if (!vdso_gettime) + printf("[WARN]\tfailed to find clock_gettime in vDSO\n"); + + vdso_time = (time_func_t)dlsym(vdso, "__vdso_time"); + if (!vdso_time) + printf("[WARN]\tfailed to find time in vDSO\n"); + + vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu"); + if (!vdso_getcpu) { + /* getcpu() was never wired up in the 32-bit vDSO. */ + printf("[%s]\tfailed to find getcpu in vDSO\n", + sizeof(long) == 8 ? "WARN" : "NOTE"); + } +} + +static int init_vsys(void) +{ +#ifdef __x86_64__ + int nerrs = 0; + FILE *maps; + char line[128]; + bool found = false; + + maps = fopen("/proc/self/maps", "r"); + if (!maps) { + printf("[WARN]\tCould not open /proc/self/maps -- assuming vsyscall is r-x\n"); + should_read_vsyscall = true; + return 0; + } + + while (fgets(line, sizeof(line), maps)) { + char r, x; + void *start, *end; + char name[128]; + if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s", + &start, &end, &r, &x, name) != 5) + continue; + + if (strcmp(name, "[vsyscall]")) + continue; + + printf("\tvsyscall map: %s", line); + + if (start != (void *)0xffffffffff600000 || + end != (void *)0xffffffffff601000) { + printf("[FAIL]\taddress range is nonsense\n"); + nerrs++; + } + + printf("\tvsyscall permissions are %c-%c\n", r, x); + should_read_vsyscall = (r == 'r'); + if (x != 'x') { + vgtod = NULL; + vtime = NULL; + vgetcpu = NULL; + } + + found = true; + break; + } + + fclose(maps); + + if (!found) { + printf("\tno vsyscall map in /proc/self/maps\n"); + should_read_vsyscall = false; + vgtod = NULL; + vtime = NULL; + vgetcpu = NULL; + } + + return nerrs; +#else + return 0; +#endif +} + +/* syscalls */ +static inline long sys_gtod(struct timeval *tv, struct timezone *tz) +{ + return syscall(SYS_gettimeofday, tv, tz); +} + +static inline int sys_clock_gettime(clockid_t id, struct timespec *ts) +{ + return syscall(SYS_clock_gettime, id, ts); +} + +static inline long sys_time(time_t *t) +{ + return syscall(SYS_time, t); +} + +static inline long sys_getcpu(unsigned * cpu, unsigned * node, + void* cache) +{ + return syscall(SYS_getcpu, cpu, node, cache); +} + +static jmp_buf jmpbuf; + +static void sigsegv(int sig, siginfo_t *info, void *ctx_void) +{ + siglongjmp(jmpbuf, 1); +} + +static double tv_diff(const struct timeval *a, const struct timeval *b) +{ + return (double)(a->tv_sec - b->tv_sec) + + (double)((int)a->tv_usec - (int)b->tv_usec) * 1e-6; +} + +static int check_gtod(const struct timeval *tv_sys1, + const struct timeval *tv_sys2, + const struct timezone *tz_sys, + const char *which, + const struct timeval *tv_other, + const struct timezone *tz_other) +{ + int nerrs = 0; + double d1, d2; + + if (tz_other && (tz_sys->tz_minuteswest != tz_other->tz_minuteswest || tz_sys->tz_dsttime != tz_other->tz_dsttime)) { + printf("[FAIL] %s tz mismatch\n", which); + nerrs++; + } + + d1 = tv_diff(tv_other, tv_sys1); + d2 = tv_diff(tv_sys2, tv_other); + printf("\t%s time offsets: %lf %lf\n", which, d1, d2); + + if (d1 < 0 || d2 < 0) { + printf("[FAIL]\t%s time was inconsistent with the syscall\n", which); + nerrs++; + } else { + printf("[OK]\t%s gettimeofday()'s timeval was okay\n", which); + } + + return nerrs; +} + +static int test_gtod(void) +{ + struct timeval tv_sys1, tv_sys2, tv_vdso, tv_vsys; + struct timezone tz_sys, tz_vdso, tz_vsys; + long ret_vdso = -1; + long ret_vsys = -1; + int nerrs = 0; + + printf("[RUN]\ttest gettimeofday()\n"); + + if (sys_gtod(&tv_sys1, &tz_sys) != 0) + err(1, "syscall gettimeofday"); + if (vdso_gtod) + ret_vdso = vdso_gtod(&tv_vdso, &tz_vdso); + if (vgtod) + ret_vsys = vgtod(&tv_vsys, &tz_vsys); + if (sys_gtod(&tv_sys2, &tz_sys) != 0) + err(1, "syscall gettimeofday"); + + if (vdso_gtod) { + if (ret_vdso == 0) { + nerrs += check_gtod(&tv_sys1, &tv_sys2, &tz_sys, "vDSO", &tv_vdso, &tz_vdso); + } else { + printf("[FAIL]\tvDSO gettimeofday() failed: %ld\n", ret_vdso); + nerrs++; + } + } + + if (vgtod) { + if (ret_vsys == 0) { + nerrs += check_gtod(&tv_sys1, &tv_sys2, &tz_sys, "vsyscall", &tv_vsys, &tz_vsys); + } else { + printf("[FAIL]\tvsys gettimeofday() failed: %ld\n", ret_vsys); + nerrs++; + } + } + + return nerrs; +} + +static int test_time(void) { + int nerrs = 0; + + printf("[RUN]\ttest time()\n"); + long t_sys1, t_sys2, t_vdso = 0, t_vsys = 0; + long t2_sys1 = -1, t2_sys2 = -1, t2_vdso = -1, t2_vsys = -1; + t_sys1 = sys_time(&t2_sys1); + if (vdso_time) + t_vdso = vdso_time(&t2_vdso); + if (vtime) + t_vsys = vtime(&t2_vsys); + t_sys2 = sys_time(&t2_sys2); + if (t_sys1 < 0 || t_sys1 != t2_sys1 || t_sys2 < 0 || t_sys2 != t2_sys2) { + printf("[FAIL]\tsyscall failed (ret1:%ld output1:%ld ret2:%ld output2:%ld)\n", t_sys1, t2_sys1, t_sys2, t2_sys2); + nerrs++; + return nerrs; + } + + if (vdso_time) { + if (t_vdso < 0 || t_vdso != t2_vdso) { + printf("[FAIL]\tvDSO failed (ret:%ld output:%ld)\n", t_vdso, t2_vdso); + nerrs++; + } else if (t_vdso < t_sys1 || t_vdso > t_sys2) { + printf("[FAIL]\tvDSO returned the wrong time (%ld %ld %ld)\n", t_sys1, t_vdso, t_sys2); + nerrs++; + } else { + printf("[OK]\tvDSO time() is okay\n"); + } + } + + if (vtime) { + if (t_vsys < 0 || t_vsys != t2_vsys) { + printf("[FAIL]\tvsyscall failed (ret:%ld output:%ld)\n", t_vsys, t2_vsys); + nerrs++; + } else if (t_vsys < t_sys1 || t_vsys > t_sys2) { + printf("[FAIL]\tvsyscall returned the wrong time (%ld %ld %ld)\n", t_sys1, t_vsys, t_sys2); + nerrs++; + } else { + printf("[OK]\tvsyscall time() is okay\n"); + } + } + + return nerrs; +} + +static int test_getcpu(int cpu) +{ + int nerrs = 0; + long ret_sys, ret_vdso = -1, ret_vsys = -1; + + printf("[RUN]\tgetcpu() on CPU %d\n", cpu); + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) { + printf("[SKIP]\tfailed to force CPU %d\n", cpu); + return nerrs; + } + + unsigned cpu_sys, cpu_vdso, cpu_vsys, node_sys, node_vdso, node_vsys; + unsigned node = 0; + bool have_node = false; + ret_sys = sys_getcpu(&cpu_sys, &node_sys, 0); + if (vdso_getcpu) + ret_vdso = vdso_getcpu(&cpu_vdso, &node_vdso, 0); + if (vgetcpu) + ret_vsys = vgetcpu(&cpu_vsys, &node_vsys, 0); + + if (ret_sys == 0) { + if (cpu_sys != cpu) { + printf("[FAIL]\tsyscall reported CPU %hu but should be %d\n", cpu_sys, cpu); + nerrs++; + } + + have_node = true; + node = node_sys; + } + + if (vdso_getcpu) { + if (ret_vdso) { + printf("[FAIL]\tvDSO getcpu() failed\n"); + nerrs++; + } else { + if (!have_node) { + have_node = true; + node = node_vdso; + } + + if (cpu_vdso != cpu) { + printf("[FAIL]\tvDSO reported CPU %hu but should be %d\n", cpu_vdso, cpu); + nerrs++; + } else { + printf("[OK]\tvDSO reported correct CPU\n"); + } + + if (node_vdso != node) { + printf("[FAIL]\tvDSO reported node %hu but should be %hu\n", node_vdso, node); + nerrs++; + } else { + printf("[OK]\tvDSO reported correct node\n"); + } + } + } + + if (vgetcpu) { + if (ret_vsys) { + printf("[FAIL]\tvsyscall getcpu() failed\n"); + nerrs++; + } else { + if (!have_node) { + have_node = true; + node = node_vsys; + } + + if (cpu_vsys != cpu) { + printf("[FAIL]\tvsyscall reported CPU %hu but should be %d\n", cpu_vsys, cpu); + nerrs++; + } else { + printf("[OK]\tvsyscall reported correct CPU\n"); + } + + if (node_vsys != node) { + printf("[FAIL]\tvsyscall reported node %hu but should be %hu\n", node_vsys, node); + nerrs++; + } else { + printf("[OK]\tvsyscall reported correct node\n"); + } + } + } + + return nerrs; +} + +static int test_vsys_r(void) +{ +#ifdef __x86_64__ + printf("[RUN]\tChecking read access to the vsyscall page\n"); + bool can_read; + if (sigsetjmp(jmpbuf, 1) == 0) { + *(volatile int *)0xffffffffff600000; + can_read = true; + } else { + can_read = false; + } + + if (can_read && !should_read_vsyscall) { + printf("[FAIL]\tWe have read access, but we shouldn't\n"); + return 1; + } else if (!can_read && should_read_vsyscall) { + printf("[FAIL]\tWe don't have read access, but we should\n"); + return 1; + } else { + printf("[OK]\tgot expected result\n"); + } +#endif + + return 0; +} + + +#ifdef __x86_64__ +#define X86_EFLAGS_TF (1UL << 8) +static volatile sig_atomic_t num_vsyscall_traps; + +static unsigned long get_eflags(void) +{ + unsigned long eflags; + asm volatile ("pushfq\n\tpopq %0" : "=rm" (eflags)); + return eflags; +} + +static void set_eflags(unsigned long eflags) +{ + asm volatile ("pushq %0\n\tpopfq" : : "rm" (eflags) : "flags"); +} + +static void sigtrap(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t *)ctx_void; + unsigned long ip = ctx->uc_mcontext.gregs[REG_RIP]; + + if (((ip ^ 0xffffffffff600000UL) & ~0xfffUL) == 0) + num_vsyscall_traps++; +} + +static int test_native_vsyscall(void) +{ + time_t tmp; + bool is_native; + + if (!vtime) + return 0; + + printf("[RUN]\tchecking for native vsyscall\n"); + sethandler(SIGTRAP, sigtrap, 0); + set_eflags(get_eflags() | X86_EFLAGS_TF); + vtime(&tmp); + set_eflags(get_eflags() & ~X86_EFLAGS_TF); + + /* + * If vsyscalls are emulated, we expect a single trap in the + * vsyscall page -- the call instruction will trap with RIP + * pointing to the entry point before emulation takes over. + * In native mode, we expect two traps, since whatever code + * the vsyscall page contains will be more than just a ret + * instruction. + */ + is_native = (num_vsyscall_traps > 1); + + printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", + (is_native ? "native" : "emulated"), + (int)num_vsyscall_traps); + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + int nerrs = 0; + + init_vdso(); + nerrs += init_vsys(); + + nerrs += test_gtod(); + nerrs += test_time(); + nerrs += test_getcpu(0); + nerrs += test_getcpu(1); + + sethandler(SIGSEGV, sigsegv, 0); + nerrs += test_vsys_r(); + +#ifdef __x86_64__ + nerrs += test_native_vsyscall(); +#endif + + return nerrs ? 1 : 0; +} diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am index da3a430849a87..5961e9c188121 100644 --- a/tools/usb/usbip/Makefile.am +++ b/tools/usb/usbip/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS := libsrc src includedir = @includedir@/usbip include_HEADERS := $(addprefix libsrc/, \ - usbip_common.h vhci_driver.h usbip_host_driver.h) + usbip_common.h vhci_driver.h usbip_host_driver.h \ + list.h sysfs_utils.h usbip_host_common.h) dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 5727dfb15a83e..d1fc0f9f00fb8 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -50,14 +50,14 @@ static int parse_status(const char *value) while (*c != '\0') { int port, status, speed, devid; - unsigned long socket; + int sockfd; char lbusid[SYSFS_BUS_ID_SIZE]; struct usbip_imported_device *idev; char hub[3]; - ret = sscanf(c, "%2s %d %d %d %x %lx %31s\n", + ret = sscanf(c, "%2s %d %d %d %x %u %31s\n", hub, &port, &status, &speed, - &devid, &socket, lbusid); + &devid, &sockfd, lbusid); if (ret < 5) { dbg("sscanf failed: %d", ret); @@ -66,7 +66,7 @@ static int parse_status(const char *value) dbg("hub %s port %d status %d speed %d devid %x", hub, port, status, speed, devid); - dbg("socket %lx lbusid %s", socket, lbusid); + dbg("sockfd %u lbusid %s", sockfd, lbusid); /* if a device is connected, look at it */ idev = &vhci_driver->idev[port]; @@ -329,9 +329,17 @@ int usbip_vhci_refresh_device_list(void) int usbip_vhci_get_free_port(uint32_t speed) { for (int i = 0; i < vhci_driver->nports; i++) { - if (speed == USB_SPEED_SUPER && - vhci_driver->idev[i].hub != HUB_SPEED_SUPER) - continue; + + switch (speed) { + case USB_SPEED_SUPER: + if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER) + continue; + break; + default: + if (vhci_driver->idev[i].hub != HUB_SPEED_HIGH) + continue; + break; + } if (vhci_driver->idev[i].status == VDEV_ST_NULL) return vhci_driver->idev[i].port; diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c index 2b3d6d2350158..3d7b42e772994 100644 --- a/tools/usb/usbip/src/utils.c +++ b/tools/usb/usbip/src/utils.c @@ -30,6 +30,7 @@ int modify_match_busid(char *busid, int add) char command[SYSFS_BUS_ID_SIZE + 4]; char match_busid_attr_path[SYSFS_PATH_MAX]; int rc; + int cmd_size; snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, @@ -37,12 +38,14 @@ int modify_match_busid(char *busid, int add) attr_name); if (add) - snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); + cmd_size = snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", + busid); else - snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); + cmd_size = snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", + busid); rc = write_sysfs_attribute(match_busid_attr_path, command, - sizeof(command)); + cmd_size); if (rc < 0) { dbg("failed to write match_busid: %s", strerror(errno)); return -1; diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000000000..e1d6ddda64546 --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,7 @@ +SUBDIRS = wmt + +all : + for d in $(SUBDIRS); do \ + (make -C $$d) \ + done + diff --git a/utils/wmt/Makefile b/utils/wmt/Makefile new file mode 100644 index 0000000000000..7c6943e3f8036 --- /dev/null +++ b/utils/wmt/Makefile @@ -0,0 +1,7 @@ +SUBDIRS = src + +all : + for d in $(SUBDIRS); do \ + (make -C $$d) \ + done + diff --git a/utils/wmt/README b/utils/wmt/README new file mode 100644 index 0000000000000..fa685e28dabc8 --- /dev/null +++ b/utils/wmt/README @@ -0,0 +1,8 @@ +copy the following file to BPI-ROOT-partition of SD-Card: + +- config\WMT_SOC.cfg to system/etc/firmware/ + +- content of folder firmware to etc/firmware/ + +- src\stp_uart_launcher, src\wmt_loader and src\wmt_loopback to usr/bin/ + diff --git a/utils/wmt/config/WMT_SOC.cfg b/utils/wmt/config/WMT_SOC.cfg new file mode 100755 index 0000000000000..cd214d83f2af7 --- /dev/null +++ b/utils/wmt/config/WMT_SOC.cfg @@ -0,0 +1,3 @@ +mt6620.defAnt=mt6620_ant_m3.cfg +mt6628.defAnt=mt6628_ant_m1.cfg +mt6630.defAnt=mt6630_ant_m1.cfg \ No newline at end of file diff --git a/utils/wmt/firmware/ROMv2_lm_patch_1_0_hdr.bin b/utils/wmt/firmware/ROMv2_lm_patch_1_0_hdr.bin new file mode 100755 index 0000000000000..f95b4a4d0ba75 Binary files /dev/null and b/utils/wmt/firmware/ROMv2_lm_patch_1_0_hdr.bin differ diff --git a/utils/wmt/firmware/ROMv2_lm_patch_1_1_hdr.bin b/utils/wmt/firmware/ROMv2_lm_patch_1_1_hdr.bin new file mode 100755 index 0000000000000..9647f376413bf Binary files /dev/null and b/utils/wmt/firmware/ROMv2_lm_patch_1_1_hdr.bin differ diff --git a/utils/wmt/firmware/WIFI_RAM_CODE_7623 b/utils/wmt/firmware/WIFI_RAM_CODE_7623 new file mode 100755 index 0000000000000..cb849cce2c72a Binary files /dev/null and b/utils/wmt/firmware/WIFI_RAM_CODE_7623 differ diff --git a/utils/wmt/firmware/nvram/WIFI b/utils/wmt/firmware/nvram/WIFI new file mode 100755 index 0000000000000..493326ebccad9 Binary files /dev/null and b/utils/wmt/firmware/nvram/WIFI differ diff --git a/utils/wmt/src/Makefile b/utils/wmt/src/Makefile new file mode 100755 index 0000000000000..7e9972503c4f5 --- /dev/null +++ b/utils/wmt/src/Makefile @@ -0,0 +1,13 @@ +CC=arm-linux-gnueabihf-gcc +#CFLAGS=-Wall + +all: + $(CC) $(CFLAGS) stp_uart_launcher.c -lpthread -o stp_uart_launcher + $(CC) $(CFLAGS) wmt_loopback.c -o wmt_loopback + $(CC) $(CFLAGS) wmt_loader.c -o wmt_loader + +.PHONY:clean +clean: + rm -rf stp_uart_launcher wmt_loopback wmt_loader *.o + + diff --git a/utils/wmt/src/stp_uart_launcher b/utils/wmt/src/stp_uart_launcher new file mode 100755 index 0000000000000..b7806d32a6e79 Binary files /dev/null and b/utils/wmt/src/stp_uart_launcher differ diff --git a/utils/wmt/src/stp_uart_launcher.c b/utils/wmt/src/stp_uart_launcher.c new file mode 100755 index 0000000000000..439beaa18611d --- /dev/null +++ b/utils/wmt/src/stp_uart_launcher.c @@ -0,0 +1,1990 @@ + +/****************************************************************************** +* C O M P I L E R F L A G S +******************************************************************************* +*/ + +/****************************************************************************** +* E X T E R N A L R E F E R E N C E S +******************************************************************************* +*/ + +#define STATIC_BUILD 1 + +#include "wmt_ioctl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ +#include +#include +#include +#include +#include +#include +//#include +#include +#include /* struct serial_struct */ +//#include + +//For directory operation +#include +#ifndef STATIC_BUILD +#include +#endif + + +#ifdef STATIC_BUILD +#define PROPERTY_VALUE_MAX 32 +#define ALOGI printf +#define ALOGE printf +#endif + +/****************************************************************************** +* C O N S T A N T S +******************************************************************************* +*/ + +#define WCN_COMBO_CHIP_ID_PROP "persist.mtk.wcn.combo.chipid" +#define WCN_DRIVER_READY_PROP "service.wcn.driver.ready" +#define WCN_COMBO_COREDUMP_PROP "service.wcn.coredump.mode" +#define WCN_FW_DBG_LOG_PROP "persist.mtk.wcn.fwlog.status" +#define WCN_DYNAMIC_DUMP_PROP "persist.mtk.wcn.dynamic.dump" +#define WCN_COMBO_AEE_PROP "ro.aee.build.info" +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "6620_launcher" +//#include "cust_mt6620_test.h" /* project custom header file */ + +#ifndef N_MTKSTP +#define N_MTKSTP (15 + 1) /* MediaTek WCN Serial Transport Protocol */ +#endif + +#define HCIUARTSETPROTO _IOW('U', 200, int) + +#define CUST_COMBO_WMT_DEV "/dev/stpwmt" +#define CUST_COMBO_STP_DEV "/dev/ttyMT2" //-- for ALPS +#define CUST_COMBO_PATCH_PATH "/etc/firmware" //-- for ALPS + + +#define CUST_BAUDRATE_DFT (115200) + +#define CUST_MULTI_PATCH (1) +#define MTK_WCN_ENABLE_COREDUMP_BY_PROPERTY 0 + +typedef enum { + STP_MIN = 0x0, + STP_UART_FULL = 0x1, + STP_UART_MAND = 0x2, + STP_BTIF_FULL = 0x3, + STP_SDIO = 0x4, + STP_MAX = 0x5, +}STP_MODE; + +#define MAX_CMD_LEN (NAME_MAX+1) + +typedef enum { + UART_DISABLE_FC = 0, /*NO flow control*/ + UART_MTK_SW_FC = 1, /*MTK SW Flow Control, differs from Linux Flow Control*/ + UART_LINUX_FC = 2, /*Linux SW Flow Control*/ + UART_HW_FC = 3, /*HW Flow Control*/ +} STP_UART_FC; + +typedef struct +{ + const char *key; + const char *defValue; + char value[PROPERTY_VALUE_MAX]; + +}SYS_PROPERTY; + + +typedef struct { + STP_UART_FC fc; + int parity; + int stop_bit; +} STP_UART_CONFIG; + +typedef struct { + STP_MODE eStpMode; + char *pPatchPath; + char *pPatchName; + char *gStpDev; + int iBaudrate; + STP_UART_CONFIG sUartConfig; +}STP_PARAMS_CONFIG, *P_STP_PARAMS_CONFIG; + + +#if CUST_MULTI_PATCH +typedef struct { + int dowloadSeq; + char addRess[4]; + char patchName[256]; +}STP_PATCH_INFO,*P_STP_PATCH_INFO; +#endif + +typedef struct { + const char *pCfgItem; + char cfgItemValue[NAME_MAX + 1]; +}CHIP_ANT_MODE_INFO, *P_CHIP_ANT_MODE_INFO; + + +typedef struct { + int chipId; + STP_MODE stpMode; + CHIP_ANT_MODE_INFO antMode; +}CHIP_MODE_INFO, *P_CHIP_MODE_INFO; +#ifndef WMT_PLAT_APEX +CHIP_MODE_INFO gChipModeInfo[] = { + {0x6620, STP_UART_FULL, {"mt6620.defAnt", "mt6620_ant_m3.cfg"}}, + {0x6628, STP_UART_FULL, {"mt6628.defAnt", "mt6628_ant_m1.cfg"}}, + {0x6630, STP_UART_FULL, {"mt6630.defAnt", "mt6630_ant_m1.cfg"}}, +}; +#else +CHIP_MODE_INFO gChipModeInfo[] = { + {0x6620, STP_UART_FULL, {"mt6620.defAnt", "WMT.cfg"}}, + {0x6628, STP_UART_FULL, {"mt6628.defAnt", "WMT.cfg"}}, + {0x6630, STP_UART_FULL, {"mt6630.defAnt", "WMT.cfg"}}, +}; +#endif +/****************************************************************************** +* D A T A T Y P E S +******************************************************************************* +*/ +struct cmd_hdr{ + char *pCmd; + int (*hdr_func)(P_STP_PARAMS_CONFIG pStpParamsConfig); +}; + +struct speed_map { + unsigned int baud; + speed_t speed; +}; + +/****************************************************************************** +* M A C R O S +******************************************************************************* +*/ +#define INIT_CMD(c, e, s) {.cmd= c, .cmd_sz=sizeof(c), .evt=e, .evt_sz=sizeof(e), .str=s} + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ +static int set_speed(int fd, struct termios *ti, int speed); +int setup_uart_param (int hComPort, int iBaudrate, STP_UART_CONFIG *stp_uart); + +int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_stp_open (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_stp_close (P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_stp_rst(P_STP_PARAMS_CONFIG pStpParamsConfig); +int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig); +static int check_chip_id(void); +static int setHifInfo(int chipId, char *cfgFilePath); +static int wmt_cfg_item_parser(char *pItem); +static int get_wmt_cfg (int chipId); +static speed_t get_speed (int baudrate); + + +/****************************************************************************** +* P U B L I C D A T A +******************************************************************************* +*/ + +/****************************************************************************** +* P R I V A T E D A T A +******************************************************************************* +*/ +static struct speed_map speeds[] = { + {115200, B115200}, + {921600, B921600}, + {1000000, B1000000}, + {1152000, B1152000}, + {2000000, B2000000}, + {2500000, B2500000}, + {3000000, B3000000}, + {3500000, B3500000}, + {4000000, B4000000}, +}; + +static STP_UART_CONFIG g_stp_uart_config; + +struct cmd_hdr cmd_hdr_table[] = { + { "baud_115200_0", cmd_hdr_baud_115k}, + { "baud_921600_0", cmd_hdr_baud_921k}, + { "baud_2000000_0", cmd_hdr_baud_2kk}, + { "baud_2500000_0", cmd_hdr_baud_2_5kk}, + { "baud_3000000_0", cmd_hdr_baud_3kk}, + //{ "baud_3200000_0", cmd_hdr_baud_3_2kk}, + //{ "baud_3250000_0", cmd_hdr_baud_3_25kk}, + { "baud_3500000_0", cmd_hdr_baud_3_5kk}, + { "baud_4000000_0", cmd_hdr_baud_4kk}, + { "open_stp", cmd_hdr_stp_open}, + { "close_stp", cmd_hdr_stp_close}, + { "rst_stp", cmd_hdr_stp_rst}, + { "srh_patch", cmd_hdr_sch_patch}, +}; + +static volatile sig_atomic_t __io_canceled = 0; +static char gPatchName[NAME_MAX+1]= {0}; +static char gPatchFolder[NAME_MAX+1]= {0}; +static char gStpDev[NAME_MAX+1]= {0}; +static int gStpMode = -1; +static char gWmtCfgName[NAME_MAX+1] = {0}; +static int gWmtFd = -1; +static int gTtyFd = -1; +static char gCmdStr[MAX_CMD_LEN]= {0}; +static char gRespStr[MAX_CMD_LEN]= {0}; +static int gFmMode = 2; /* 1: i2c, 2: comm I/F */ +static const char *gUartName = NULL; + +#if CUST_MULTI_PATCH +static unsigned int gPatchNum = 0; +static unsigned int gDwonSeq = 0; +static P_STP_PATCH_INFO pStpPatchInfo = NULL; +static STP_PATCH_INFO gStpPatchInfo; +#endif + +pthread_t thread_handle = -1; +/****************************************************************************** +* F U N C T I O N S +******************************************************************************* +*/ + +/* Used as host uart param setup callback */ +int setup_uart_param ( + int hComPort, + int iBaudrate, + STP_UART_CONFIG *stpUartConfig) +{ + struct termios ti; + int fd; + + if(!stpUartConfig){ + ALOGE("Invalid stpUartConfig"); + return -2; + } + + ALOGI("setup_uart_param %d %d\n", iBaudrate, stpUartConfig->fc); + + fd = hComPort; + if (fd < 0) { + ALOGE("Invalid serial port"); + return -2; + } + + tcflush(fd, TCIOFLUSH); + + if (tcgetattr(fd, &ti) < 0) { + ALOGE("Can't get port settings"); + return -3; + } + + cfmakeraw(&ti); + + ALOGI("ti.c_cflag = 0x%08x\n", ti.c_cflag); + ti.c_cflag |= CLOCAL; + ALOGI("CLOCAL = 0x%x\n", CLOCAL); + ALOGI("(ori)ti.c_iflag = 0x%08x\n", ti.c_iflag); + ALOGI("(ori)ti.c_cflag = 0x%08x\n", ti.c_cflag); + ALOGI("stpUartConfig->fc= %d (0:none,sw,hw,linux)\n", stpUartConfig->fc); + + if(stpUartConfig->fc == UART_DISABLE_FC){ + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag &= ~(0x80000000); + } else if(stpUartConfig->fc == UART_MTK_SW_FC){ + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag |= 0x80000000; /*MTK Software FC*/ + } else if(stpUartConfig->fc == UART_HW_FC){ + ti.c_cflag |= CRTSCTS; /*RTS, CTS Enable*/ + ti.c_iflag &= ~(0x80000000); + } else if(stpUartConfig->fc == UART_LINUX_FC){ + ti.c_iflag |= (IXON | IXOFF | IXANY); /*Linux Software FC*/ + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag &= ~(0x80000000); + }else { + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag &= ~(0x80000000); + } + + ALOGI("c_c CRTSCTS = 0x%16x\n", CRTSCTS); + ALOGI("c_i IXON = 0x%08x\n", IXON); + ALOGI("c_i IXOFF = 0x%08x\n", IXOFF); + ALOGI("c_i IXANY = 0x%08x\n", IXANY); + ALOGI("(aft)ti.c_iflag = 0x%08x\n", ti.c_iflag); + ALOGI("(aft)ti.c_cflag = 0x%08x\n\n", ti.c_cflag); + + if (tcsetattr(fd, TCSANOW, &ti) < 0) { + ALOGE("Can't set port settings"); + return -4; + } + + /* Set baudrate */ + if (set_speed(fd, &ti, iBaudrate) < 0) { + ALOGE("Can't set initial baud rate"); + return -5; + } + + tcflush(fd, TCIOFLUSH); + + return 0; +} + +static void sig_hup(int sig) +{ + fprintf(stderr, "sig_hup...\n"); +} + +static void sig_term(int sig) +{ + fprintf(stderr, "sig_term...\n"); + __io_canceled = 1; + ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 1); +} + + +static speed_t get_speed (int baudrate) +{ + unsigned int idx; + for (idx = 0; idx < sizeof(speeds)/sizeof(speeds[0]); idx++) { + if (baudrate == (int)speeds[idx].baud) { + return speeds[idx].speed; + } + } + return CBAUDEX; +} + +int set_speed(int fd, struct termios *ti, int speed) +{ + struct serial_struct ss; + int baudenum = get_speed(speed); + + if (speed != CBAUDEX) { + //printf("%s: standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum); + if ((ioctl(fd, TIOCGSERIAL, &ss)) < 0) { + ALOGI("%s: BAUD: error to get the serial_struct info:%s\n", __FUNCTION__, strerror(errno)); + return -1; + } + ss.flags &= ~ASYNC_SPD_CUST; +#if defined(SERIAL_STRUCT_EXT) /*modified in serial_struct.h*/ + memset(ss.reserved, 0x00, sizeof(ss.reserved)); +#endif + ss.flags |= (1 << 13); /*set UPFLOWLATENCY flat to tty, or serial_core will reset tty->low_latency to 0*/ + /*set standard buadrate setting*/ + if ((ioctl(fd, TIOCSSERIAL, &ss)) < 0) { + ALOGI("%s: BAUD: error to set serial_struct:%s\n", __FUNCTION__, strerror(errno)); + return -2; + } + cfsetospeed(ti, baudenum); + cfsetispeed(ti, baudenum); + return tcsetattr(fd, TCSANOW, ti); + } + else { + ALOGI("%s: unsupported non-standard baudrate: %d -> 0x%08x\n", __FUNCTION__, speed, baudenum); + return -3; + } +} + + +int cmd_hdr_baud_115k (P_STP_PARAMS_CONFIG pStpParamsConfig) { + + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 115200, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_921k (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 921600, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2000000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_2_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 2500000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_3kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3000000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_3_2kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3200000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_3_25kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3250000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_3_5kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 3500000, gStpUartConfig) : -1; +} + +int cmd_hdr_baud_4kk (P_STP_PARAMS_CONFIG pStpParamsConfig) { + STP_UART_CONFIG *gStpUartConfig = &pStpParamsConfig->sUartConfig; + return (gTtyFd != -1) ? setup_uart_param(gTtyFd, 4000000, gStpUartConfig) : -1; +} + +int cmd_hdr_stp_open (P_STP_PARAMS_CONFIG pStpParamsConfig) { + int ld; + if ((STP_UART_FULL == gStpMode) && (-1 == gTtyFd)) { + gTtyFd = open(gStpDev, O_RDWR | O_NOCTTY); + if (gTtyFd < 0) { + fprintf(stderr, "Can't open serial port %s\n", gStpDev); + return -2; + } + ALOGI("real_tty(%s) opened(%d)\n", gStpDev, gTtyFd); + + /* Set TTY to N_MTKSTP line discipline */ + ld = N_MTKSTP; + if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) { + fprintf(stderr, "Can't set ldisc to N_MTKSTP\n"); + return -3; + } + + //printf("Set tty->low_latency\n"); + if (ioctl(gTtyFd, HCIUARTSETPROTO, 0) < 0) { + ALOGE("Can't set HCIUARTSETPROTO\n"); + return -4; + } + return 0; + } + else { + fprintf(stderr, "stp_open fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd); + return -1; + } +} + +int cmd_hdr_stp_close (P_STP_PARAMS_CONFIG pStpParamsConfig) { + int ld; + + if ((STP_UART_FULL == gStpMode) && (0 <= gTtyFd)) { + /* Restore TTY line discipline */ + ld = N_TTY; + if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) { + ALOGE("Can't restore line discipline"); + return -2; + } + + close(gTtyFd); + gTtyFd = -1; + return 0; + } else if (gTtyFd == -1) { + return 0; + } else { + fprintf(stderr, "stp_close fail: stp_mode(%d) real_tty_fd(%d) \n", gStpMode, gTtyFd); + return -1; + } +} + +int cmd_hdr_stp_rst (P_STP_PARAMS_CONFIG pStpParamsConfig) { + int ret = 0; + /*this step fail?*/ + ret = cmd_hdr_stp_close(pStpParamsConfig); + /*here, launcher is close state*/ + ret = cmd_hdr_stp_open(pStpParamsConfig); + return ret; +} + +#if CUST_MULTI_PATCH +int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig) +{ + //#define PATCH_PATH "/system/etc/firmware" + int chipId = 0; + int hwVersion = 0; + int fwVersion = 0; + char chipName[16] = {0}; + char patchFullName[256] = {0}; + unsigned int patchVer = 0; + DIR *pDir = NULL; + int patchFd = -1; + int iRet = 0; + int bytes; + unsigned int patchNum = 0; + char patchInfo[8] = {0}; + unsigned int isFirst = 1; + P_STP_PATCH_INFO pstPaInfo = NULL; + struct dirent* pDirent = NULL; + + if (gWmtFd > 0) + { + /*1. ioctl to get CHIP ID*/ + chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0); + if((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId)) + { + chipId = 0x6735; + ALOGI("for denali chipid convert\n"); + } + if (0x0326 == chipId) { + chipId = 0x6755; + ALOGI("for jade chipid convert\n"); + } + if (0x0279 == chipId) { + chipId = 0x6797; + ALOGI("for everest chipid convert\n"); + } + strncpy(chipName, "mt",strlen("mt")); + sprintf(chipName + strlen("mt"), "%04x", chipId); + +#if 0 + /* single patch 6630 */ + if(!strcmp(chipName,"mt6630"))//apply to MT6630 + { + strcat (chipName, "_patch"); + ALOGI ("6630 patch name pre-fix:%s\n", chipName); + + /*2. ioctl to get FIRMWARE VERSION*/ + fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2); + ALOGI ("fwVersion:0x%04x\n", fwVersion); + + /*3. open directory patch located*/ + if (NULL == pStpParamsConfig->pPatchPath) + { + pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH; + } + pDir = opendir(pStpParamsConfig->pPatchPath); + if (NULL == pDir) + { + ALOGE("patch path cannot be opened"); + iRet = -1; + return iRet; + } + while (NULL != (pDirent = readdir(pDir))) + { + patchVer = 0; + + if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName)))) + { /*4.1. search patch name begined with chipName*/ + strcpy (patchFullName, pStpParamsConfig->pPatchPath); + strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened. + strcat (patchFullName, pDirent->d_name); + + ALOGI ("%s\n", patchFullName); + /*4.1. search patch name mt[CHIP ID]xxx.bin*/ + if (0 < (patchFd = (open(patchFullName, O_RDONLY )))) + { + /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */ + if (-1 != lseek (patchFd, 22, SEEK_SET)) + { + read(patchFd, ((char *)&patchVer) + 1, 1); + read(patchFd, ((char *)&patchVer), 1); + /*print hardware version information in patch*/ + ALOGI ("fw Ver in patch: 0x%04x\n", patchVer); + if (0 == ((patchVer ^ fwVersion) & 0x00ff)) + { + ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, patchFullName); + ALOGI ("fw Ver in patch matches with firmware version\n"); + close (patchFd); + break; + } + } + else + { + ALOGE("seek failed\n"); + } + close (patchFd); + patchFd = -1; + } + else + { + ALOGI("open patch file(%s) failed\n", patchFullName); + //ALOGE(patchFullName); + } + } + } + /*5. return value*/ + closedir(pDir); + pDir = NULL; + } +#endif + + if ((!strcmp(chipName, "mt6620")) || (!strcmp(chipName, "mt6628")) || (!strcmp(chipName, "mt6630")) || + (!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592")) || + (!strcmp(chipName, "mt8127"))|| (!strcmp(chipName, "mt7623")) || (!strcmp(chipName, "mt6571")) || (!strcmp(chipName, "mt6752")) || + (!strcmp(chipName, "mt8163")) || (!strcmp(chipName, "mt6580")) || + (!strcmp(chipName, "mt6735")) || (!strcmp(chipName, "mt6755")) || (!strcmp(chipName, "mt6797"))) + { + if ((!strcmp(chipName, "mt6572")) || (!strcmp(chipName, "mt6582")) || (!strcmp(chipName, "mt6592"))) + { + strncpy(chipName, "ROMv1", strlen("ROMv1")); + chipName[5] = '\0'; + }else if(!strcmp(chipName,"mt8127") || !strcmp(chipName,"mt6571")){ + strncpy(chipName,"ROMv2",strlen("ROMv2")); + chipName[5] = '\0'; + } else if (!strcmp(chipName, "mt6755") ||!strcmp(chipName, "mt6752") || !strcmp(chipName, "mt6735") + || !strcmp(chipName, "mt8163") || !strcmp(chipName, "mt6580") || !strcmp(chipName, "mt7623")) { + strncpy(chipName, "ROMv2_lm", strlen("ROMv2_lm")); + } else if (!strcmp(chipName, "mt6797")) { + strncpy(chipName, "ROMv3", strlen("ROMv3")); + chipName[5] = '\0'; + } + strcat (chipName, "_patch"); + ALOGI ("patch name pre-fix:%s\n", chipName); + /*2. ioctl to get FIRMWARE VERSION*/ + fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2); + ALOGI ("fwVersion:0x%04x\n", fwVersion); + /*3. open directory patch located*/ + if (NULL == pStpParamsConfig->pPatchPath) + { + pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH; + } + + { + pDir = opendir(pStpParamsConfig->pPatchPath); + if (NULL == pDir) + { + ALOGE("patch path cannot be opened"); + iRet = -1; + return iRet; + } + while (NULL != (pDirent = readdir(pDir))) + { + patchVer = 0; + + if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName)))) + { /*4.1. search patch name begined with chipName*/ + strcpy (patchFullName, pStpParamsConfig->pPatchPath); + strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened. + strcat (patchFullName, pDirent->d_name); + + ALOGI ("%s\n", patchFullName); + /*4.1. search patch name mt[CHIP ID]xxx.bin*/ + if (0 <= (patchFd = (open(patchFullName, O_RDONLY )))) + { + /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */ + if (-1 != lseek (patchFd, 22, SEEK_SET)) + { + memset(&gStpPatchInfo,0,sizeof(gStpPatchInfo)); + memset(patchInfo,0,sizeof(patchInfo)); + + bytes = read(patchFd, ((char *)&patchVer) + 1, 1); + if (-1 == bytes) { + ALOGI ("read patchVer1 failed!\n"); + goto readfailed; + } + bytes = read(patchFd, ((char *)&patchVer), 1); + if (-1 == bytes) { + ALOGI ("read patchVer failed!\n"); + goto readfailed; + } + /*print hardware version information in patch*/ + ALOGI ("fw Ver in patch: 0x%04x\n", patchVer); + if (0 == ((patchVer ^ fwVersion) & 0x00ff)) { + bytes = read(patchFd, patchInfo, 4); + if (-1 == bytes) { + ALOGI ("read patchInfo failed!\n"); + goto readfailed; + } + patchInfo[4] = '\0'; + ALOGI("read patch info:0x%02x,0x%02x,0x%02x,0x%02x\n",patchInfo[0],patchInfo[1],patchInfo[2],patchInfo[3]); + if (1 == isFirst) { + gPatchNum = (patchInfo[0] & 0xF0) >> 4; + ALOGI("gpatchnum = [%d]\n",gPatchNum); + ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_NUM,gPatchNum); + + gDwonSeq = (patchInfo[0] & 0x0F); + ALOGI("gdwonseq = [%d]\n",gDwonSeq); + gStpPatchInfo.dowloadSeq = gDwonSeq; + memcpy(gStpPatchInfo.addRess,patchInfo,sizeof(gStpPatchInfo.addRess)); + gStpPatchInfo.addRess[0] = 0x00; + strncpy(gStpPatchInfo.patchName, patchFullName, sizeof(gStpPatchInfo.patchName) - 1); + gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0'; + //printf("gStpPatchInfo address info:0x%02x,0x%02x,0x%02x,0x%02x\n",gStpPatchInfo.addRess[0],gStpPatchInfo.addRess[1],gStpPatchInfo.addRess[2],gStpPatchInfo.addRess[3]); + ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_INFO,&gStpPatchInfo); + isFirst ++; + } else { + gDwonSeq = (patchInfo[0] & 0x0F); + ALOGI("gdwonseq = [%d]\n",gDwonSeq); + gStpPatchInfo.dowloadSeq = gDwonSeq; + memcpy(gStpPatchInfo.addRess,patchInfo,sizeof(gStpPatchInfo.addRess)); + gStpPatchInfo.addRess[0] = 0x00; + strncpy(gStpPatchInfo.patchName, patchFullName, sizeof(gStpPatchInfo.patchName) - 1); + gStpPatchInfo.patchName[sizeof(gStpPatchInfo.patchName) - 1] = '\0'; + //printf("gStpPatchInfo address info:0x%02x,0x%02x,0x%02x,0x%02x\n",gStpPatchInfo.addRess[0],gStpPatchInfo.addRess[1],gStpPatchInfo.addRess[2],gStpPatchInfo.addRess[3]); + ioctl(gWmtFd,WMT_IOCTL_SET_PATCH_INFO,&gStpPatchInfo); + } + } + } + else + { + ALOGE("seek failed\n"); + } +readfailed: + close (patchFd); + patchFd = -1; + } + else + { + ALOGI("open patch file(%s) failed\n", patchFullName); + //ALOGE(patchFullName); + } + } + } + /*5. return value*/ + closedir(pDir); + pDir = NULL; + } + } + } + else + { + ALOGE("file descriptor is not valid\n"); + iRet = -2; + } + return iRet; +} +#else +int cmd_hdr_sch_patch (P_STP_PARAMS_CONFIG pStpParamsConfig) +{ + //#define PATCH_PATH "/system/etc/firmware" + int chipId = 0; + int hwVersion = 0; + int fwVersion = 0; + char chipName[16] = {0}; + char patchFullName[256] = {0}; + unsigned int patchVer = 0; + DIR *pDir = NULL; + int patchFd = -1; + struct dirent* pDirent = NULL; + int iRet = -1; + + if (gWmtFd > 0) + { + /*1. ioctl to get CHIP ID*/ + chipId = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 0); + strcpy(chipName, "mt"); + sprintf (chipName + strlen(chipName), "%04x", chipId); + strcat (chipName, "_patch"); + ALOGI ("patch name pre-fix:%s\n", chipName); +#if 0 + /*2. ioctl to get HARDWARE VERSION*/ + hwVersion = ioctl(gWmtFd, 12, 1); + ALOGI ("hwVersion:0x%04x\n", hwVersion); +#else + /*2. ioctl to get FIRMWARE VERSION*/ + fwVersion = ioctl(gWmtFd, WMT_IOCTL_GET_CHIP_INFO, 2); + ALOGI ("fwVersion:0x%04x\n", fwVersion); +#endif + /*3. open directory patch located*/ + if (NULL == pStpParamsConfig->pPatchPath) + { + pStpParamsConfig->pPatchPath = CUST_COMBO_PATCH_PATH; + } + pDir = opendir(pStpParamsConfig->pPatchPath); + if (NULL == pDir) + { + ALOGE("patch path cannot be opened"); + iRet = -2; + return iRet; + } + while (NULL != (pDirent = readdir(pDir))) + { + patchVer = 0; + + if (0 == (strncmp(pDirent->d_name, chipName, strlen(chipName)))) + { /*4.1. search patch name begined with chipName*/ + strcpy (patchFullName, pStpParamsConfig->pPatchPath); + strcat (patchFullName, "/"); // robust, if input patch is /etc/firmwre/ no issue should be happened. + strcat (patchFullName, pDirent->d_name); + + ALOGI ("%s\n", patchFullName); + /*4.1. search patch name mt[CHIP ID]xxx.bin*/ + if (0 < (patchFd = (open(patchFullName, O_RDONLY )))) + { + + /*4.2. read patch header and check if metch with MAJOR+MINOR number in fw version */ + if (-1 != lseek (patchFd, 22, SEEK_SET)) + { + + read(patchFd, ((char *)&patchVer) + 1, 1); + read(patchFd, ((char *)&patchVer), 1); + /*print firmware version information in patch*/ + ALOGI ("fw Ver in patch: 0x%04x\n", patchVer); + if (0 == ((patchVer ^ fwVersion) & 0x00ff)) + { + ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, patchFullName); + ALOGI ("fw Ver in patch matches with firmware version\n"); + iRet = 0; + close (patchFd); + break; + } + } + else + { + ALOGE("seek failed\n"); + } + close (patchFd); + patchFd = -1; + } + else + { + //printf("open patch file(%s) failed\n", patchFullName); + ALOGE(patchFullName); + } + } + + } + + /*5. return value*/ + closedir(pDir); + pDir = NULL; + } + else + { + ALOGE("file descriptor is not valid\n"); + iRet = -1; + } + return iRet; +} +#endif +/* +ret 0: success +ret 1: cmd not found +ret -x: handler return value +*/ +int handle_cmd (P_STP_PARAMS_CONFIG pStpParamsConfig, char *cmd, int len) { + int ret = 1; + int i; + int cmd_len; + + for (i = 0; i < (int)(sizeof(cmd_hdr_table)/sizeof(cmd_hdr_table[0])); ++i) { + cmd_len = (int)strlen(cmd_hdr_table[i].pCmd); + if (!strncmp(cmd_hdr_table[i].pCmd, cmd, (len < cmd_len) ? len : cmd_len)) { + ret = (*cmd_hdr_table[i].hdr_func)(pStpParamsConfig); + } + } + + return ret; +} + +void display_usage(int chipid) +{ + unsigned int index = 0; + char * usage1[] = { + "MTK WCN combo tool set, version 1.0-release", + "Usage: consys_launcher -m mode -p patchfolderpath", + " -m (BT/GPS/FM common interface mode selection)", + " -1: UART mode (common interface: UART)", + " -3: BTIF mode (common interface: BTIF)", + " -4: SDIO mode (common interface: SDIO)", + " -p (MTK WCN soc conssy chip firmware patch location)", + " -e.g. /etc/firmware", + "e.g. consys_launcher -m 3 -p /etc/firmware/", + }; + char * usage2[] = { + "MTK WCN combo tool set, version 1.0-release", + "Usage: 6620_launcher -m mode -p patchfolderpath [-d uartdevicenode] [-b baudrate] [-c uartflowcontrol]", +// " -m (BT/GPS/FM common interface mode selection)", +// " -1: UART mode (common interface: UART)", +// " -1: UART full mode (common interface UART)", +// " -2: UART mandetary mode (common interface UART)", + " -4: UART mode (common interface SDIO)", + " -p (MTK WCN Combo chip firmware patch location)", + " -e.g. /etc/firmware", + " -b (Baudrate set when BT/GPS/FM runs under UART mode, no needed under SDIO mode)", + " -115200/921600/2000000/2500000/3000000/3500000/4000000", + " -d (UART device node, when under UART mode, no needed under SDIO mode)", + " -e.g. /dev/ttyMT1, /dev/ttyMT2, /dev/ttyHS2, etc.", + " -c (UART flowcontrol set)", + " -0, no flowcontrol default value, please donot modify this parameter", + "e.g. 6620_launcher 4 /etc/firmware/mt6628_patch_hdr.bin", + "e.g. 6620_launcher -m 1 -p /etc/firmware/", + "e.g. 6620_launcher -m 1 -n /etc/firmware/mt6628_patch_hdr.bin", + "e.g. 6620_launcher -m 4 -d /dev/ttyMT2 -b 4000000 -n /etc/firmware/mt6628_patch_hdr.bin", + }; + if(0x6582 == chipid || 0x8127 == chipid) + { + for (index = 0; index < sizeof (usage1)/sizeof (usage1[0]); index++ ) + { + ALOGI("%s\n", usage1[index]); + } + }else + { + for (index = 0; index < sizeof (usage2)/sizeof (usage2[0]); index++ ) + { + ALOGI("%s\n", usage2[index]); + } + } + exit(EXIT_FAILURE); +} + + +int para_valid_check (P_STP_PARAMS_CONFIG pStpParamConfig) +{ + if ((NULL != pStpParamConfig->pPatchPath) || (NULL != pStpParamConfig->pPatchName)) + { + if (NULL != pStpParamConfig->pPatchPath){ + ALOGI ("MCU patch folder path: %s\n", pStpParamConfig->pPatchPath); + } + if (NULL != pStpParamConfig->pPatchName){ + ALOGI ("MCU patch full path: %s\n", pStpParamConfig->pPatchName); + } + } + else + { + puts ("MCU patch name or patch not found, exit."); + return -1; + } + if(pStpParamConfig->eStpMode != STP_SDIO && pStpParamConfig->eStpMode != STP_UART_MAND && pStpParamConfig->eStpMode != STP_UART_FULL) + { + puts("Stp Mode is not set, common interface use default: SDIO Mode"); + pStpParamConfig->eStpMode = STP_SDIO; + return 0; + } + //SDIO mode: eStpMode = STP_SDIO && (pPachName != NULL || pPatchPath != NULL) + if (pStpParamConfig->eStpMode == STP_SDIO) + { + ALOGI ("Common Interface: SDIO mode\n"); + } + else if (pStpParamConfig->eStpMode == STP_UART_MAND || pStpParamConfig->eStpMode == STP_UART_FULL) + { + //UART mode: (eStpMode = STP_MAND_MODE || STP_FULL_MODE) && (pPachName != NULL || pPatchPath != NULL) && (iBaudrate > 0) + ALOGI ("Common Interface: UART mode\n"); + if (NULL == pStpParamConfig->gStpDev){ + pStpParamConfig->gStpDev = CUST_COMBO_STP_DEV; + ALOGI ("no uart device input, use default: %s\n", pStpParamConfig->gStpDev); + } + if (pStpParamConfig->iBaudrate < 0) + { + //FixMe:Chaozhong, add baudrate validation check + pStpParamConfig->iBaudrate = 4000000; + ALOGI ("no baudrate input, use default: %d\n", pStpParamConfig->iBaudrate); + } + + } + return 0; +} + +static int wmt_cfg_item_parser(char *pItem) +{ + int maxIndex = sizeof (gChipModeInfo) / sizeof (gChipModeInfo[0]); + int index = 0; + int length = 0; + char *str = NULL; + char *keyStr = NULL; + char *valueStr = NULL; + if (NULL == pItem) + { + ALOGI("Warning:pItem is NULL\n"); + return -1; + } + /*all item must be start with mt66xx*/ + str = strstr(pItem, "m"); + if (NULL == str) + { + ALOGI("Warning:no string start with 'm' found in %s\n", pItem); + return -2; + } + + for (index = 0; index < maxIndex; index++) + { + keyStr = (char*)gChipModeInfo[index].antMode.pCfgItem; + + if (0 == strncasecmp(str, keyStr, strlen (keyStr))) + { + str = strstr(str, "="); + if (NULL == str) + { + ALOGI("Warning:no '=' found in %s\n", str); + return -3; + } + str = strstr(str, "m"); + if (NULL == str) + { + ALOGI("Warning:no 'm' found in %s\n", str); + return -4; + } + + + while (((*str)==' ') || ((*str)=='\t') || ((*str)=='\n')) + { + if (str >= pItem + strlen(pItem)) + { + break; + } + str++; + } + valueStr = str; + + while (((*str)!=' ') && ((*str)!='\t') && ((*str)!='\0') && ((*str)!='\n') && ((*str)!='\r')) + { + if (str >= pItem + strlen(pItem)) + { + ALOGI("break\n"); + break; + } + str++; + + } + *str = '\0'; + length = sizeof(gChipModeInfo[index].antMode.cfgItemValue); + strncpy(gChipModeInfo[index].antMode.cfgItemValue, valueStr, length - 1); + gChipModeInfo[index].antMode.cfgItemValue[length - 1] = '\0'; + ALOGI("Info:key:%s value:%s\n", keyStr, gChipModeInfo[index].antMode.cfgItemValue); + break; + } + } + + return 0; +} + +static void set_coredump_flag(void) +{ +#define ANDROID_BUILD_TYPE "ro.build.type" +#define COREDUMP_CTRL_FILE "/data/coredump" + SYS_PROPERTY buildTypeProp; + buildTypeProp.key = ANDROID_BUILD_TYPE; + buildTypeProp.defValue = NULL; + SYS_PROPERTY coredump_mode; + coredump_mode.key = WCN_COMBO_COREDUMP_PROP; + coredump_mode.defValue = NULL; + SYS_PROPERTY aee_property; + aee_property.key = WCN_COMBO_AEE_PROP; + aee_property.defValue = NULL; + int coredumpEnableFlag = 0; + int iRet = -1; + int coredumpFd = -1; + if (gWmtFd < 0) { + ALOGI("%s:invalid wmt fd\n", __func__); + return; + } +#ifndef STATIC_BUILD +#if MTK_WCN_ENABLE_COREDUMP_BY_PROPERTY + iRet = property_get(coredump_mode.key, coredump_mode.value, NULL); + if (0 != iRet) { + ALOGI("key:(%s)-value:(%s)\n", coredump_mode.key, coredump_mode.value); + } else { + ALOGI("get coredump_mode property(%s) failed\n", coredump_mode.key); + iRet = property_set(coredump_mode.key, "0"); + if (0 != iRet) + ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", coredump_mode.key, "0", iRet, errno); + else + ALOGI("set property(%s) default value is %s succeed.\n", coredump_mode.key, "0"); + } + if (0 == strcmp(coredump_mode.value, "1")) { + coredumpEnableFlag = 1; + ALOGI("Connectivity coredump set aee mode: %d\n", coredumpEnableFlag); + } else if (0 == strcmp(coredump_mode.value, "2")) { + coredumpEnableFlag = 2; + ALOGI("Connectivity coredump set stp_dump mode: %d\n", coredumpEnableFlag); + } else { + coredumpEnableFlag = 0; + ALOGI("Connectivity coredump is disabled!\n"); + } + +#else + //read from system property + //iRet = property_get(buildTypeProp.key, buildTypeProp.value, buildTypeProp.defValue); + iRet = 0; + + if (0 != iRet) + { + ALOGI("key:(%s)-value:(%s)\n", buildTypeProp.key, buildTypeProp.value); + if (0 == strcmp(buildTypeProp.value, "eng")) { + coredumpEnableFlag = 1; + ALOGI("Connectivity coredump set default aee mode: %d\n", coredumpEnableFlag); + } else if (0 == strcmp(buildTypeProp.value, "userdebug")) { + iRet = property_get(coredump_mode.key, coredump_mode.value, NULL); + if (0 != iRet) { + ALOGI("key:(%s)-value:(%s)\n", coredump_mode.key, coredump_mode.value); + if (0 == strcmp(coredump_mode.value, "1")) { + coredumpEnableFlag = 1; + ALOGI("Connectivity coredump set aee mode: %d\n", coredumpEnableFlag); + } else if (0 == strcmp(coredump_mode.value, "2")) { + coredumpEnableFlag = 2; + ALOGI("Connectivity coredump set stp_dump mode: %d\n", coredumpEnableFlag); + } else { + coredumpEnableFlag = 0; + ALOGI("Connectivity coredump is disabled!\n"); + } + } else { + ALOGI("get coredump_mode property(%s) failed\n", coredump_mode.key); + coredumpEnableFlag = 0; + ALOGI("Connectivity coredump is disabled!\n"); + } + iRet = property_get(aee_property.key, aee_property.value, NULL); + if (0 != iRet) { + ALOGI("key:(%s)-value:(%s)\n", aee_property.key, aee_property.value); + if (0 == strcmp(aee_property.value, "mtk")) { + coredumpEnableFlag = 1; + ALOGI("Connectivity coredump set aee mode: %d\n", coredumpEnableFlag); + } + } else { + ALOGI("get coredump_mode property(%s) failed\n", coredump_mode.key); + coredumpEnableFlag = 2; + ALOGI("Connectivity coredump set stp_dump mode: %d\n", coredumpEnableFlag); + } + } else { + coredumpEnableFlag = 0; + iRet = property_set(coredump_mode.key, "0"); + if (0 != iRet) + ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", coredump_mode.key, "0", iRet, errno); + else + ALOGI("set property(%s) to %s succeed.\n", coredump_mode.key, "0"); + } + } + else + { + ALOGI("get system build type(%s) failed\n", buildTypeProp.key); + } +#endif +#if 0 + coredumpFd = open(COREDUMP_CTRL_FILE, O_RDWR | O_NOCTTY); + if (coredumpFd >= 0) + { + ALOGI("coredump control file: %s found.\n", COREDUMP_CTRL_FILE); + coredumpEnableFlag = 1; + if (0 == close(coredumpFd)) + { + ALOGI("close %s succeed\n", COREDUMP_CTRL_FILE); + } + else + { + ALOGE("close %s failed, errno:%d\n", COREDUMP_CTRL_FILE, errno); + } + coredumpFd = -1; + } else + { + ALOGI("coredump control file: %s not found, errno:%d.\n", COREDUMP_CTRL_FILE, errno); + } + if (coredumpEnableFlag) +#endif + +#endif + /*set coredump mode to kernel driver*/ + ioctl(gWmtFd, WMT_IOCTL_WMT_COREDUMP_CTRL, coredumpEnableFlag); + return; +} + + +static int get_wmt_cfg (int chipId) +{ +#define WMTCFGFILEPATH "/system/etc/firmware/WMT.cfg" +#define OPENMODE "r" +#define MAXLINELEN 512 + FILE * file = NULL; + int iRet = -1; + char *pStr = NULL; + char line[MAXLINELEN]; + + file = fopen(WMTCFGFILEPATH, OPENMODE); + if (NULL == file) + { + ALOGI("%s cannot be opened, errno:%d\n", WMTCFGFILEPATH, errno); + return -2; + } + iRet = 0; + do { + pStr = fgets(line, MAXLINELEN, file); + if (NULL == pStr) + { + ALOGI("NULL is returned, eighter EOF or error maybe found\n"); + break; + } + + wmt_cfg_item_parser(line); + + memset(line, 0, MAXLINELEN); + + }while (pStr != NULL); + + if (NULL != file) + { + + if (0 == fclose(file)) + { + ALOGI("close %s succeed\n", WMTCFGFILEPATH); + } + else + { + ALOGI("close %s failed, errno:%d\n", WMTCFGFILEPATH, errno); + } + } + return iRet; +} + + +static int get_chip_info_index (int chipId) +{ + + int i = 0; + int index = -1; + + int left = 0; + int middle = 0; + int right = sizeof (gChipModeInfo) / sizeof (gChipModeInfo[0]) - 1; + + if ((chipId < gChipModeInfo[left].chipId) || (chipId > gChipModeInfo[right].chipId)) + return index; + + middle = (left + right) / 2; + + while (left <= right) + { + if (chipId > gChipModeInfo[middle].chipId) + { + left = middle + 1; + } + else if (chipId < gChipModeInfo[middle].chipId) + { + right = middle - 1; + } + else + { + index = middle; + break; + } + middle = (left + right) / 2; + } + + if (0 > index) + ALOGI("no supported chipid found\n"); + else + ALOGI("index:%d, chipId:0x%x\n", index, gChipModeInfo[index].chipId); + + return index; +} + +static int query_chip_id(void) +{ + + int chipId = -1; + int iRet = -1; + SYS_PROPERTY chipIdProp; + //chipIdProp.key = WCN_COMBO_CHIP_ID_PROP; + chipIdProp.defValue = NULL; +#ifndef STATIC_BUILD + //read from system property + iRet = property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue); + if (0 != iRet) + { + chipId = strtoul(chipIdProp.value, NULL, 16); + ALOGI("key:(%s)-value:(%s),chipId:0x%04x\n", chipIdProp.key, chipIdProp.value, chipId); + } + else + { + ALOGI("get chipId property(%s) failed\n", chipIdProp.key); + // we do not return here, use another way to get chip id + } +#else + chipId = 0x7623; +#endif + +#if 1 + //read from config file + if (0 > get_chip_info_index(chipId)) + { + //no wcn.combo.chipid property information found + //get chip id + chipId = ioctl(gWmtFd, WMT_IOCTL_WMT_QUERY_CHIPID, NULL); + if(chipId > 0) + { + ALOGI ("chip id is 0x%x\n", chipId); + ALOGI("chiId:0x%x, setting to property(%s)\n", chipId, chipIdProp.key); +#ifndef STATIC_BUILD + sprintf (chipIdProp.value, "0x%04x", chipId); + iRet = property_set(chipIdProp.key, chipIdProp.value); + if (0 != iRet) + { + ALOGI("set property(%s) to %s failed,iRet:%d, errno:%d\n", chipIdProp.key, chipIdProp.value, iRet, errno); + } + else + { + ALOGI("set property(%s) to %s succeed.\n", chipIdProp.key, chipIdProp.value); + } + + // read again + if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue)) + { + ALOGI("chipIdProp:key(%s)value(%s)\n", chipIdProp.key, chipIdProp.value); + } + else + { + ALOGI("get chipId property failed, errno:%d\n", errno); + chipId = -1; + } +#endif + } + } +#endif + return chipId; +} + + +static int check_chip_id(void) +{ + +#define COMBO_IOC_MAGIC 'h' +#define COMBO_IOCTL_GET_CHIP_ID _IOR(COMBO_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_SET_CHIP_ID _IOW(COMBO_IOC_MAGIC, 1, int) + + int chipId = -1; +#ifdef STATIC_BUILD + SYS_PROPERTY chipIdProp; + chipIdProp.key = WCN_COMBO_CHIP_ID_PROP; + chipIdProp.defValue = NULL; +#endif + int fdHifsdio = -1; + +#ifndef STATIC_BUILD +#if 1 + //read from system property + if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue)) + { + chipId = strtoul(chipIdProp.value, NULL, 16); + ALOGI("key:(%s)-value:(%s),chipId:0x%04x\n", chipIdProp.key, chipIdProp.value, chipId); + } + else + { + ALOGI("get chipId property(%s) failed\n", chipIdProp.key); + // we do not return here, use another way to get chip id + } +#else + /*read from config file*/ + +#endif + +#else + chipId = 0x7623; +#endif + //open HIF-SDIO + fdHifsdio = open("/dev/hifsdiod", O_RDWR | O_NOCTTY); + if (fdHifsdio < 0) + { + ALOGI ("open hifsdiod fail\n"); + return -1; + } + + //read from config file + if (0 > get_chip_info_index(chipId)) + { + //no wcn.combo.chipid property information found + //get chip id + chipId = ioctl(fdHifsdio, COMBO_IOCTL_GET_CHIP_ID, NULL); + ALOGI ("chip id is 0x%x\n", chipId); +#ifndef STATIC_BUILD + //assume we get 0x6628 here + ALOGI("chiId:0x%x, setting to property(%s)\n", chipId, chipIdProp.key); + sprintf (chipIdProp.value, "0x%04x", chipId); + property_set(chipIdProp.key, chipIdProp.value); + ALOGI("set property(%s) to %s done.\n", chipIdProp.key, chipIdProp.value); + // read again + if (0 != property_get(chipIdProp.key, chipIdProp.value, chipIdProp.defValue)) + { + ALOGI("chipIdProp:key(%s)value(%s)\n", chipIdProp.key, chipIdProp.value); + } + else + { + ALOGI("get chipId property failed, errno:%d\n", errno); + chipId = -1; + } +#endif + } + else + { + ioctl(fdHifsdio, COMBO_IOCTL_SET_CHIP_ID, chipId); + ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId); + } + + //close HIF-SDIO + close (fdHifsdio); + fdHifsdio = -1; + + return chipId; +} + +static int setHifInfo(int chipId, char *cfgFilePath) +{ + int index = -1; + index = get_chip_info_index(chipId); + if ((gStpMode <= STP_MIN) || (STP_SDIO < gStpMode)) + { + ALOGI ("STP Mode is not set, fetching default mode...\n"); + + if (0 <= index) + { + gStpMode = gChipModeInfo[index].stpMode; + } + else + { + //gStpMode = STP_UART_FULL; + gStpMode = -1; + } + + } + + if ((0 <= index) && (NULL != cfgFilePath)) + { + memset(gWmtCfgName, 0, sizeof(gWmtCfgName)); + strncpy (gWmtCfgName, cfgFilePath, sizeof(gWmtCfgName) - 1); + gWmtCfgName[sizeof(gWmtCfgName) - 1] = '\0'; + strcat (gWmtCfgName, "/"); + strcat (gWmtCfgName, gChipModeInfo[index].antMode.cfgItemValue); + gWmtCfgName[strlen(cfgFilePath) + strlen("/") + strlen(gChipModeInfo[index].antMode.cfgItemValue)] = '\0'; + #if 0 + ALOGI ("strlen(cfgFilePath):%d, strlen('/'):%d, strlen(gChipModeInfo[index].antMode.cfgItemValue):%d\n", strlen(cfgFilePath),\ + strlen("/"), \ + strlen(gChipModeInfo[index].antMode.cfgItemValue)\ + ); + #endif + } + else + { + memset(gWmtCfgName, 0, sizeof(gWmtCfgName)); + } + ALOGI ("chipId(0x%04x), default Mode(%d), strlen(gWmtCfgName)(%u), wmtCfgFile(%s)\n", chipId, gStpMode, strlen(gWmtCfgName), gWmtCfgName); + return gStpMode; +} + +static void* launcher_pwr_on_chip(void * arg) +{ + int retryCounter = 0; + int i_ret = -1; + int chipid = *(int*) arg; + char readyStr[PROPERTY_VALUE_MAX] = {0}; + int iRet = -1; + + pthread_setname_np(pthread_self(), "pwr_on_conn"); + + ALOGI("enter power on connsys flow"); + do { + i_ret = ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 1); + if (0 == i_ret){ + break; + } else { + ioctl(gWmtFd, WMT_IOCTL_LPBK_POWER_CTRL, 0); + ALOGI("power on %x failed, retrying, retry counter:%d\n", chipid, retryCounter); + usleep(1000000); + } + retryCounter++; + }while (retryCounter < 20); + + pthread_detach(thread_handle); + thread_handle = -1; + + return NULL; +} +static void* launcher_set_fwdbg_flag(void * arg) +{ + int i_ret = -1; + int flag = *(int*) arg; + + pthread_setname_np(pthread_self(), "dump_fwemi_log"); + ALOGI("dump firmware dbg log from emi buffer "); + i_ret = ioctl(gWmtFd, WMT_IOCTL_FW_DBGLOG_CTRL, flag); + if (i_ret < 0) { + ALOGI("ioctl error: err msg: %s\n", strerror(errno)); + pthread_detach(thread_handle); + thread_handle = -1; + } + return NULL; +} + +/* + * -m: mode (SDIO/UART) + * -d: uart device node + * -b: baudrate + * -c: enable SW FC or not + * -p: patch folder path + * -n: patch file name (fullpath) + * + */ +int main(int argc, char *argv[]) +{ + static const char *opString = "m:d:b:c:p:n:?"; + struct uart_t *u = NULL; + int opt, ld, err; + int baud = 0; + struct sigaction sa; + struct pollfd fds[2]; + int fd_num = 0; + int len = 0; + int uartFcCtrl = 0; + int argCount = 0; + int chipId = -1; + int i_ret = 1; + int retry = 0; + int polling_flag = 0; + int dynamicdump_flag = 0; + int dump_retry = 0; + int fwdbgEnableFlag = 0; + char readyStr[PROPERTY_VALUE_MAX] = {0}; + STP_PARAMS_CONFIG sStpParaConfig; + char fwStateStr0[PROPERTY_VALUE_MAX] = {0}; + char fwStateStr[PROPERTY_VALUE_MAX] = "no"; + char dynamicDump0[PROPERTY_VALUE_MAX] = {0}; + char dynamicDump[PROPERTY_VALUE_MAX] = {0}; + +#ifndef STATIC_BUILD + do { + i_ret = property_get(WCN_DRIVER_READY_PROP, readyStr, NULL); + if (0 >= i_ret) { + ALOGI("get property(%s) failed i_ret:%d\n", WCN_DRIVER_READY_PROP, i_ret); + } else { + ALOGI("get property(%s) is %s\n", WCN_DRIVER_READY_PROP, readyStr); + if (!strcmp(readyStr, "yes")) + break; + } + usleep(300000); + } while (1); +#endif + + do { + gWmtFd = open(CUST_COMBO_WMT_DEV, O_RDWR | O_NOCTTY); + if (gWmtFd < 0) { + ALOGI("Can't open device node(%s) error:%d \n", CUST_COMBO_WMT_DEV,gWmtFd); + usleep(300000); + } + else + break; + }while(1); + ALOGE("open device node succeed.(Node:%s, fd:%d) \n", CUST_COMBO_WMT_DEV, gWmtFd); + + do{ + chipId = query_chip_id(); + if(0 > chipId) + { + usleep(300000); + chipId = ioctl(gWmtFd,WMT_IOCTL_WMT_QUERY_CHIPID,NULL); + ALOGI("chiId from kernel by ioctl:0x%04x\n", chipId); + if(-1 != chipId) + break; + }else + break; + }while(1); + ALOGI("chiId:0x%04x\n", chipId); + + if((0x0321 == chipId) || (0x0335 == chipId) || (0x0337 == chipId)) + { + chipId = 0x6735; + ALOGI("for denali chipid convert\n"); + } + if (0x0326 == chipId) + { + chipId = 0x6755; + ALOGI("for jade chipid convert\n"); + } + if ((0x6735 == chipId) || (0x6752 == chipId) || (0x6582 == chipId) || (0x6592 == chipId) + || (0x6572 == chipId) || (0x6571 == chipId) || (0x8127 == chipId) + || (0x8163 == chipId) || (0x6580 == chipId) || (0x6755 == chipId) || (0x6797 == chipId) || (0x7623 == chipId) ) { + ALOGI("run SOC chip flow\n"); + gStpMode = STP_BTIF_FULL; + memset(gPatchFolder, 0, sizeof(gPatchFolder)); + + opt = getopt(argc, argv, opString); + while (opt != -1) + { + switch (opt) + { + case 'm': + gStpMode = atoi(optarg); + sStpParaConfig.eStpMode = gStpMode; + ALOGI("stpmode[%d]\n",gStpMode); + break; + case 'p': + //gPatchFolder = optarg; + strcpy(gPatchFolder, optarg); + sStpParaConfig.pPatchPath = gPatchFolder; + break; + case '?': + default: + display_usage(chipId); + break; + } + opt = getopt(argc, argv, opString); + } + /* send default patch file name path to driver */ + ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName); + /* set fm mode & stp mode*/ + ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((gFmMode & 0x0F) << 4) |(gStpMode & 0x0F)); +#ifndef WMT_PLAT_APEX + set_coredump_flag(); +#endif + }else + { + ALOGI("run combo chip flow\n"); + sStpParaConfig.pPatchPath = NULL; + sStpParaConfig.pPatchName = NULL; + sStpParaConfig.gStpDev = NULL; + sStpParaConfig.eStpMode = -1; + sStpParaConfig.iBaudrate = -1; + sStpParaConfig.sUartConfig.fc = UART_DISABLE_FC; + sStpParaConfig.sUartConfig.parity = 0; + sStpParaConfig.sUartConfig.stop_bit = 0; + + /*Default parameters starts*/ + baud = 4000000; + gStpMode = -1; + uartFcCtrl = UART_DISABLE_FC; + strncpy(gStpDev, CUST_COMBO_STP_DEV, sizeof(gStpDev) - 1); + gStpDev[sizeof(gStpDev) - 1] = '\0'; + memset(gPatchFolder, 0, sizeof(gPatchFolder)); + memset(gPatchName, 0, sizeof(gPatchName)); + /*Default parameters ends*/ + + opt = getopt(argc, argv, opString); + while (opt != -1) + { + switch (opt) + { + case 'm': + gStpMode = atoi(optarg); + sStpParaConfig.eStpMode = gStpMode; + break; + case 'd': + strncpy(gStpDev, optarg, sizeof(gStpDev) - 1); + gStpDev[sizeof(gStpDev) - 1] = '\0'; + sStpParaConfig.gStpDev = gStpDev; + break; + case 'b': + baud = atoi(optarg); + sStpParaConfig.iBaudrate = baud; + break; + case 'c': + uartFcCtrl = atoi(optarg); + sStpParaConfig.sUartConfig.fc = uartFcCtrl; + ALOGI("c found\n"); + break; + case 'p': + //gPatchFolder = optarg; + strcpy(gPatchFolder, optarg); + sStpParaConfig.pPatchPath = gPatchFolder; + break; + case 'n': + //gPatchName = optarg; + strcpy(gPatchName, optarg); + sStpParaConfig.pPatchName = gPatchName; + break; + case '?': + default: + display_usage(chipId); + break; + } + opt = getopt(argc, argv, opString); + } +#if 0 + ALOGI ("argc = %d, optind= %d\n", argc, optind); + { + int i = 0; + for (i = 0; i < argc; i++) + { + ALOGI("arg[%d] = %s\n", i, argv[i]); + } + } +#endif + + + if (0 > get_chip_info_index(chipId)) + { + ALOGI("invalid chip, check again\n"); + chipId = query_chip_id(); + ALOGI("chiId:0x%04x\n", chipId); + } + + ioctl(gWmtFd, WMT_IOCTL_WMT_TELL_CHIPID, chipId); + ALOGI("set chipId(0x%x) to HIF-SDIO module\n", chipId); + + get_wmt_cfg(chipId); + + setHifInfo(chipId, sStpParaConfig.pPatchPath); + ALOGI("HifConfig:0x%04x, wmtCfgFile:%s\n", sStpParaConfig.eStpMode, gWmtCfgName); +#ifndef WMT_PLAT_APEX + set_coredump_flag(); +#endif + if (0 != para_valid_check(&sStpParaConfig)) + { + //Try to use custom method to check parameters + if (argc > optind)//argv[optind] + { + // For this competible usage , we only left STP mode set and firmware patch input, omit flowcontrol set + //First baud for STP UART mode, otherwise, SDIO mode + baud = atoi(argv[optind]); + if (baud >= CUST_BAUDRATE_DFT) { + ALOGI("get baud rate(%d) for UART mode\n", baud); + gStpMode = STP_UART_FULL; + sStpParaConfig.iBaudrate = baud; + } + else if (baud == 1){ + ALOGI("Definitively use SDIO mode\n"); + gStpMode = STP_SDIO; + } + else { + ALOGI("invalid baud rate(%d) for UART, use SDIO mode\n", baud); + gStpMode = STP_SDIO; + } + sStpParaConfig.eStpMode = gStpMode; + + //Firmare patch analysis + optind++; + memset(gPatchName, 0, sizeof(gPatchName)); + if (argc > optind) + { + strncat(gPatchName, argv[optind], sizeof(gPatchName)-1); + sStpParaConfig.pPatchName = gPatchName; + ALOGI("PatchFile:%s\n", sStpParaConfig.pPatchName); + } + else + { + sStpParaConfig.pPatchName = NULL; + ALOGI("no patch file \n"); + } + //Flow Control analysis + optind++; + if (argc > optind) + { + uartFcCtrl = atoi(argv[optind]); + sStpParaConfig.sUartConfig.fc = uartFcCtrl; + ALOGI("flowcontrol flag: %d\n", sStpParaConfig.sUartConfig.fc); + } + else + { + ALOGI("no flow control flat set\n"); + } + + } + } + if (0 != para_valid_check(&sStpParaConfig)) + { + display_usage(chipId); + } + + /* send default patch file name path to driver */ + ioctl(gWmtFd, WMT_IOCTL_SET_PATCH_NAME, gPatchName); + /* send uart name to driver*/ + if (sStpParaConfig.gStpDev) { + gUartName = strstr(sStpParaConfig.gStpDev, "tty"); + if (!gUartName) { + ALOGI("no uart name found in %s\n", sStpParaConfig.gStpDev); + } else { + ALOGI("uart name %s\n", gUartName); + } + } + + if (!gUartName) { + gUartName = "ttyMT2"; + ALOGI("use default uart %s\n", gUartName); + } + + ioctl(gWmtFd, WMT_IOCTL_PORT_NAME, gUartName); + + /* send hardware interface configuration to driver */ + ioctl(gWmtFd, WMT_IOCTL_SET_STP_MODE, ((baud & 0xFFFFFF) << 8) | ((gFmMode & 0x0F) << 4) |(gStpMode & 0x0F)); + + /* send WMT config name configuration to driver */ + ioctl(gWmtFd, WMT_IOCTL_WMT_CFG_NAME, gWmtCfgName); + } + + ioctl(gWmtFd, WMT_IOCTL_SET_LAUNCHER_KILL, 0); + + i_ret = ioctl(gWmtFd, WMT_IOCTL_GET_APO_FLAG, NULL); + if (i_ret != 0) { + if (pthread_create(&thread_handle, NULL, launcher_pwr_on_chip, &chipId)) { + ALOGE("create pwr on thread fail\n"); + } else { + ALOGI("create pwr on thread ok\n"); + } + } else { + ALOGI("no supported always power on\n"); + } + /*set signal handler*/ + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = sig_hup; + sigaction(SIGHUP, &sa, NULL); + + + fds[0].fd = gWmtFd; /* stp_wmt fd */ + fds[0].events = POLLIN | POLLRDNORM; /* wait read events */ + ++fd_num; + +#ifndef STATIC_BUILD + i_ret = property_get(WCN_FW_DBG_LOG_PROP, fwStateStr0, NULL); + if (0 >= i_ret) { + ALOGI("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, i_ret); + } else + ALOGI("get property fwStateStr0 (%s) is %s\n", WCN_FW_DBG_LOG_PROP, fwStateStr0); + i_ret = property_get(WCN_DYNAMIC_DUMP_PROP, dynamicDump0, NULL); + if (0 >= i_ret) { + ALOGI("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, i_ret); + } else + ALOGI("get property dynamicDump0 (%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump0); +#endif + +#if 0 //does this part needed?, no uart device is opened at this time. + if (gStpMode == STP_UART_FULL) { + fds[1].fd = gTtyFd; /* real tty fd */ + fds[1].events = POLLERR | POLLHUP; /* POLLERR | POLLHUP is unnecessary? */ + ++fd_num; + } +#endif + + + while (!__io_canceled) { + fds[0].revents = 0; +#if 0 //does this part needed?, do we need to poll on uart? + if (gStpMode == STP_UART_FULL) { + fds[1].revents = 0; + } +#endif + err = poll(fds, fd_num, 2000); // 5 seconds + if (err < 0) { + if (errno == EINTR) { + continue; + } + else { + ALOGI("poll error:%d errno:%d, %s\n", err, errno, strerror(errno)); + break; + } + } + else if (!err) { + continue; + } +#if 0 //does this part needed?, do we need to poll on uart? + if (gStpMode == STP_UART_FULL) { + if (fds[1].revents & (POLLERR | POLLHUP)) { + ALOGI("poll result: pa[1].revents:0x%x\n", fds[1].revents); + break; + } + } +#endif + if (fds[0].revents & POLLIN) { + memset(gCmdStr, 0, sizeof(gCmdStr)); + len = read(gWmtFd, gCmdStr, sizeof(gCmdStr)-1); + if (len > 0 && len < (int)sizeof(gCmdStr)) { + //printf ("POLLIN(%d) and read(%d)\n", gWmtFd, len); + } + else { + ALOGI("POLLIN(%d) but read fail:%d\n", gWmtFd, len); + continue; + } + gCmdStr[len] = '\0'; + //ALOGI("rx_cmd_str:%s\n", gCmdStr); + err = handle_cmd(&sStpParaConfig, gCmdStr, len); + if (!err) { + //ALOGI("handle_cmd(%s), respond ok \n", gCmdStr); + snprintf(gRespStr, sizeof(gRespStr), "ok"); + } + else { + if (err == 1) { + snprintf(gRespStr, sizeof(gRespStr), "cmd not found"); + } + else { + snprintf(gRespStr, sizeof(gRespStr), "resp_%d", err); + } + } + ALOGI("cmd(%s) resp(%s)\n", gCmdStr, gRespStr); + len = write(gWmtFd, gRespStr, strlen(gRespStr)); + if (len != (int)strlen(gRespStr)) { + fprintf(stderr, "write resp(%d) fail: len(%d), errno(%d, %s)\n", gWmtFd, len, errno, (len == -1) ? strerror(errno) : ""); + } + } +#if 0 + if (polling_flag == 0) { + if (retry++ <= 5) { +#ifndef STATIC_BUILD + i_ret = property_get(WCN_FW_DBG_LOG_PROP, fwStateStr, NULL); + if (0 >= i_ret) { + ALOGI("get property(%s) failed ret:%d\n", WCN_FW_DBG_LOG_PROP, i_ret); + } else { + ALOGI("get property(%s) is %s\n", WCN_FW_DBG_LOG_PROP, fwStateStr); + if (strcmp(fwStateStr, fwStateStr0)) + polling_flag = 1; + } +#else + polling_flag =1; +#endif + } + } + if (polling_flag == 1 || retry == 6) { + ALOGI("polling_flag:%d, retry: %d\n", polling_flag, retry); + if (!strcmp(fwStateStr, "yes")) { + fwdbgEnableFlag = 1; + i_ret = pthread_create(&thread_handle, NULL, launcher_set_fwdbg_flag, &fwdbgEnableFlag); + if (i_ret) { + ALOGE("create enable firmware dbglog thread fail\n"); + } else + ALOGI("create enable firmware dbglog thread ok\n"); + } else { + i_ret = ioctl(gWmtFd, WMT_IOCTL_FW_DBGLOG_CTRL, fwdbgEnableFlag); + if (i_ret < 0) + ALOGI("ioctl error: err msg: %s\n", strerror(errno)); + } + } + +#ifndef STATIC_BUILD + if (dynamicdump_flag == 0) { + if (dump_retry++ <= 5) { + i_ret = property_get(WCN_DYNAMIC_DUMP_PROP, dynamicDump, NULL); + if (0 >= i_ret) { + ALOGI("get property(%s) failed ret:%d\n", WCN_DYNAMIC_DUMP_PROP, i_ret); + } else { + ALOGI("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump); + if (strcmp(dynamicDump, dynamicDump0)) + dynamicdump_flag = 1; + } + } + } + if (dynamicdump_flag == 1) { + ALOGI("dynamicdump_flag:%d, dump_retry: %d\n", dynamicdump_flag, dump_retry); + ALOGI("get property(%s) is %s\n", WCN_DYNAMIC_DUMP_PROP, dynamicDump); + i_ret = ioctl(gWmtFd, WMT_IOCTL_DYNAMIC_DUMP_CTRL, dynamicDump); + if (i_ret < 0) + ALOGI("ioctl error: err msg: %s\n", strerror(errno)); + } +#endif + +#endif + } + +clean_up: + + if (gWmtFd >= 0) { + close(gWmtFd); + gWmtFd = -1; + } + + if (gStpMode == STP_UART_FULL && gTtyFd >= 0) { + /* Restore TTY line discipline */ + ld = N_TTY; + if (ioctl(gTtyFd, TIOCSETD, &ld) < 0) { + ALOGE("Can't restore line discipline"); + exit(1); + } + + close(gTtyFd); + gTtyFd = -1; + } + + return 0; +} + diff --git a/utils/wmt/src/wmt_ioctl.h b/utils/wmt/src/wmt_ioctl.h new file mode 100755 index 0000000000000..78d7f258c9e94 --- /dev/null +++ b/utils/wmt/src/wmt_ioctl.h @@ -0,0 +1,27 @@ +#ifndef _WMT_IOCTL_H_ +#define _WMT_IOCTL_H_ + +#include + +#define WMT_IOC_MAGIC 0xa0 +#define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC,4,char*) +#define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC,5,int) +#define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC,6,int) +#define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC,7,int) +#define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC,8,char*) +#define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC,12,int) +#define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC,13,int) +#define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC,14,int) +#define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC,15,char*) +#define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*) +#define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*) +#define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int) +#define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int) +#define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int) +#define WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC,25,char*) +#define WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC,26,char*) +#define WMT_IOCTL_GET_APO_FLAG _IOR(WMT_IOC_MAGIC, 28, int) +#define WMT_IOCTL_FW_DBGLOG_CTRL _IOR(WMT_IOC_MAGIC, 29, int) +#define WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, char*) + +#endif diff --git a/utils/wmt/src/wmt_loader b/utils/wmt/src/wmt_loader new file mode 100755 index 0000000000000..63d0ff32d09f8 Binary files /dev/null and b/utils/wmt/src/wmt_loader differ diff --git a/utils/wmt/src/wmt_loader.c b/utils/wmt/src/wmt_loader.c new file mode 100755 index 0000000000000..36ff5a6c7b0c1 --- /dev/null +++ b/utils/wmt/src/wmt_loader.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +//For directory operation +#include + +#include + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "wmt_loader" + +#define WCN_COMBO_LOADER_DEV "/dev/wmtdetect" + +#define WMT_DETECT_IOC_MAGIC 'w' +#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_DETECT_IOC_MAGIC, 1, int) +#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_DETECT_IOC_MAGIC, 2, int) +#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 3, int) +#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_DETECT_IOC_MAGIC, 4, int) +#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_DETECT_IOC_MAGIC, 5, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_DETECT_IOC_MAGIC, 6, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_DETECT_IOC_MAGIC, 7, int) +#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_DETECT_IOC_MAGIC, 8, int) + + +static int gLoaderFd = -1; + +int main(int argc, char *argv[]) +{ + int iRet = -1; + int chipId = -1; + int count = 0; + int gLoaderFd = -1; + + printf("init combo device\r\n"); + do{ + gLoaderFd = open(WCN_COMBO_LOADER_DEV, O_RDWR | O_NOCTTY); + if(gLoaderFd < 0) + { + count ++; + printf("Can't open device node(%s) count(%d)\n", WCN_COMBO_LOADER_DEV,count); + usleep(300000); + } else + break; + } while(1); + + printf("Opened combo device\r\n"); + + // Get Device ID + chipId = ioctl(gLoaderFd, COMBO_IOCTL_GET_SOC_CHIP_ID, NULL); + printf("get device id : %d\r\n", chipId); + if( chipId == -1) { + printf("invalid device id, exit\r\n"); + return -1; + } + + // Set Device ID + iRet = ioctl(gLoaderFd, COMBO_IOCTL_SET_CHIP_ID, chipId); + printf("set device id : %d\r\n", chipId); + if( iRet < 0 ) { + printf("failed to set device id\r\n"); + return -1; + } + + // do module init + iRet = ioctl(gLoaderFd, COMBO_IOCTL_DO_MODULE_INIT, chipId); + printf("do module init: %d\r\n", chipId); + if( iRet < 0 ) { + printf("failed to init module \r\n"); + return -1; + } + + return 0; +} diff --git a/utils/wmt/src/wmt_loopback b/utils/wmt/src/wmt_loopback new file mode 100755 index 0000000000000..8d62a5dfcd798 Binary files /dev/null and b/utils/wmt/src/wmt_loopback differ diff --git a/utils/wmt/src/wmt_loopback.c b/utils/wmt/src/wmt_loopback.c new file mode 100755 index 0000000000000..f08818031245a --- /dev/null +++ b/utils/wmt/src/wmt_loopback.c @@ -0,0 +1,320 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ +#include "wmt_ioctl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include /* struct serial_struct */ + +#define LEN_MAX 1024 + +typedef enum { + LEN_FIXED = 0, + LEN_INC = 1, + LEN_DEC = 2, + LEN_RAND = 3, + COMBO_POWER_ON = 4, + COMBO_POWER_OFF = 5, + ADIE_LPK = 6, + LPBK_OP_MAX +} LPBK_OP_ENUM; + +unsigned char WMT_TEST_LPBK_CMD[] = {0x1, 0x2, 0x0, 0x0, 0x7}; +unsigned char WMT_TEST_LPBK_EVT[] = {0x2, 0x2, 0x0, 0x0, 0x0}; +/* +unsigned char out_buf[2048] = {0}; +unsigned char in_buf[2048] = {0}; +*/ +struct lpbk_package{ + long payload_length; + unsigned char out_payload[2048]; + unsigned char in_payload[2048]; +}; + +static int wmt_loopback(int type, int count, int max, int delay) { + ssize_t s_result = 0; + int wmt_fd; + int ret = -1; + int loop = 0; + int offset; + unsigned short buf_length = 0; + unsigned short len_in_cmd; + struct lpbk_package lpbk_buffer; + printf("*type(%d) count(%d) max(%d) \n", type, count, max); + + if(type >= LPBK_OP_MAX){ + printf("[%s] cannot support %d opeartion\n", __FUNCTION__, type); + return -1; + } + + /* open wmt dev */ + wmt_fd = open("/dev/stpwmt", O_RDWR | O_NOCTTY); + if (wmt_fd < 0) { + printf("[%s] Can't open stpwmt \n", __FUNCTION__); + return -1; + } + + if(type == COMBO_POWER_ON){ + printf("[power on combo chip]\n"); + if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1) != 0) + { + printf("[%s] power on combo chip failed\n", __FUNCTION__); + close(wmt_fd); + wmt_fd = -1; + return -1; + } else { + close(wmt_fd); + printf("[power on combo chip ok!]\n"); + } + return 0; + } + + if(type == COMBO_POWER_OFF){ + printf("[power off combo chip]\n"); + if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 0) != 0) + { + printf("[%s] power off combo chip failed\n", __FUNCTION__); + close(wmt_fd); + ret = -1; + } else { + close(wmt_fd); + printf("[power off combo chip ok!]\n"); + } + return 0; + } + + /*turn LPBK function on*/ + printf("[power on combo chip]\n"); + if(ioctl(wmt_fd, WMT_IOCTL_LPBK_POWER_CTRL, 1) != 0) + { + printf("[%s] Can't power on combo chip ok! failed\n", __FUNCTION__); + close(wmt_fd); + wmt_fd = -1; + return -1; + } else { + printf("[power on combo chip ok!]\n"); + } + + /* init length */ + switch (type) { + case LEN_FIXED: + buf_length = (unsigned short)max; + break; + case LEN_INC: + buf_length = 1; + break; + case LEN_DEC: + buf_length = max; + break; + default: + /* random */ + break; + } + + if( (type >= LEN_FIXED) && (type <= LEN_RAND) ) + { + for (loop = 0; loop < count; loop++) { + //<1> init buffer + memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package)); + lpbk_buffer.payload_length = buf_length; + for (offset = 0; offset < buf_length; offset++) { + lpbk_buffer.out_payload[offset] = (offset + 1)/*for test use: begin from 1*/ & 0xFF; + } + + /*<2> do LPBK*/ + usleep(delay * 1000); + + if(( ret = ioctl(wmt_fd, WMT_IOCTL_LPBK_TEST, &lpbk_buffer)) != lpbk_buffer.payload_length){ + printf("[%s] LPBK operation failed, return length = %d\n", __FUNCTION__, ret); + break; + } + + /*<3> compare result*/ + if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) { + printf("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __FUNCTION__); + break; + } + printf("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld) \n", __FUNCTION__, loop, lpbk_buffer.payload_length); + + /*<4> update buffer length */ + switch (type) { + case LEN_INC: + buf_length = (buf_length == max) ? 1 : buf_length + 1; + break; + case LEN_DEC: + buf_length = (buf_length == 1) ? max : buf_length - 1; + break; + case LEN_RAND: + buf_length = rand() % max + 1; + break; + default: + /* no change */ + break; + } + } + } + else if( type == ADIE_LPK ) + { + int adie_chipID = 0; + for (loop = 0; loop < count; loop++) { + //<1> init buffer + memset((void *)&lpbk_buffer, 0, sizeof(struct lpbk_package)); + adie_chipID = 0; + + /*<2> do LPBK*/ + usleep(delay * 1000); + + if(( ret = ioctl(wmt_fd, WMT_IOCTL_ADIE_LPBK_TEST, &lpbk_buffer)) != 2){ + printf("[%s] ADIE_LPK operation failed, return length = %d\n", __FUNCTION__, ret); + break; + } + adie_chipID = ((lpbk_buffer.out_payload[1] >> 4) & 0xf)*1000 + + (lpbk_buffer.out_payload[1] & 0xf)*100 + + ((lpbk_buffer.out_payload[0] >> 4) & 0xf)*10 + + (lpbk_buffer.out_payload[0] & 0xf); + + /*<3> compare result*/ + if ( adie_chipID != max ) { + printf("[%s] ADIE_LPK payload compare error\n", __FUNCTION__); + break; + } + printf("[%s] exec ADIE_LPK succeed(loop = %d, ChipID = %d) \n", __FUNCTION__, + loop, adie_chipID); + } + } + + /*Not to power off chip on default, please manually to do this*/ +#if 0 + /*turn off LPBK function*/ + if(ioctl(wmt_fd, 7, 0) != 0) + { + printf("[%s] turn lpbk function off failed\n", __FUNCTION__); + ret = -1; + } + else + { + ret = 0; + } +#endif + ret = 0; + +end: + if (loop != count) { + printf("fail at loop(%d) buf_length(%d)\n", loop, buf_length); + } + + /* close wmt dev */ + if (wmt_fd >= 0) { + close(wmt_fd); + } + + return ret; +} +static void print_usage(void) +{ + unsigned int usage_lines = 0; + static char *(usage[]) = { + "6620_wmt_lpbk type count length delay", + " --type: essential", + " -0: loopback test with fixed packet length", + " -1: loopback test with packet length increase 1 per packet based on 1", + " -2: loopback test packet length decrease 1 per packet based on 1024", + " -3: loopback test with random packet length", + " -4: only turn loopback function on without test", + " -5: only turn loopback function off without test", + " -6: loopback test spi bus by get Adie chpid in SOC chip", + " --count: optional, total packet count, 1000 by default", + " --length: optional, 1 ~ 1024, 1024 by default", + " --delay: optional, interval between packets (ms), 0 by default", + + }; + for (usage_lines = 0 ; usage_lines < sizeof (usage)/sizeof(usage[0]); usage_lines++) + { + printf("%s\n", usage[usage_lines]); + } +} + +int main(int argc, char *argv[]) +{ + int type = LEN_FIXED; + int count = 1000; + int length = 1024; + int delay = 0; + if(argc <= 1) + { + printf ("Error lack of arguments\n"); + print_usage(); + return -1; + } + + if ((argc > 1) && (argv[1] != NULL)) { + printf("type: argv[1] %s %d\n", argv[1], atoi(argv[1])); + type = atoi(argv[1]); + } + + if ((argc > 2) && (argv[2] != NULL)) { + printf("count: argv[2] %s %d\n", argv[2], atoi(argv[2])); + count = atoi(argv[2]); + } + + if ((argc > 3) && (argv[3] != NULL)) { + printf("count: argv[3] %s %d\n", argv[3], atoi(argv[3])); + length = atoi(argv[3]); + if (0 == length) { + printf("length is zero, reset default value 1024\n"); + length = 1024; + } + } + + if ((argc > 4) && (argv[4] != NULL)) { + printf("count: argv[4] %s %d\n", argv[4], atoi(argv[4])); + delay = atoi(argv[4]); + } + return wmt_loopback(type, count, length, delay); +} + diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c index a3f18d3623661..d7fd46fe9efb3 100644 --- a/virt/kvm/arm/hyp/vgic-v2-sr.c +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c @@ -34,11 +34,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base) else elrsr1 = 0; -#ifdef CONFIG_CPU_BIG_ENDIAN - cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1; -#else cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0; -#endif } static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base) diff --git a/virt/kvm/arm/mmio.c b/virt/kvm/arm/mmio.c index b6e715fd3c90a..dac7ceb1a6777 100644 --- a/virt/kvm/arm/mmio.c +++ b/virt/kvm/arm/mmio.c @@ -112,7 +112,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) } trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, - data); + &data); data = vcpu_data_host_to_guest(vcpu, data, len); vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); } @@ -182,14 +182,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), len); - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data); kvm_mmio_write_buf(data_buf, len, data); ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, data_buf); } else { trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len, - fault_ipa, 0); + fault_ipa, NULL); ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len, data_buf); diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index b36945d49986d..9dea96380339f 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -509,8 +509,6 @@ static void unmap_hyp_range(pgd_t *pgdp, phys_addr_t start, u64 size) */ void free_hyp_pgds(void) { - unsigned long addr; - mutex_lock(&kvm_hyp_pgd_mutex); if (boot_hyp_pgd) { @@ -521,10 +519,10 @@ void free_hyp_pgds(void) if (hyp_pgd) { unmap_hyp_range(hyp_pgd, hyp_idmap_start, PAGE_SIZE); - for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) - unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE); - for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) - unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE); + unmap_hyp_range(hyp_pgd, kern_hyp_va(PAGE_OFFSET), + (uintptr_t)high_memory - PAGE_OFFSET); + unmap_hyp_range(hyp_pgd, kern_hyp_va(VMALLOC_START), + VMALLOC_END - VMALLOC_START); free_pages((unsigned long)hyp_pgd, hyp_pgd_order); hyp_pgd = NULL; @@ -1312,7 +1310,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, return -EFAULT; } - if (is_vm_hugetlb_page(vma) && !logging_active) { + if (vma_kernel_pagesize(vma) == PMD_SIZE && !logging_active) { hugetlb = true; gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT; } else { diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c index b7baf581611ae..99e026d2dade9 100644 --- a/virt/kvm/arm/vgic/vgic-irqfd.c +++ b/virt/kvm/arm/vgic/vgic-irqfd.c @@ -112,8 +112,7 @@ int kvm_vgic_setup_default_irq_routing(struct kvm *kvm) u32 nr = dist->nr_spis; int i, ret; - entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry), - GFP_KERNEL); + entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 547f12dc4d543..59ce2fb498211 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -393,6 +393,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu) int ret = 0; u32 *intids; int nr_irqs, i; + u8 pendmask; nr_irqs = vgic_copy_lpi_list(vcpu, &intids); if (nr_irqs < 0) @@ -400,7 +401,6 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu) for (i = 0; i < nr_irqs; i++) { int byte_offset, bit_nr; - u8 pendmask; byte_offset = intids[i] / BITS_PER_BYTE; bit_nr = intids[i] % BITS_PER_BYTE; @@ -775,6 +775,8 @@ static int vgic_its_alloc_collection(struct vgic_its *its, return E_ITS_MAPC_COLLECTION_OOR; collection = kzalloc(sizeof(*collection), GFP_KERNEL); + if (!collection) + return -ENOMEM; collection->collection_id = coll_id; collection->target_addr = COLLECTION_NOT_MAPPED; diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c index 96ea597db0e77..502f2100e7bfa 100644 --- a/virt/kvm/arm/vgic/vgic-v3.c +++ b/virt/kvm/arm/vgic/vgic-v3.c @@ -324,13 +324,13 @@ int vgic_v3_save_pending_tables(struct kvm *kvm) int last_byte_offset = -1; struct vgic_irq *irq; int ret; + u8 val; list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { int byte_offset, bit_nr; struct kvm_vcpu *vcpu; gpa_t pendbase, ptr; bool stored; - u8 val; vcpu = irq->target_vcpu; if (!vcpu) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9deb5a245b830..2447d7c017e70 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -136,6 +136,11 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm); static unsigned long long kvm_createvm_count; static unsigned long long kvm_active_vms; +__weak void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, + unsigned long start, unsigned long end) +{ +} + bool kvm_is_reserved_pfn(kvm_pfn_t pfn) { if (pfn_valid(pfn)) @@ -361,6 +366,9 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, kvm_flush_remote_tlbs(kvm); spin_unlock(&kvm->mmu_lock); + + kvm_arch_mmu_notifier_invalidate_range(kvm, start, end); + srcu_read_unlock(&kvm->srcu, idx); } @@ -4010,7 +4018,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, if (!vcpu_align) vcpu_align = __alignof__(struct kvm_vcpu); kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, vcpu_align, - 0, NULL); + SLAB_ACCOUNT, NULL); if (!kvm_vcpu_cache) { r = -ENOMEM; goto out_free_3;